eduucaldas created this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D84348
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
@@ -867,24 +867,47 @@
}
EXPECT_TRUE(treeDumpEqual(
R"cpp(
-namespace a {
+namespace n {
struct S {
template<typename T>
- static T f(){}
+ struct TS {
+ static void f();
+ };
};
}
+template<typename T>
+struct TS {
+ struct S {
+ template<typename U>
+ static U f();
+ };
+};
void test() {
- :: // global-namespace-specifier
- a:: // namespace-specifier
- S:: // type-name-specifier
+ :: // global-namespace-specifier
+ n:: // namespace-specifier
+ S:: // type-name-specifier
+ template TS<int>:: // type-template-instantiation-specifier
+ f();
+
+ n:: // namespace-specifier
+ S:: // type-name-specifier
+ TS<int>:: // type-template-instantiation-specifier
+ f();
+
+ TS<int>:: // type-name-specifier
+ S:: // type-name-specifier
f<int>();
+
+ TS<int>:: // type-name-specifier
+ S:: // type-name-specifier
+ template f<int>();
}
)cpp",
R"txt(
*: TranslationUnit
|-NamespaceDefinition
| |-namespace
-| |-a
+| |-n
| |-{
| |-SimpleDeclaration
| | |-struct
@@ -898,19 +921,58 @@
| | | | `-T
| | | |->
| | | `-SimpleDeclaration
-| | | |-static
-| | | |-T
-| | | |-SimpleDeclarator
-| | | | |-f
-| | | | `-ParametersAndQualifiers
-| | | | |-(
-| | | | `-)
-| | | `-CompoundStatement
-| | | |-{
-| | | `-}
+| | | |-struct
+| | | |-TS
+| | | |-{
+| | | |-SimpleDeclaration
+| | | | |-static
+| | | | |-void
+| | | | |-SimpleDeclarator
+| | | | | |-f
+| | | | | `-ParametersAndQualifiers
+| | | | | |-(
+| | | | | `-)
+| | | | `-;
+| | | |-}
+| | | `-;
| | |-}
| | `-;
| `-}
+|-TemplateDeclaration
+| |-template
+| |-<
+| |-UnknownDeclaration
+| | |-typename
+| | `-T
+| |->
+| `-SimpleDeclaration
+| |-struct
+| |-TS
+| |-{
+| |-SimpleDeclaration
+| | |-struct
+| | |-S
+| | |-{
+| | |-TemplateDeclaration
+| | | |-template
+| | | |-<
+| | | |-UnknownDeclaration
+| | | | |-typename
+| | | | `-U
+| | | |->
+| | | `-SimpleDeclaration
+| | | |-static
+| | | |-U
+| | | |-SimpleDeclarator
+| | | | |-f
+| | | | `-ParametersAndQualifiers
+| | | | |-(
+| | | | `-)
+| | | `-;
+| | |-}
+| | `-;
+| |-}
+| `-;
`-SimpleDeclaration
|-void
|-SimpleDeclarator
@@ -924,14 +986,82 @@
| |-UnknownExpression
| | |-IdExpression
| | | |-NestedNameSpecifier
- | | | | |-NameSpecifier
+ | | | | |-GlobalNameSpecifier
+ | | | | | `-::
+ | | | | |-NamespaceNameSpecifier
+ | | | | | |-n
+ | | | | | `-::
+ | | | | |-TypeNameSpecifier
+ | | | | | |-S
+ | | | | | `-::
+ | | | | `-TypeWithTemplateNameSpecifier
+ | | | | |-template
+ | | | | |-TS
+ | | | | |-<
+ | | | | |-int
+ | | | | |->
+ | | | | `-::
+ | | | `-UnqualifiedId
+ | | | `-f
+ | | |-(
+ | | `-)
+ | `-;
+ |-ExpressionStatement
+ | |-UnknownExpression
+ | | |-IdExpression
+ | | | |-NestedNameSpecifier
+ | | | | |-NamespaceNameSpecifier
+ | | | | | |-n
+ | | | | | `-::
+ | | | | |-TypeNameSpecifier
+ | | | | | |-S
+ | | | | | `-::
+ | | | | `-TypeNameSpecifier
+ | | | | |-TS
+ | | | | |-<
+ | | | | |-int
+ | | | | |->
+ | | | | `-::
+ | | | `-UnqualifiedId
+ | | | `-f
+ | | |-(
+ | | `-)
+ | `-;
+ |-ExpressionStatement
+ | |-UnknownExpression
+ | | |-IdExpression
+ | | | |-NestedNameSpecifier
+ | | | | |-TypeNameSpecifier
+ | | | | | |-TS
+ | | | | | |-<
+ | | | | | |-int
+ | | | | | |->
| | | | | `-::
- | | | | |-NameSpecifier
- | | | | | |-a
+ | | | | `-TypeNameSpecifier
+ | | | | |-S
+ | | | | `-::
+ | | | `-UnqualifiedId
+ | | | |-f
+ | | | |-<
+ | | | |-int
+ | | | `->
+ | | |-(
+ | | `-)
+ | `-;
+ |-ExpressionStatement
+ | |-UnknownExpression
+ | | |-IdExpression
+ | | | |-NestedNameSpecifier
+ | | | | |-TypeNameSpecifier
+ | | | | | |-TS
+ | | | | | |-<
+ | | | | | |-int
+ | | | | | |->
| | | | | `-::
- | | | | `-NameSpecifier
+ | | | | `-TypeNameSpecifier
| | | | |-S
| | | | `-::
+ | | | |-template
| | | `-UnqualifiedId
| | | |-f
| | | |-<
@@ -944,7 +1074,7 @@
)txt"));
}
-TEST_P(SyntaxTreeTest, QualifiedIdWithTemplateKeyword) {
+TEST_P(SyntaxTreeTest, QualifiedIdWithDependentType) {
if (!GetParam().isCXX()) {
return;
}
@@ -955,63 +1085,17 @@
}
EXPECT_TRUE(treeDumpEqual(
R"cpp(
-struct X {
- template<int> static void f();
- template<int>
- struct Y {
- static void f();
- };
-};
-template<typename T> void test() {
- // TODO: Expose `id-expression` from `DependentScopeDeclRefExpr`
- T::template f<0>(); // nested-name-specifier template unqualified-id
- T::template Y<0>::f(); // nested-name-specifier template :: unqualified-id
+template <typename T>
+void test() {
+ T::template U<int>::f();
+
+ T::U::f();
+
+ T::template f<0>();
}
)cpp",
R"txt(
*: TranslationUnit
-|-SimpleDeclaration
-| |-struct
-| |-X
-| |-{
-| |-TemplateDeclaration
-| | |-template
-| | |-<
-| | |-SimpleDeclaration
-| | | `-int
-| | |->
-| | `-SimpleDeclaration
-| | |-static
-| | |-void
-| | |-SimpleDeclarator
-| | | |-f
-| | | `-ParametersAndQualifiers
-| | | |-(
-| | | `-)
-| | `-;
-| |-TemplateDeclaration
-| | |-template
-| | |-<
-| | |-SimpleDeclaration
-| | | `-int
-| | |->
-| | `-SimpleDeclaration
-| | |-struct
-| | |-Y
-| | |-{
-| | |-SimpleDeclaration
-| | | |-static
-| | | |-void
-| | | |-SimpleDeclarator
-| | | | |-f
-| | | | `-ParametersAndQualifiers
-| | | | |-(
-| | | | `-)
-| | | `-;
-| | |-}
-| | `-;
-| |-}
-| `-;
`-TemplateDeclaration
|-template
|-<
@@ -1030,31 +1114,52 @@
|-{
|-ExpressionStatement
| |-UnknownExpression
- | | |-UnknownExpression
- | | | |-T
- | | | |-::
- | | | |-template
- | | | |-f
- | | | |-<
- | | | |-IntegerLiteralExpression
- | | | | `-0
- | | | `->
+ | | |-IdExpression
+ | | | |-NestedNameSpecifier
+ | | | | |-TypeNameSpecifier
+ | | | | | |-T
+ | | | | | `-::
+ | | | | `-TypeWithTemplateNameSpecifier
+ | | | | |-template
+ | | | | |-U
+ | | | | |-<
+ | | | | |-int
+ | | | | |->
+ | | | | `-::
+ | | | `-UnqualifiedId
+ | | | `-f
+ | | |-(
+ | | `-)
+ | `-;
+ |-ExpressionStatement
+ | |-UnknownExpression
+ | | |-IdExpression
+ | | | |-NestedNameSpecifier
+ | | | | |-TypeNameSpecifier
+ | | | | | |-T
+ | | | | | `-::
+ | | | | `-IdentifierNameSpecifier
+ | | | | |-U
+ | | | | `-::
+ | | | `-UnqualifiedId
+ | | | `-f
| | |-(
| | `-)
| `-;
|-ExpressionStatement
| |-UnknownExpression
- | | |-UnknownExpression
- | | | |-T
- | | | |-::
+ | | |-IdExpression
+ | | | |-NestedNameSpecifier
+ | | | | `-TypeNameSpecifier
+ | | | | |-T
+ | | | | `-::
| | | |-template
- | | | |-Y
- | | | |-<
- | | | |-IntegerLiteralExpression
- | | | | `-0
- | | | |->
- | | | |-::
- | | | `-f
+ | | | `-UnqualifiedId
+ | | | |-f
+ | | | |-<
+ | | | |-IntegerLiteralExpression
+ | | | | `-0
+ | | | `->
| | |-(
| | `-)
| `-;
@@ -1112,7 +1217,7 @@
| |-UnknownExpression
| | |-IdExpression
| | | |-NestedNameSpecifier
- | | | | `-NameSpecifier
+ | | | | `-TypeNameSpecifier
| | | | |-decltype
| | | | |-(
| | | | |-IdExpression
Index: clang/lib/Tooling/Syntax/Nodes.cpp
===================================================================
--- clang/lib/Tooling/Syntax/Nodes.cpp
+++ clang/lib/Tooling/Syntax/Nodes.cpp
@@ -116,8 +116,18 @@
return OS << "ParametersAndQualifiers";
case NodeKind::MemberPointer:
return OS << "MemberPointer";
- case NodeKind::NameSpecifier:
- return OS << "NameSpecifier";
+ case NodeKind::GlobalNameSpecifier:
+ return OS << "GlobalNameSpecifier";
+ case NodeKind::NamespaceNameSpecifier:
+ return OS << "NamespaceNameSpecifier";
+ case NodeKind::TypeNameSpecifier:
+ return OS << "TypeNameSpecifier";
+ case NodeKind::UnknownNameSpecifier:
+ return OS << "UnknownNameSpecifier";
+ case NodeKind::IdentifierNameSpecifier:
+ return OS << "IdentifierNameSpecifier";
+ case NodeKind::TypeWithTemplateNameSpecifier:
+ return OS << "TypeWithTemplateNameSpecifier";
case NodeKind::NestedNameSpecifier:
return OS << "NestedNameSpecifier";
}
@@ -142,6 +152,8 @@
return OS << "ArrowToken";
case syntax::NodeRole::ExternKeyword:
return OS << "ExternKeyword";
+ case syntax::NodeRole::TemplateKeyword:
+ return OS << "TemplateKeyword";
case syntax::NodeRole::BodyStatement:
return OS << "BodyStatement";
case syntax::NodeRole::CaseStatement_value:
@@ -210,6 +222,11 @@
findChild(syntax::NodeRole::IdExpression_qualifier));
}
+syntax::Leaf *syntax::IdExpression::templateKeyword() {
+ return llvm::cast_or_null<syntax::Leaf>(
+ findChild(syntax::NodeRole::TemplateKeyword));
+}
+
syntax::UnqualifiedId *syntax::IdExpression::unqualifiedId() {
return llvm::cast_or_null<syntax::UnqualifiedId>(
findChild(syntax::NodeRole::IdExpression_id));
Index: clang/lib/Tooling/Syntax/BuildTree.cpp
===================================================================
--- clang/lib/Tooling/Syntax/BuildTree.cpp
+++ clang/lib/Tooling/Syntax/BuildTree.cpp
@@ -695,21 +695,6 @@
return true;
}
- syntax::NestedNameSpecifier *
- BuildNestedNameSpecifier(NestedNameSpecifierLoc QualifierLoc) {
- if (!QualifierLoc)
- return nullptr;
- for (auto it = QualifierLoc; it; it = it.getPrefix()) {
- auto *NS = new (allocator()) syntax::NameSpecifier;
- Builder.foldNode(Builder.getRange(it.getLocalSourceRange()), NS, nullptr);
- Builder.markChild(NS, syntax::NodeRole::NestedNameSpecifier_specifier);
- }
- auto *NNS = new (allocator()) syntax::NestedNameSpecifier;
- Builder.foldNode(Builder.getRange(QualifierLoc.getSourceRange()), NNS,
- nullptr);
- return NNS;
- }
-
bool TraverseUserDefinedLiteral(UserDefinedLiteral *S) {
// The semantic AST node `UserDefinedLiteral` (UDL) may have one child node
// referencing the location of the UDL suffix (`_w` in `1.2_w`). The
@@ -759,23 +744,110 @@
return true;
}
+ syntax::NameSpecifier *
+ BuildNameSpecifier(NestedNameSpecifier::SpecifierKind K) {
+ switch (K) {
+ case clang::NestedNameSpecifier::Global:
+ return new (allocator()) syntax::GlobalNameSpecifier;
+ case clang::NestedNameSpecifier::Namespace:
+ case clang::NestedNameSpecifier::NamespaceAlias:
+ return new (allocator()) syntax::NamespaceNameSpecifier;
+ case clang::NestedNameSpecifier::TypeSpec:
+ return new (allocator()) syntax::TypeNameSpecifier;
+ case clang::NestedNameSpecifier::TypeSpecWithTemplate:
+ return new (allocator()) syntax::TypeWithTemplateNameSpecifier;
+ case clang::NestedNameSpecifier::Identifier:
+ return new (allocator()) syntax::IdentifierNameSpecifier;
+ case clang::NestedNameSpecifier::Super:
+ // FIXME: Support Microsoft's __super
+ return new (allocator()) syntax::UnknownNameSpecifier;
+ }
+ }
+
+ // FIXME: Fix `NestedNameSpecifierLoc::getLocalSourceRange` instead
+ // Given a nested-name-specifier `std::T::template X<U>::`
+ // return the range for the last specifier i.e. `template X<U>::`
+ SourceRange getLocalSourceRange(const NestedNameSpecifierLoc &NNSLoc) {
+ // The method `NestedNameSpecifierLoc::getLocalSourceRange` *should* return
+ // the desired `SourceRange`, but there is a corner case. For a
+ // `DependentTemplateSpecializationType` this method returns its qualifiers
+ // as well, in other words in the example above this method returns
+ // `T::template X<U>::` instead of only `template X<U>::`
+ auto SR = NNSLoc.getLocalSourceRange();
+
+ if (auto TL = NNSLoc.getTypeLoc()) {
+ if (auto DependentTL =
+ TL.getAs<DependentTemplateSpecializationTypeLoc>()) {
+ if (DependentTL.getTemplateKeywordLoc().isValid())
+ SR.setBegin(DependentTL.getTemplateKeywordLoc());
+ else
+ SR.setBegin(DependentTL.getTemplateNameLoc());
+ }
+ }
+ return SR;
+ }
+
+ syntax::NestedNameSpecifier *
+ BuildNestedNameSpecifier(const NestedNameSpecifierLoc &QualifierLoc) {
+ if (!QualifierLoc)
+ return nullptr;
+ for (auto it = QualifierLoc; it; it = it.getPrefix()) {
+ auto *NS = BuildNameSpecifier(it.getNestedNameSpecifier()->getKind());
+ Builder.foldNode(Builder.getRange(getLocalSourceRange(it)), NS, nullptr);
+ Builder.markChild(NS, syntax::NodeRole::NestedNameSpecifier_specifier);
+ }
+ auto *NNS = new (allocator()) syntax::NestedNameSpecifier;
+ Builder.foldNode(Builder.getRange(QualifierLoc.getSourceRange()), NNS,
+ nullptr);
+ return NNS;
+ }
+
+ // FIXME: I feel like this could be upstreamed.
+ SourceRange getUnqualifiedIdSourceRange(DeclRefExpr *S) {
+ if (S->hasExplicitTemplateArgs())
+ return SourceRange(S->getNameInfo().getBeginLoc(), S->getRAngleLoc());
+ return S->getNameInfo().getSourceRange();
+ }
+
bool WalkUpFromDeclRefExpr(DeclRefExpr *S) {
if (auto *NNS = BuildNestedNameSpecifier(S->getQualifierLoc()))
Builder.markChild(NNS, syntax::NodeRole::IdExpression_qualifier);
+ if (auto TKL = S->getTemplateKeywordLoc(); TKL.isValid())
+ Builder.markChildToken(TKL, syntax::NodeRole::TemplateKeyword);
+
auto *unqualifiedId = new (allocator()) syntax::UnqualifiedId;
- // Get `UnqualifiedId` from `DeclRefExpr`.
- // FIXME: Extract this logic so that it can be used by `MemberExpr`,
- // and other semantic constructs, now it is tied to `DeclRefExpr`.
- if (!S->hasExplicitTemplateArgs()) {
- Builder.foldNode(Builder.getRange(S->getNameInfo().getSourceRange()),
- unqualifiedId, nullptr);
- } else {
- auto templateIdSourceRange =
- SourceRange(S->getNameInfo().getBeginLoc(), S->getRAngleLoc());
- Builder.foldNode(Builder.getRange(templateIdSourceRange), unqualifiedId,
- nullptr);
- }
+
+ Builder.foldNode(Builder.getRange(getUnqualifiedIdSourceRange(S)),
+ unqualifiedId, nullptr);
+
+ Builder.markChild(unqualifiedId, syntax::NodeRole::IdExpression_id);
+
+ Builder.foldNode(Builder.getExprRange(S),
+ new (allocator()) syntax::IdExpression, S);
+ return true;
+ }
+
+ // FIXME: Same logic as DeclRefExpr. How to DRY?
+ SourceRange getUnqualifiedIdSourceRange(DependentScopeDeclRefExpr *S) {
+ if (S->hasExplicitTemplateArgs())
+ return SourceRange(S->getNameInfo().getBeginLoc(), S->getRAngleLoc());
+ return S->getNameInfo().getSourceRange();
+ }
+
+ // FIXME: Same logic as DeclRefExpr. How to DRY
+ bool WalkUpFromDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
+ if (auto *NNS = BuildNestedNameSpecifier(S->getQualifierLoc()))
+ Builder.markChild(NNS, syntax::NodeRole::IdExpression_qualifier);
+
+ if (auto TKL = S->getTemplateKeywordLoc(); TKL.isValid())
+ Builder.markChildToken(TKL, syntax::NodeRole::TemplateKeyword);
+
+ auto *unqualifiedId = new (allocator()) syntax::UnqualifiedId;
+
+ Builder.foldNode(Builder.getRange(getUnqualifiedIdSourceRange(S)),
+ unqualifiedId, nullptr);
+
Builder.markChild(unqualifiedId, syntax::NodeRole::IdExpression_id);
Builder.foldNode(Builder.getExprRange(S),
Index: clang/include/clang/Tooling/Syntax/Nodes.h
===================================================================
--- clang/include/clang/Tooling/Syntax/Nodes.h
+++ clang/include/clang/Tooling/Syntax/Nodes.h
@@ -95,9 +95,15 @@
TrailingReturnType,
ParametersAndQualifiers,
MemberPointer,
+ UnqualifiedId,
+ // Nested Name Specifiers.
NestedNameSpecifier,
- NameSpecifier,
- UnqualifiedId
+ UnknownNameSpecifier,
+ GlobalNameSpecifier,
+ NamespaceNameSpecifier,
+ TypeNameSpecifier,
+ IdentifierNameSpecifier,
+ TypeWithTemplateNameSpecifier
};
/// For debugging purposes.
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeKind K);
@@ -138,6 +144,7 @@
/// Tokens or Keywords
ArrowToken,
ExternKeyword,
+ TemplateKeyword,
/// An inner statement for those that have only a single child of kind
/// statement, e.g. loop body for while, for, etc; inner statement for case,
/// default, etc.
@@ -196,11 +203,77 @@
/// A sequence of these specifiers make a `nested-name-specifier`.
/// e.g. the `std::` or `vector<int>::` in `std::vector<int>::size`.
-class NameSpecifier final : public Tree {
+class NameSpecifier : public Tree {
public:
- NameSpecifier() : Tree(NodeKind::NameSpecifier) {}
+ NameSpecifier(NodeKind K) : Tree(K) {}
static bool classof(const Node *N) {
- return N->kind() == NodeKind::NameSpecifier;
+ return N->kind() == NodeKind::GlobalNameSpecifier ||
+ N->kind() == NodeKind::TypeNameSpecifier ||
+ N->kind() == NodeKind::NamespaceNameSpecifier ||
+ N->kind() == NodeKind::TypeWithTemplateNameSpecifier ||
+ N->kind() == NodeKind::UnknownNameSpecifier;
+ }
+};
+
+/// The global namespace name specifier, e.g. the first `::` in
+/// `::std::vector<int>`
+class GlobalNameSpecifier final : public NameSpecifier {
+public:
+ GlobalNameSpecifier() : NameSpecifier(NodeKind::GlobalNameSpecifier) {}
+ static bool classof(const Node *N) {
+ return N->kind() == NodeKind::GlobalNameSpecifier;
+ }
+};
+
+/// A type name specifier, it can be of the form: `type-name::` or
+/// `decltype-name::` e.g. the `string::` in `std::string::size` or the
+/// `decltype(s)::` in `decltype(s)::size`.
+class TypeNameSpecifier final : public NameSpecifier {
+public:
+ TypeNameSpecifier() : NameSpecifier(NodeKind::TypeNameSpecifier) {}
+ static bool classof(const Node *N) {
+ return N->kind() == NodeKind::TypeNameSpecifier;
+ }
+};
+
+/// A namespace name specifier, of the form `namespace-name::`
+/// e.g. the `std::` in `std::vector<int>::size`.
+class NamespaceNameSpecifier final : public NameSpecifier {
+public:
+ NamespaceNameSpecifier() : NameSpecifier(NodeKind::NamespaceNameSpecifier) {}
+ static bool classof(const Node *N) {
+ return N->kind() == NodeKind::NamespaceNameSpecifier;
+ }
+};
+
+/// A dependent type name specifier, of the form `namespace-name::`
+/// e.g. the `std::` in `std::vector<int>::size`.
+class IdentifierNameSpecifier final : public NameSpecifier {
+public:
+ IdentifierNameSpecifier()
+ : NameSpecifier(NodeKind::IdentifierNameSpecifier) {}
+ static bool classof(const Node *N) {
+ return N->kind() == NodeKind::IdentifierNameSpecifier;
+ }
+};
+
+/// A type name specifier coming from a template instantiation.
+/// e.g. the `vector<int>::` in `std::vector<int>::size`.
+class TypeWithTemplateNameSpecifier final : public NameSpecifier {
+public:
+ TypeWithTemplateNameSpecifier()
+ : NameSpecifier(NodeKind::TypeWithTemplateNameSpecifier) {}
+ static bool classof(const Node *N) {
+ return N->kind() == NodeKind::TypeWithTemplateNameSpecifier;
+ }
+};
+
+/// A name specifier we don't support yet
+class UnknownNameSpecifier final : public NameSpecifier {
+public:
+ UnknownNameSpecifier() : NameSpecifier(NodeKind::UnknownNameSpecifier) {}
+ static bool classof(const Node *N) {
+ return N->kind() == NodeKind::UnknownNameSpecifier;
}
};
@@ -239,8 +312,8 @@
return N->kind() == NodeKind::IdExpression;
}
syntax::NestedNameSpecifier *qualifier();
- // TODO after expose `id-expression` from `DependentScopeDeclRefExpr`:
// Add accessor for `template_opt`.
+ syntax::Leaf *templateKeyword();
syntax::UnqualifiedId *unqualifiedId();
};
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits