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); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits