[clang] be14a22 - [Syntax] Build nodes for simple cases of top level declarations

Ilya Biryukov via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 11 23:08:22 PST 2019


Author: Ilya Biryukov
Date: 2019-12-12T08:04:22+01:00
New Revision: be14a22b47e5c61ff36e4183dcb4f8b138466157

URL: https://github.com/llvm/llvm-project/commit/be14a22b47e5c61ff36e4183dcb4f8b138466157
DIFF: https://github.com/llvm/llvm-project/commit/be14a22b47e5c61ff36e4183dcb4f8b138466157.diff

LOG: [Syntax] Build nodes for simple cases of top level declarations

Summary:
More complicated nodes (e.g. template declarations) will be implemented
in the follow-up patches.

Reviewers: gribozavr2

Reviewed By: gribozavr2

Subscribers: merge_guards_bot, cfe-commits

Tags: #clang

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

Added: 
    

Modified: 
    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

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Tooling/Syntax/Nodes.h b/clang/include/clang/Tooling/Syntax/Nodes.h
index c4db4da892c2..25acc1757428 100644
--- a/clang/include/clang/Tooling/Syntax/Nodes.h
+++ b/clang/include/clang/Tooling/Syntax/Nodes.h
@@ -60,7 +60,15 @@ enum class NodeKind : uint16_t {
 
   // Declarations
   UnknownDeclaration,
+  EmptyDeclaration,
+  StaticAssertDeclaration,
+  LinkageSpecificationDeclaration,
   SimpleDeclaration,
+  NamespaceDefinition,
+  NamespaceAliasDefinition,
+  UsingNamespaceDirective,
+  UsingDeclaration,
+  TypeAliasDeclaration
 };
 /// For debugging purposes.
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeKind K);
@@ -91,7 +99,9 @@ enum class NodeRole : uint8_t {
   IfStatement_elseStatement,
   ReturnStatement_value,
   ExpressionStatement_expression,
-  CompoundStatement_statement
+  CompoundStatement_statement,
+  StaticAssertDeclaration_condition,
+  StaticAssertDeclaration_message
 };
 /// For debugging purposes.
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeRole R);
@@ -311,7 +321,7 @@ class Declaration : public Tree {
   Declaration(NodeKind K) : Tree(K) {}
   static bool classof(const Node *N) {
     return NodeKind::UnknownDeclaration <= N->kind() &&
-           N->kind() <= NodeKind::SimpleDeclaration;
+           N->kind() <= NodeKind::TypeAliasDeclaration;
   }
 };
 
@@ -324,6 +334,38 @@ class UnknownDeclaration final : public Declaration {
   }
 };
 
+/// A semicolon in the top-level context. Does not declare anything.
+class EmptyDeclaration final : public Declaration {
+public:
+  EmptyDeclaration() : Declaration(NodeKind::EmptyDeclaration) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::EmptyDeclaration;
+  }
+};
+
+/// static_assert(<condition>, <message>)
+/// static_assert(<condition>)
+class StaticAssertDeclaration final : public Declaration {
+public:
+  StaticAssertDeclaration() : Declaration(NodeKind::StaticAssertDeclaration) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::StaticAssertDeclaration;
+  }
+  syntax::Expression *condition();
+  syntax::Expression *message();
+};
+
+/// extern <string-literal> declaration
+/// extern <string-literal> { <decls>  }
+class LinkageSpecificationDeclaration final : public Declaration {
+public:
+  LinkageSpecificationDeclaration()
+      : Declaration(NodeKind::LinkageSpecificationDeclaration) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::LinkageSpecificationDeclaration;
+  }
+};
+
 /// Groups multiple declarators (e.g. variables, typedefs, etc.) together. All
 /// grouped declarators share the same declaration specifiers (e.g. 'int' or
 /// 'typedef').
@@ -334,6 +376,54 @@ class SimpleDeclaration final : public Declaration {
     return N->kind() == NodeKind::SimpleDeclaration;
   }
 };
