]> granicus.if.org Git - clang/commitdiff
[AST] Fix RecursiveASTVisitor visiting implicit constructor initializers.
authorJohan Vikstrom <jvikstrom@google.com>
Mon, 5 Aug 2019 12:20:43 +0000 (12:20 +0000)
committerJohan Vikstrom <jvikstrom@google.com>
Mon, 5 Aug 2019 12:20:43 +0000 (12:20 +0000)
Summary: RecursiveASTVisitor was visiting implcit constructor initializers. This caused semantic highlighting in clangd to emit error logs. Fixes this by checking if the constructor is written or if the visitor should visit implicit decls.

Reviewers: hokein, ilya-biryukov

Subscribers: kadircet, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D65735

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

include/clang/AST/RecursiveASTVisitor.h
unittests/Tooling/CMakeLists.txt
unittests/Tooling/RecursiveASTVisitorTests/ImplicitCtorInitializer.cpp [new file with mode: 0644]

index dd2c1dad71b2447153d3f84362a1e44bd53df53b..eb047bd5c56ede1f5ed4be086173fe618ad559e8 100644 (file)
@@ -2023,7 +2023,8 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
   if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
     // Constructor initializers.
     for (auto *I : Ctor->inits()) {
-      TRY_TO(TraverseConstructorInitializer(I));
+      if (I->isWritten() || getDerived().shouldVisitImplicitCode())
+        TRY_TO(TraverseConstructorInitializer(I));
     }
   }
 
index a10bff6d838270af1a495d53fd3b27b828b093c7..99a3e0f209f1021cbdad1131c5250745fb504447 100644 (file)
@@ -31,6 +31,7 @@ add_clang_unittest(ToolingTests
   RecursiveASTVisitorTests/CXXOperatorCallExprTraverser.cpp
   RecursiveASTVisitorTests/DeclRefExpr.cpp
   RecursiveASTVisitorTests/ImplicitCtor.cpp
+  RecursiveASTVisitorTests/ImplicitCtorInitializer.cpp
   RecursiveASTVisitorTests/InitListExprPostOrder.cpp
   RecursiveASTVisitorTests/InitListExprPostOrderNoQueue.cpp
   RecursiveASTVisitorTests/InitListExprPreOrder.cpp
diff --git a/unittests/Tooling/RecursiveASTVisitorTests/ImplicitCtorInitializer.cpp b/unittests/Tooling/RecursiveASTVisitorTests/ImplicitCtorInitializer.cpp
new file mode 100644 (file)
index 0000000..5b133e1
--- /dev/null
@@ -0,0 +1,57 @@
+//=- unittest/Tooling/RecursiveASTVisitorTests/ImplicitCtorInitializer.cpp -=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestVisitor.h"
+
+using namespace clang;
+
+namespace {
+
+class CXXCtorInitializerVisitor
+    : public ExpectedLocationVisitor<CXXCtorInitializerVisitor> {
+public:
+  CXXCtorInitializerVisitor(bool VisitImplicitCode)
+      : VisitImplicitCode(VisitImplicitCode) {}
+
+  bool shouldVisitImplicitCode() const { return VisitImplicitCode; }
+
+  bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
+    if (!Init->isWritten())
+      VisitedImplicitInitializer = true;
+    Match("initializer", Init->getSourceLocation());
+    return ExpectedLocationVisitor<
+        CXXCtorInitializerVisitor>::TraverseConstructorInitializer(Init);
+  }
+
+  bool VisitedImplicitInitializer = false;
+
+private:
+  bool VisitImplicitCode;
+};
+
+// Check to ensure that CXXCtorInitializer is not visited when implicit code
+// should not be visited and that it is visited when implicit code should be
+// visited.
+TEST(RecursiveASTVisitor, CXXCtorInitializerVisitNoImplicit) {
+  for (bool VisitImplCode : {true, false}) {
+    CXXCtorInitializerVisitor Visitor(VisitImplCode);
+    Visitor.ExpectMatch("initializer", 7, 17);
+    EXPECT_TRUE(Visitor.runOver(R"cpp(
+        class A {};
+        class B : public A {
+          B() {};
+        };
+        class C : public A {
+          C() : A() {}
+        };
+      )cpp",
+                                CXXCtorInitializerVisitor::Lang_CXX));
+    EXPECT_EQ(Visitor.VisitedImplicitInitializer, VisitImplCode);
+  }
+}
+} // end anonymous namespace