ilya-biryukov created this revision.
ilya-biryukov added a reviewer: gribozavr2.
Herald added a project: clang.
ilya-biryukov added a parent revision: D72072: [AST] Respect 
shouldTraversePostOrder when traversing type locs.

They cover part of types and names for some declarations, including
common cases like variables, functions, etc.

See the comment of Declarator for more details.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D72089

Files:
  clang/include/clang/Tooling/Syntax/Nodes.h
  clang/lib/Tooling/Syntax/BuildTree.cpp
  clang/lib/Tooling/Syntax/Nodes.cpp
  clang/unittests/Tooling/Syntax/TreeTest.cpp

Index: clang/unittests/Tooling/Syntax/TreeTest.cpp
===================================================================
--- clang/unittests/Tooling/Syntax/TreeTest.cpp
+++ clang/unittests/Tooling/Syntax/TreeTest.cpp
@@ -173,17 +173,21 @@
 *: TranslationUnit
 |-SimpleDeclaration
 | |-int
-| |-main
-| |-(
-| |-)
+| |-SimpleDeclarator
+| | |-main
+| | `-ParametersAndQualifiers
+| |   |-(
+| |   `-)
 | `-CompoundStatement
 |   |-{
 |   `-}
 `-SimpleDeclaration
   |-void
-  |-foo
-  |-(
-  |-)
+  |-SimpleDeclarator
+  | |-foo
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
   `-CompoundStatement
     |-{
     `-}
@@ -200,9 +204,11 @@
 *: TranslationUnit
 `-SimpleDeclaration
   |-int
-  |-main
-  |-(
-  |-)
+  |-SimpleDeclarator
+  | |-main
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
   `-CompoundStatement
     |-{
     |-IfStatement
@@ -245,9 +251,11 @@
 *: TranslationUnit
 `-SimpleDeclaration
   |-void
-  |-test
-  |-(
-  |-)
+  |-SimpleDeclarator
+  | |-test
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
   `-CompoundStatement
     |-{
     |-ForStatement
@@ -267,18 +275,21 @@
 *: TranslationUnit
 `-SimpleDeclaration
   |-void
-  |-test
-  |-(
-  |-)
+  |-SimpleDeclarator
+  | |-test
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
   `-CompoundStatement
     |-{
     |-DeclarationStatement
     | |-SimpleDeclaration
     | | |-int
-    | | |-a
-    | | |-=
-    | | `-UnknownExpression
-    | |   `-10
+    | | `-SimpleDeclarator
+    | |   |-a
+    | |   |-=
+    | |   `-UnknownExpression
+    | |     `-10
     | `-;
     `-}
 )txt"},
