diff options
Diffstat (limited to 'tools/clang-format')
-rw-r--r-- | tools/clang-format/CMakeLists.txt | 6 | ||||
-rw-r--r-- | tools/clang-format/ClangFormat.cpp | 65 | ||||
-rw-r--r-- | tools/clang-format/Makefile | 2 | ||||
-rwxr-xr-x | tools/clang-format/clang-format-diff.py | 32 | ||||
-rw-r--r-- | tools/clang-format/clang-format.py | 83 | ||||
-rwxr-xr-x | tools/clang-format/git-clang-format | 3 |
6 files changed, 122 insertions, 69 deletions
diff --git a/tools/clang-format/CMakeLists.txt b/tools/clang-format/CMakeLists.txt index 7bb3fbf..f80a3ec 100644 --- a/tools/clang-format/CMakeLists.txt +++ b/tools/clang-format/CMakeLists.txt @@ -1,15 +1,15 @@ set(LLVM_LINK_COMPONENTS support) -set(LLVM_USED_LIBS clangFormat clangTooling clangBasic clangAST) add_clang_executable(clang-format ClangFormat.cpp ) target_link_libraries(clang-format + clangBasic clangFormat + clangLex + clangRewrite clangTooling - clangBasic - clangRewriteFrontend ) install(TARGETS clang-format RUNTIME DESTINATION bin) diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp index 768165b..cebb275 100644 --- a/tools/clang-format/ClangFormat.cpp +++ b/tools/clang-format/ClangFormat.cpp @@ -17,13 +17,14 @@ #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Version.h" #include "clang/Format/Format.h" #include "clang/Lex/Lexer.h" #include "clang/Rewrite/Core/Rewriter.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Signals.h" -#include "llvm/ADT/StringMap.h" using namespace llvm; @@ -31,7 +32,7 @@ static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden); // Mark all our options with this category, everything else (except for -version // and -help) will be hidden. -cl::OptionCategory ClangFormatCategory("Clang-format options"); +static cl::OptionCategory ClangFormatCategory("Clang-format options"); static cl::list<unsigned> Offsets("offset", @@ -62,6 +63,14 @@ static cl::opt<std::string> Style("style", cl::desc(clang::format::StyleOptionHelpDescription), cl::init("file"), cl::cat(ClangFormatCategory)); +static cl::opt<std::string> +FallbackStyle("fallback-style", + cl::desc("The name of the predefined style used as a\n" + "fallback in case clang-format is invoked with\n" + "-style=file, but can not find the .clang-format\n" + "file to use.\n" + "Use -fallback-style=none to skip formatting."), + cl::init("LLVM"), cl::cat(ClangFormatCategory)); static cl::opt<std::string> AssumeFilename("assume-filename", @@ -94,7 +103,7 @@ static cl::list<std::string> FileNames(cl::Positional, cl::desc("[<file> ...]"), namespace clang { namespace format { -static FileID createInMemoryFile(StringRef FileName, const MemoryBuffer *Source, +static FileID createInMemoryFile(StringRef FileName, MemoryBuffer *Source, SourceManager &Sources, FileManager &Files) { const FileEntry *Entry = Files.getVirtualFile(FileName == "-" ? "<stdin>" : FileName, @@ -173,6 +182,26 @@ static bool fillRanges(SourceManager &Sources, FileID ID, return false; } +static void outputReplacementXML(StringRef Text) { + size_t From = 0; + size_t Index; + while ((Index = Text.find_first_of("\n\r", From)) != StringRef::npos) { + llvm::outs() << Text.substr(From, Index - From); + switch (Text[Index]) { + case '\n': + llvm::outs() << " "; + break; + case '\r': + llvm::outs() << " "; + break; + default: + llvm_unreachable("Unexpected character encountered!"); + } + From = Index + 1; + } + llvm::outs() << Text.substr(From); +} + // Returns true on error. static bool format(StringRef FileName) { FileManager Files((FileSystemOptions())); @@ -180,11 +209,13 @@ static bool format(StringRef FileName) { IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), new DiagnosticOptions); SourceManager Sources(Diagnostics, Files); - OwningPtr<MemoryBuffer> Code; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(FileName, Code)) { - llvm::errs() << ec.message() << "\n"; + ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = + MemoryBuffer::getFileOrSTDIN(FileName); + if (std::error_code EC = CodeOrErr.getError()) { + llvm::errs() << EC.message() << "\n"; return true; } + std::unique_ptr<llvm::MemoryBuffer> Code = std::move(CodeOrErr.get()); if (Code->getBufferSize() == 0) return false; // Empty files are formatted correctly. FileID ID = createInMemoryFile(FileName, Code.get(), Sources, Files); @@ -192,8 +223,8 @@ static bool format(StringRef FileName) { if (fillRanges(Sources, ID, Code.get(), Ranges)) return true; - FormatStyle FormatStyle = - getStyle(Style, (FileName == "-") ? AssumeFilename : FileName); + FormatStyle FormatStyle = getStyle( + Style, (FileName == "-") ? AssumeFilename : FileName, FallbackStyle); Lexer Lex(ID, Sources.getBuffer(ID), Sources, getFormattingLangOpts(FormatStyle.Standard)); tooling::Replacements Replaces = reformat(FormatStyle, Lex, Sources, Ranges); @@ -205,8 +236,9 @@ static bool format(StringRef FileName) { I != E; ++I) { llvm::outs() << "<replacement " << "offset='" << I->getOffset() << "' " - << "length='" << I->getLength() << "'>" - << I->getReplacementText() << "</replacement>\n"; + << "length='" << I->getLength() << "'>"; + outputReplacementXML(I->getReplacementText()); + llvm::outs() << "</replacement>\n"; } llvm::outs() << "</replacements>\n"; } else { @@ -217,8 +249,8 @@ static bool format(StringRef FileName) { return true; } else { if (Cursor.getNumOccurrences() != 0) - outs() << "{ \"Cursor\": " << tooling::shiftedCodePosition( - Replaces, Cursor) << " }\n"; + outs() << "{ \"Cursor\": " + << tooling::shiftedCodePosition(Replaces, Cursor) << " }\n"; Rewrite.getEditBuffer(ID).write(outs()); } } @@ -228,6 +260,11 @@ static bool format(StringRef FileName) { } // namespace format } // namespace clang +static void PrintVersion() { + raw_ostream &OS = outs(); + OS << clang::getClangToolFullVersion("clang-format") << '\n'; +} + int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); @@ -241,6 +278,7 @@ int main(int argc, const char **argv) { I->second->setHiddenFlag(cl::ReallyHidden); } + cl::SetVersionPrinter(PrintVersion); cl::ParseCommandLineOptions( argc, argv, "A tool to format C/C++/Obj-C code.\n\n" @@ -256,7 +294,8 @@ int main(int argc, const char **argv) { if (DumpConfig) { std::string Config = clang::format::configurationAsText(clang::format::getStyle( - Style, FileNames.empty() ? AssumeFilename : FileNames[0])); + Style, FileNames.empty() ? AssumeFilename : FileNames[0], + FallbackStyle)); llvm::outs() << Config << "\n"; return 0; } diff --git a/tools/clang-format/Makefile b/tools/clang-format/Makefile index 4902244..a26ef59 100644 --- a/tools/clang-format/Makefile +++ b/tools/clang-format/Makefile @@ -18,7 +18,7 @@ include $(CLANG_LEVEL)/../../Makefile.config LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option USEDLIBS = clangFormat.a clangTooling.a clangFrontend.a clangSerialization.a \ clangDriver.a clangParse.a clangSema.a clangAnalysis.a \ - clangRewriteFrontend.a clangRewriteCore.a clangEdit.a clangAST.a \ + clangRewriteFrontend.a clangRewrite.a clangEdit.a clangAST.a \ clangLex.a clangBasic.a include $(CLANG_LEVEL)/Makefile diff --git a/tools/clang-format/clang-format-diff.py b/tools/clang-format/clang-format-diff.py index 60b8fb7..d6d0d44 100755 --- a/tools/clang-format/clang-format-diff.py +++ b/tools/clang-format/clang-format-diff.py @@ -15,9 +15,10 @@ ClangFormat Diff Reformatter This script reads input from a unified diff and reformats all the changed lines. This is useful to reformat all the lines touched by a specific patch. -Example usage for git users: +Example usage for git/svn users: git diff -U0 HEAD^ | clang-format-diff.py -p1 -i + svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i """ @@ -37,12 +38,20 @@ binary = 'clang-format' def main(): parser = argparse.ArgumentParser(description= 'Reformat changed lines in diff. Without -i ' - 'option just output the diff that would be' + 'option just output the diff that would be ' 'introduced.') parser.add_argument('-i', action='store_true', default=False, help='apply edits to files instead of displaying a diff') - parser.add_argument('-p', default=0, + parser.add_argument('-p', metavar='NUM', default=0, help='strip the smallest prefix containing P slashes') + parser.add_argument('-regex', metavar='PATTERN', default=None, + help='custom pattern selecting file paths to reformat ' + '(case sensitive, overrides -iregex)') + parser.add_argument('-iregex', metavar='PATTERN', default= + r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc|js|proto' + r'|protodevel)', + help='custom pattern selecting file paths to reformat ' + '(case insensitive, overridden by -regex)') parser.add_argument( '-style', help= @@ -59,10 +68,12 @@ def main(): if filename == None: continue - # FIXME: Add other types containing C++/ObjC code. - if not (filename.endswith(".cpp") or filename.endswith(".cc") or - filename.endswith(".h")): - continue + if args.regex is not None: + if not re.match('^%s$' % args.regex, filename): + continue + else: + if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE): + continue match = re.search('^@@.*\+(\d+)(,(\d+))?', line) if match: @@ -85,11 +96,8 @@ def main(): if args.style: command.extend(['-style', args.style]) p = subprocess.Popen(command, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - stdin=subprocess.PIPE) + stderr=None, stdin=subprocess.PIPE) stdout, stderr = p.communicate() - if stderr: - print stderr if p.returncode != 0: sys.exit(p.returncode); @@ -102,7 +110,7 @@ def main(): '(before formatting)', '(after formatting)') diff_string = string.join(diff, '') if len(diff_string) > 0: - print diff_string + sys.stdout.write(diff_string) if __name__ == '__main__': main() diff --git a/tools/clang-format/clang-format.py b/tools/clang-format/clang-format.py index f5a5756..16a1879 100644 --- a/tools/clang-format/clang-format.py +++ b/tools/clang-format/clang-format.py @@ -32,48 +32,51 @@ binary = 'clang-format' # used. style = 'file' -# Get the current text. -buf = vim.current.buffer -text = '\n'.join(buf) +def main(): + # Get the current text. + buf = vim.current.buffer + text = '\n'.join(buf) -# Determine range to format. -cursor = int(vim.eval('line2byte(line("."))+col(".")')) - 2 -lines = '%s:%s' % (vim.current.range.start + 1, vim.current.range.end + 1) + # Determine range to format. + lines = '%s:%s' % (vim.current.range.start + 1, vim.current.range.end + 1) -# Avoid flashing an ugly, ugly cmd prompt on Windows when invoking clang-format. -startupinfo = None -if sys.platform.startswith('win32'): - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - startupinfo.wShowWindow = subprocess.SW_HIDE + # Determine the cursor position. + cursor = int(vim.eval('line2byte(line("."))+col(".")')) - 2 + if cursor < 0: + print 'Couldn\'t determine cursor position. Is your file empty?' + return -# Call formatter. -command = [binary, '-lines', lines, '-style', style, '-cursor', str(cursor)] -if vim.current.buffer.name: - command.extend(['-assume-filename', vim.current.buffer.name]) -p = subprocess.Popen(command, - stdout=subprocess.PIPE, stderr=subprocess.PIPE, - stdin=subprocess.PIPE, startupinfo=startupinfo) -stdout, stderr = p.communicate(input=text) + # Avoid flashing an ugly, ugly cmd prompt on Windows when invoking clang-format. + startupinfo = None + if sys.platform.startswith('win32'): + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + startupinfo.wShowWindow = subprocess.SW_HIDE -# If successful, replace buffer contents. -if stderr: - message = stderr.splitlines()[0] - parts = message.split(' ', 2) - if len(parts) > 2: - message = parts[2] - print 'Formatting failed: %s (total %d warnings, %d errors)' % ( - message, stderr.count('warning:'), stderr.count('error:')) + # Call formatter. + command = [binary, '-lines', lines, '-style', style, '-cursor', str(cursor)] + if vim.current.buffer.name: + command.extend(['-assume-filename', vim.current.buffer.name]) + p = subprocess.Popen(command, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + stdin=subprocess.PIPE, startupinfo=startupinfo) + stdout, stderr = p.communicate(input=text) -if not stdout: - print ('No output from clang-format (crashed?).\n' + - 'Please report to bugs.llvm.org.') -else: - lines = stdout.split('\n') - output = json.loads(lines[0]) - lines = lines[1:] - sequence = difflib.SequenceMatcher(None, vim.current.buffer, lines) - for op in reversed(sequence.get_opcodes()): - if op[0] is not 'equal': - vim.current.buffer[op[1]:op[2]] = lines[op[3]:op[4]] - vim.command('goto %d' % (output['Cursor'] + 1)) + # If successful, replace buffer contents. + if stderr: + print stderr + + if not stdout: + print ('No output from clang-format (crashed?).\n' + + 'Please report to bugs.llvm.org.') + else: + lines = stdout.split('\n') + output = json.loads(lines[0]) + lines = lines[1:] + sequence = difflib.SequenceMatcher(None, vim.current.buffer, lines) + for op in reversed(sequence.get_opcodes()): + if op[0] is not 'equal': + vim.current.buffer[op[1]:op[2]] = lines[op[3]:op[4]] + vim.command('goto %d' % (output['Cursor'] + 1)) + +main() diff --git a/tools/clang-format/git-clang-format b/tools/clang-format/git-clang-format index b0737ed..c40b74d 100755 --- a/tools/clang-format/git-clang-format +++ b/tools/clang-format/git-clang-format @@ -75,6 +75,9 @@ def main(): 'm', # ObjC 'mm', # ObjC++ 'cc', 'cp', 'cpp', 'c++', 'cxx', 'hpp', # C++ + # Other languages that clang-format supports + 'proto', 'protodevel', # Protocol Buffers + 'js', # JavaScript ]) p = argparse.ArgumentParser( |