From 30ddf33877ec91815bee893b05850fc9b87fc09e Mon Sep 17 00:00:00 2001 From: Daniel Jasper Date: Wed, 23 Sep 2015 08:30:47 +0000 Subject: clang-format: Add initial #include sorting capabilities. To implement this nicely, add a function that merges two sets of replacements that are meant to be done in sequence. This functionality will also be useful for other applications, e.g. formatting the result of clang-tidy fixes. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@248367 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/clang-format/ClangFormat.cpp | 90 +++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 31 deletions(-) (limited to 'tools/clang-format/ClangFormat.cpp') diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp index 5037e901f3..ce9324e304 100644 --- a/tools/clang-format/ClangFormat.cpp +++ b/tools/clang-format/ClangFormat.cpp @@ -19,7 +19,6 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/Version.h" #include "clang/Format/Format.h" -#include "clang/Rewrite/Core/Rewriter.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -27,6 +26,7 @@ #include "llvm/Support/Signals.h" using namespace llvm; +using clang::tooling::Replacements; static cl::opt Help("h", cl::desc("Alias for -help"), cl::Hidden); @@ -97,6 +97,10 @@ static cl::opt "clang-format from an editor integration"), cl::init(0), cl::cat(ClangFormatCategory)); +static cl::opt SortIncludes("sort-includes", + cl::desc("Sort touched include lines"), + cl::cat(ClangFormatCategory)); + static cl::list FileNames(cl::Positional, cl::desc("[ ...]"), cl::cat(ClangFormatCategory)); @@ -121,9 +125,14 @@ static bool parseLineRange(StringRef Input, unsigned &FromLine, LineRange.second.getAsInteger(0, ToLine); } -static bool fillRanges(SourceManager &Sources, FileID ID, - const MemoryBuffer *Code, - std::vector &Ranges) { +static bool fillRanges(MemoryBuffer *Code, + std::vector &Ranges) { + FileManager Files((FileSystemOptions())); + DiagnosticsEngine Diagnostics( + IntrusiveRefCntPtr(new DiagnosticIDs), + new DiagnosticOptions); + SourceManager Sources(Diagnostics, Files); + FileID ID = createInMemoryFile("-", Code, Sources, Files); if (!LineRanges.empty()) { if (!Offsets.empty() || !Lengths.empty()) { llvm::errs() << "error: cannot use -lines with -offset/-length\n"; @@ -144,7 +153,9 @@ static bool fillRanges(SourceManager &Sources, FileID ID, SourceLocation End = Sources.translateLineCol(ID, ToLine, UINT_MAX); if (Start.isInvalid() || End.isInvalid()) return true; - Ranges.push_back(CharSourceRange::getCharRange(Start, End)); + unsigned Offset = Sources.getFileOffset(Start); + unsigned Length = Sources.getFileOffset(End) - Offset; + Ranges.push_back(tooling::Range(Offset, Length)); } return false; } @@ -177,7 +188,9 @@ static bool fillRanges(SourceManager &Sources, FileID ID, } else { End = Sources.getLocForEndOfFile(ID); } - Ranges.push_back(CharSourceRange::getCharRange(Start, End)); + unsigned Offset = Sources.getFileOffset(Start); + unsigned Length = Sources.getFileOffset(End) - Offset; + Ranges.push_back(tooling::Range(Offset, Length)); } return false; } @@ -202,13 +215,18 @@ static void outputReplacementXML(StringRef Text) { llvm::outs() << Text.substr(From); } +static void outputReplacementsXML(const Replacements &Replaces) { + for (const auto &R : Replaces) { + outs() << ""; + outputReplacementXML(R.getReplacementText()); + outs() << "\n"; + } +} + // Returns true on error. static bool format(StringRef FileName) { - FileManager Files((FileSystemOptions())); - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs), - new DiagnosticOptions); - SourceManager Sources(Diagnostics, Files); ErrorOr> CodeOrErr = MemoryBuffer::getFileOrSTDIN(FileName); if (std::error_code EC = CodeOrErr.getError()) { @@ -218,16 +236,27 @@ static bool format(StringRef FileName) { std::unique_ptr Code = std::move(CodeOrErr.get()); if (Code->getBufferSize() == 0) return false; // Empty files are formatted correctly. - FileID ID = createInMemoryFile(FileName, Code.get(), Sources, Files); - std::vector Ranges; - if (fillRanges(Sources, ID, Code.get(), Ranges)) + std::vector Ranges; + if (fillRanges(Code.get(), Ranges)) return true; - FormatStyle FormatStyle = getStyle( Style, (FileName == "-") ? AssumeFilename : FileName, FallbackStyle); + Replacements Replaces; + std::string ChangedCode; + if (SortIncludes) { + Replaces = + sortIncludes(FormatStyle, Code->getBuffer(), Ranges, FileName); + ChangedCode = tooling::applyAllReplacements(Code->getBuffer(), Replaces); + for (const auto &R : Replaces) + Ranges.push_back({R.getOffset(), R.getLength()}); + } else { + ChangedCode = Code->getBuffer().str(); + } + bool IncompleteFormat = false; - tooling::Replacements Replaces = - reformat(FormatStyle, Sources, ID, Ranges, &IncompleteFormat); + Replaces = tooling::mergeReplacements( + Replaces, + reformat(FormatStyle, ChangedCode, Ranges, FileName, &IncompleteFormat)); if (OutputXML) { llvm::outs() << "\ngetOffset() << "' " - << "length='" << I->getLength() << "'>"; - outputReplacementXML(I->getReplacementText()); - llvm::outs() << "\n"; - } + outputReplacementsXML(Replaces); llvm::outs() << "\n"; } else { - Rewriter Rewrite(Sources, LangOptions()); - tooling::applyAllReplacements(Replaces, Rewrite); + std::string FormattedCode = + applyAllReplacements(Code->getBuffer(), Replaces); if (Inplace) { if (FileName == "-") llvm::errs() << "error: cannot use -i when reading from stdin.\n"; - else if (Rewrite.overwriteChangedFiles()) - return true; + else { + std::error_code EC; + raw_fd_ostream FileOut(FileName, EC, llvm::sys::fs::F_Text); + if (EC) { + llvm::errs() << EC.message() << "\n"; + return true; + } + FileOut << FormattedCode; + } } else { if (Cursor.getNumOccurrences() != 0) outs() << "{ \"Cursor\": " << tooling::shiftedCodePosition(Replaces, Cursor) << ", \"IncompleteFormat\": " << (IncompleteFormat ? "true" : "false") << " }\n"; - Rewrite.getEditBuffer(ID).write(outs()); + outs() << FormattedCode; } } return false; -- cgit v1.2.3