@@ -286,9 +297,11 @@
 *: TranslationUnit
 `-SimpleDeclaration
   |-void
-  |-test
-  |-(
-  |-)
+  |-SimpleDeclarator
+  | |-test
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
   `-CompoundStatement
     |-{
     |-EmptyStatement
@@ -308,9 +321,11 @@
 *: TranslationUnit
 `-SimpleDeclaration
   |-void
-  |-test
-  |-(
-  |-)
+  |-SimpleDeclarator
+  | |-test
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
   `-CompoundStatement
     |-{
     |-SwitchStatement
@@ -344,9 +359,11 @@
 *: TranslationUnit
 `-SimpleDeclaration
   |-void
-  |-test
-  |-(
-  |-)
+  |-SimpleDeclarator
+  | |-test
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
   `-CompoundStatement
     |-{
     |-WhileStatement
@@ -374,9 +391,11 @@
 *: TranslationUnit
 `-SimpleDeclaration
   |-int
-  |-test
-  |-(
-  |-)
+  |-SimpleDeclarator
+  | |-test
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
   `-CompoundStatement
     |-{
     |-ReturnStatement
@@ -397,26 +416,31 @@
 *: TranslationUnit
 `-SimpleDeclaration
   |-void
-  |-test
-  |-(
-  |-)
+  |-SimpleDeclarator
+  | |-test
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
   `-CompoundStatement
     |-{
     |-DeclarationStatement
     | |-SimpleDeclaration
     | | |-int
-    | | |-a
-    | | |-[
-    | | |-UnknownExpression
-    | | | `-3
-    | | `-]
+    | | `-SimpleDeclarator
+    | |   |-a
+    | |   `-ArraySubscript
+    | |     |-[
+    | |     |-UnknownExpression
+    | |     | `-3
+    | |     `-]
     | `-;
     |-RangeBasedForStatement
     | |-for
     | |-(
     | |-SimpleDeclaration
     | | |-int
-    | | |-x
+    | | |-SimpleDeclarator
+    | | | `-x
     | | `-:
     | |-UnknownExpression
     | | `-a
@@ -432,9 +456,11 @@
 *: TranslationUnit
 `-SimpleDeclaration
   |-void
-  |-main
-  |-(
-  |-)
+  |-SimpleDeclarator
+  | |-main
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
   `-CompoundStatement
     |-{
     |-UnknownStatement
@@ -459,9 +485,11 @@
 *: TranslationUnit
 `-SimpleDeclaration
   |-void
-  |-test
-  |-(
-  |-)
+  |-SimpleDeclarator
+  | |-test
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
   `-CompoundStatement
     |-{
     |-ExpressionStatement
@@ -499,10 +527,12 @@
 *: TranslationUnit
 `-SimpleDeclaration
   |-int
-  |-*
-  |-a
+  |-SimpleDeclarator
+  | |-*
+  | `-a
   |-,
-  |-b
+  |-SimpleDeclarator
+  | `-b
   `-;
   )txt"},
       {R"cpp(
@@ -513,10 +543,12 @@
 `-SimpleDeclaration
   |-typedef
   |-int
-  |-*
-  |-a
+  |-SimpleDeclarator
+  | |-*
+  | `-a
   |-,
-  |-b
+  |-SimpleDeclarator
+  | `-b
   `-;
   )txt"},
       // Multiple declarators inside a statement.
@@ -530,27 +562,33 @@
 *: TranslationUnit
 `-SimpleDeclaration
   |-void
-  |-foo
-  |-(
-  |-)
+  |-SimpleDeclarator
+  | |-foo
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
   `-CompoundStatement
     |-{
     |-DeclarationStatement
     | |-SimpleDeclaration
     | | |-int
-    | | |-*
-    | | |-a
+    | | |-SimpleDeclarator
+    | | | |-*
+    | | | `-a
     | | |-,
-    | | `-b
+    | | `-SimpleDeclarator
+    | |   `-b
     | `-;
     |-DeclarationStatement
     | |-SimpleDeclaration
     | | |-typedef
     | | |-int
-    | | |-*
-    | | |-ta
+    | | |-SimpleDeclarator
+    | | | |-*
+    | | | `-ta
     | | |-,
-    | | `-tb
+    | | `-SimpleDeclarator
+    | |   `-tb
     | `-;
     `-}
   )txt"},
@@ -606,9 +644,11 @@
   |->
   `-SimpleDeclaration
     |-int
-    |-foo
-    |-(
-    |-)
+    |-SimpleDeclarator
+    | |-foo
+    | `-ParametersAndQualifiers
+    |   |-(
+    |   `-)
     `-CompoundStatement
       |-{
       `-}
@@ -641,9 +681,11 @@
   | |->
   | `-SimpleDeclaration
   |   |-U
-  |   |-foo
-  |   |-(
-  |   |-)
+  |   |-SimpleDeclarator
+  |   | |-foo
+  |   | `-ParametersAndQualifiers
+  |   |   |-(
+  |   |   `-)
   |   `-;
   |-}
   `-;
@@ -745,7 +787,8 @@
 | |-{
 | |-SimpleDeclaration
 | | |-int
-| | |-a
+| | |-SimpleDeclarator
+| | | `-a
 | | `-;
 | `-}
 `-UsingDeclaration
@@ -844,7 +887,8 @@
 | |-"C"
 | `-SimpleDeclaration
 |   |-int
-|   |-a
+|   |-SimpleDeclarator
+|   | `-a
 |   `-;
 `-LinkageSpecificationDeclaration
   |-extern
@@ -852,11 +896,13 @@
   |-{
   |-SimpleDeclaration
   | |-int
-  | |-b
+  | |-SimpleDeclarator
+  | | `-b
   | `-;
   |-SimpleDeclaration
   | |-int
-  | |-c
+  | |-SimpleDeclarator
+  | | `-c
   | `-;
   `-}
        )txt"},
@@ -871,9 +917,11 @@
 *: TranslationUnit
 `-SimpleDeclaration
   |-void
-  |-test
-  |-(
-  |-)
+  |-SimpleDeclarator
+  | |-test
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
   `-CompoundStatement
     |-{
     |-IfStatement
@@ -912,9 +960,11 @@
 *: TranslationUnit
 `-SimpleDeclaration
   |-void
-  |-test
-  |-(
-  |-)
+  |-SimpleDeclarator
+  | |-test
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   `-)
   `-CompoundStatement
     |-{
     |-CompoundStatement
@@ -933,6 +983,309 @@
     | `-}
     `-}
        )txt"},
+      {R"cpp(
+static_assert(true, "message");
+static_assert(true);
+    )cpp",
+       R"txt(
+*: TranslationUnit
+|-StaticAssertDeclaration
+| |-static_assert
+| |-(
+| |-UnknownExpression
+| | `-true
+| |-,
+| |-UnknownExpression
+| | `-"message"
+| |-)
+| `-;
+`-StaticAssertDeclaration
+  |-static_assert
+  |-(
+  |-UnknownExpression
+  | `-true
+  |-)
+  `-;
+       )txt"},
+      // Array subscripts in declarators.
+      {R"cpp(
+int a[10];
+int b[] = {1,2,3};
+    )cpp",
+       R"txt(
+*: TranslationUnit
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-a
+| | `-ArraySubscript
+| |   |-[
+| |   |-UnknownExpression
+| |   | `-10
+| |   `-]
+| `-;
+`-SimpleDeclaration
+  |-int
+  |-SimpleDeclarator
+  | |-b
+  | |-ArraySubscript
+  | | |-[
+  | | `-]
+  | |-=
+  | `-UnknownExpression
+  |   |-{
+  |   |-1
+  |   |-,
+  |   |-2
+  |   |-,
+  |   |-3
+  |   `-}
+  `-;
+       )txt"},
+      // Parameter lists in declarators.
+      {R"cpp(
+int foo(int a, int b);
+    )cpp",
+       R"txt(
+*: TranslationUnit
+`-SimpleDeclaration
+  |-int
+  |-SimpleDeclarator
+  | |-foo
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   |-SimpleDeclaration
+  |   | |-int
+  |   | `-SimpleDeclarator
+  |   |   `-a
+  |   |-,
+  |   |-SimpleDeclaration
+  |   | |-int
+  |   | `-SimpleDeclarator
+  |   |   `-b
+  |   `-)
+  `-;
+       )txt"},
+      // Trailing return type in parameter lists.
+      {R"cpp(
+auto foo() -> int;
+    )cpp",
+       R"txt(
+*: TranslationUnit
+`-SimpleDeclaration
+  |-auto
+  |-SimpleDeclarator
+  | |-foo
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   |-)
+  |   `-TrailingReturnType
+  |     |-->
+  |     `-int
+  `-;
+       )txt"},
+      // Exception specification in parameter lists.
+      {R"cpp(
+int a() noexcept;
+int b() noexcept(true);
+int c() throw();
+    )cpp",
+       R"txt(
+*: TranslationUnit
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-a
+| | `-ParametersAndQualifiers
+| |   |-(
+| |   |-)
+| |   `-noexcept
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-b
+| | `-ParametersAndQualifiers
+| |   |-(
+| |   |-)
+| |   |-noexcept
+| |   |-(
+| |   |-UnknownExpression
+| |   | `-true
+| |   `-)
+| `-;
+`-SimpleDeclaration
+  |-int
+  |-SimpleDeclarator
+  | |-c
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   |-)
+  |   |-throw
+  |   |-(
+  |   `-)
+  `-;
+       )txt"},
+      // Declarators in parentheses.
+      {R"cpp(
+int (a);
+int *(b);
+int (*c)(int);
+int *(d)(int);
+    )cpp",
+       R"txt(
+*: TranslationUnit
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | `-ParenDeclarator
+| |   |-(
+| |   |-a
+| |   `-)
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-*
+| | `-ParenDeclarator
+| |   |-(
+| |   |-b
+| |   `-)
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-SimpleDeclarator
+| | |-ParenDeclarator
+| | | |-(
+| | | |-*
+| | | |-c
+| | | `-)
+| | `-ParametersAndQualifiers
+| |   |-(
+| |   |-SimpleDeclaration
+| |   | `-int
+| |   `-)
+| `-;
+`-SimpleDeclaration
+  |-int
+  |-SimpleDeclarator
+  | |-*
+  | |-ParenDeclarator
+  | | |-(
+  | | |-d
+  | | `-)
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   |-SimpleDeclaration
+  |   | `-int
+  |   `-)
+  `-;
+       )txt"},
+      // CV qualifiers.
+      {R"cpp(
+const int west = -1;
+int const east = 1;
+const int const universal = 0;
+const int const *const *volatile b;
+    )cpp",
+       R"txt(
+*: TranslationUnit
+|-SimpleDeclaration
+| |-const
+| |-int
+| |-SimpleDeclarator
+| | |-west
+| | |-=
+| | `-UnknownExpression
+| |   |--
+| |   `-1
+| `-;
+|-SimpleDeclaration
+| |-int
+| |-const
+| |-SimpleDeclarator
+| | |-east
+| | |-=
+| | `-UnknownExpression
+| |   `-1
+| `-;
+|-SimpleDeclaration
+| |-const
+| |-int
+| |-const
+| |-SimpleDeclarator
+| | |-universal
+| | |-=
+| | `-UnknownExpression
+| |   `-0
+| `-;
+`-SimpleDeclaration
+  |-const
+  |-int
+  |-const
+  |-SimpleDeclarator
+  | |-*
+  | |-const
+  | |-*
+  | |-volatile
+  | `-b
+  `-;
+       )txt"},
+      // Ranges of declarators with trailing return types.
+      {R"cpp(
+auto foo() -> auto(*)(int) -> double*;
+    )cpp",
+       R"txt(
+*: TranslationUnit
+`-SimpleDeclaration
+  |-auto
+  |-SimpleDeclarator
+  | |-foo
+  | `-ParametersAndQualifiers
+  |   |-(
+  |   |-)
+  |   `-TrailingReturnType
+  |     |-->
+  |     |-auto
+  |     `-SimpleDeclarator
+  |       |-ParenDeclarator
+  |       | |-(
+  |       | |-*
+  |       | `-)
+  |       `-ParametersAndQualifiers
+  |         |-(
+  |         |-SimpleDeclaration
+  |         | `-int
+  |         |-)
+  |         `-TrailingReturnType
+  |           |-->
+  |           |-double
+  |           `-SimpleDeclarator
+  |             `-*
+  `-;
+       )txt"},
+      // Member pointers.
+      {R"cpp(
+struct X {};
+int X::* a;
+    )cpp",
+       R"txt(
+*: TranslationUnit
+|-struct
+|-X
+|-{
+|-}
+|-;
+`-SimpleDeclaration
+  |-int
+  |-SimpleDeclarator
+  | |-MemberPointer
+  | | |-X
+  | | |-::
+  | | `-*
+  | `-a
+  `-;
+       )txt"},
   };
 
   for (const auto &T : Cases) {
Index: clang/lib/Tooling/Syntax/Nodes.cpp
===================================================================
--- clang/lib/Tooling/Syntax/Nodes.cpp
+++ clang/lib/Tooling/Syntax/Nodes.cpp
@@ -72,6 +72,18 @@
     return OS << "UsingDeclaration";
   case NodeKind::TypeAliasDeclaration:
     return OS << "TypeAliasDeclaration";
+  case NodeKind::SimpleDeclarator:
+    return OS << "SimpleDeclarator";
+  case NodeKind::ParenDeclarator:
+    return OS << "ParenDeclarator";
+  case NodeKind::ArraySubscript:
+    return OS << "ArraySubscript";
+  case NodeKind::TrailingReturnType:
+    return OS << "TrailingReturnType";
+  case NodeKind::ParametersAndQualifiers:
+    return OS << "ParametersAndQualifiers";
+  case NodeKind::MemberPointer:
+    return OS << "MemberPointer";
   }
   llvm_unreachable("unknown node kind");
 }
@@ -108,6 +120,18 @@
     return OS << "StaticAssertDeclaration_condition";
   case syntax::NodeRole::StaticAssertDeclaration_message:
     return OS << "StaticAssertDeclaration_message";
+  case syntax::NodeRole::SimpleDeclaration_declarator:
+    return OS << "SimpleDeclaration_declarator";
+  case syntax::NodeRole::ArraySubscript_sizeExpression:
+    return OS << "ArraySubscript_sizeExpression";
+  case syntax::NodeRole::TrailingReturnType_arrow:
+    return OS << "TrailingReturnType_arrow";
+  case syntax::NodeRole::TrailingReturnType_declarator:
+    return OS << "TrailingReturnType_declarator";
+  case syntax::NodeRole::ParametersAndQualifiers_parameter:
+    return OS << "ParametersAndQualifiers_parameter";
+  case syntax::NodeRole::ParametersAndQualifiers_trailingReturn:
+    return OS << "ParametersAndQualifiers_trailingReturn";
   }
   llvm_unreachable("invalid role");
 }
@@ -250,3 +274,73 @@
   return llvm::cast_or_null<syntax::Expression>(
       findChild(syntax::NodeRole::StaticAssertDeclaration_message));
 }
+
+std::vector<syntax::SimpleDeclarator *>
+syntax::SimpleDeclaration::declarators() {
+  std::vector<syntax::SimpleDeclarator *> Children;
+  for (auto *C = firstChild(); C; C = C->nextSibling()) {
+    if (C->role() == syntax::NodeRole::SimpleDeclaration_declarator)
+      Children.push_back(llvm::cast<syntax::SimpleDeclarator>(C));
+  }
+  return Children;
+}
+
+syntax::Leaf *syntax::ParenDeclarator::lparen() {
+  return llvm::cast_or_null<syntax::Leaf>(
+      findChild(syntax::NodeRole::OpenParen));
+}
+
+syntax::Leaf *syntax::ParenDeclarator::rparen() {
+  return llvm::cast_or_null<syntax::Leaf>(
+      findChild(syntax::NodeRole::CloseParen));
+}
+
+syntax::Leaf *syntax::ArraySubscript::lbracket() {
+  return llvm::cast_or_null<syntax::Leaf>(
+      findChild(syntax::NodeRole::OpenParen));
+}
+
+syntax::Expression *syntax::ArraySubscript::sizeExpression() {
+  return llvm::cast_or_null<syntax::Expression>(
+      findChild(syntax::NodeRole::ArraySubscript_sizeExpression));
+}
+
+syntax::Leaf *syntax::ArraySubscript::rbracket() {
+  return llvm::cast_or_null<syntax::Leaf>(
+      findChild(syntax::NodeRole::CloseParen));
+}
+
+syntax::Leaf *syntax::TrailingReturnType::arrow() {
+  return llvm::cast_or_null<syntax::Leaf>(
+      findChild(syntax::NodeRole::TrailingReturnType_arrow));
+}
+
+syntax::SimpleDeclarator *syntax::TrailingReturnType::declarator() {
+  return llvm::cast_or_null<syntax::SimpleDeclarator>(
+      findChild(syntax::NodeRole::TrailingReturnType_declarator));
+}
+
+syntax::Leaf *syntax::ParametersAndQualifiers::lparen() {
+  return llvm::cast_or_null<syntax::Leaf>(
+      findChild(syntax::NodeRole::OpenParen));
+}
+
+std::vector<syntax::SimpleDeclaration *>
+syntax::ParametersAndQualifiers::parameters() {
+  std::vector<syntax::SimpleDeclaration *> Children;
+  for (auto *C = firstChild(); C; C = C->nextSibling()) {
+    if (C->role() == syntax::NodeRole::ParametersAndQualifiers_parameter)
+      Children.push_back(llvm::cast<syntax::SimpleDeclaration>(C));
+  }
+  return Children;
+}
+
+syntax::Leaf *syntax::ParametersAndQualifiers::rparen() {
+  return llvm::cast_or_null<syntax::Leaf>(
+      findChild(syntax::NodeRole::CloseParen));
+}
+
+syntax::TrailingReturnType *syntax::ParametersAndQualifiers::trailingReturn() {
+  return llvm::cast_or_null<syntax::TrailingReturnType>(
+      findChild(syntax::NodeRole::ParametersAndQualifiers_trailingReturn));
+}
Index: clang/lib/Tooling/Syntax/BuildTree.cpp
===================================================================
--- clang/lib/Tooling/Syntax/BuildTree.cpp
+++ clang/lib/Tooling/Syntax/BuildTree.cpp
@@ -6,10 +6,15 @@
 //
 //===----------------------------------------------------------------------===//
 #include "clang/Tooling/Syntax/BuildTree.h"
+#include "clang/AST/ASTFwd.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclarationName.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Stmt.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/AST/TypeLocVisitor.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
@@ -20,6 +25,7 @@
 #include "clang/Tooling/Syntax/Tree.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/Casting.h"
@@ -34,6 +40,97 @@
 LLVM_ATTRIBUTE_UNUSED
 static bool isImplicitExpr(clang::Expr *E) { return E->IgnoreImplicit() != E; }
 
+static SourceLocation getQualifiedNameStart(DeclaratorDecl *D) {
+  auto DN = D->getDeclName();
+  bool IsAnonymous = DN.isIdentifier() && !DN.getAsIdentifierInfo();
+  if (IsAnonymous)
+    return SourceLocation();
+  return D->getQualifierLoc() ? D->getQualifierLoc().getBeginLoc()
+                              : D->getLocation();
+}
+
+namespace {
+struct GetStartLoc : TypeLocVisitor<GetStartLoc, SourceLocation> {
+  SourceLocation VisitParenTypeLoc(ParenTypeLoc T) {
+    auto L = Visit(T.getInnerLoc());
+    if (L.isValid())
+      return L;
+    return T.getLParenLoc();
+  }
+
+  // Types spelled in the prefix part of the declarator.
+  SourceLocation VisitPointerTypeLoc(PointerTypeLoc T) {
+    return HandlePointer(T);
+  }
+
+  SourceLocation VisitMemberPointerTypeLoc(MemberPointerTypeLoc T) {
+    return HandlePointer(T);
+  }
+
+  SourceLocation VisitBlockPointerTypeLoc(BlockPointerTypeLoc T) {
+    return HandlePointer(T);
+  }
+
+  SourceLocation VisitReferenceTypeLoc(ReferenceTypeLoc T) {
+    return HandlePointer(T);
+  }
+
+  SourceLocation VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc T) {
+    return HandlePointer(T);
+  }
+
+  // All other cases are not important, as they are either part of declaration
+  // specifiers (e.g. inheritors of TypeSpecTypeLoc) or introduce modifiers on
+  // existing declarators (e.g. QualifiedTypeLoc). They cannot start the
+  // declarator themselves, but their underlying type can.
+  SourceLocation VisitTypeLoc(TypeLoc T) {
+    auto N = T.getNextTypeLoc();
+    if (!N)
+      return SourceLocation();
+    return Visit(N);
+  }
+
+  SourceLocation VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc T) {
+    if (T.getTypePtr()->hasTrailingReturn())
+      return SourceLocation(); // avoid recursing into the suffix of declarator.
+    return VisitTypeLoc(T);
+  }
+
+private:
+  template <class PtrLoc> SourceLocation HandlePointer(PtrLoc T) {
+    auto L = Visit(T.getPointeeLoc());
+    if (L.isValid())
+      return L;
+    return T.getLocalSourceRange().getBegin();
+  }
+};
+} // namespace
+
+/// Gets the range of declarator as defined by the C++ grammar. E.g.
+///     `int a;` -> range of `a`,
+///     `int *a;` -> range of `*a`,
+///     `int a[10];` -> range of `a[10]`,
+///     `int *a = nullptr` -> range of `*a = nullptr`.
+/// FIMXE: \p Name must be a source range, e.g. for `operator+`.
+static SourceRange getDeclaratorRange(const SourceManager &SM, TypeLoc T,
+                                      SourceLocation Name,
+                                      SourceRange Initializer) {
+  SourceLocation Start = GetStartLoc().Visit(T);
+  SourceLocation End = T.getSourceRange().getEnd();
+  assert(End.isValid());
+  if (Name.isValid()) {
+    if (Start.isInvalid())
+      Start = Name;
+    if (SM.isBeforeInTranslationUnit(End, Name))
+      End = Name;
+  }
+  if (Initializer.isValid()) {
+    assert(SM.isBeforeInTranslationUnit(End, Initializer.getEnd()));
+    End = Initializer.getEnd();
+  }
+  return SourceRange(Start, End);
+}
+
 /// A helper class for constructing the syntax tree while traversing a clang
 /// AST.
 ///
@@ -57,6 +154,7 @@
   }
 
   llvm::BumpPtrAllocator &allocator() { return Arena.allocator(); }
+  const SourceManager &sourceManager() const { return Arena.sourceManager(); }
 
   /// Populate children for \p New node, assuming it covers tokens from \p
   /// Range.
@@ -64,11 +162,11 @@
 
   /// Must be called with the range of each `DeclaratorDecl`. Ensures the
   /// corresponding declarator nodes are covered by `SimpleDeclaration`.
-  void noticeDeclaratorRange(llvm::ArrayRef<syntax::Token> Range);
+  void noticeDeclRange(llvm::ArrayRef<syntax::Token> Range);
 
   /// Notifies that we should not consume trailing semicolon when computing
   /// token range of \p D.
-  void noticeDeclaratorWithoutSemicolon(Decl *D);
+  void noticeDeclWithoutSemicolon(Decl *D);
 
   /// Mark the \p Child node with a corresponding \p Role. All marked children
   /// should be consumed by foldNode.
@@ -81,6 +179,13 @@
 
   /// Set role for a token starting at \p Loc.
   void markChildToken(SourceLocation Loc, NodeRole R);
+  /// Set role for \p T.
+  void markChildToken(const syntax::Token *T, NodeRole R);
+
+  /// Set role for the node that spans exactly \p Range.
+  void markChild(llvm::ArrayRef<syntax::Token> Range, NodeRole R);
+  /// Set role for the delayed node that spans exactly \p Range.
+  void markDelayedChild(llvm::ArrayRef<syntax::Token> Range, NodeRole R);
 
   /// Finish building the tree and consume the root node.
   syntax::TranslationUnit *finalize() && {
@@ -170,6 +275,14 @@
 
     ~Forest() { assert(DelayedFolds.empty()); }
 
+    void assignRoleDelayed(llvm::ArrayRef<syntax::Token> Range,
+                           syntax::NodeRole Role) {
+      auto It = DelayedFolds.find(Range.begin());
+      assert(It != DelayedFolds.end());
+      assert(It->second.End == Range.end());
+      It->second.Role = Role;
+    }
+
     void assignRole(llvm::ArrayRef<syntax::Token> Range,
                     syntax::NodeRole Role) {
       assert(!Range.empty());
@@ -188,11 +301,18 @@
                       syntax::Tree *Node) {
       // Execute delayed folds inside `Tokens`.
       auto BeginExecuted = DelayedFolds.lower_bound(Tokens.begin());
-      auto It = BeginExecuted;
-      for (; It != DelayedFolds.end() && It->second.End <= Tokens.end(); ++It)
+      auto EndExecuted = BeginExecuted;
+      for (; EndExecuted != DelayedFolds.end() &&
+             EndExecuted->second.End <= Tokens.end();
+           ++EndExecuted)
+        ;
+      // We go in reverse order to ensure we fold deeper nodes first.
+      for (auto RevIt = EndExecuted; RevIt != BeginExecuted; --RevIt) {
+        auto It = std::prev(RevIt);
         foldChildrenEager(A, llvm::makeArrayRef(It->first, It->second.End),
                           It->second.Node);
-      DelayedFolds.erase(BeginExecuted, It);
+      }
+      DelayedFolds.erase(BeginExecuted, EndExecuted);
 
       // Attach children to `Node`.
       foldChildrenEager(A, Tokens, Node);
@@ -299,6 +419,7 @@
     struct DelayedFold {
       const syntax::Token *End = nullptr;
       syntax::Tree *Node = nullptr;
+      NodeRole Role = NodeRole::Unknown;
     };
     std::map<const syntax::Token *, DelayedFold> DelayedFolds;
   };
@@ -322,16 +443,43 @@
 
   bool shouldTraversePostOrder() const { return true; }
 
-  bool WalkUpFromDeclaratorDecl(DeclaratorDecl *D) {
+  bool WalkUpFromDeclaratorDecl(DeclaratorDecl *DD) {
     // Ensure declarators are covered by SimpleDeclaration.
-    Builder.noticeDeclaratorRange(Builder.getRange(D));
-    // FIXME: build nodes for the declarator too.
+    Builder.noticeDeclRange(Builder.getRange(DD));
+
+    // Build the declarator node.
+    SourceRange Initializer;
+    if (auto *V = llvm::dyn_cast<VarDecl>(DD)) {
+      auto *I = V->getInit();
+      // (!) initializers in range-based-for are not part of the declarator
+      if (I && !V->isCXXForRangeDecl())
+        Initializer = I->getSourceRange();
+    }
+    auto Declarator = getDeclaratorRange(
+        Builder.sourceManager(), DD->getTypeSourceInfo()->getTypeLoc(),
+        getQualifiedNameStart(DD), Initializer);
+    if (Declarator.isValid()) {
+      auto Tokens =
+          Builder.getRange(Declarator.getBegin(), Declarator.getEnd());
+      Builder.foldNode(Tokens, new (allocator()) syntax::SimpleDeclarator);
+      Builder.markChild(Tokens, syntax::NodeRole::SimpleDeclaration_declarator);
+    }
+
     return true;
   }
+
   bool WalkUpFromTypedefNameDecl(TypedefNameDecl *D) {
-    // Also a declarator.
-    Builder.noticeDeclaratorRange(Builder.getRange(D));
-    // FIXME: build nodes for the declarator too.
+    // Ensure declarators are covered by SimpleDeclaration.
+    Builder.noticeDeclRange(Builder.getRange(D));
+
+    auto R = getDeclaratorRange(
+        Builder.sourceManager(), D->getTypeSourceInfo()->getTypeLoc(),
+        /*Name=*/D->getLocation(), /*Initializer=*/SourceRange());
+    if (R.isValid()) {
+      auto Tokens = Builder.getRange(R.getBegin(), R.getEnd());
+      Builder.foldNode(Tokens, new (allocator()) syntax::SimpleDeclarator);
+      Builder.markChild(Tokens, syntax::NodeRole::SimpleDeclaration_declarator);
+    }
     return true;
   }
 
@@ -406,7 +554,7 @@
     if (auto *DS = llvm::dyn_cast_or_null<DeclStmt>(S)) {
       // We want to consume the semicolon, make sure SimpleDeclaration does not.
       for (auto *D : DS->decls())
-        Builder.noticeDeclaratorWithoutSemicolon(D);
+        Builder.noticeDeclWithoutSemicolon(D);
     } else if (auto *E = llvm::dyn_cast_or_null<Expr>(S)) {
       // (!) do not recurse into subexpressions.
       // we do not have syntax trees for expressions yet, so we only want to see
@@ -436,6 +584,62 @@
     return true;
   }
 
+  bool TraverseParenTypeLoc(ParenTypeLoc L) {
+    // (!) we reverse order of traversal to get the proper syntax structure.
+    if (!WalkUpFromParenTypeLoc(L))
+      return false;
+    return TraverseTypeLoc(L.getInnerLoc());
+  }
+
+  bool WalkUpFromParenTypeLoc(ParenTypeLoc L) {
+    Builder.markChildToken(L.getLParenLoc(), syntax::NodeRole::OpenParen);
+    Builder.markChildToken(L.getRParenLoc(), syntax::NodeRole::CloseParen);
+    Builder.foldNode(Builder.getRange(L.getLParenLoc(), L.getRParenLoc()),
+                     new (allocator()) syntax::ParenDeclarator);
+    return true;
+  }
+
+  // Declarator chunks, they are produced by type locs and some clang::Decls.
+  bool WalkUpFromArrayTypeLoc(ArrayTypeLoc L) {
+    Builder.markChildToken(L.getLBracketLoc(), syntax::NodeRole::OpenParen);
+    Builder.markExprChild(L.getSizeExpr(),
+                          syntax::NodeRole::ArraySubscript_sizeExpression);
+    Builder.markChildToken(L.getRBracketLoc(), syntax::NodeRole::CloseParen);
+    Builder.foldNode(Builder.getRange(L.getLBracketLoc(), L.getRBracketLoc()),
+                     new (allocator()) syntax::ArraySubscript);
+    return true;
+  }
+
+  bool WalkUpFromFunctionTypeLoc(FunctionTypeLoc L) {
+    Builder.markChildToken(L.getLParenLoc(), syntax::NodeRole::OpenParen);
+    for (auto *P : L.getParams())
+      Builder.markDelayedChild(
+          Builder.getRange(P),
+          syntax::NodeRole::ParametersAndQualifiers_parameter);
+    Builder.markChildToken(L.getRParenLoc(), syntax::NodeRole::CloseParen);
+    Builder.foldNode(Builder.getRange(L.getLParenLoc(), L.getEndLoc()),
+                     new (allocator()) syntax::ParametersAndQualifiers);
+    return true;
+  }
+
+  bool WalkUpFromFunctionProtoTypeLoc(FunctionProtoTypeLoc L) {
+    if (!L.getTypePtr()->hasTrailingReturn())
+      return WalkUpFromFunctionTypeLoc(L);
+
+    auto TrailingReturnTokens = BuildTrailingReturn(L);
+    // Finish building the node for parameters.
+    Builder.markChild(TrailingReturnTokens,
+                      syntax::NodeRole::ParametersAndQualifiers_trailingReturn);
+    return WalkUpFromFunctionTypeLoc(L);
+  }
+
+  bool WalkUpFromMemberPointerTypeLoc(MemberPointerTypeLoc L) {
+    auto SR = L.getLocalSourceRange();
+    Builder.foldNode(Builder.getRange(SR.getBegin(), SR.getEnd()),
+                     new (allocator()) syntax::MemberPointer);
+    return true;
+  }
+
   // The code below is very regular, it could even be generated with some
   // preprocessor magic. We merely assign roles to the corresponding children
   // and fold resulting nodes.
@@ -608,6 +812,37 @@
   }
 
 private:
+  /// Returns the range of the built node.
+  llvm::ArrayRef<syntax::Token> BuildTrailingReturn(FunctionProtoTypeLoc L) {
+    assert(L.getTypePtr()->hasTrailingReturn());
+
+    auto ReturnedType = L.getReturnLoc();
+    // Build node for the declarator, if any.
+    auto ReturnDeclaratorRange =
+        getDeclaratorRange(this->Builder.sourceManager(), ReturnedType,
+                           /*Name=*/SourceLocation(),
+                           /*Initializer=*/SourceLocation());
+    llvm::ArrayRef<syntax::Token> ReturnDeclaratorTokens;
+    if (ReturnDeclaratorRange.isValid()) {
+      ReturnDeclaratorTokens = Builder.getRange(
+          ReturnDeclaratorRange.getBegin(), ReturnDeclaratorRange.getEnd());
+      Builder.foldNode(ReturnDeclaratorTokens,
+                       new (allocator()) syntax::SimpleDeclarator);
+    }
+
+    // Build node for trailing return type.
+    auto Return =
+        Builder.getRange(ReturnedType.getBeginLoc(), ReturnedType.getEndLoc());
+    auto *Arrow = Return.begin() - 1;
+    assert(Arrow->kind() == tok::arrow);
+    auto Tokens = llvm::makeArrayRef(Arrow, Return.end());
+    Builder.markChildToken(Arrow, syntax::NodeRole::TrailingReturnType_arrow);
+    if (!ReturnDeclaratorTokens.empty())
+      Builder.markChild(ReturnDeclaratorTokens,
+                        syntax::NodeRole::TrailingReturnType_declarator);
+    Builder.foldNode(Tokens, new (allocator()) syntax::TrailingReturnType);
+    return Tokens;
+  }
   /// Builds either a `TemplateDeclaration` or `ExplicitTemplateInstantiation`,
   /// depending on the kind of specialization.
   void BuildTemplateNodes(ClassTemplateSpecializationDecl *C) {
@@ -647,15 +882,14 @@
   Pending.foldChildren(Arena, Range, New);
 }
 
-void syntax::TreeBuilder::noticeDeclaratorRange(
-    llvm::ArrayRef<syntax::Token> Range) {
+void syntax::TreeBuilder::noticeDeclRange(llvm::ArrayRef<syntax::Token> Range) {
   if (Pending.extendDelayedFold(Range))
     return;
   Pending.foldChildrenDelayed(Range,
                               new (allocator()) syntax::SimpleDeclaration);
 }
 
-void syntax::TreeBuilder::noticeDeclaratorWithoutSemicolon(Decl *D) {
+void syntax::TreeBuilder::noticeDeclWithoutSemicolon(Decl *D) {
   DeclsWithoutSemicolons.insert(D);
 }
 
@@ -665,6 +899,22 @@
   Pending.assignRole(*findToken(Loc), Role);
 }
 
+void syntax::TreeBuilder::markChildToken(const syntax::Token *T, NodeRole R) {
+  if (!T)
+    return;
+  Pending.assignRole(*T, R);
+}
+
+void syntax::TreeBuilder::markChild(llvm::ArrayRef<syntax::Token> Range,
+                                    NodeRole R) {
+  Pending.assignRole(Range, R);
+}
+
+void syntax::TreeBuilder::markDelayedChild(llvm::ArrayRef<syntax::Token> Range,
+                                           NodeRole R) {
+  Pending.assignRoleDelayed(Range, R);
+}
+
 void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) {
   if (!Child)
     return;
Index: clang/include/clang/Tooling/Syntax/Nodes.h
===================================================================
--- clang/include/clang/Tooling/Syntax/Nodes.h
+++ clang/include/clang/Tooling/Syntax/Nodes.h
@@ -38,10 +38,10 @@
   Leaf,
   TranslationUnit,
 
-  // Expressions
+  // Expressions.
   UnknownExpression,
 
-  // Statements
+  // Statements.
   UnknownStatement,
   DeclarationStatement,
   EmptyStatement,
@@ -58,7 +58,7 @@
   ExpressionStatement,
   CompoundStatement,
 
-  // Declarations
+  // Declarations.
   UnknownDeclaration,
   EmptyDeclaration,
   StaticAssertDeclaration,
@@ -70,7 +70,16 @@
   NamespaceAliasDefinition,
   UsingNamespaceDirective,
   UsingDeclaration,
-  TypeAliasDeclaration
+  TypeAliasDeclaration,
+
+  // Declarators.
+  SimpleDeclarator,
+  ParenDeclarator,
+
+  ArraySubscript,
+  TrailingReturnType,
+  ParametersAndQualifiers,
+  MemberPointer
 };
 /// For debugging purposes.
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeKind K);
@@ -103,11 +112,19 @@
   ExpressionStatement_expression,
   CompoundStatement_statement,
   StaticAssertDeclaration_condition,
-  StaticAssertDeclaration_message
+  StaticAssertDeclaration_message,
+  SimpleDeclaration_declarator,
+  ArraySubscript_sizeExpression,
+  TrailingReturnType_arrow,
+  TrailingReturnType_declarator,
+  ParametersAndQualifiers_parameter,
+  ParametersAndQualifiers_trailingReturn
 };
 /// For debugging purposes.
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeRole R);
 
+class SimpleDeclarator;
+
 /// A root node for a translation unit. Parent is always null.
 class TranslationUnit final : public Tree {
 public:
@@ -377,6 +394,8 @@
   static bool classof(const Node *N) {
     return N->kind() == NodeKind::SimpleDeclaration;
   }
+  /// FIXME: use custom iterator instead of 'vector'.
+  std::vector<syntax::SimpleDeclarator *> declarators();
 };
 
 /// template <template-parameters> <declaration>
@@ -449,6 +468,99 @@
   }
 };
 
+/// Covers a name, an initializer and a part of the type outside declaration
+/// specifiers. Examples are:
+///     `*a` in `int *a`
+///     `a[10]` in `int a[10]`
+///     `*a = nullptr` in `int *a = nullptr`
+/// Declarators can be unnamed too:
+///     `**` in `new int**`
+///     `* = nullptr` in `void foo(int* = nullptr)`
+/// Most declarators you encounter are instances of SimpleDeclarator. They may
+/// contain an inner declarator inside parentheses, we represent it as
+/// ParenDeclarator. E.g.
+///     `(*a)` in `int (*a) = 10`
+class Declarator : public Tree {
+public:
+  Declarator(NodeKind K) : Tree(K) {}
+  static bool classof(const Node *N) {
+    return NodeKind::SimpleDeclarator <= N->kind() &&
+           N->kind() <= NodeKind::ParenDeclarator;
+  }
+};
+
+/// A top-level declarator without parentheses. See comment of Declarator for
+/// more details.
+class SimpleDeclarator final : public Declarator {
+public:
+  SimpleDeclarator() : Declarator(NodeKind::SimpleDeclarator) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::SimpleDeclarator;
+  }
+};
+
+/// Declarator inside parentheses.
+/// E.g. `(***a)` from `int (***a) = nullptr;`
+/// See comment of Declarator for more details.
+class ParenDeclarator final : public Declarator {
+public:
+  ParenDeclarator() : Declarator(NodeKind::ParenDeclarator) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::ParenDeclarator;
+  }
+  syntax::Leaf *lparen();
+  syntax::Leaf *rparen();
+};
+
+/// Array size specified inside a declarator.
+/// E.g. `[10]` in `int a[10]`.
+class ArraySubscript final : public Tree {
+public:
+  ArraySubscript() : Tree(NodeKind::ArraySubscript) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::ArraySubscript;
+  }
+  syntax::Leaf *lbracket();
+  syntax::Expression *sizeExpression();
+  syntax::Leaf *rbracket();
+};
+
+/// Trailing return type inside parameter list, starting from the arrow token.
+/// E.g. `-> int***`.
+class TrailingReturnType final : public Tree {
+public:
+  TrailingReturnType() : Tree(NodeKind::TrailingReturnType) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::TrailingReturnType;
+  }
+  syntax::Leaf *arrow();
+  syntax::SimpleDeclarator *declarator();
+};
+
+/// Parameter list for a function type.
+class ParametersAndQualifiers final : public Tree {
+public:
+  ParametersAndQualifiers() : Tree(NodeKind::ParametersAndQualifiers) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::ParametersAndQualifiers;
+  }
+  syntax::Leaf *lparen();
+  /// FIXME: use custom iterator instead of 'vector'.
+  std::vector<syntax::SimpleDeclaration *> parameters();
+  syntax::Leaf *rparen();
+  syntax::TrailingReturnType *trailingReturn();
+};
+
+/// Member pointer inside a declarator
+/// E.g. `X::*` in `int X::* a = 0;`
+class MemberPointer final : public Tree {
+public:
+  MemberPointer() : Tree(NodeKind::MemberPointer) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::MemberPointer;
+  }
+};
+
 } // namespace syntax
 } // namespace clang
 #endif
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D72089: [Sy... Ilya Biryukov via Phabricator via cfe-commits

Reply via email to