forked from OSchip/llvm-project
[SyntaxTree] Use simplified grammar rule for `NestedNameSpecifier` grammar nodes
This is our grammar rule for nested-name-specifiers: globalbal-specifier: /*empty*/ simple-template-specifier: template_opt simple-template-id name-specifier: global-specifier decltype-specifier identifier simple-template-specifier nested-name-specifier: list(name-specifier, ::, non-empty, terminated) It is a relaxed version of C++ [expr.prim.id] and quite simpler to map to our API. TODO: refine name specifiers, `simple-template-name-specifier` and decltype-name-specifier` are token soup for now.
This commit is contained in:
parent
25367dfefb
commit
8abb5fb68f
|
@ -95,9 +95,13 @@ enum class NodeKind : uint16_t {
|
|||
TrailingReturnType,
|
||||
ParametersAndQualifiers,
|
||||
MemberPointer,
|
||||
UnqualifiedId,
|
||||
// Nested Name Specifiers.
|
||||
NestedNameSpecifier,
|
||||
NameSpecifier,
|
||||
UnqualifiedId
|
||||
GlobalNameSpecifier,
|
||||
DecltypeNameSpecifier,
|
||||
IdentifierNameSpecifier,
|
||||
SimpleTemplateNameSpecifier
|
||||
};
|
||||
/// For debugging purposes.
|
||||
raw_ostream &operator<<(raw_ostream &OS, NodeKind K);
|
||||
|
@ -138,6 +142,7 @@ enum class NodeRole : uint8_t {
|
|||
/// 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 @@ enum class NodeRole : uint8_t {
|
|||
IdExpression_id,
|
||||
IdExpression_qualifier,
|
||||
NestedNameSpecifier_specifier,
|
||||
NestedNameSpecifier_delimiter,
|
||||
ParenExpression_subExpression
|
||||
};
|
||||
/// For debugging purposes.
|
||||
|
@ -195,12 +201,60 @@ public:
|
|||
};
|
||||
|
||||
/// 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 {
|
||||
/// e.g. the `std` or `vector<int>` in `std::vector<int>::size`.
|
||||
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, this specifier doesn't correspond to a
|
||||
/// token instead an absence of tokens before a `::` characterizes it, in
|
||||
/// `::std::vector<int>` it would be characterized by the absence of a token
|
||||
/// before the first `::`
|
||||
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 +267,7 @@ public:
|
|||
return N->kind() <= NodeKind::NestedNameSpecifier;
|
||||
}
|
||||
std::vector<NameSpecifier *> specifiers();
|
||||
std::vector<Leaf *> delimiters();
|
||||
};
|
||||
|
||||
/// Models an `unqualified-id`. C++ [expr.prim.id.unqual]
|
||||
|
@ -239,8 +294,7 @@ public:
|
|||
return N->kind() == NodeKind::IdExpression;
|
||||
}
|
||||
NestedNameSpecifier *qualifier();
|
||||
// TODO after expose `id-expression` from `DependentScopeDeclRefExpr`:
|
||||
// Add accessor for `template_opt`.
|
||||
Leaf *templateKeyword();
|
||||
UnqualifiedId *unqualifiedId();
|
||||
};
|
||||
|
||||
|
|
|
@ -286,6 +286,11 @@ public:
|
|||
foldNode(Range, New, nullptr);
|
||||
}
|
||||
|
||||
void foldNode(ArrayRef<syntax::Token> Range, syntax::Tree *New,
|
||||
NestedNameSpecifierLoc L) {
|
||||
// FIXME: add mapping for NestedNameSpecifierLoc
|
||||
foldNode(Range, New, nullptr);
|
||||
}
|
||||
/// Notifies that we should not consume trailing semicolon when computing
|
||||
/// token range of \p D.
|
||||
void noticeDeclWithoutSemicolon(Decl *D);
|
||||
|
@ -690,21 +695,6 @@ public:
|
|||
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
|
||||
|
@ -754,23 +744,118 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
syntax::NameSpecifier *BuildNameSpecifier(const NestedNameSpecifier &NNS) {
|
||||
switch (NNS.getKind()) {
|
||||
case NestedNameSpecifier::Global:
|
||||
return new (allocator()) syntax::GlobalNameSpecifier;
|
||||
case NestedNameSpecifier::Namespace:
|
||||
case NestedNameSpecifier::NamespaceAlias:
|
||||
case NestedNameSpecifier::Identifier:
|
||||
return new (allocator()) syntax::IdentifierNameSpecifier;
|
||||
case NestedNameSpecifier::TypeSpecWithTemplate:
|
||||
return new (allocator()) syntax::SimpleTemplateNameSpecifier;
|
||||
case NestedNameSpecifier::TypeSpec: {
|
||||
const auto *NNSType = NNS.getAsType();
|
||||
assert(NNSType);
|
||||
if (isa<DecltypeType>(NNSType))
|
||||
return new (allocator()) syntax::DecltypeNameSpecifier;
|
||||
if (isa<TemplateSpecializationType, DependentTemplateSpecializationType>(
|
||||
NNSType))
|
||||
return new (allocator()) syntax::SimpleTemplateNameSpecifier;
|
||||
return new (allocator()) syntax::IdentifierNameSpecifier;
|
||||
}
|
||||
case 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
|
||||
///
|
||||
/// e.g. `std::T::template X<U>::` => `template X<U>::`
|
||||
SourceRange getLocalSourceRange(const NestedNameSpecifierLoc &NNSLoc) {
|
||||
auto SR = NNSLoc.getLocalSourceRange();
|
||||
|
||||
// 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>::`
|
||||
if (auto TL = NNSLoc.getTypeLoc()) {
|
||||
if (auto DependentTL =
|
||||
TL.getAs<DependentTemplateSpecializationTypeLoc>()) {
|
||||
// The 'template' keyword is always present in dependent template
|
||||
// specializations. Except in the case of incorrect code
|
||||
// TODO: Treat the case of incorrect code.
|
||||
SR.setBegin(DependentTL.getTemplateKeywordLoc());
|
||||
}
|
||||
}
|
||||
|
||||
return SR;
|
||||
}
|
||||
|
||||
syntax::NestedNameSpecifier *
|
||||
BuildNestedNameSpecifier(const NestedNameSpecifierLoc &QualifierLoc) {
|
||||
if (!QualifierLoc)
|
||||
return nullptr;
|
||||
for (auto it = QualifierLoc; it; it = it.getPrefix()) {
|
||||
assert(it.hasQualifier());
|
||||
auto *NS = BuildNameSpecifier(*it.getNestedNameSpecifier());
|
||||
assert(NS);
|
||||
if (!isa<syntax::GlobalNameSpecifier>(NS))
|
||||
Builder.foldNode(Builder.getRange(getLocalSourceRange(it)).drop_back(),
|
||||
NS, it);
|
||||
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,
|
||||
QualifierLoc);
|
||||
return NNS;
|
||||
}
|
||||
|
||||
bool WalkUpFromDeclRefExpr(DeclRefExpr *S) {
|
||||
if (auto *NNS = BuildNestedNameSpecifier(S->getQualifierLoc()))
|
||||
Builder.markChild(NNS, syntax::NodeRole::IdExpression_qualifier);
|
||||
auto *Qualifier = BuildNestedNameSpecifier(S->getQualifierLoc());
|
||||
if (Qualifier)
|
||||
Builder.markChild(Qualifier, syntax::NodeRole::IdExpression_qualifier);
|
||||
|
||||
auto TemplateKeywordLoc = S->getTemplateKeywordLoc();
|
||||
if (TemplateKeywordLoc.isValid())
|
||||
Builder.markChildToken(TemplateKeywordLoc,
|
||||
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(S->getLocation(), S->getEndLoc()),
|
||||
unqualifiedId, nullptr);
|
||||
|
||||
Builder.markChild(unqualifiedId, syntax::NodeRole::IdExpression_id);
|
||||
|
||||
Builder.foldNode(Builder.getExprRange(S),
|
||||
new (allocator()) syntax::IdExpression, S);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Same logic as DeclRefExpr.
|
||||
bool WalkUpFromDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
|
||||
auto *Qualifier = BuildNestedNameSpecifier(S->getQualifierLoc());
|
||||
if (Qualifier)
|
||||
Builder.markChild(Qualifier, syntax::NodeRole::IdExpression_qualifier);
|
||||
|
||||
auto TemplateKeywordLoc = S->getTemplateKeywordLoc();
|
||||
if (TemplateKeywordLoc.isValid())
|
||||
Builder.markChildToken(TemplateKeywordLoc,
|
||||
syntax::NodeRole::TemplateKeyword);
|
||||
|
||||
auto *unqualifiedId = new (allocator()) syntax::UnqualifiedId;
|
||||
|
||||
Builder.foldNode(Builder.getRange(S->getLocation(), S->getEndLoc()),
|
||||
unqualifiedId, nullptr);
|
||||
|
||||
Builder.markChild(unqualifiedId, syntax::NodeRole::IdExpression_id);
|
||||
|
||||
Builder.foldNode(Builder.getExprRange(S),
|
||||
|
|
|
@ -116,8 +116,14 @@ raw_ostream &syntax::operator<<(raw_ostream &OS, NodeKind K) {
|
|||
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 @@ raw_ostream &syntax::operator<<(raw_ostream &OS, NodeRole R) {
|
|||
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 @@ raw_ostream &syntax::operator<<(raw_ostream &OS, NodeRole R) {
|
|||
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 @@ syntax::NestedNameSpecifier *syntax::IdExpression::qualifier() {
|
|||
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 cast_or_null<syntax::UnqualifiedId>(
|
||||
findChild(syntax::NodeRole::IdExpression_id));
|
||||
|
|
|
@ -873,24 +873,47 @@ TEST_P(SyntaxTreeTest, QualifiedId) {
|
|||
}
|
||||
EXPECT_TRUE(treeDumpEqual(
|
||||
R"cpp(
|
||||
namespace a {
|
||||
namespace n {
|
||||
struct S {
|
||||
template<typename T>
|
||||
static T f(){}
|
||||
struct ST {
|
||||
static void f();
|
||||
};
|
||||
};
|
||||
}
|
||||
template<typename T>
|
||||
struct ST {
|
||||
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 ST<int>:: // type-template-instantiation-specifier
|
||||
f();
|
||||
|
||||
n:: // namespace-specifier
|
||||
S:: // type-name-specifier
|
||||
ST<int>:: // type-template-instantiation-specifier
|
||||
f();
|
||||
|
||||
ST<int>:: // type-name-specifier
|
||||
S:: // type-name-specifier
|
||||
f<int>();
|
||||
|
||||
ST<int>:: // type-name-specifier
|
||||
S:: // type-name-specifier
|
||||
template f<int>();
|
||||
}
|
||||
)cpp",
|
||||
R"txt(
|
||||
*: TranslationUnit
|
||||
|-NamespaceDefinition
|
||||
| |-namespace
|
||||
| |-a
|
||||
| |-n
|
||||
| |-{
|
||||
| |-SimpleDeclaration
|
||||
| | |-struct
|
||||
|
@ -904,19 +927,58 @@ void test() {
|
|||
| | | | `-T
|
||||
| | | |->
|
||||
| | | `-SimpleDeclaration
|
||||
| | | |-static
|
||||
| | | |-T
|
||||
| | | |-SimpleDeclarator
|
||||
| | | | |-f
|
||||
| | | | `-ParametersAndQualifiers
|
||||
| | | | |-(
|
||||
| | | | `-)
|
||||
| | | `-CompoundStatement
|
||||
| | | |-{
|
||||
| | | `-}
|
||||
| | | |-struct
|
||||
| | | |-ST
|
||||
| | | |-{
|
||||
| | | |-SimpleDeclaration
|
||||
| | | | |-static
|
||||
| | | | |-void
|
||||
| | | | |-SimpleDeclarator
|
||||
| | | | | |-f
|
||||
| | | | | `-ParametersAndQualifiers
|
||||
| | | | | |-(
|
||||
| | | | | `-)
|
||||
| | | | `-;
|
||||
| | | |-}
|
||||
| | | `-;
|
||||
| | |-}
|
||||
| | `-;
|
||||
| `-}
|
||||
|-TemplateDeclaration
|
||||
| |-template
|
||||
| |-<
|
||||
| |-UnknownDeclaration
|
||||
| | |-typename
|
||||
| | `-T
|
||||
| |->
|
||||
| `-SimpleDeclaration
|
||||
| |-struct
|
||||
| |-ST
|
||||
| |-{
|
||||
| |-SimpleDeclaration
|
||||
| | |-struct
|
||||
| | |-S
|
||||
| | |-{
|
||||
| | |-TemplateDeclaration
|
||||
| | | |-template
|
||||
| | | |-<
|
||||
| | | |-UnknownDeclaration
|
||||
| | | | |-typename
|
||||
| | | | `-U
|
||||
| | | |->
|
||||
| | | `-SimpleDeclaration
|
||||
| | | |-static
|
||||
| | | |-U
|
||||
| | | |-SimpleDeclarator
|
||||
| | | | |-f
|
||||
| | | | `-ParametersAndQualifiers
|
||||
| | | | |-(
|
||||
| | | | `-)
|
||||
| | | `-;
|
||||
| | |-}
|
||||
| | `-;
|
||||
| |-}
|
||||
| `-;
|
||||
`-SimpleDeclaration
|
||||
|-void
|
||||
|-SimpleDeclarator
|
||||
|
@ -930,14 +992,81 @@ void test() {
|
|||
| |-UnknownExpression
|
||||
| | |-IdExpression
|
||||
| | | |-NestedNameSpecifier
|
||||
| | | | |-NameSpecifier
|
||||
| | | | | `-::
|
||||
| | | | |-NameSpecifier
|
||||
| | | | | |-a
|
||||
| | | | | `-::
|
||||
| | | | `-NameSpecifier
|
||||
| | | | |-S
|
||||
| | | | `-::
|
||||
| | | | |-::
|
||||
| | | | |-IdentifierNameSpecifier
|
||||
| | | | | `-n
|
||||
| | | | |-::
|
||||
| | | | |-IdentifierNameSpecifier
|
||||
| | | | | `-S
|
||||
| | | | |-::
|
||||
| | | | |-SimpleTemplateNameSpecifier
|
||||
| | | | | |-template
|
||||
| | | | | |-ST
|
||||
| | | | | |-<
|
||||
| | | | | |-int
|
||||
| | | | | `->
|
||||
| | | | `-::
|
||||
| | | `-UnqualifiedId
|
||||
| | | `-f
|
||||
| | |-(
|
||||
| | `-)
|
||||
| `-;
|
||||
|-ExpressionStatement
|
||||
| |-UnknownExpression
|
||||
| | |-IdExpression
|
||||
| | | |-NestedNameSpecifier
|
||||
| | | | |-IdentifierNameSpecifier
|
||||
| | | | | `-n
|
||||
| | | | |-::
|
||||
| | | | |-IdentifierNameSpecifier
|
||||
| | | | | `-S
|
||||
| | | | |-::
|
||||
| | | | |-SimpleTemplateNameSpecifier
|
||||
| | | | | |-ST
|
||||
| | | | | |-<
|
||||
| | | | | |-int
|
||||
| | | | | `->
|
||||
| | | | `-::
|
||||
| | | `-UnqualifiedId
|
||||
| | | `-f
|
||||
| | |-(
|
||||
| | `-)
|
||||
| `-;
|
||||
|-ExpressionStatement
|
||||
| |-UnknownExpression
|
||||
| | |-IdExpression
|
||||
| | | |-NestedNameSpecifier
|
||||
| | | | |-SimpleTemplateNameSpecifier
|
||||
| | | | | |-ST
|
||||
| | | | | |-<
|
||||
| | | | | |-int
|
||||
| | | | | `->
|
||||
| | | | |-::
|
||||
| | | | |-IdentifierNameSpecifier
|
||||
| | | | | `-S
|
||||
| | | | `-::
|
||||
| | | `-UnqualifiedId
|
||||
| | | |-f
|
||||
| | | |-<
|
||||
| | | |-int
|
||||
| | | `->
|
||||
| | |-(
|
||||
| | `-)
|
||||
| `-;
|
||||
|-ExpressionStatement
|
||||
| |-UnknownExpression
|
||||
| | |-IdExpression
|
||||
| | | |-NestedNameSpecifier
|
||||
| | | | |-SimpleTemplateNameSpecifier
|
||||
| | | | | |-ST
|
||||
| | | | | |-<
|
||||
| | | | | |-int
|
||||
| | | | | `->
|
||||
| | | | |-::
|
||||
| | | | |-IdentifierNameSpecifier
|
||||
| | | | | `-S
|
||||
| | | | `-::
|
||||
| | | |-template
|
||||
| | | `-UnqualifiedId
|
||||
| | | |-f
|
||||
| | | |-<
|
||||
|
@ -950,7 +1079,7 @@ void test() {
|
|||
)txt"));
|
||||
}
|
||||
|
||||
TEST_P(SyntaxTreeTest, QualifiedIdWithTemplateKeyword) {
|
||||
TEST_P(SyntaxTreeTest, QualifiedIdWithDependentType) {
|
||||
if (!GetParam().isCXX()) {
|
||||
return;
|
||||
}
|
||||
|
@ -961,63 +1090,17 @@ TEST_P(SyntaxTreeTest, QualifiedIdWithTemplateKeyword) {
|
|||
}
|
||||
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
|
||||
|-<
|
||||
|
@ -1036,31 +1119,52 @@ template<typename T> void test() {
|
|||
|-{
|
||||
|-ExpressionStatement
|
||||
| |-UnknownExpression
|
||||
| | |-UnknownExpression
|
||||
| | | |-T
|
||||
| | | |-::
|
||||
| | | |-template
|
||||
| | | |-f
|
||||
| | | |-<
|
||||
| | | |-IntegerLiteralExpression
|
||||
| | | | `-0
|
||||
| | | `->
|
||||
| | |-IdExpression
|
||||
| | | |-NestedNameSpecifier
|
||||
| | | | |-IdentifierNameSpecifier
|
||||
| | | | | `-T
|
||||
| | | | |-::
|
||||
| | | | |-SimpleTemplateNameSpecifier
|
||||
| | | | | |-template
|
||||
| | | | | |-U
|
||||
| | | | | |-<
|
||||
| | | | | |-int
|
||||
| | | | | `->
|
||||
| | | | `-::
|
||||
| | | `-UnqualifiedId
|
||||
| | | `-f
|
||||
| | |-(
|
||||
| | `-)
|
||||
| `-;
|
||||
|-ExpressionStatement
|
||||
| |-UnknownExpression
|
||||
| | |-UnknownExpression
|
||||
| | | |-T
|
||||
| | | |-::
|
||||
| | |-IdExpression
|
||||
| | | |-NestedNameSpecifier
|
||||
| | | | |-IdentifierNameSpecifier
|
||||
| | | | | `-T
|
||||
| | | | |-::
|
||||
| | | | |-IdentifierNameSpecifier
|
||||
| | | | | `-U
|
||||
| | | | `-::
|
||||
| | | `-UnqualifiedId
|
||||
| | | `-f
|
||||
| | |-(
|
||||
| | `-)
|
||||
| `-;
|
||||
|-ExpressionStatement
|
||||
| |-UnknownExpression
|
||||
| | |-IdExpression
|
||||
| | | |-NestedNameSpecifier
|
||||
| | | | |-IdentifierNameSpecifier
|
||||
| | | | | `-T
|
||||
| | | | `-::
|
||||
| | | |-template
|
||||
| | | |-Y
|
||||
| | | |-<
|
||||
| | | |-IntegerLiteralExpression
|
||||
| | | | `-0
|
||||
| | | |->
|
||||
| | | |-::
|
||||
| | | `-f
|
||||
| | | `-UnqualifiedId
|
||||
| | | |-f
|
||||
| | | |-<
|
||||
| | | |-IntegerLiteralExpression
|
||||
| | | | `-0
|
||||
| | | `->
|
||||
| | |-(
|
||||
| | `-)
|
||||
| `-;
|
||||
|
@ -1118,14 +1222,14 @@ void test(S s) {
|
|||
| |-UnknownExpression
|
||||
| | |-IdExpression
|
||||
| | | |-NestedNameSpecifier
|
||||
| | | | `-NameSpecifier
|
||||
| | | | |-decltype
|
||||
| | | | |-(
|
||||
| | | | |-IdExpression
|
||||
| | | | | `-UnqualifiedId
|
||||
| | | | | `-s
|
||||
| | | | |-)
|
||||
| | | | `-::
|
||||
| | | | |-DecltypeNameSpecifier
|
||||
| | | | | |-decltype
|
||||
| | | | | |-(
|
||||
| | | | | |-IdExpression
|
||||
| | | | | | `-UnqualifiedId
|
||||
| | | | | | `-s
|
||||
| | | | | `-)
|
||||
| | | | `-::
|
||||
| | | `-UnqualifiedId
|
||||
| | | `-f
|
||||
| | |-(
|
||||
|
|
Loading…
Reference in New Issue