+
+/// namespace <name> { <decls> }
+class NamespaceDefinition final : public Declaration {
+public:
+  NamespaceDefinition() : Declaration(NodeKind::NamespaceDefinition) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::NamespaceDefinition;
+  }
+};
+
+/// namespace <name> = <namespace-reference>
+class NamespaceAliasDefinition final : public Declaration {
+public:
+  NamespaceAliasDefinition()
+      : Declaration(NodeKind::NamespaceAliasDefinition) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::NamespaceAliasDefinition;
+  }
+};
+
+/// using namespace <name>
+class UsingNamespaceDirective final : public Declaration {
+public:
+  UsingNamespaceDirective() : Declaration(NodeKind::UsingNamespaceDirective) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::UsingNamespaceDirective;
+  }
+};
+
+/// using <scope>::<name>
+/// using typename <scope>::<name>
+class UsingDeclaration final : public Declaration {
+public:
+  UsingDeclaration() : Declaration(NodeKind::UsingDeclaration) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::UsingDeclaration;
+  }
+};
+
+/// using <name> = <type>
+class TypeAliasDeclaration final : public Declaration {
+public:
+  TypeAliasDeclaration() : Declaration(NodeKind::TypeAliasDeclaration) {}
+  static bool classof(const Node *N) {
+    return N->kind() == NodeKind::TypeAliasDeclaration;
+  }
+};
+
 } // namespace syntax
 } // namespace clang
 #endif

diff  --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp
index 67081497d04c..e13bb2d06992 100644
--- a/clang/lib/Tooling/Syntax/BuildTree.cpp
+++ b/clang/lib/Tooling/Syntax/BuildTree.cpp
@@ -295,7 +295,7 @@ class syntax::TreeBuilder {
 
   syntax::Arena &Arena;
   Forest Pending;
-  llvm::DenseSet<Decl*> DeclsWithoutSemicolons;
+  llvm::DenseSet<Decl *> DeclsWithoutSemicolons;
 };
 
 namespace {
@@ -397,6 +397,18 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
     return true;
   }
 
+  bool WalkUpFromNamespaceDecl(NamespaceDecl *S) {
+    auto Tokens = Builder.getRange(S);
+    if (Tokens.front().kind() == tok::coloncolon) {
+      // Handle nested namespace definitions. Those start at '::' token, e.g.
+      // namespace a^::b {}
+      // FIXME: build corresponding nodes for the name of this namespace.
+      return true;
+    }
+    Builder.foldNode(Tokens, new (allocator()) syntax::NamespaceDefinition);
+    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.
@@ -504,6 +516,64 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
     return true;
   }
 
+  bool WalkUpFromEmptyDecl(EmptyDecl *S) {
+    Builder.foldNode(Builder.getRange(S),
+                     new (allocator()) syntax::EmptyDeclaration);
+    return true;
+  }
+
+  bool WalkUpFromStaticAssertDecl(StaticAssertDecl *S) {
+    Builder.markExprChild(S->getAssertExpr(),
+                          syntax::NodeRole::StaticAssertDeclaration_condition);
+    Builder.markExprChild(S->getMessage(),
+                          syntax::NodeRole::StaticAssertDeclaration_message);
+    Builder.foldNode(Builder.getRange(S),
+                     new (allocator()) syntax::StaticAssertDeclaration);
+    return true;
+  }
+
+  bool WalkUpFromLinkageSpecDecl(LinkageSpecDecl *S) {
+    Builder.foldNode(Builder.getRange(S),
+                     new (allocator()) syntax::LinkageSpecificationDeclaration);
+    return true;
+  }
+
+  bool WalkUpFromNamespaceAliasDecl(NamespaceAliasDecl *S) {
+    Builder.foldNode(Builder.getRange(S),
+                     new (allocator()) syntax::NamespaceAliasDefinition);
+    return true;
+  }
+
+  bool WalkUpFromUsingDirectiveDecl(UsingDirectiveDecl *S) {
+    Builder.foldNode(Builder.getRange(S),
+                     new (allocator()) syntax::UsingNamespaceDirective);
+    return true;
+  }
+
+  bool WalkUpFromUsingDecl(UsingDecl *S) {
+    Builder.foldNode(Builder.getRange(S),
+                     new (allocator()) syntax::UsingDeclaration);
+    return true;
+  }
+
+  bool WalkUpFromUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *S) {
+    Builder.foldNode(Builder.getRange(S),
+                     new (allocator()) syntax::UsingDeclaration);
+    return true;
+  }
+
+  bool WalkUpFromUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *S) {
+    Builder.foldNode(Builder.getRange(S),
+                     new (allocator()) syntax::UsingDeclaration);
+    return true;
+  }
+
+  bool WalkUpFromTypeAliasDecl(TypeAliasDecl *S) {
+    Builder.foldNode(Builder.getRange(S),
+                     new (allocator()) syntax::TypeAliasDeclaration);
+    return true;
+  }
+
 private:
   /// A small helper to save some typing.
   llvm::BumpPtrAllocator &allocator() { return Builder.allocator(); }
