r315918 - Recommit r315738 "[clang-refactor] Apply source replacements"
Alex Lorenz via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 16 10:31:16 PDT 2017
Author: arphaman
Date: Mon Oct 16 10:31:16 2017
New Revision: 315918
URL: http://llvm.org/viewvc/llvm-project?rev=315918&view=rev
Log:
Recommit r315738 "[clang-refactor] Apply source replacements"
The fixed commit ensures that ParsedSourceRange works correctly
with Windows paths.
Original message:
This commit actually brings clang-refactor to a usable state as it can now
apply the refactoring changes to source files.
The -selection option is now also fully supported.
Differential Revision: https://reviews.llvm.org/D38402
Added:
cfe/trunk/test/Refactor/tool-apply-replacements.cpp
cfe/trunk/test/Refactor/tool-selection-option.c
cfe/trunk/unittests/Frontend/ParsedSourceLocationTest.cpp
Modified:
cfe/trunk/include/clang/Frontend/CommandLineSourceLoc.h
cfe/trunk/tools/clang-refactor/ClangRefactor.cpp
cfe/trunk/unittests/Frontend/CMakeLists.txt
Modified: cfe/trunk/include/clang/Frontend/CommandLineSourceLoc.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CommandLineSourceLoc.h?rev=315918&r1=315917&r2=315918&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/CommandLineSourceLoc.h (original)
+++ cfe/trunk/include/clang/Frontend/CommandLineSourceLoc.h Mon Oct 16 10:31:16 2017
@@ -51,6 +51,52 @@ public:
}
};
+/// A source range that has been parsed on the command line.
+struct ParsedSourceRange {
+ std::string FileName;
+ /// The starting location of the range. The first element is the line and
+ /// the second element is the column.
+ std::pair<unsigned, unsigned> Begin;
+ /// The ending location of the range. The first element is the line and the
+ /// second element is the column.
+ std::pair<unsigned, unsigned> End;
+
+ /// Returns a parsed source range from a string or None if the string is
+ /// invalid.
+ ///
+ /// These source string has the following format:
+ ///
+ /// file:start_line:start_column[-end_line:end_column]
+ ///
+ /// If the end line and column are omitted, the starting line and columns
+ /// are used as the end values.
+ static Optional<ParsedSourceRange> fromString(StringRef Str) {
+ std::pair<StringRef, StringRef> RangeSplit = Str.rsplit('-');
+ unsigned EndLine, EndColumn;
+ bool HasEndLoc = false;
+ if (!RangeSplit.second.empty()) {
+ std::pair<StringRef, StringRef> Split = RangeSplit.second.rsplit(':');
+ if (Split.first.getAsInteger(10, EndLine) ||
+ Split.second.getAsInteger(10, EndColumn)) {
+ // The string does not end in end_line:end_column, so the '-'
+ // probably belongs to the filename which menas the whole
+ // string should be parsed.
+ RangeSplit.first = Str;
+ } else
+ HasEndLoc = true;
+ }
+ auto Begin = ParsedSourceLocation::FromString(RangeSplit.first);
+ if (Begin.FileName.empty())
+ return None;
+ if (!HasEndLoc) {
+ EndLine = Begin.Line;
+ EndColumn = Begin.Column;
+ }
+ return ParsedSourceRange{std::move(Begin.FileName),
+ {Begin.Line, Begin.Column},
+ {EndLine, EndColumn}};
+ }
+};
}
namespace llvm {
Added: cfe/trunk/test/Refactor/tool-apply-replacements.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Refactor/tool-apply-replacements.cpp?rev=315918&view=auto
==============================================================================
--- cfe/trunk/test/Refactor/tool-apply-replacements.cpp (added)
+++ cfe/trunk/test/Refactor/tool-apply-replacements.cpp Mon Oct 16 10:31:16 2017
@@ -0,0 +1,11 @@
+// RUN: rm -f %t.cp.cpp
+// RUN: cp %s %t.cp.cpp
+// RUN: clang-refactor local-rename -selection=%t.cp.cpp:9:7 -new-name=test %t.cp.cpp --
+// RUN: grep -v CHECK %t.cp.cpp | FileCheck %t.cp.cpp
+// RUN: cp %s %t.cp.cpp
+// RUN: clang-refactor local-rename -selection=%t.cp.cpp:9:7-9:15 -new-name=test %t.cp.cpp --
+// RUN: grep -v CHECK %t.cp.cpp | FileCheck %t.cp.cpp
+
+class RenameMe {
+// CHECK: class test {
+};
Added: cfe/trunk/test/Refactor/tool-selection-option.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Refactor/tool-selection-option.c?rev=315918&view=auto
==============================================================================
--- cfe/trunk/test/Refactor/tool-selection-option.c (added)
+++ cfe/trunk/test/Refactor/tool-selection-option.c Mon Oct 16 10:31:16 2017
@@ -0,0 +1,15 @@
+// RUN: rm -f %t.cp.c
+// RUN: cp %s %t.cp.c
+// RUN: clang-refactor local-rename -selection=%t.cp.c:6:5 -new-name=test -v %t.cp.c -- | FileCheck --check-prefix=CHECK1 %s
+// RUN: clang-refactor local-rename -selection=%t.cp.c:6:5-6:9 -new-name=test -v %t.cp.c -- | FileCheck --check-prefix=CHECK2 %s
+
+int test;
+
+// CHECK1: invoking action 'local-rename':
+// CHECK1-NEXT: -selection={{.*}}.cp.c:6:5 -> {{.*}}.cp.c:6:5
+
+// CHECK2: invoking action 'local-rename':
+// CHECK2-NEXT: -selection={{.*}}.cp.c:6:5 -> {{.*}}.cp.c:6:9
+
+// RUN: not clang-refactor local-rename -selection=%s:6:5 -new-name=test -v %t.cp.c -- 2>&1 | FileCheck --check-prefix=CHECK-FILE-ERR %s
+// CHECK-FILE-ERR: given file is not in the target TU
Modified: cfe/trunk/tools/clang-refactor/ClangRefactor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-refactor/ClangRefactor.cpp?rev=315918&r1=315917&r2=315918&view=diff
==============================================================================
--- cfe/trunk/tools/clang-refactor/ClangRefactor.cpp (original)
+++ cfe/trunk/tools/clang-refactor/ClangRefactor.cpp Mon Oct 16 10:31:16 2017
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "TestSupport.h"
+#include "clang/Frontend/CommandLineSourceLoc.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Refactoring.h"
@@ -54,7 +55,7 @@ public:
/// Prints any additional state associated with the selection argument to
/// the given output stream.
- virtual void print(raw_ostream &OS) = 0;
+ virtual void print(raw_ostream &OS) {}
/// Returns a replacement refactoring result consumer (if any) that should
/// consume the results of a refactoring operation.
@@ -99,6 +100,41 @@ private:
TestSelectionRangesInFile TestSelections;
};
+/// Stores the parsed -selection=filename:line:column[-line:column] option.
+class SourceRangeSelectionArgument final : public SourceSelectionArgument {
+public:
+ SourceRangeSelectionArgument(ParsedSourceRange Range)
+ : Range(std::move(Range)) {}
+
+ bool forAllRanges(const SourceManager &SM,
+ llvm::function_ref<void(SourceRange R)> Callback) override {
+ const FileEntry *FE = SM.getFileManager().getFile(Range.FileName);
+ FileID FID = FE ? SM.translateFile(FE) : FileID();
+ if (!FE || FID.isInvalid()) {
+ llvm::errs() << "error: -selection=" << Range.FileName
+ << ":... : given file is not in the target TU\n";
+ return true;
+ }
+
+ SourceLocation Start = SM.getMacroArgExpandedLocation(
+ SM.translateLineCol(FID, Range.Begin.first, Range.Begin.second));
+ SourceLocation End = SM.getMacroArgExpandedLocation(
+ SM.translateLineCol(FID, Range.End.first, Range.End.second));
+ if (Start.isInvalid() || End.isInvalid()) {
+ llvm::errs() << "error: -selection=" << Range.FileName << ':'
+ << Range.Begin.first << ':' << Range.Begin.second << '-'
+ << Range.End.first << ':' << Range.End.second
+ << " : invalid source location\n";
+ return true;
+ }
+ Callback(SourceRange(Start, End));
+ return false;
+ }
+
+private:
+ ParsedSourceRange Range;
+};
+
std::unique_ptr<SourceSelectionArgument>
SourceSelectionArgument::fromString(StringRef Value) {
if (Value.startswith("test:")) {
@@ -110,10 +146,12 @@ SourceSelectionArgument::fromString(Stri
return llvm::make_unique<TestSourceSelectionArgument>(
std::move(*ParsedTestSelection));
}
- // FIXME: Support true selection ranges.
+ Optional<ParsedSourceRange> Range = ParsedSourceRange::fromString(Value);
+ if (Range)
+ return llvm::make_unique<SourceRangeSelectionArgument>(std::move(*Range));
llvm::errs() << "error: '-selection' option must be specified using "
"<file>:<line>:<column> or "
- "<file>:<line>:<column>-<line>:<column> format";
+ "<file>:<line>:<column>-<line>:<column> format\n";
return nullptr;
}
@@ -268,11 +306,22 @@ private:
class ClangRefactorConsumer : public RefactoringResultConsumer {
public:
- void handleError(llvm::Error Err) {
+ void handleError(llvm::Error Err) override {
llvm::errs() << llvm::toString(std::move(Err)) << "\n";
}
- // FIXME: Consume atomic changes and apply them to files.
+ void handle(AtomicChanges Changes) override {
+ SourceChanges.insert(SourceChanges.begin(), Changes.begin(), Changes.end());
+ }
+
+ void handle(SymbolOccurrences Occurrences) override {
+ RefactoringResultConsumer::handle(std::move(Occurrences));
+ }
+
+ const AtomicChanges &getSourceChanges() const { return SourceChanges; }
+
+private:
+ AtomicChanges SourceChanges;
};
class ClangRefactorTool {
@@ -352,6 +401,39 @@ public:
}
}
+ bool applySourceChanges(const AtomicChanges &Replacements) {
+ std::set<std::string> Files;
+ for (const auto &Change : Replacements)
+ Files.insert(Change.getFilePath());
+ // FIXME: Add automatic formatting support as well.
+ tooling::ApplyChangesSpec Spec;
+ // FIXME: We should probably cleanup the result by default as well.
+ Spec.Cleanup = false;
+ for (const auto &File : Files) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferErr =
+ llvm::MemoryBuffer::getFile(File);
+ if (!BufferErr) {
+ llvm::errs() << "error: failed to open " << File << " for rewriting\n";
+ return true;
+ }
+ auto Result = tooling::applyAtomicChanges(File, (*BufferErr)->getBuffer(),
+ Replacements, Spec);
+ if (!Result) {
+ llvm::errs() << toString(Result.takeError());
+ return true;
+ }
+
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(File, EC, llvm::sys::fs::F_Text);
+ if (EC) {
+ llvm::errs() << EC.message() << "\n";
+ return true;
+ }
+ OS << *Result;
+ }
+ return false;
+ }
+
bool invokeAction(RefactoringActionSubcommand &Subcommand,
const CompilationDatabase &DB,
ArrayRef<std::string> Sources) {
@@ -423,7 +505,7 @@ public:
// FIXME (Alex L): Implement non-selection based invocation path.
}))
return true;
- return HasFailed;
+ return HasFailed || applySourceChanges(Consumer.getSourceChanges());
}
};
Modified: cfe/trunk/unittests/Frontend/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Frontend/CMakeLists.txt?rev=315918&r1=315917&r2=315918&view=diff
==============================================================================
--- cfe/trunk/unittests/Frontend/CMakeLists.txt (original)
+++ cfe/trunk/unittests/Frontend/CMakeLists.txt Mon Oct 16 10:31:16 2017
@@ -7,6 +7,7 @@ add_clang_unittest(FrontendTests
CompilerInstanceTest.cpp
FrontendActionTest.cpp
CodeGenActionTest.cpp
+ ParsedSourceLocationTest.cpp
PCHPreambleTest.cpp
)
target_link_libraries(FrontendTests
Added: cfe/trunk/unittests/Frontend/ParsedSourceLocationTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Frontend/ParsedSourceLocationTest.cpp?rev=315918&view=auto
==============================================================================
--- cfe/trunk/unittests/Frontend/ParsedSourceLocationTest.cpp (added)
+++ cfe/trunk/unittests/Frontend/ParsedSourceLocationTest.cpp Mon Oct 16 10:31:16 2017
@@ -0,0 +1,37 @@
+//===- unittests/Frontend/ParsedSourceLocationTest.cpp - ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/CommandLineSourceLoc.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+TEST(ParsedSourceRange, ParseTest) {
+ auto Check = [](StringRef Value, StringRef Filename, unsigned BeginLine,
+ unsigned BeginColumn, unsigned EndLine, unsigned EndColumn) {
+ Optional<ParsedSourceRange> PSR = ParsedSourceRange::fromString(Value);
+ ASSERT_TRUE(PSR);
+ EXPECT_EQ(PSR->FileName, Filename);
+ EXPECT_EQ(PSR->Begin.first, BeginLine);
+ EXPECT_EQ(PSR->Begin.second, BeginColumn);
+ EXPECT_EQ(PSR->End.first, EndLine);
+ EXPECT_EQ(PSR->End.second, EndColumn);
+ };
+
+ Check("/Users/test/a-b.cpp:1:2", "/Users/test/a-b.cpp", 1, 2, 1, 2);
+ Check("/Users/test/a-b.cpp:1:2-3:4", "/Users/test/a-b.cpp", 1, 2, 3, 4);
+
+ Check("C:/Users/bob/a-b.cpp:1:2", "C:/Users/bob/a-b.cpp", 1, 2, 1, 2);
+ Check("C:/Users/bob/a-b.cpp:1:2-3:4", "C:/Users/bob/a-b.cpp", 1, 2, 3, 4);
+}
+
+} // anonymous namespace
More information about the cfe-commits
mailing list