Home | History | Annotate | Download | only in Tooling
      1 //===- unittest/Tooling/FixitTest.cpp ------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "TestVisitor.h"
     11 #include "clang/Basic/Diagnostic.h"
     12 #include "clang/Tooling/FixIt.h"
     13 
     14 using namespace clang;
     15 
     16 using tooling::fixit::getText;
     17 using tooling::fixit::createRemoval;
     18 using tooling::fixit::createReplacement;
     19 
     20 namespace {
     21 
     22 struct CallsVisitor : TestVisitor<CallsVisitor> {
     23   bool VisitCallExpr(CallExpr *Expr) {
     24     OnCall(Expr, Context);
     25     return true;
     26   }
     27 
     28   std::function<void(CallExpr *, ASTContext *Context)> OnCall;
     29 };
     30 
     31 std::string LocationToString(SourceLocation Loc, ASTContext *Context) {
     32   return Loc.printToString(Context->getSourceManager());
     33 }
     34 
     35 TEST(FixItTest, getText) {
     36   CallsVisitor Visitor;
     37 
     38   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
     39     EXPECT_EQ("foo(x, y)", getText(*CE, *Context));
     40     EXPECT_EQ("foo(x, y)", getText(CE->getSourceRange(), *Context));
     41 
     42     Expr *P0 = CE->getArg(0);
     43     Expr *P1 = CE->getArg(1);
     44     EXPECT_EQ("x", getText(*P0, *Context));
     45     EXPECT_EQ("y", getText(*P1, *Context));
     46   };
     47   Visitor.runOver("void foo(int x, int y) { foo(x, y); }");
     48 
     49   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
     50     EXPECT_EQ("APPLY(foo, x, y)", getText(*CE, *Context));
     51   };
     52   Visitor.runOver("#define APPLY(f, x, y) f(x, y)\n"
     53                   "void foo(int x, int y) { APPLY(foo, x, y); }");
     54 }
     55 
     56 TEST(FixItTest, getTextWithMacro) {
     57   CallsVisitor Visitor;
     58 
     59   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
     60     EXPECT_EQ("F OO", getText(*CE, *Context));
     61     Expr *P0 = CE->getArg(0);
     62     Expr *P1 = CE->getArg(1);
     63     EXPECT_EQ("", getText(*P0, *Context));
     64     EXPECT_EQ("", getText(*P1, *Context));
     65   };
     66   Visitor.runOver("#define F foo(\n"
     67                   "#define OO x, y)\n"
     68                   "void foo(int x, int y) { F OO ; }");
     69 
     70   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
     71     EXPECT_EQ("", getText(*CE, *Context));
     72     Expr *P0 = CE->getArg(0);
     73     Expr *P1 = CE->getArg(1);
     74     EXPECT_EQ("x", getText(*P0, *Context));
     75     EXPECT_EQ("y", getText(*P1, *Context));
     76   };
     77   Visitor.runOver("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n"
     78                   "void foo(int x, int y) { FOO(x,y) }");
     79 }
     80 
     81 TEST(FixItTest, createRemoval) {
     82   CallsVisitor Visitor;
     83 
     84   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
     85     FixItHint Hint = createRemoval(*CE);
     86     EXPECT_EQ("foo(x, y)", getText(Hint.RemoveRange.getAsRange(), *Context));
     87     EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
     88     EXPECT_TRUE(Hint.CodeToInsert.empty());
     89 
     90     Expr *P0 = CE->getArg(0);
     91     FixItHint Hint0 = createRemoval(*P0);
     92     EXPECT_EQ("x", getText(Hint0.RemoveRange.getAsRange(), *Context));
     93     EXPECT_TRUE(Hint0.InsertFromRange.isInvalid());
     94     EXPECT_TRUE(Hint0.CodeToInsert.empty());
     95 
     96     Expr *P1 = CE->getArg(1);
     97     FixItHint Hint1 = createRemoval(*P1);
     98     EXPECT_EQ("y", getText(Hint1.RemoveRange.getAsRange(), *Context));
     99     EXPECT_TRUE(Hint1.InsertFromRange.isInvalid());
    100     EXPECT_TRUE(Hint1.CodeToInsert.empty());
    101   };
    102   Visitor.runOver("void foo(int x, int y) { foo(x, y); }");
    103 
    104   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
    105     Expr *P0 = CE->getArg(0);
    106     FixItHint Hint0 = createRemoval(*P0);
    107     EXPECT_EQ("x + y", getText(Hint0.RemoveRange.getAsRange(), *Context));
    108 
    109     Expr *P1 = CE->getArg(1);
    110     FixItHint Hint1 = createRemoval(*P1);
    111     EXPECT_EQ("y + x", getText(Hint1.RemoveRange.getAsRange(), *Context));
    112   };
    113   Visitor.runOver("void foo(int x, int y) { foo(x + y, y + x); }");
    114 }
    115 
    116 TEST(FixItTest, createRemovalWithMacro) {
    117   CallsVisitor Visitor;
    118 
    119   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
    120     FixItHint Hint = createRemoval(*CE);
    121     EXPECT_EQ("FOO", getText(Hint.RemoveRange.getAsRange(), *Context));
    122     EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
    123     EXPECT_TRUE(Hint.CodeToInsert.empty());
    124 
    125     Expr *P0 = CE->getArg(0);
    126     FixItHint Hint0 = createRemoval(*P0);
    127     EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:17>",
    128               LocationToString(Hint0.RemoveRange.getBegin(), Context));
    129     EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:17>",
    130               LocationToString(Hint0.RemoveRange.getEnd(), Context));
    131     EXPECT_TRUE(Hint0.InsertFromRange.isInvalid());
    132     EXPECT_TRUE(Hint0.CodeToInsert.empty());
    133 
    134     Expr *P1 = CE->getArg(1);
    135     FixItHint Hint1 = createRemoval(*P1);
    136     EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:20>",
    137               LocationToString(Hint1.RemoveRange.getBegin(), Context));
    138     EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:20>",
    139               LocationToString(Hint1.RemoveRange.getEnd(), Context));
    140     EXPECT_TRUE(Hint1.InsertFromRange.isInvalid());
    141     EXPECT_TRUE(Hint1.CodeToInsert.empty());
    142   };
    143   Visitor.runOver("#define FOO foo(1, 1)\n"
    144                   "void foo(int x, int y) { FOO; }");
    145 
    146   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
    147     FixItHint Hint = createRemoval(*CE);
    148     EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:37>",
    149               LocationToString(Hint.RemoveRange.getBegin(), Context));
    150     EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:45>",
    151               LocationToString(Hint.RemoveRange.getEnd(), Context));
    152     EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
    153     EXPECT_TRUE(Hint.CodeToInsert.empty());
    154   };
    155   Visitor.runOver("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n"
    156                   "void foo(int x, int y) { FOO(x,y) }");
    157 }
    158 
    159 TEST(FixItTest, createReplacement) {
    160   CallsVisitor Visitor;
    161 
    162   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
    163     Expr *P0 = CE->getArg(0);
    164     Expr *P1 = CE->getArg(1);
    165     FixItHint Hint0 = createReplacement(*P0, *P1, *Context);
    166     FixItHint Hint1 = createReplacement(*P1, *P0, *Context);
    167 
    168     // Validate Hint0 fields.
    169     EXPECT_EQ("x", getText(Hint0.RemoveRange.getAsRange(), *Context));
    170     EXPECT_TRUE(Hint0.InsertFromRange.isInvalid());
    171     EXPECT_EQ(Hint0.CodeToInsert, "y");
    172 
    173     // Validate Hint1 fields.
    174     EXPECT_EQ("y", getText(Hint1.RemoveRange.getAsRange(), *Context));
    175     EXPECT_TRUE(Hint1.InsertFromRange.isInvalid());
    176     EXPECT_EQ(Hint1.CodeToInsert, "x");
    177   };
    178 
    179   Visitor.runOver("void foo(int x, int y) { foo(x, y); }");
    180 
    181   Visitor.runOver("#define APPLY(f, x, y) f(x, y)\n"
    182                   "void foo(int x, int y) { APPLY(foo, x, y); }");
    183 
    184   Visitor.runOver("#define APPLY(f, P) f(P)\n"
    185                   "#define PAIR(x, y) x, y\n"
    186                   "void foo(int x, int y) { APPLY(foo, PAIR(x, y)); }\n");
    187 }
    188 
    189 TEST(FixItTest, createReplacementWithMacro) {
    190   CallsVisitor Visitor;
    191 
    192   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
    193     Expr *P0 = CE->getArg(0);
    194     Expr *P1 = CE->getArg(1);
    195     FixItHint Hint = createReplacement(*P0, *P1, *Context);
    196     EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:17>",
    197               LocationToString(Hint.RemoveRange.getBegin(), Context));
    198     EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:1:17>",
    199               LocationToString(Hint.RemoveRange.getEnd(), Context));
    200     EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
    201     EXPECT_TRUE(Hint.CodeToInsert.empty());
    202   };
    203 
    204   Visitor.runOver("#define FOO foo(1, 1)\n"
    205                   "void foo(int x, int y) { FOO; }");
    206 
    207   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
    208     Expr *P0 = CE->getArg(0);
    209     Expr *P1 = CE->getArg(1);
    210     FixItHint Hint = createReplacement(*P0, *P1, *Context);
    211     EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:2:30>",
    212               LocationToString(Hint.RemoveRange.getBegin(), Context));
    213     EXPECT_EQ("input.cc:2:26 <Spelling=input.cc:2:30>",
    214               LocationToString(Hint.RemoveRange.getEnd(), Context));
    215     EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
    216     EXPECT_EQ("y", Hint.CodeToInsert);
    217   };
    218   Visitor.runOver("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n"
    219                   "void foo(int x, int y) { FOO(x,y) }");
    220 
    221   Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
    222     Expr *P0 = CE->getArg(0);
    223     Expr *P1 = CE->getArg(1);
    224     FixItHint Hint = createReplacement(*P0, *P1, *Context);
    225     EXPECT_EQ("x + y", getText(Hint.RemoveRange.getAsRange(), *Context));
    226     EXPECT_TRUE(Hint.InsertFromRange.isInvalid());
    227     EXPECT_EQ("y + x", Hint.CodeToInsert);
    228   };
    229   Visitor.runOver("void foo(int x, int y) { foo(x + y, y + x); }");
    230 }
    231 
    232 } // end anonymous namespace
    233