eduucaldas updated this revision to Diff 280511.
eduucaldas added a comment.
- Remove UnknownNameSpecifier, answer to comments
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D84348/new/
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,81 @@
| |-UnknownExpression
| | |-IdExpression
| | | |-NestedNameSpecifier
- | | | | |-NameSpecifier
- | | | | | `-::
- | | | | |-NameSpecifier
- | | | | | |-a
- | | | | | `-::
- | | | | `-NameSpecifier
- | | | | |-S
- | | | | `-::
+ | | | | |-::
+ | | | | |-IdentifierNameSpecifier
+ | | | | | `-n
+ | | | | |-::
+ | | | | |-IdentifierNameSpecifier
+ | | | | | `-S
+ | | | | |-::
+ | | | | |-SimpleTemplateNameSpecifier
+ | | | | | |-template
+ | | | | | |-TS
+ | | | | | |-<
+ | | | | | |-int
+ | | | | | `->
+ | | | | `-::
+ | | | `-UnqualifiedId
+ | | | `-f
+ | | |-(
+ | | `-)
+ | `-;
+ |-ExpressionStatement
+ | |-UnknownExpression
+ | | |-IdExpression
+ | | | |-NestedNameSpecifier
+ | | | | |-IdentifierNameSpecifier
+ | | | | | `-n
+ | | | | |-::
+ | | | | |-IdentifierNameSpecifier
+ | | | | | `-S
+ | | | | |-::
+ | | | | |-SimpleTemplateNameSpecifier
+ | | | | | |-TS
+ | | | | | |-<
+ | | | | | |-int
+ | | | | | `->
+ | | | | `-::
+ | | | `-UnqualifiedId
+ | | | `-f
+ | | |-(
+ | | `-)
+ | `-;
+ |-ExpressionStatement
+ | |-UnknownExpression
+ | | |-IdExpression
+ | | | |-NestedNameSpecifier
+ | | | | |-SimpleTemplateNameSpecifier
+ | | | | | |-TS
+ | | | | | |-<
+ | | | | | |-int
+ | | | | | `->
+ | | | | |-::
+ | | | | |-IdentifierNameSpecifier
+ | | | | | `-S
+ | | | | `-::
+ | | | `-UnqualifiedId
+ | | | |-f
+ | | | |-<
+ | | | |-int
+ | | | `->
+ | | |-(
+ | | `-)
+ | `-;
+ |-ExpressionStatement
+ | |-UnknownExpression
+ | | |-IdExpression
+ | | | |-NestedNameSpecifier
+ | | | | |-SimpleTemplateNameSpecifier
+ | | | | | |-TS
+ | | | | | |-<
+ | | | | | |-int
+ | | | | | `->
+ | | | | |-::
+ | | | | |-IdentifierNameSpecifier
+ | | | | | `-S
+ | | | | `-::
+ | | | |-template
| | | `-UnqualifiedId
| | | |-f
| | | |-<
@@ -944,7 +1073,7 @@
)txt"));
}
-TEST_P(SyntaxTreeTest, QualifiedIdWithTemplateKeyword) {
+TEST_P(SyntaxTreeTest, QualifiedIdWithDependentType) {
if (!GetParam().isCXX()) {
return;
}
@@ -955,63 +1084,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 +1113,52 @@
|-{
|-ExpressionStatement
| |-UnknownExpression
- | | |-UnknownExpression
- | | | |-T
- | | | |-::
- | | | |-template
- | | | |-f
- | | | |-<
- | | | |-IntegerLiteralExpression
- | | | | `-0
- | | | `->
+ | | |-IdExpression
+ | | | |-NestedNameSpecifier
+ | | | | |-IdentifierNameSpecifier
+ | | | | | `-T
+ | | | | |-::
+ | | | | |-SimpleTemplateNameSpecifier
+ | | | | | |-template
+ | | | | | |-U
+ | | | | | |-<
+ | | | | | |-int
+ | | | | | `->
+ | | | | `-::
+ | | | `-UnqualifiedId
+ | | | `-f
+ | | |-(
+ | | `-)
+ | `-;
+ |-ExpressionStatement
+ | |-UnknownExpression
+ | | |-IdExpression
+ | | | |-NestedNameSpecifier
+ | | | | |-IdentifierNameSpecifier
+ | | | | | `-T
+ | | | | |-::
+ | | | | |-IdentifierNameSpecifier
+ | | | | | `-U
+ | | | | `-::
+ | | | `-UnqualifiedId
+ | | | `-f
| | |-(
| | `-)
| `-;
|-ExpressionStatement
| |-UnknownExpression
- | | |-UnknownExpression
- | | | |-T
- | | | |-::
+ | | |-IdExpression
+ | | | |-NestedNameSpecifier
+ | | | | |-IdentifierNameSpecifier
+ | | | | | `-T
+ | | | | `-::
| | | |-template
- | | | |-Y
- | | | |-<
- | | | |-IntegerLiteralExpression
- | | | | `-0
- | | | |->
- | | | |-::
- | | | `-f
+ | | | `-UnqualifiedId
+ | | | |-f
+ | | | |-<
+ | | | |-IntegerLiteralExpression
+ | | | | `-0
+ | | | `->
| | |-(
| | `-)
| `-;
@@ -1112,14 +1216,14 @@
| |-UnknownExpression
| | |-IdExpression
| | | |-NestedNameSpecifier
- | | | | `-NameSpecifier
- | | | | |-decltype
- | | | | |-(
- | | | | |-IdExpression
- | | | | | `-UnqualifiedId
- | | | | | `-s
- | | | | |-)
- | | | | `-::
+ | | | | |-DecltypeNameSpecifier
+ | | | | | |-decltype
+ | | | | | |-(
+ | | | | | |-IdExpression
+ | | | | | | `-UnqualifiedId
+ | | | | | | `-s
+ | | | | | `-)
+ | | | | `-::
| | | `-UnqualifiedId
| | | `-f
| | |-(
Index: clang/lib/Tooling/Syntax/Nodes.cpp
===================================================================
--- clang/lib/Tooling/Syntax/Nodes.cpp
+++ clang/lib/Tooling/Syntax/Nodes.cpp
@@ -116,8 +116,14 @@
return OS << "ParametersAndQualifiers";
case NodeKind::MemberPointer:
return OS << "MemberPointer";
- case NodeKind::NameSpecifier:
- return OS << "NameSpecifier";
+ case NodeKind::GlobalNameSpecifier:
+ return OS << "GlobalNameSpecifier";
+ case NodeKind::DecltypeNameSpecifier:
+ return OS << "DecltypeNameSpecifier";
+ case NodeKind::IdentifierNameSpecifier:
+ return OS << "IdentifierNameSpecifier";
+ case NodeKind::SimpleTemplateNameSpecifier:
+ return OS << "SimpleTemplateNameSpecifier";
case NodeKind::NestedNameSpecifier:
return OS << "NestedNameSpecifier";
}
@@ -142,6 +148,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:
@@ -190,12 +198,23 @@
return OS << "IdExpression_qualifier";
case syntax::NodeRole::NestedNameSpecifier_specifier:
return OS << "NestedNameSpecifier_specifier";
+ case syntax::NodeRole::NestedNameSpecifier_delimiter:
+ return OS << "NestedNameSpecifier_delimiter";
case syntax::NodeRole::ParenExpression_subExpression:
return OS << "ParenExpression_subExpression";
}
llvm_unreachable("invalid role");
}
+std::vector<syntax::Leaf *> syntax::NestedNameSpecifier::delimiters() {
+ std::vector<syntax::Leaf *> Children;
+ for (auto *C = firstChild(); C; C = C->nextSibling()) {
+ assert(C->role() == syntax::NodeRole::NestedNameSpecifier_delimiter);
+ Children.push_back(llvm::cast<syntax::Leaf>(C));
+ }
+ return Children;
+}
+
std::vector<syntax::NameSpecifier *> syntax::NestedNameSpecifier::specifiers() {
std::vector<syntax::NameSpecifier *> Children;
for (auto *C = firstChild(); C; C = C->nextSibling()) {
@@ -210,6 +229,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,138 @@
return true;
}
+ bool isDecltype(const Type &T) {
+ return T.getTypeClass() == Type::TypeClass::Decltype;
+ }
+
+ bool isTemplateInstantiation(const Type &T) {
+ return T.getTypeClass() == Type::TypeClass::TemplateSpecialization ||
+ T.getTypeClass() == Type::TypeClass::DependentTemplateSpecialization;
+ }
+
+ syntax::NameSpecifier *BuildNameSpecifier(const NestedNameSpecifier &NNS) {
+ switch (NNS.getKind()) {
+ case clang::NestedNameSpecifier::Global:
+ return new (allocator()) syntax::GlobalNameSpecifier;
+ case clang::NestedNameSpecifier::Namespace:
+ case clang::NestedNameSpecifier::NamespaceAlias:
+ case clang::NestedNameSpecifier::Identifier:
+ return new (allocator()) syntax::IdentifierNameSpecifier;
+ case clang::NestedNameSpecifier::TypeSpecWithTemplate:
+ return new (allocator()) syntax::SimpleTemplateNameSpecifier;
+ case clang::NestedNameSpecifier::TypeSpec: {
+ const auto *NNSType = NNS.getAsType();
+ assert(NNSType);
+ if (isDecltype(*NNSType))
+ return new (allocator()) syntax::DecltypeNameSpecifier;
+ if (!isTemplateInstantiation(*NNSType))
+ return new (allocator()) syntax::IdentifierNameSpecifier;
+ return new (allocator()) syntax::SimpleTemplateNameSpecifier;
+ }
+ case clang::NestedNameSpecifier::Super:
+ // FIXME: Support Microsoft's __super
+ llvm::report_fatal_error("We don't yet support the __super specifier",
+ true);
+ }
+ }
+
+ // FIXME: Fix `NestedNameSpecifierLoc::getLocalSourceRange` for the
+ // `DependentTemplateSpecializationType` case.
+ /// Given a nested-name-specifier return the range for the last name specifier
+ /// without '::`.
+ ///
+ /// e.g. `std::T::template X<U>::` => `template X<U>`
+ SourceRange getLocalSourceRange(const NestedNameSpecifierLoc &NNSLoc) {
+ auto SR = NNSLoc.getLocalSourceRange();
+
+ // Remove "::" from the `SourceRange`
+ SR.setEnd(SR.getEnd().getLocWithOffset(-1));
+
+ // The method `NestedNameSpecifierLoc::getLocalSourceRange` *should* return
+ // the desired `SourceRange` with a trailing '::', 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>::`
+ if (auto TL = NNSLoc.getTypeLoc()) {
+ if (auto DependentTL =
+ TL.getAs<DependentTemplateSpecializationTypeLoc>()) {
+ // The 'template' keyword is always present in dependent template
+ // specializations
+ SR.setBegin(DependentTL.getTemplateKeywordLoc());
+ }
+ }
+
+ return SR;
+ }
+
+ syntax::NestedNameSpecifier *
+ BuildNestedNameSpecifier(const NestedNameSpecifierLoc &QualifierLoc) {
+ if (!QualifierLoc)
+ return nullptr;
+ for (auto it = QualifierLoc; it; it = it.getPrefix()) {
+ const auto *NNS = it.getNestedNameSpecifier();
+ assert(NNS);
+ auto *NS = BuildNameSpecifier(*NNS);
+ if (!syntax::GlobalNameSpecifier::classof(NS))
+ Builder.foldNode(Builder.getRange(getLocalSourceRange(it)), NS,
+ nullptr);
+ Builder.markChild(NS, syntax::NodeRole::NestedNameSpecifier_specifier);
+ Builder.markChildToken(it.getEndLoc(),
+ syntax::NodeRole::NestedNameSpecifier_delimiter);
+ }
+ auto *NNS = new (allocator()) syntax::NestedNameSpecifier;
+ Builder.foldNode(
+ Builder.getRange(QualifierLoc.getSourceRange()), NNS,
+ nullptr); // FIXME: add link to semantic NestedNameSpecifier
+ 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,13 @@
TrailingReturnType,
ParametersAndQualifiers,
MemberPointer,
+ UnqualifiedId,
+ // Nested Name Specifiers.
NestedNameSpecifier,
- NameSpecifier,
- UnqualifiedId
+ GlobalNameSpecifier,
+ DecltypeNameSpecifier,
+ IdentifierNameSpecifier,
+ SimpleTemplateNameSpecifier
};
/// For debugging purposes.
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, NodeKind K);
@@ -138,6 +142,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.
@@ -167,6 +172,7 @@
IdExpression_id,
IdExpression_qualifier,
NestedNameSpecifier_specifier,
+ NestedNameSpecifier_delimiter,
ParenExpression_subExpression
};
/// For debugging purposes.
@@ -196,11 +202,57 @@
/// 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::DecltypeNameSpecifier ||
+ N->kind() == NodeKind::IdentifierNameSpecifier ||
+ N->kind() == NodeKind::SimpleTemplateNameSpecifier;
+ }
+};
+
+/// 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 name specifier holding a decltype, of the form: `decltype ( expression )
+/// ::` e.g. the `decltype(s)::` in `decltype(s)::size`.
+class DecltypeNameSpecifier final : public NameSpecifier {
+public:
+ DecltypeNameSpecifier() : NameSpecifier(NodeKind::DecltypeNameSpecifier) {}
+ static bool classof(const Node *N) {
+ return N->kind() == NodeKind::DecltypeNameSpecifier;
+ }
+};
+
+/// A identifier name specifier, of the form `identifier ::`
+/// 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 name specifier with a simple-template-id, of the form `template_opt
+/// identifier < template-args > ::` e.g. the `vector<int>::` in
+/// `std::vector<int>::size`.
+class SimpleTemplateNameSpecifier final : public NameSpecifier {
+public:
+ SimpleTemplateNameSpecifier()
+ : NameSpecifier(NodeKind::SimpleTemplateNameSpecifier) {}
+ static bool classof(const Node *N) {
+ return N->kind() == NodeKind::SimpleTemplateNameSpecifier;
}
};
@@ -213,6 +265,7 @@
return N->kind() <= NodeKind::NestedNameSpecifier;
}
std::vector<syntax::NameSpecifier *> specifiers();
+ std::vector<syntax::Leaf *> delimiters();
};
/// Models an `unqualified-id`. C++ [expr.prim.id.unqual]
@@ -239,8 +292,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