aboutsummaryrefslogtreecommitdiff
path: root/tools/clang-format
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-04-16 16:02:28 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-04-16 16:02:28 +0000
commit7442d6faa2719e4e7d33a7021c406c5a4facd74d (patch)
treec72b9241553fc9966179aba84f90f17bfa9235c3 /tools/clang-format
parentb52119637f743680a99710ce5fdb6646da2772af (diff)
downloadsrc-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.cpp38
-rw-r--r--tools/clang-format/clang-format-test.el126
-rw-r--r--tools/clang-format/clang-format.el25
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))))