From d95f88a616952ec36d065748f72f75f4d97d6ee7 Mon Sep 17 00:00:00 2001 From: Alexander Kornienko Date: Thu, 18 Jul 2013 22:54:56 +0000 Subject: [PATCH] Added -lines X:Y option to specify line range to process. This is a more human-friendly alternative to -offset and -length. Differential Revision: http://llvm-reviews.chandlerc.com/D1160 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186625 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/Format/line-ranges.cpp | 11 ++++ test/Format/multiple-inputs-error.cpp | 4 +- tools/clang-format/ClangFormat.cpp | 83 +++++++++++++++++++++------ 3 files changed, 81 insertions(+), 17 deletions(-) create mode 100644 test/Format/line-ranges.cpp diff --git a/test/Format/line-ranges.cpp b/test/Format/line-ranges.cpp new file mode 100644 index 0000000000..370445aed1 --- /dev/null +++ b/test/Format/line-ranges.cpp @@ -0,0 +1,11 @@ +// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp +// RUN: clang-format -style=LLVM -lines=1:1 -lines=5:5 -i %t.cpp +// RUN: FileCheck -strict-whitespace -input-file=%t.cpp %s +// CHECK: {{^int\ \*i;$}} + int*i; + +// CHECK: {{^\ \ int\ \ \*\ \ i;$}} + int * i; + +// CHECK: {{^\ \ int\ \*i;$}} + int * i; diff --git a/test/Format/multiple-inputs-error.cpp b/test/Format/multiple-inputs-error.cpp index 8ee9ac65eb..1aa9c9f3e2 100644 --- a/test/Format/multiple-inputs-error.cpp +++ b/test/Format/multiple-inputs-error.cpp @@ -1,6 +1,8 @@ // RUN: cp %s %t-1.cpp // RUN: cp %s %t-2.cpp // RUN: not clang-format 2>&1 >/dev/null -offset=1 -length=0 %t-1.cpp %t-2.cpp |FileCheck %s -// CHECK: error: "-offset" and "-length" can only be used for single file. +// RUN: not clang-format 2>&1 >/dev/null -lines=1:1 %t-1.cpp %t-2.cpp |FileCheck %s -check-prefix=CHECK-LINE +// CHECK: error: -offset, -length and -lines can only be used for single file. +// CHECK-LINE: error: -offset, -length and -lines can only be used for single file. int i ; diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp index 7f0fb501b4..faf96fdf78 100644 --- a/tools/clang-format/ClangFormat.cpp +++ b/tools/clang-format/ClangFormat.cpp @@ -53,6 +53,14 @@ static cl::list "of the file.\n" "Can only be used with one input file."), cl::cat(ClangFormatCategory)); +static cl::list +LineRanges("lines", cl::desc(": - format a range of\n" + "lines (both 1-based).\n" + "Multiple ranges can be formatted by specifying\n" + "several -lines arguments.\n" + "Can't be used with -offset and -length.\n" + "Can only be used with one input file."), + cl::cat(ClangFormatCategory)); static cl::opt Style("style", cl::desc("Coding style, currently supports:\n" @@ -150,21 +158,43 @@ FormatStyle getStyle(StringRef StyleName, StringRef FileName) { return Style; } +// Parses : input to a pair of line numbers. // Returns true on error. -static bool format(std::string FileName) { - FileManager Files((FileSystemOptions())); - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs), - new DiagnosticOptions); - SourceManager Sources(Diagnostics, Files); - OwningPtr Code; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(FileName, Code)) { - llvm::errs() << ec.message() << "\n"; - return true; +static bool parseLineRange(StringRef Input, unsigned &FromLine, + unsigned &ToLine) { + std::pair LineRange = Input.split(':'); + return LineRange.first.getAsInteger(0, FromLine) || + LineRange.second.getAsInteger(0, ToLine); +} + +static bool fillRanges(SourceManager &Sources, FileID ID, + const MemoryBuffer *Code, + std::vector &Ranges) { + if (!LineRanges.empty()) { + if (!Offsets.empty() || !Lengths.empty()) { + llvm::errs() << "error: cannot use -lines with -offset/-length\n"; + return true; + } + + for (unsigned i = 0, e = LineRanges.size(); i < e; ++i) { + unsigned FromLine, ToLine; + if (parseLineRange(LineRanges[i], FromLine, ToLine)) { + llvm::errs() << "error: invalid : pair\n"; + return true; + } + if (FromLine > ToLine) { + llvm::errs() << "error: start line should be less than end line\n"; + return true; + } + SourceLocation Start = Sources.translateLineCol(ID, FromLine, 1); + SourceLocation End = Sources.translateLineCol(ID, ToLine, UINT_MAX); + if (Start.isInvalid() || End.isInvalid()) + return true; + Ranges.push_back(CharSourceRange::getCharRange(Start, End)); + } + return false; } - if (Code->getBufferSize() == 0) - return true; // Empty files are formatted correctly. - FileID ID = createInMemoryFile(FileName, Code.get(), Sources, Files); + if (Offsets.empty()) Offsets.push_back(0); if (Offsets.size() != Lengths.size() && @@ -173,7 +203,6 @@ static bool format(std::string FileName) { << "error: number of -offset and -length arguments must match.\n"; return true; } - std::vector Ranges; for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { if (Offsets[i] >= Code->getBufferSize()) { llvm::errs() << "error: offset " << Offsets[i] @@ -196,6 +225,28 @@ static bool format(std::string FileName) { } Ranges.push_back(CharSourceRange::getCharRange(Start, End)); } + return false; +} + +// Returns true on error. +static bool format(std::string FileName) { + FileManager Files((FileSystemOptions())); + DiagnosticsEngine Diagnostics( + IntrusiveRefCntPtr(new DiagnosticIDs), + new DiagnosticOptions); + SourceManager Sources(Diagnostics, Files); + OwningPtr Code; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(FileName, Code)) { + llvm::errs() << ec.message() << "\n"; + return true; + } + if (Code->getBufferSize() == 0) + return true; // Empty files are formatted correctly. + FileID ID = createInMemoryFile(FileName, Code.get(), Sources, Files); + std::vector Ranges; + if (fillRanges(Sources, ID, Code.get(), Ranges)) + return true; + FormatStyle FormatStyle = getStyle(Style, FileName); Lexer Lex(ID, Sources.getBuffer(ID), Sources, getFormattingLangOpts(FormatStyle.Standard)); @@ -282,8 +333,8 @@ int main(int argc, const char **argv) { Error = clang::format::format(FileNames[0]); break; default: - if (!Offsets.empty() || !Lengths.empty()) { - llvm::errs() << "error: \"-offset\" and \"-length\" can only be used for " + if (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty()) { + llvm::errs() << "error: -offset, -length and -lines can only be used for " "single file.\n"; return 1; } -- 2.50.1