r269188 - [tooling] FixItHint Tooling refactoring
Etienne Bergeron via cfe-commits
cfe-commits at lists.llvm.org
Wed May 11 07:31:39 PDT 2016
Author: etienneb
Date: Wed May 11 09:31:39 2016
New Revision: 269188
URL: http://llvm.org/viewvc/llvm-project?rev=269188&view=rev
Log:
[tooling] FixItHint Tooling refactoring
Summary:
This is the refactoring to lift some FixItHint into tooling.
used by: http://reviews.llvm.org/D19807
Reviewers: klimek, alexfh
Subscribers: cfe-commits
Differential Revision: http://reviews.llvm.org/D19941
Added:
cfe/trunk/include/clang/Tooling/FixIt.h
cfe/trunk/lib/Tooling/FixIt.cpp
cfe/trunk/unittests/Tooling/FixItTest.cpp
Modified:
cfe/trunk/lib/Tooling/CMakeLists.txt
cfe/trunk/unittests/Tooling/CMakeLists.txt
Added: cfe/trunk/include/clang/Tooling/FixIt.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/FixIt.h?rev=269188&view=auto
==============================================================================
--- cfe/trunk/include/clang/Tooling/FixIt.h (added)
+++ cfe/trunk/include/clang/Tooling/FixIt.h Wed May 11 09:31:39 2016
@@ -0,0 +1,72 @@
+//===--- FixIt.h - FixIt Hint utilities -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements functions to ease source rewriting from AST-nodes.
+//
+// Example swapping A and B expressions:
+//
+// Expr *A, *B;
+// tooling::fixit::createReplacement(*A, *B);
+// tooling::fixit::createReplacement(*B, *A);
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_FIXIT_H
+#define LLVM_CLANG_TOOLING_FIXIT_H
+
+#include "clang/AST/ASTContext.h"
+
+namespace clang {
+namespace tooling {
+namespace fixit {
+
+namespace internal {
+StringRef getText(SourceRange Range, const ASTContext &Context);
+
+/// \brief Returns the SourceRange of a SourceRange. This identity function is
+/// used by the following template abstractions.
+inline SourceRange getSourceRange(const SourceRange &Range) { return Range; }
+
+/// \brief Returns the SourceRange of the token at Location \p Loc.
+inline SourceRange getSourceRange(const SourceLocation &Loc) {
+ return SourceRange(Loc);
+}
+
+/// \brief Returns the SourceRange of an given Node. \p Node is typically a
+/// 'Stmt', 'Expr' or a 'Decl'.
+template <typename T> SourceRange getSourceRange(const T &Node) {
+ return Node.getSourceRange();
+}
+} // end namespace internal
+
+// \brief Returns a textual representation of \p Node.
+template <typename T>
+StringRef getText(const T &Node, const ASTContext &Context) {
+ return internal::getText(internal::getSourceRange(Node), Context);
+}
+
+// \brief Returns a FixItHint to remove \p Node.
+// TODO: Add support for related syntactical elements (i.e. comments, ...).
+template <typename T> FixItHint createRemoval(const T &Node) {
+ return FixItHint::CreateRemoval(internal::getSourceRange(Node));
+}
+
+// \brief Returns a FixItHint to replace \p Destination by \p Source.
+template <typename D, typename S>
+FixItHint createReplacement(const D &Destination, const S &Source,
+ const ASTContext &Context) {
+ return FixItHint::CreateReplacement(internal::getSourceRange(Destination),
+ getText(Source, Context));
+}
+
+} // end namespace fixit
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_FIXINT_H
Modified: cfe/trunk/lib/Tooling/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/CMakeLists.txt?rev=269188&r1=269187&r2=269188&view=diff
==============================================================================
--- cfe/trunk/lib/Tooling/CMakeLists.txt (original)
+++ cfe/trunk/lib/Tooling/CMakeLists.txt Wed May 11 09:31:39 2016
@@ -7,6 +7,7 @@ add_clang_library(clangTooling
CommonOptionsParser.cpp
CompilationDatabase.cpp
FileMatchTrie.cpp
+ FixIt.cpp
JSONCompilationDatabase.cpp
Refactoring.cpp
RefactoringCallbacks.cpp
Added: cfe/trunk/lib/Tooling/FixIt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/FixIt.cpp?rev=269188&view=auto
==============================================================================
--- cfe/trunk/lib/Tooling/FixIt.cpp (added)
+++ cfe/trunk/lib/Tooling/FixIt.cpp Wed May 11 09:31:39 2016
@@ -0,0 +1,31 @@
+//===--- FixIt.cpp - FixIt Hint utilities -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains implementations of utitilies to ease source code rewriting
+// by providing helper functions related to FixItHint.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Tooling/FixIt.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang {
+namespace tooling {
+namespace fixit {
+
+namespace internal {
+StringRef getText(SourceRange Range, const ASTContext &Context) {
+ return Lexer::getSourceText(CharSourceRange::getTokenRange(Range),
+ Context.getSourceManager(),
+ Context.getLangOpts());
+}
+} // end namespace internal
+
+} // end namespace fixit
+} // end namespace tooling
+} // end namespace clang
Modified: cfe/trunk/unittests/Tooling/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/CMakeLists.txt?rev=269188&r1=269187&r2=269188&view=diff
==============================================================================
--- cfe/trunk/unittests/Tooling/CMakeLists.txt (original)
+++ cfe/trunk/unittests/Tooling/CMakeLists.txt Wed May 11 09:31:39 2016
@@ -12,18 +12,19 @@ endif()
add_clang_unittest(ToolingTests
CommentHandlerTest.cpp
CompilationDatabaseTest.cpp
+ FixItTest.cpp
LookupTest.cpp
- ToolingTest.cpp
+ QualTypeNamesTest.cpp
RecursiveASTVisitorTest.cpp
RecursiveASTVisitorTestCallVisitor.cpp
RecursiveASTVisitorTestDeclVisitor.cpp
RecursiveASTVisitorTestExprVisitor.cpp
RecursiveASTVisitorTestTypeLocVisitor.cpp
- RefactoringTest.cpp
- RewriterTest.cpp
RefactoringCallbacksTest.cpp
+ RefactoringTest.cpp
ReplacementsYamlTest.cpp
- QualTypeNamesTest.cpp
+ RewriterTest.cpp
+ ToolingTest.cpp
)
target_link_libraries(ToolingTests
Added: cfe/trunk/unittests/Tooling/FixItTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/FixItTest.cpp?rev=269188&view=auto
==============================================================================
--- cfe/trunk/unittests/Tooling/FixItTest.cpp (added)
+++ cfe/trunk/unittests/Tooling/FixItTest.cpp Wed May 11 09:31:39 2016
@@ -0,0 +1,232 @@
+//===- unittest/Tooling/FixitTest.cpp ------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestVisitor.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang;
+
+using tooling::fixit::getText;
+using tooling::fixit::createRemoval;
+using tooling::fixit::createReplacement;
+
+namespace {
+
+struct CallsVisitor : TestVisitor<CallsVisitor> {
+ bool VisitCallExpr(CallExpr *Expr) {
+ OnCall(Expr, Context);
+ return true;
+ }
+
+ std::function<void(CallExpr *, ASTContext *Context)> OnCall;
+};
+
+std::string LocationToString(SourceLocation Loc, ASTContext *Context) {
+ return Loc.printToString(Context->getSourceManager());
+}
+
+TEST(FixItTest, getText) {
+ CallsVisitor Visitor;
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ EXPECT_EQ("foo(x, y)", getText(*CE, *Context));
+ EXPECT_EQ("foo(x, y)", getText(CE->getSourceRange(), *Context));
+
+ Expr *P0 = CE->getArg(0);
+ Expr *P1 = CE->getArg(1);
+ EXPECT_EQ("x", getText(*P0, *Context));
+ EXPECT_EQ("y", getText(*P1, *Context));
+ };
+ Visitor.runOver("void foo(int x, int y) { foo(x, y); }");
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ EXPECT_EQ("APPLY(foo, x, y)", getText(*CE, *Context));
+ };
+ Visitor.runOver("#define APPLY(f, x, y) f(x, y)\n"
+ "void foo(int x, int y) { APPLY(foo, x, y); }");
+}
+
+TEST(FixItTest, getTextWithMacro) {
+ CallsVisitor Visitor;
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ EXPECT_EQ("F OO", getText(*CE, *Context));
+ Expr *P0 = CE->getArg(0);
+ Expr *P1 = CE->getArg(1);
+ EXPECT_EQ("", getText(*P0, *Context));
+ EXPECT_EQ("", getText(*P1, *Context));
+ };
+ Visitor.runOver("#define F foo(\n"
+ "#define OO x, y)\n"
+ "void foo(int x, int y) { F OO ; }");
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ EXPECT_EQ("", getText(*CE, *Context));
+ Expr *P0 = CE->getArg(0);
+ Expr *P1 = CE->getArg(1);
+ EXPECT_EQ("x", getText(*P0, *Context));
+ EXPECT_EQ("y", getText(*P1, *Context));
+ };
+ Visitor.runOver("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n"
+ "void foo(int x, int y) { FOO(x,y) }");
+}
+
+TEST(FixItTest, createRemoval) {
+ CallsVisitor Visitor;
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ FixItHint Hint = createRemoval(*CE);
+ EXPECT_EQ("foo(x, y)", getText(Hint.RemoveRange.getAsRange(), *Context));
+ EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
+ EXPECT_TRUE(Hint.CodeToInsert.empty());
+
+ Expr *P0 = CE->getArg(0);
+ FixItHint Hint0 = createRemoval(*P0);
+ EXPECT_EQ("x", getText(Hint0.RemoveRange.getAsRange(), *Context));
+ EXPECT_TRUE(Hint0.InsertFromRange.isInvalid());
+ EXPECT_TRUE(Hint0.CodeToInsert.empty());
+
+ Expr *P1 = CE->getArg(1);
+ FixItHint Hint1 = createRemoval(*P1);
+ EXPECT_EQ("y", getText(Hint1.RemoveRange.getAsRange(), *Context));
+ EXPECT_TRUE(Hint1.InsertFromRange.isInvalid());
+ EXPECT_TRUE(Hint1.CodeToInsert.empty());
+ };
+ Visitor.runOver("void foo(int x, int y) { foo(x, y); }");
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ Expr *P0 = CE->getArg(0);
+ FixItHint Hint0 = createRemoval(*P0);
+ EXPECT_EQ("x + y", getText(Hint0.RemoveRange.getAsRange(), *Context));
+
+ Expr *P1 = CE->getArg(1);
+ FixItHint Hint1 = createRemoval(*P1);
+ EXPECT_EQ("y + x", getText(Hint1.RemoveRange.getAsRange(), *Context));
+ };
+ Visitor.runOver("void foo(int x, int y) { foo(x + y, y + x); }");
+}
+
+TEST(FixItTest, createRemovalWithMacro) {
+ CallsVisitor Visitor;
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ FixItHint Hint = createRemoval(*CE);
+ EXPECT_EQ("FOO", getText(Hint.RemoveRange.getAsRange(), *Context));
+ EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
+ EXPECT_TRUE(Hint.CodeToInsert.empty());
+
+ Expr *P0 = CE->getArg(0);
+ FixItHint Hint0 = createRemoval(*P0);
+ EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:17>",
+ LocationToString(Hint0.RemoveRange.getBegin(), Context));
+ EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:17>",
+ LocationToString(Hint0.RemoveRange.getEnd(), Context));
+ EXPECT_TRUE(Hint0.InsertFromRange.isInvalid());
+ EXPECT_TRUE(Hint0.CodeToInsert.empty());
+
+ Expr *P1 = CE->getArg(1);
+ FixItHint Hint1 = createRemoval(*P1);
+ EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:20>",
+ LocationToString(Hint1.RemoveRange.getBegin(), Context));
+ EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:20>",
+ LocationToString(Hint1.RemoveRange.getEnd(), Context));
+ EXPECT_TRUE(Hint1.InsertFromRange.isInvalid());
+ EXPECT_TRUE(Hint1.CodeToInsert.empty());
+ };
+ Visitor.runOver("#define FOO foo(1, 1)\n"
+ "void foo(int x, int y) { FOO; }");
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ FixItHint Hint = createRemoval(*CE);
+ EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:37>",
+ LocationToString(Hint.RemoveRange.getBegin(), Context));
+ EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:45>",
+ LocationToString(Hint.RemoveRange.getEnd(), Context));
+ EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
+ EXPECT_TRUE(Hint.CodeToInsert.empty());
+ };
+ Visitor.runOver("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n"
+ "void foo(int x, int y) { FOO(x,y) }");
+}
+
+TEST(FixItTest, createReplacement) {
+ CallsVisitor Visitor;
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ Expr *P0 = CE->getArg(0);
+ Expr *P1 = CE->getArg(1);
+ FixItHint Hint0 = createReplacement(*P0, *P1, *Context);
+ FixItHint Hint1 = createReplacement(*P1, *P0, *Context);
+
+ // Validate Hint0 fields.
+ EXPECT_EQ("x", getText(Hint0.RemoveRange.getAsRange(), *Context));
+ EXPECT_TRUE(Hint0.InsertFromRange.isInvalid());
+ EXPECT_EQ(Hint0.CodeToInsert, "y");
+
+ // Validate Hint1 fields.
+ EXPECT_EQ("y", getText(Hint1.RemoveRange.getAsRange(), *Context));
+ EXPECT_TRUE(Hint1.InsertFromRange.isInvalid());
+ EXPECT_EQ(Hint1.CodeToInsert, "x");
+ };
+
+ Visitor.runOver("void foo(int x, int y) { foo(x, y); }");
+
+ Visitor.runOver("#define APPLY(f, x, y) f(x, y)\n"
+ "void foo(int x, int y) { APPLY(foo, x, y); }");
+
+ Visitor.runOver("#define APPLY(f, P) f(P)\n"
+ "#define PAIR(x, y) x, y\n"
+ "void foo(int x, int y) { APPLY(foo, PAIR(x, y)); }\n");
+}
+
+TEST(FixItTest, createReplacementWithMacro) {
+ CallsVisitor Visitor;
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ Expr *P0 = CE->getArg(0);
+ Expr *P1 = CE->getArg(1);
+ FixItHint Hint = createReplacement(*P0, *P1, *Context);
+ EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:17>",
+ LocationToString(Hint.RemoveRange.getBegin(), Context));
+ EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:17>",
+ LocationToString(Hint.RemoveRange.getEnd(), Context));
+ EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
+ EXPECT_TRUE(Hint.CodeToInsert.empty());
+ };
+
+ Visitor.runOver("#define FOO foo(1, 1)\n"
+ "void foo(int x, int y) { FOO; }");
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ Expr *P0 = CE->getArg(0);
+ Expr *P1 = CE->getArg(1);
+ FixItHint Hint = createReplacement(*P0, *P1, *Context);
+ EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:2:30>",
+ LocationToString(Hint.RemoveRange.getBegin(), Context));
+ EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:2:30>",
+ LocationToString(Hint.RemoveRange.getEnd(), Context));
+ EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
+ EXPECT_EQ("y", Hint.CodeToInsert);
+ };
+ Visitor.runOver("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n"
+ "void foo(int x, int y) { FOO(x,y) }");
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ Expr *P0 = CE->getArg(0);
+ Expr *P1 = CE->getArg(1);
+ FixItHint Hint = createReplacement(*P0, *P1, *Context);
+ EXPECT_EQ("x + y", getText(Hint.RemoveRange.getAsRange(), *Context));
+ EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
+ EXPECT_EQ("y + x", Hint.CodeToInsert);
+ };
+ Visitor.runOver("void foo(int x, int y) { foo(x + y, y + x); }");
+}
+
+} // end anonymous namespace
More information about the cfe-commits
mailing list