diff options
author | David L. Jones <dlj@google.com> | 2017-11-10 01:07:01 +0000 |
---|---|---|
committer | David L. Jones <dlj@google.com> | 2017-11-10 01:07:01 +0000 |
commit | 41af1698c520ea38edf83e7c91f1e519d34f20c1 (patch) | |
tree | 05c516cb7514d80a5e8deccb07cd0f7c228b70d4 /tools/clang-format | |
parent | cd1b175aa96d9d675c09fc54dfd96ba41e3f2279 (diff) | |
parent | 4d085086c74a8fbce197f61548f488a63f300933 (diff) |
Creating branches/google/testing and tags/google/testing/ from r317203
git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/google/testing@317856 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/clang-format')
-rw-r--r-- | tools/clang-format/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tools/clang-format/ClangFormat.cpp | 56 | ||||
-rw-r--r-- | tools/clang-format/clang-format.py | 19 | ||||
-rw-r--r-- | tools/clang-format/fuzzer/CMakeLists.txt | 6 | ||||
-rw-r--r-- | tools/clang-format/fuzzer/ClangFormatFuzzer.cpp | 7 | ||||
-rwxr-xr-x | tools/clang-format/git-clang-format | 87 |
6 files changed, 120 insertions, 57 deletions
diff --git a/tools/clang-format/CMakeLists.txt b/tools/clang-format/CMakeLists.txt index a13633eaef..c695ba3442 100644 --- a/tools/clang-format/CMakeLists.txt +++ b/tools/clang-format/CMakeLists.txt @@ -15,7 +15,7 @@ target_link_libraries(clang-format ${CLANG_FORMAT_LIB_DEPS} ) -if( LLVM_USE_SANITIZE_COVERAGE ) +if( LLVM_LIB_FUZZING_ENGINE OR LLVM_USE_SANITIZE_COVERAGE ) add_subdirectory(fuzzer) endif() diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp index ac0d0a8512..e169b9e585 100644 --- a/tools/clang-format/ClangFormat.cpp +++ b/tools/clang-format/ClangFormat.cpp @@ -102,6 +102,10 @@ static cl::opt<bool> SortIncludes( "SortIncludes style flag"), cl::cat(ClangFormatCategory)); +static cl::opt<bool> + Verbose("verbose", cl::desc("If set, shows the list of processed files"), + cl::cat(ClangFormatCategory)); + static cl::list<std::string> FileNames(cl::Positional, cl::desc("[<file> ...]"), cl::cat(ClangFormatCategory)); @@ -276,14 +280,17 @@ static bool format(StringRef FileName) { } // Get new affected ranges after sorting `#includes`. Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); - bool IncompleteFormat = false; + FormattingAttemptStatus Status; Replacements FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges, - AssumedFileName, &IncompleteFormat); + AssumedFileName, &Status); Replaces = Replaces.merge(FormatChanges); if (OutputXML) { outs() << "<?xml version='1.0'?>\n<replacements " "xml:space='preserve' incomplete_format='" - << (IncompleteFormat ? "true" : "false") << "'>\n"; + << (Status.FormatComplete ? "false" : "true") << "'"; + if (!Status.FormatComplete) + outs() << " line=" << Status.Line; + outs() << ">\n"; if (Cursor.getNumOccurrences() != 0) outs() << "<cursor>" << FormatChanges.getShiftedCodePosition(CursorPosition) @@ -307,11 +314,15 @@ static bool format(StringRef FileName) { if (Rewrite.overwriteChangedFiles()) return true; } else { - if (Cursor.getNumOccurrences() != 0) + if (Cursor.getNumOccurrences() != 0) { outs() << "{ \"Cursor\": " << FormatChanges.getShiftedCodePosition(CursorPosition) << ", \"IncompleteFormat\": " - << (IncompleteFormat ? "true" : "false") << " }\n"; + << (Status.FormatComplete ? "false" : "true"); + if (!Status.FormatComplete) + outs() << ", \"Line\": " << Status.Line; + outs() << " }\n"; + } Rewrite.getEditBuffer(ID).write(outs()); } } @@ -321,8 +332,7 @@ static bool format(StringRef FileName) { } // namespace format } // namespace clang -static void PrintVersion() { - raw_ostream &OS = outs(); +static void PrintVersion(raw_ostream &OS) { OS << clang::getClangToolFullVersion("clang-format") << '\n'; } @@ -341,8 +351,10 @@ int main(int argc, const char **argv) { "together with <file>s, the files are edited in-place. Otherwise, the\n" "result is written to the standard output.\n"); - if (Help) + if (Help) { cl::PrintHelpMessage(); + return 0; + } if (DumpConfig) { llvm::Expected<clang::format::FormatStyle> FormatStyle = @@ -359,23 +371,19 @@ int main(int argc, const char **argv) { } bool Error = false; - switch (FileNames.size()) { - case 0: + if (FileNames.empty()) { Error = clang::format::format("-"); - break; - case 1: - Error = clang::format::format(FileNames[0]); - break; - default: - if (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty()) { - errs() << "error: -offset, -length and -lines can only be used for " - "single file.\n"; - return 1; - } - for (unsigned i = 0; i < FileNames.size(); ++i) - Error |= clang::format::format(FileNames[i]); - break; + return Error ? 1 : 0; + } + if (FileNames.size() != 1 && (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) { + errs() << "error: -offset, -length and -lines can only be used for " + "single file.\n"; + return 1; + } + for (const auto &FileName : FileNames) { + if (Verbose) + errs() << "Formatting " << FileName << "\n"; + Error |= clang::format::format(FileName); } return Error ? 1 : 0; } - diff --git a/tools/clang-format/clang-format.py b/tools/clang-format/clang-format.py index ae8a6ebf74..5fe592a920 100644 --- a/tools/clang-format/clang-format.py +++ b/tools/clang-format/clang-format.py @@ -62,9 +62,20 @@ def main(): # Determine range to format. if vim.eval('exists("l:lines")') == '1': - lines = vim.eval('l:lines') + lines = ['-lines', vim.eval('l:lines')] + elif vim.eval('exists("l:formatdiff")') == '1': + with open(vim.current.buffer.name, 'r') as f: + ondisk = f.read().splitlines(); + sequence = difflib.SequenceMatcher(None, ondisk, vim.current.buffer) + lines = [] + for op in reversed(sequence.get_opcodes()): + if op[0] not in ['equal', 'delete']: + lines += ['-lines', '%s:%s' % (op[3] + 1, op[4])] + if lines == []: + return else: - lines = '%s:%s' % (vim.current.range.start + 1, vim.current.range.end + 1) + lines = ['-lines', '%s:%s' % (vim.current.range.start + 1, + vim.current.range.end + 1)] # Determine the cursor position. cursor = int(vim.eval('line2byte(line("."))+col(".")')) - 2 @@ -81,8 +92,8 @@ def main(): # Call formatter. command = [binary, '-style', style, '-cursor', str(cursor)] - if lines != 'all': - command.extend(['-lines', lines]) + if lines != ['-lines', 'all']: + command += lines if fallback_style: command.extend(['-fallback-style', fallback_style]) if vim.current.buffer.name: diff --git a/tools/clang-format/fuzzer/CMakeLists.txt b/tools/clang-format/fuzzer/CMakeLists.txt index c7772fcb2f..8f777324af 100644 --- a/tools/clang-format/fuzzer/CMakeLists.txt +++ b/tools/clang-format/fuzzer/CMakeLists.txt @@ -1,5 +1,9 @@ set(LLVM_LINK_COMPONENTS support) +if(LLVM_USE_SANITIZE_COVERAGE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=fuzzer") +endif() + add_clang_executable(clang-format-fuzzer EXCLUDE_FROM_ALL ClangFormatFuzzer.cpp @@ -7,5 +11,5 @@ add_clang_executable(clang-format-fuzzer target_link_libraries(clang-format-fuzzer ${CLANG_FORMAT_LIB_DEPS} - LLVMFuzzer + ${LLVM_LIB_FUZZING_ENGINE} ) diff --git a/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp b/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp index 5334ce873e..d440a6124b 100644 --- a/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp +++ b/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp @@ -20,7 +20,10 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { std::string s((const char *)data, size); auto Style = getGoogleStyle(clang::format::FormatStyle::LK_Cpp); Style.ColumnLimit = 60; - applyAllReplacements(s, clang::format::reformat( - Style, s, {clang::tooling::Range(0, s.size())})); + auto Replaces = reformat(Style, s, clang::tooling::Range(0, s.size())); + auto Result = applyAllReplacements(s, Replaces); + + // Output must be checked, as otherwise we crash. + if (!Result) {} return 0; } diff --git a/tools/clang-format/git-clang-format b/tools/clang-format/git-clang-format index 74fd451a84..60cd4fb25b 100755 --- a/tools/clang-format/git-clang-format +++ b/tools/clang-format/git-clang-format @@ -20,9 +20,10 @@ clang-format on the changes in current files or a specific commit. For further details, run: git clang-format -h -Requires Python 2.7 +Requires Python 2.7 or Python 3 """ +from __future__ import print_function import argparse import collections import contextlib @@ -138,15 +139,15 @@ def main(): if opts.verbose >= 1: ignored_files.difference_update(changed_lines) if ignored_files: - print 'Ignoring changes in the following files (wrong extension):' + print('Ignoring changes in the following files (wrong extension):') for filename in ignored_files: - print ' ', filename + print(' %s' % filename) if changed_lines: - print 'Running clang-format on the following files:' + print('Running clang-format on the following files:') for filename in changed_lines: - print ' ', filename + print(' %s' % filename) if not changed_lines: - print 'no modified files to format' + print('no modified files to format') return # The computed diff outputs absolute paths, so we must cd before accessing # those files. @@ -163,20 +164,20 @@ def main(): binary=opts.binary, style=opts.style) if opts.verbose >= 1: - print 'old tree:', old_tree - print 'new tree:', new_tree + print('old tree: %s' % old_tree) + print('new tree: %s' % new_tree) if old_tree == new_tree: if opts.verbose >= 0: - print 'clang-format did not modify any files' + print('clang-format did not modify any files') elif opts.diff: print_diff(old_tree, new_tree) else: changed_files = apply_changes(old_tree, new_tree, force=opts.force, patch_mode=opts.patch) if (opts.verbose >= 0 and not opts.patch) or opts.verbose >= 1: - print 'changed files:' + print('changed files:') for filename in changed_files: - print ' ', filename + print(' %s' % filename) def load_git_config(non_string_options=None): @@ -257,7 +258,7 @@ def get_object_type(value): stdout, stderr = p.communicate() if p.returncode != 0: return None - return stdout.strip() + return convert_string(stdout.strip()) def compute_diff_and_extract_lines(commits, files): @@ -300,6 +301,7 @@ def extract_lines(patch_file): list of line `Range`s.""" matches = {} for line in patch_file: + line = convert_string(line) match = re.search(r'^\+\+\+\ [^/]+/(.*)', line) if match: filename = match.group(1).rstrip('\r\n') @@ -320,8 +322,10 @@ def filter_by_extension(dictionary, allowed_extensions): `allowed_extensions` must be a collection of lowercase file extensions, excluding the period.""" allowed_extensions = frozenset(allowed_extensions) - for filename in dictionary.keys(): + for filename in list(dictionary.keys()): base_ext = filename.rsplit('.', 1) + if len(base_ext) == 1 and '' in allowed_extensions: + continue if len(base_ext) == 1 or base_ext[1].lower() not in allowed_extensions: del dictionary[filename] @@ -344,8 +348,13 @@ def run_clang_format_and_save_to_tree(changed_lines, revision=None, """Run clang-format on each file and save the result to a git tree. Returns the object ID (SHA-1) of the created tree.""" + def iteritems(container): + try: + return container.iteritems() # Python 2 + except AttributeError: + return container.items() # Python 3 def index_info_generator(): - for filename, line_ranges in changed_lines.iteritems(): + for filename, line_ranges in iteritems(changed_lines): if revision: git_metadata_cmd = ['git', 'ls-tree', '%s:%s' % (revision, os.path.dirname(filename)), @@ -356,6 +365,9 @@ def run_clang_format_and_save_to_tree(changed_lines, revision=None, mode = oct(int(stdout.split()[0], 8)) else: mode = oct(os.stat(filename).st_mode) + # Adjust python3 octal format so that it matches what git expects + if mode.startswith('0o'): + mode = '0' + mode[2:] blob_id = clang_format_to_blob(filename, line_ranges, revision=revision, binary=binary, @@ -376,7 +388,7 @@ def create_tree(input_lines, mode): with temporary_index_file(): p = subprocess.Popen(cmd, stdin=subprocess.PIPE) for line in input_lines: - p.stdin.write('%s\0' % line) + p.stdin.write(to_bytes('%s\0' % line)) p.stdin.close() if p.wait() != 0: die('`%s` failed' % ' '.join(cmd)) @@ -431,7 +443,7 @@ def clang_format_to_blob(filename, line_ranges, revision=None, die('`%s` failed' % ' '.join(clang_format_cmd)) if git_show and git_show.wait() != 0: die('`%s` failed' % ' '.join(git_show_cmd)) - return stdout.rstrip('\r\n') + return convert_string(stdout).rstrip('\r\n') @contextlib.contextmanager @@ -488,10 +500,10 @@ def apply_changes(old_tree, new_tree, force=False, patch_mode=False): if not force: unstaged_files = run('git', 'diff-files', '--name-status', *changed_files) if unstaged_files: - print >>sys.stderr, ('The following files would be modified but ' - 'have unstaged changes:') - print >>sys.stderr, unstaged_files - print >>sys.stderr, 'Please commit, stage, or stash them first.' + print('The following files would be modified but ' + 'have unstaged changes:', file=sys.stderr) + print(unstaged_files, file=sys.stderr) + print('Please commit, stage, or stash them first.', file=sys.stderr) sys.exit(2) if patch_mode: # In patch mode, we could just as well create an index from the new tree @@ -518,25 +530,50 @@ def run(*args, **kwargs): p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) stdout, stderr = p.communicate(input=stdin) + + stdout = convert_string(stdout) + stderr = convert_string(stderr) + if p.returncode == 0: if stderr: if verbose: - print >>sys.stderr, '`%s` printed to stderr:' % ' '.join(args) - print >>sys.stderr, stderr.rstrip() + print('`%s` printed to stderr:' % ' '.join(args), file=sys.stderr) + print(stderr.rstrip(), file=sys.stderr) if strip: stdout = stdout.rstrip('\r\n') return stdout if verbose: - print >>sys.stderr, '`%s` returned %s' % (' '.join(args), p.returncode) + print('`%s` returned %s' % (' '.join(args), p.returncode), file=sys.stderr) if stderr: - print >>sys.stderr, stderr.rstrip() + print(stderr.rstrip(), file=sys.stderr) sys.exit(2) def die(message): - print >>sys.stderr, 'error:', message + print('error:', message, file=sys.stderr) sys.exit(2) +def to_bytes(str_input): + # Encode to UTF-8 to get binary data. + if isinstance(str_input, bytes): + return str_input + return str_input.encode('utf-8') + + +def to_string(bytes_input): + if isinstance(bytes_input, str): + return bytes_input + return bytes_input.encode('utf-8') + + +def convert_string(bytes_input): + try: + return to_string(bytes_input.decode('utf-8')) + except AttributeError: # 'str' object has no attribute 'decode'. + return str(bytes_input) + except UnicodeError: + return str(bytes_input) + if __name__ == '__main__': main() |