diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:02:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:02:28 +0000 |
commit | 7442d6faa2719e4e7d33a7021c406c5a4facd74d (patch) | |
tree | c72b9241553fc9966179aba84f90f17bfa9235c3 /tools/clang-format | |
parent | b52119637f743680a99710ce5fdb6646da2772af (diff) | |
download | src-7442d6faa2719e4e7d33a7021c406c5a4facd74d.tar.gz src-7442d6faa2719e4e7d33a7021c406c5a4facd74d.zip |
Vendor import of clang trunk r300422:vendor/clang/clang-trunk-r300422
Notes
Notes:
svn path=/vendor/clang/dist/; revision=317019
svn path=/vendor/clang/clang-trunk-r300422/; revision=317020; tag=vendor/clang/clang-trunk-r300422
Diffstat (limited to 'tools/clang-format')
-rw-r--r-- | tools/clang-format/ClangFormat.cpp | 38 | ||||
-rw-r--r-- | tools/clang-format/clang-format-test.el | 126 | ||||
-rw-r--r-- | tools/clang-format/clang-format.el | 25 |
3 files changed, 170 insertions, 19 deletions
diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp index 6c50daf53834..ac0d0a8512f4 100644 --- a/tools/clang-format/ClangFormat.cpp +++ b/tools/clang-format/ClangFormat.cpp @@ -236,8 +236,15 @@ static void outputReplacementsXML(const Replacements &Replaces) { // Returns true on error. static bool format(StringRef FileName) { + if (!OutputXML && Inplace && FileName == "-") { + errs() << "error: cannot use -i when reading from stdin.\n"; + return false; + } + // On Windows, overwriting a file with an open file mapping doesn't work, + // so read the whole file into memory when formatting in-place. ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = - MemoryBuffer::getFileOrSTDIN(FileName); + !OutputXML && Inplace ? MemoryBuffer::getFileAsStream(FileName) : + MemoryBuffer::getFileOrSTDIN(FileName); if (std::error_code EC = CodeOrErr.getError()) { errs() << EC.message() << "\n"; return true; @@ -249,12 +256,18 @@ static bool format(StringRef FileName) { if (fillRanges(Code.get(), Ranges)) return true; StringRef AssumedFileName = (FileName == "-") ? AssumeFileName : FileName; - FormatStyle FormatStyle = + + llvm::Expected<FormatStyle> FormatStyle = getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer()); + if (!FormatStyle) { + llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n"; + return true; + } + if (SortIncludes.getNumOccurrences() != 0) - FormatStyle.SortIncludes = SortIncludes; + FormatStyle->SortIncludes = SortIncludes; unsigned CursorPosition = Cursor; - Replacements Replaces = sortIncludes(FormatStyle, Code->getBuffer(), Ranges, + Replacements Replaces = sortIncludes(*FormatStyle, Code->getBuffer(), Ranges, AssumedFileName, &CursorPosition); auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(), Replaces); if (!ChangedCode) { @@ -264,7 +277,7 @@ static bool format(StringRef FileName) { // Get new affected ranges after sorting `#includes`. Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); bool IncompleteFormat = false; - Replacements FormatChanges = reformat(FormatStyle, *ChangedCode, Ranges, + Replacements FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &IncompleteFormat); Replaces = Replaces.merge(FormatChanges); if (OutputXML) { @@ -291,9 +304,7 @@ static bool format(StringRef FileName) { Rewriter Rewrite(Sources, LangOptions()); tooling::applyAllReplacements(Replaces, Rewrite); if (Inplace) { - if (FileName == "-") - errs() << "error: cannot use -i when reading from stdin.\n"; - else if (Rewrite.overwriteChangedFiles()) + if (Rewrite.overwriteChangedFiles()) return true; } else { if (Cursor.getNumOccurrences() != 0) @@ -334,10 +345,15 @@ int main(int argc, const char **argv) { cl::PrintHelpMessage(); if (DumpConfig) { - std::string Config = - clang::format::configurationAsText(clang::format::getStyle( + llvm::Expected<clang::format::FormatStyle> FormatStyle = + clang::format::getStyle( Style, FileNames.empty() ? AssumeFileName : FileNames[0], - FallbackStyle)); + FallbackStyle); + if (!FormatStyle) { + llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n"; + return 1; + } + std::string Config = clang::format::configurationAsText(*FormatStyle); outs() << Config << "\n"; return 0; } diff --git a/tools/clang-format/clang-format-test.el b/tools/clang-format/clang-format-test.el new file mode 100644 index 000000000000..0e1f4dde406b --- /dev/null +++ b/tools/clang-format/clang-format-test.el @@ -0,0 +1,126 @@ +;;; clang-format-test.el --- unit tests for clang-format.el -*- lexical-binding: t; -*- + +;; Copyright (C) 2017 Google Inc. + +;; Author: Philipp Stephani <phst@google.com> + +;; This file is distributed under the University of Illinois Open Source +;; License. See LICENSE.TXT for details. + +;;; Commentary: + +;; Unit tests for clang-format.el. + +;;; Code: + +(require 'clang-format) + +(require 'cl-lib) +(require 'ert) +(require 'pcase) + +(ert-deftest clang-format-buffer--buffer-encoding () + "Tests that encoded text is handled properly." + (cl-letf* ((call-process-args nil) + ((symbol-function 'call-process-region) + (lambda (&rest args) + (push args call-process-args) + (pcase-exhaustive args + (`(,_start ,_end ,_program ,_delete (,stdout ,_stderr) + ,_display . ,_args) + (with-current-buffer stdout + (insert "<?xml version='1.0'?> +<replacements xml:space='preserve' incomplete_format='false'> +<replacement offset='4' length='0'> </replacement> +<replacement offset='10' length='0'> </replacement> +</replacements> +")) + 0))))) + (with-temp-buffer + (let ((buffer-file-name "foo.cpp") + (buffer-file-coding-system 'utf-8-with-signature-dos) + (default-process-coding-system 'latin-1-unix)) + (insert "ä =ö;\nü= ß;\n") + (goto-char (point-min)) + (end-of-line) + (clang-format-buffer)) + (should (equal (buffer-string) "ä = ö;\nü = ß;\n")) + (should (eolp)) + (should (equal (buffer-substring (point) (point-max)) + "\nü = ß;\n"))) + (should-not (cdr call-process-args)) + (pcase-exhaustive call-process-args + (`((,start ,end ,_program ,delete (,_stdout ,_stderr) ,display . ,args)) + (should-not start) + (should-not end) + (should-not delete) + (should-not display) + (should (equal args + '("-output-replacements-xml" "-assume-filename" "foo.cpp" + "-style" "file" + ;; Beginning of buffer, no byte-order mark. + "-offset" "0" + ;; We have two lines with 2×2 bytes for the umlauts, + ;; 1 byte for the line ending, and 3 bytes for the + ;; other ASCII characters each. + "-length" "16" + ;; Length of a single line (without line ending). + "-cursor" "7"))))))) + +(ert-deftest clang-format-buffer--process-encoding () + "Tests that text is sent to the clang-format process in the +right encoding." + (cl-letf* ((hexdump (executable-find "hexdump")) + (original-call-process-region + (symbol-function 'call-process-region)) + (call-process-inputs nil) + ;; We redirect the input to hexdump so that we have guaranteed + ;; ASCII output. + ((symbol-function 'call-process-region) + (lambda (&rest args) + (pcase-exhaustive args + (`(,start ,end ,_program ,_delete (,stdout ,_stderr) + ,_display . ,_args) + (with-current-buffer stdout + (insert "<?xml version='1.0'?> +<replacements xml:space='preserve' incomplete_format='false'> +</replacements> +")) + (let ((stdin (current-buffer))) + (with-temp-buffer + (prog1 + (let ((stdout (current-buffer))) + (with-current-buffer stdin + (funcall original-call-process-region + start end hexdump nil stdout nil + "-v" "-e" "/1 \"%02x \""))) + (push (buffer-string) call-process-inputs))))))))) + (skip-unless hexdump) + (with-temp-buffer + (let ((buffer-file-name "foo.cpp") + (buffer-file-coding-system 'utf-8-with-signature-dos) + (default-process-coding-system 'latin-1-unix)) + (insert "ä\n") + (clang-format-buffer)) + (should (equal (buffer-string) "ä\n")) + (should (eobp))) + (should (equal call-process-inputs '("c3 a4 0a "))))) + +(ert-deftest clang-format-buffer--end-to-end () + "End-to-end test for ‘clang-format-buffer’. +Actually calls the clang-format binary." + (skip-unless (file-executable-p clang-format-executable)) + (with-temp-buffer + (let ((buffer-file-name "foo.cpp") + (buffer-file-coding-system 'utf-8-with-signature-dos) + (default-process-coding-system 'latin-1-unix)) + (insert "ä =ö;\nü= ß;\n") + (goto-char (point-min)) + (end-of-line) + (clang-format-buffer)) + (should (equal (buffer-string) "ä = ö;\nü = ß;\n")) + (should (eolp)) + (should (equal (buffer-substring (point) (point-max)) + "\nü = ß;\n")))) + +;;; clang-format-test.el ends here diff --git a/tools/clang-format/clang-format.el b/tools/clang-format/clang-format.el index 0ac2da3ad29a..aa9c3ff4ca0b 100644 --- a/tools/clang-format/clang-format.el +++ b/tools/clang-format/clang-format.el @@ -95,9 +95,10 @@ of the buffer." (defun clang-format--replace (offset length &optional text) "Replace the region defined by OFFSET and LENGTH with TEXT. OFFSET and LENGTH are measured in bytes, not characters. OFFSET -is a zero-based file offset." - (let ((start (clang-format--filepos-to-bufferpos offset 'exact)) - (end (clang-format--filepos-to-bufferpos (+ offset length) 'exact))) +is a zero-based file offset, assuming ‘utf-8-unix’ coding." + (let ((start (clang-format--filepos-to-bufferpos offset 'exact 'utf-8-unix)) + (end (clang-format--filepos-to-bufferpos (+ offset length) 'exact + 'utf-8-unix))) (goto-char start) (delete-region start end) (when text @@ -130,11 +131,18 @@ is no active region. If no style is given uses `clang-format-style'." (unless style (setq style clang-format-style)) - (let ((file-start (clang-format--bufferpos-to-filepos start 'approximate)) - (file-end (clang-format--bufferpos-to-filepos end 'approximate)) - (cursor (clang-format--bufferpos-to-filepos (point) 'exact)) + (let ((file-start (clang-format--bufferpos-to-filepos start 'approximate + 'utf-8-unix)) + (file-end (clang-format--bufferpos-to-filepos end 'approximate + 'utf-8-unix)) + (cursor (clang-format--bufferpos-to-filepos (point) 'exact 'utf-8-unix)) (temp-buffer (generate-new-buffer " *clang-format-temp*")) - (temp-file (make-temp-file "clang-format"))) + (temp-file (make-temp-file "clang-format")) + ;; Output is XML, which is always UTF-8. Input encoding should match + ;; the encoding used to convert between buffer and file positions, + ;; otherwise the offsets calculated above are off. For simplicity, we + ;; always use ‘utf-8-unix’ and ignore the buffer coding system. + (default-process-coding-system '(utf-8-unix . utf-8-unix))) (unwind-protect (let ((status (call-process-region nil nil clang-format-executable @@ -164,7 +172,8 @@ is no active region. If no style is given uses `clang-format-style'." (dolist (rpl replacements) (apply #'clang-format--replace rpl))) (when cursor - (goto-char (clang-format--filepos-to-bufferpos cursor 'exact))) + (goto-char (clang-format--filepos-to-bufferpos cursor 'exact + 'utf-8-unix))) (if incomplete-format (message "(clang-format: incomplete (syntax errors)%s)" stderr) (message "(clang-format: success%s)" stderr)))) |