]> granicus.if.org Git - clang/commitdiff
Teach RAV to visit parameter variable declarations of implicit functions. Fixes PR16182.
authorMichael Han <fragmentshaders@gmail.com>
Wed, 11 Sep 2013 15:53:29 +0000 (15:53 +0000)
committerMichael Han <fragmentshaders@gmail.com>
Wed, 11 Sep 2013 15:53:29 +0000 (15:53 +0000)
Normally RAV visits parameter variable declarations of a function by traversing the TypeLoc of
the parameter declarations. However, for implicit functions, their parameters don't have any
TypeLoc, because they are implicit.

So for implicit functions, we visit their parameter variable declarations by traversing them through
the function declaration, and visit them accordingly.

Reviewed by Richard Smith and Manuel Klimek.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@190528 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/RecursiveASTVisitor.h
unittests/ASTMatchers/ASTMatchersTest.cpp
unittests/Tooling/RecursiveASTVisitorTest.cpp
unittests/Tooling/TestVisitor.h

index ac7795f933997e004a318f976cd4ec16e079e523..acba46dcd789915c3d32e54c514f8b58ffa235d3 100644 (file)
@@ -1776,6 +1776,14 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
   // including exception specifications.
   if (TypeSourceInfo *TSI = D->getTypeSourceInfo()) {
     TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
+  } else if (getDerived().shouldVisitImplicitCode()) {
+    // Visit parameter variable declarations of the implicit function
+    // if the traverser is visiting implicit code. Parameter variable
+    // declarations do not have valid TypeSourceInfo, so to visit them
+    // we need to traverse the declarations explicitly.
+    for (FunctionDecl::param_const_iterator I = D->param_begin(),
+                                            E = D->param_end(); I != E; ++I)
+      TRY_TO(TraverseDecl(*I));
   }
 
   if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
index 4994192bda334a44e98717369786862449d0790e..556b0b896e639e9bec75cd4c530e0be609c7e3f8 100644 (file)
@@ -1361,8 +1361,12 @@ TEST(Matcher, References) {
                       ReferenceClassX));
   EXPECT_TRUE(
       matches("class X {}; void y(X y) { const X &x = y; }", ReferenceClassX));
+  // The match here is on the implicit copy constructor code for
+  // class X, not on code 'X x = y'.
   EXPECT_TRUE(
-      notMatches("class X {}; void y(X y) { X x = y; }", ReferenceClassX));
+      matches("class X {}; void y(X y) { X x = y; }", ReferenceClassX));
+  EXPECT_TRUE(
+      notMatches("class X {}; extern X x;", ReferenceClassX));
   EXPECT_TRUE(
       notMatches("class X {}; void y(X *y) { X *&x = y; }", ReferenceClassX));
 }
index b1d6f4a37c07177b46ca2d74dc7a46ad5407d9e1..b3a8915a59de5718979659cd23c0027790ba9802 100644 (file)
@@ -37,6 +37,17 @@ public:
  }
 };
 
+class ParmVarDeclVisitorForImplicitCode :
+  public ExpectedLocationVisitor<ParmVarDeclVisitorForImplicitCode> {
+public:
+  bool shouldVisitImplicitCode() const { return true; }
+
+  bool VisitParmVarDecl(ParmVarDecl *ParamVar) {
+    Match(ParamVar->getNameAsString(), ParamVar->getLocStart());
+    return true;
+  }
+};
+
 class CXXMemberCallVisitor
   : public ExpectedLocationVisitor<CXXMemberCallVisitor> {
 public:
@@ -144,6 +155,20 @@ public:
   }
 };
 
+// Test RAV visits parameter variable declaration of the implicit
+// copy assignment operator.
+TEST(RecursiveASTVisitor, VisitsParmVarDeclForImplicitCode) {
+  ParmVarDeclVisitorForImplicitCode Visitor;
+  // Match parameter variable name of implicit copy assignment operator.
+  // This parameter name does not have a valid IdentifierInfo, and shares
+  // same SourceLocation with its class declaration, so we match an empty name
+  // with the class' source location.
+  Visitor.ExpectMatch("", 1, 7);
+  EXPECT_TRUE(Visitor.runOver(
+    "class X {};\n"
+    "void foo(X a, X b) {a = b;}"));
+}
+
 TEST(RecursiveASTVisitor, VisitsBaseClassDeclarations) {
   TypeLocVisitor Visitor;
   Visitor.ExpectMatch("class X", 1, 30);
index 5ee118ebdccef2db166afb5e7b9996a6c7e46cb3..ec751c350e068be7bb347aed3541a02e6c654dc2 100644 (file)
@@ -31,7 +31,7 @@ namespace clang {
 /// This is a drop-in replacement for RecursiveASTVisitor itself, with the
 /// additional capability of running it over a snippet of code.
 ///
-/// Visits template instantiations (but not implicit code) by default.
+/// Visits template instantiations and implicit code by default.
 template <typename T>
 class TestVisitor : public RecursiveASTVisitor<T> {
 public:
@@ -56,6 +56,10 @@ public:
     return true;
   }
 
+  bool shouldVisitImplicitCode() const {
+    return true;
+  }
+
 protected:
   virtual ASTFrontendAction* CreateTestAction() {
     return new TestAction(this);