diff --git a/clang/include/clang/Tooling/Syntax/Nodes.h b/clang/include/clang/Tooling/Syntax/Nodes.h --- a/clang/include/clang/Tooling/Syntax/Nodes.h +++ b/clang/include/clang/Tooling/Syntax/Nodes.h @@ -60,7 +60,15 @@ // 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,8 @@ IfStatement_elseStatement, ReturnStatement_value, ExpressionStatement_expression, - CompoundStatement_statement + CompoundStatement_statement, + StaticAssertDeclaration_condition }; /// For debugging purposes. llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeRole R); @@ -311,7 +320,7 @@ 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 +333,37 @@ } }; +/// 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(, ) +/// static_assert() +class StaticAssertDeclaration final : public Declaration { +public: + StaticAssertDeclaration() : Declaration(NodeKind::StaticAssertDeclaration) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::StaticAssertDeclaration; + } + syntax::Expression *condition(); +}; + +/// extern declaration +/// extern { } +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 +374,54 @@ return N->kind() == NodeKind::SimpleDeclaration; } }; + +/// namespace { } +class NamespaceDefinition final : public Declaration { +public: + NamespaceDefinition() : Declaration(NodeKind::NamespaceDefinition) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::NamespaceDefinition; + } +}; + +/// namespace = +class NamespaceAliasDefinition final : public Declaration { +public: + NamespaceAliasDefinition() + : Declaration(NodeKind::NamespaceAliasDefinition) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::NamespaceAliasDefinition; + } +}; + +/// using namespace +class UsingNamespaceDirective final : public Declaration { +public: + UsingNamespaceDirective() : Declaration(NodeKind::UsingNamespaceDirective) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::UsingNamespaceDirective; + } +}; + +/// using :: +/// using typename :: +class UsingDeclaration final : public Declaration { +public: + UsingDeclaration() : Declaration(NodeKind::UsingDeclaration) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::UsingDeclaration; + } +}; + +/// using = +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 --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -295,7 +295,7 @@ syntax::Arena &Arena; Forest Pending; - llvm::DenseSet DeclsWithoutSemicolons; + llvm::DenseSet DeclsWithoutSemicolons; }; namespace { @@ -504,6 +504,68 @@ 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.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 WalkUpFromNamespaceDecl(NamespaceDecl *S) { + Builder.foldNode(Builder.getRange(S), + new (allocator()) syntax::NamespaceDefinition); + 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(); } diff --git a/clang/lib/Tooling/Syntax/Nodes.cpp b/clang/lib/Tooling/Syntax/Nodes.cpp --- a/clang/lib/Tooling/Syntax/Nodes.cpp +++ b/clang/lib/Tooling/Syntax/Nodes.cpp @@ -50,8 +50,24 @@ 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,8 @@ return OS << "ExpressionStatement_expression"; case syntax::NodeRole::CompoundStatement_statement: return OS << "CompoundStatement_statement"; + case syntax::NodeRole::StaticAssertDeclaration_condition: + return OS << "StaticAssertDeclaration_condition"; } llvm_unreachable("invalid role"); } @@ -216,3 +234,8 @@ return llvm::cast_or_null( findChild(syntax::NodeRole::CloseParen)); } + +syntax::Expression *syntax::StaticAssertDeclaration::condition() { + return llvm::cast_or_null( + findChild(syntax::NodeRole::StaticAssertDeclaration_condition)); +} diff --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp --- a/clang/unittests/Tooling/Syntax/TreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -512,7 +512,205 @@ | | `-tb | `-; `-} - )txt"}}; + )txt"}, + {R"cpp( +namespace a { namespace b {} } +namespace {} + +namespace foo = a; + )cpp", + R"txt( +*: TranslationUnit +|-NamespaceDefinition +| |-namespace +| |-a +| |-{ +| |-NamespaceDefinition +| | |-namespace +| | |-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 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"}, + {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"}}; for (const auto &T : Cases) { auto *Root = buildTree(T.first);