@@ -553,6 +623,9 @@ void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) {
 }
 
 void syntax::TreeBuilder::markExprChild(Expr *Child, NodeRole Role) {
+  if (!Child)
+    return;
+
   Pending.assignRole(getExprRange(Child), Role);
 }
 

diff  --git a/clang/lib/Tooling/Syntax/Nodes.cpp b/clang/lib/Tooling/Syntax/Nodes.cpp
index b2ed4ffa22c2..5b0c5107c134 100644
--- a/clang/lib/Tooling/Syntax/Nodes.cpp
+++ b/clang/lib/Tooling/Syntax/Nodes.cpp
@@ -50,8 +50,24 @@ llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeKind K) {
     return OS << "CompoundStatement";
   case NodeKind::UnknownDeclaration:
     return OS << "UnknownDeclaration";
+  case NodeKind::EmptyDeclaration:
+    return OS << "EmptyDeclaration";
+  case NodeKind::StaticAssertDeclaration:
+    return OS << "StaticAssertDeclaration";
+  case NodeKind::LinkageSpecificationDeclaration:
+    return OS << "LinkageSpecificationDeclaration";
   case NodeKind::SimpleDeclaration:
     return OS << "SimpleDeclaration";
+  case NodeKind::NamespaceDefinition:
+    return OS << "NamespaceDefinition";
+  case NodeKind::NamespaceAliasDefinition:
+    return OS << "NamespaceAliasDefinition";
+  case NodeKind::UsingNamespaceDirective:
+    return OS << "UsingNamespaceDirective";
+  case NodeKind::UsingDeclaration:
+    return OS << "UsingDeclaration";
+  case NodeKind::TypeAliasDeclaration:
+    return OS << "TypeAliasDeclaration";
   }
   llvm_unreachable("unknown node kind");
 }
@@ -84,6 +100,10 @@ llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeRole R) {
     return OS << "ExpressionStatement_expression";
   case syntax::NodeRole::CompoundStatement_statement:
     return OS << "CompoundStatement_statement";
+  case syntax::NodeRole::StaticAssertDeclaration_condition:
+    return OS << "StaticAssertDeclaration_condition";
+  case syntax::NodeRole::StaticAssertDeclaration_message:
+    return OS << "StaticAssertDeclaration_message";
   }
   llvm_unreachable("invalid role");
 }
@@ -216,3 +236,13 @@ syntax::Leaf *syntax::CompoundStatement::rbrace() {
   return llvm::cast_or_null<syntax::Leaf>(
       findChild(syntax::NodeRole::CloseParen));
 }
+
+syntax::Expression *syntax::StaticAssertDeclaration::condition() {
+  return llvm::cast_or_null<syntax::Expression>(
+      findChild(syntax::NodeRole::StaticAssertDeclaration_condition));
+}
+
+syntax::Expression *syntax::StaticAssertDeclaration::message() {
+  return llvm::cast_or_null<syntax::Expression>(
+      findChild(syntax::NodeRole::StaticAssertDeclaration_message));
+}

