[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