diff  --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp
index 98b895a5dd67..e9c11c76259a 100644
--- a/clang/unittests/Tooling/Syntax/TreeTest.cpp
+++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp
@@ -512,7 +512,190 @@ void foo() {
     | | `-tb
     | `-;
     `-}
-  )txt"}};
+  )txt"},
+      {R"cpp(
+namespace a { namespace b {} }
+namespace a::b {}
+namespace {}
+
+namespace foo = a;
+    )cpp",
+       R"txt(
+*: TranslationUnit
+|-NamespaceDefinition
+| |-namespace
+| |-a
+| |-{
+| |-NamespaceDefinition
+| | |-namespace
+| | |-b
+| | |-{
+| | `-}
+| `-}
+|-NamespaceDefinition
+| |-namespace
+| |-a
+| |-::
+| |-b
+| |-{
+| `-}
+|-NamespaceDefinition
+| |-namespace
+| |-{
+| `-}
+`-NamespaceAliasDefinition
+  |-namespace
+  |-foo
+  |-=
+  |-a
+  `-;
+)txt"},
+      {R"cpp(
+namespace ns {}
+using namespace ::ns;
+    )cpp",
+       R"txt(
+*: TranslationUnit
+|-NamespaceDefinition
+| |-namespace
+| |-ns
+| |-{
+| `-}
+`-UsingNamespaceDirective
+  |-using
+  |-namespace
+  |-::
+  |-ns
+  `-;
+       )txt"},
+      {R"cpp(
+namespace ns { int a; }
+using ns::a;
+    )cpp",
+       R"txt(
+*: TranslationUnit
+|-NamespaceDefinition
+| |-namespace
+| |-ns
+| |-{
+| |-SimpleDeclaration
+| | |-int
+| | |-a
+| | `-;
+| `-}
+`-UsingDeclaration
+  |-using
+  |-ns
+  |-::
+  |-a
+  `-;
+       )txt"},
+      {R"cpp(
+template <class T> struct X {
+  using T::foo;
+  using typename T::bar;
+};
+    )cpp",
+       R"txt(
+*: TranslationUnit
+`-UnknownDeclaration
+  |-template
+  |-<
+  |-UnknownDeclaration
+  | |-class
+  | `-T
+  |->
+  |-struct
+  |-X
+  |-{
+  |-UsingDeclaration
+  | |-using
+  | |-T
+  | |-::
+  | |-foo
+  | `-;
+  |-UsingDeclaration
+  | |-using
+  | |-typename
+  | |-T
+  | |-::
+  | |-bar
+  | `-;
+  |-}
+  `-;
+       )txt"},
+      {R"cpp(
+using type = int;
+    )cpp",
+       R"txt(
+*: TranslationUnit
+`-TypeAliasDeclaration
+  |-using
+  |-type
+  |-=
+  |-int
+  `-;
+       )txt"},
+      {R"cpp(
+;
+    )cpp",
+       R"txt(
+*: TranslationUnit
+`-EmptyDeclaration
+  `-;
+       )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"},
+      {R"cpp(
+extern "C" int a;
+extern "C" { int b; int c; }
+    )cpp",
+       R"txt(
+*: TranslationUnit
+|-LinkageSpecificationDeclaration
+| |-extern
+| |-"C"
+| `-SimpleDeclaration
+|   |-int
+|   |-a
+|   `-;
+`-LinkageSpecificationDeclaration
+  |-extern
+  |-"C"
+  |-{
+  |-SimpleDeclaration
+  | |-int
+  | |-b
+  | `-;
+  |-SimpleDeclaration
+  | |-int
+  | |-c
+  | `-;
+  `-}
+       )txt"},
+  };
 
   for (const auto &T : Cases) {
     SCOPED_TRACE(T.first);


        


More information about the cfe-commits mailing list