Skip to content

Commit dd12826

Browse files
hlopkogribozavr
authored andcommitted
[Syntax] Build template declaration nodes
Summary: Copy of https://reviews.llvm.org/D72334, submitting with Ilya's permission. Handles template declaration of all kinds. Also builds template declaration nodes for specializations and explicit instantiations of classes. Some missing things will be addressed in the follow-up patches: specializations of functions and variables, template parameters. Reviewers: gribozavr2 Reviewed By: gribozavr2 Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D76346
1 parent ef64ba8 commit dd12826

File tree

4 files changed

+414
-32
lines changed

4 files changed

+414
-32
lines changed

clang/include/clang/Tooling/Syntax/Nodes.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ enum class NodeKind : uint16_t {
6464
StaticAssertDeclaration,
6565
LinkageSpecificationDeclaration,
6666
SimpleDeclaration,
67+
TemplateDeclaration,
68+
ExplicitTemplateInstantiation,
6769
NamespaceDefinition,
6870
NamespaceAliasDefinition,
6971
UsingNamespaceDirective,
@@ -112,6 +114,9 @@ enum class NodeRole : uint8_t {
112114
StaticAssertDeclaration_condition,
113115
StaticAssertDeclaration_message,
114116
SimpleDeclaration_declarator,
117+
TemplateDeclaration_declaration,
118+
ExplicitTemplateInstantiation_externKeyword,
119+
ExplicitTemplateInstantiation_declaration,
115120
ArraySubscript_sizeExpression,
116121
TrailingReturnType_arrow,
117122
TrailingReturnType_declarator,
@@ -396,6 +401,34 @@ class SimpleDeclaration final : public Declaration {
396401
std::vector<syntax::SimpleDeclarator *> declarators();
397402
};
398403

404+
/// template <template-parameters> <declaration>
405+
class TemplateDeclaration final : public Declaration {
406+
public:
407+
TemplateDeclaration() : Declaration(NodeKind::TemplateDeclaration) {}
408+
static bool classof(const Node *N) {
409+
return N->kind() == NodeKind::TemplateDeclaration;
410+
}
411+
syntax::Leaf *templateKeyword();
412+
syntax::Declaration *declaration();
413+
};
414+
415+
/// template <declaration>
416+
/// Examples:
417+
/// template struct X<int>
418+
/// template void foo<int>()
419+
/// template int var<double>
420+
class ExplicitTemplateInstantiation final : public Declaration {
421+
public:
422+
ExplicitTemplateInstantiation()
423+
: Declaration(NodeKind::ExplicitTemplateInstantiation) {}
424+
static bool classof(const Node *N) {
425+
return N->kind() == NodeKind::ExplicitTemplateInstantiation;
426+
}
427+
syntax::Leaf *templateKeyword();
428+
syntax::Leaf *externKeyword();
429+
syntax::Declaration *declaration();
430+
};
431+
399432
/// namespace <name> { <decls> }
400433
class NamespaceDefinition final : public Declaration {
401434
public:

clang/lib/Tooling/Syntax/BuildTree.cpp

Lines changed: 139 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "clang/Basic/LLVM.h"
1919
#include "clang/Basic/SourceLocation.h"
2020
#include "clang/Basic/SourceManager.h"
21+
#include "clang/Basic/Specifiers.h"
2122
#include "clang/Basic/TokenKinds.h"
2223
#include "clang/Lex/Lexer.h"
2324
#include "clang/Tooling/Syntax/Nodes.h"
@@ -189,7 +190,6 @@ class syntax::TreeBuilder {
189190
/// Should be called for expressions in non-statement position to avoid
190191
/// wrapping into expression statement.
191192
void markExprChild(Expr *Child, NodeRole Role);
192-
193193
/// Set role for a token starting at \p Loc.
194194
void markChildToken(SourceLocation Loc, NodeRole R);
195195
/// Set role for \p T.
@@ -199,6 +199,9 @@ class syntax::TreeBuilder {
199199
void markChild(llvm::ArrayRef<syntax::Token> Range, NodeRole R);
200200
/// Set role for the delayed node that spans exactly \p Range.
201201
void markDelayedChild(llvm::ArrayRef<syntax::Token> Range, NodeRole R);
202+
/// Set role for the node that may or may not be delayed. Node must span
203+
/// exactly \p Range.
204+
void markMaybeDelayedChild(llvm::ArrayRef<syntax::Token> Range, NodeRole R);
202205

203206
/// Finish building the tree and consume the root node.
204207
syntax::TranslationUnit *finalize() && {
@@ -215,6 +218,9 @@ class syntax::TreeBuilder {
215218
return TU;
216219
}
217220

221+
/// Finds a token starting at \p L. The token must exist if \p L is valid.
222+
const syntax::Token *findToken(SourceLocation L) const;
223+
218224
/// getRange() finds the syntax tokens corresponding to the passed source
219225
/// locations.
220226
/// \p First is the start position of the first token and \p Last is the start
@@ -227,15 +233,22 @@ class syntax::TreeBuilder {
227233
Arena.sourceManager().isBeforeInTranslationUnit(First, Last));
228234
return llvm::makeArrayRef(findToken(First), std::next(findToken(Last)));
229235
}
230-
llvm::ArrayRef<syntax::Token> getRange(const Decl *D) const {
231-
auto Tokens = getRange(D->getBeginLoc(), D->getEndLoc());
232-
if (llvm::isa<NamespaceDecl>(D))
233-
return Tokens;
234-
if (DeclsWithoutSemicolons.count(D))
235-
return Tokens;
236-
// FIXME: do not consume trailing semicolon on function definitions.
237-
// Most declarations own a semicolon in syntax trees, but not in clang AST.
238-
return withTrailingSemicolon(Tokens);
236+
237+
llvm::ArrayRef<syntax::Token>
238+
getTemplateRange(const ClassTemplateSpecializationDecl *D) const {
239+
auto R = D->getSourceRange();
240+
auto Tokens = getRange(R.getBegin(), R.getEnd());
241+
return maybeAppendSemicolon(Tokens, D);
242+
}
243+
244+
llvm::ArrayRef<syntax::Token> getDeclRange(const Decl *D) const {
245+
llvm::ArrayRef<clang::syntax::Token> Tokens;
246+
// We want to drop the template parameters for specializations.
247+
if (const auto *S = llvm::dyn_cast<TagDecl>(D))
248+
Tokens = getRange(S->TypeDecl::getBeginLoc(), S->getEndLoc());
249+
else
250+
Tokens = getRange(D->getBeginLoc(), D->getEndLoc());
251+
return maybeAppendSemicolon(Tokens, D);
239252
}
240253
llvm::ArrayRef<syntax::Token> getExprRange(const Expr *E) const {
241254
return getRange(E->getBeginLoc(), E->getEndLoc());
@@ -255,6 +268,18 @@ class syntax::TreeBuilder {
255268
}
256269

257270
private:
271+
llvm::ArrayRef<syntax::Token>
272+
maybeAppendSemicolon(llvm::ArrayRef<syntax::Token> Tokens,
273+
const Decl *D) const {
274+
if (llvm::isa<NamespaceDecl>(D))
275+
return Tokens;
276+
if (DeclsWithoutSemicolons.count(D))
277+
return Tokens;
278+
// FIXME: do not consume trailing semicolon on function definitions.
279+
// Most declarations own a semicolon in syntax trees, but not in clang AST.
280+
return withTrailingSemicolon(Tokens);
281+
}
282+
258283
llvm::ArrayRef<syntax::Token>
259284
withTrailingSemicolon(llvm::ArrayRef<syntax::Token> Tokens) const {
260285
assert(!Tokens.empty());
@@ -265,9 +290,6 @@ class syntax::TreeBuilder {
265290
return Tokens;
266291
}
267292

268-
/// Finds a token starting at \p L. The token must exist.
269-
const syntax::Token *findToken(SourceLocation L) const;
270-
271293
/// A collection of trees covering the input tokens.
272294
/// When created, each tree corresponds to a single token in the file.
273295
/// Clients call 'foldChildren' to attach one or more subtrees to a parent
@@ -298,6 +320,15 @@ class syntax::TreeBuilder {
298320
It->second.Role = Role;
299321
}
300322

323+
void assignRoleMaybeDelayed(llvm::ArrayRef<syntax::Token> Range,
324+
syntax::NodeRole Role) {
325+
auto It = DelayedFolds.find(Range.begin());
326+
if (It == DelayedFolds.end())
327+
return assignRole(Range, Role);
328+
assert(It->second.End == Range.end());
329+
It->second.Role = Role;
330+
}
331+
301332
void assignRole(llvm::ArrayRef<syntax::Token> Range,
302333
syntax::NodeRole Role) {
303334
assert(!Range.empty());
@@ -460,7 +491,7 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
460491

461492
bool WalkUpFromDeclaratorDecl(DeclaratorDecl *DD) {
462493
// Ensure declarators are covered by SimpleDeclaration.
463-
Builder.noticeDeclRange(Builder.getRange(DD));
494+
Builder.noticeDeclRange(Builder.getDeclRange(DD));
464495

465496
// Build the declarator node.
466497
SourceRange Initializer;
@@ -485,7 +516,7 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
485516

486517
bool WalkUpFromTypedefNameDecl(TypedefNameDecl *D) {
487518
// Ensure declarators are covered by SimpleDeclaration.
488-
Builder.noticeDeclRange(Builder.getRange(D));
519+
Builder.noticeDeclRange(Builder.getDeclRange(D));
489520

490521
auto R = getDeclaratorRange(
491522
Builder.sourceManager(), D->getTypeSourceInfo()->getTypeLoc(),
@@ -500,19 +531,59 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
500531

501532
bool VisitDecl(Decl *D) {
502533
assert(!D->isImplicit());
503-
Builder.foldNode(Builder.getRange(D),
534+
Builder.foldNode(Builder.getDeclRange(D),
504535
new (allocator()) syntax::UnknownDeclaration());
505536
return true;
506537
}
507538

539+
// RAV does not call WalkUpFrom* on explicit instantiations, so we have to
540+
// override Traverse.
541+
// FIXME: make RAV call WalkUpFrom* instead.
542+
bool
543+
TraverseClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *C) {
544+
if (!RecursiveASTVisitor::TraverseClassTemplateSpecializationDecl(C))
545+
return false;
546+
if (C->isExplicitSpecialization())
547+
return true; // we are only interested in explicit instantiations.
548+
if (!WalkUpFromClassTemplateSpecializationDecl(C))
549+
return false;
550+
foldExplicitTemplateInstantiation(
551+
Builder.getTemplateRange(C), Builder.findToken(C->getExternLoc()),
552+
Builder.findToken(C->getTemplateKeywordLoc()), Builder.getDeclRange(C));
553+
return true;
554+
}
555+
556+
bool WalkUpFromTemplateDecl(TemplateDecl *S) {
557+
foldTemplateDeclaration(
558+
Builder.getDeclRange(S),
559+
Builder.findToken(S->getTemplateParameters()->getTemplateLoc()),
560+
Builder.getDeclRange(S->getTemplatedDecl()));
561+
return true;
562+
}
563+
508564
bool WalkUpFromTagDecl(TagDecl *C) {
509565
// FIXME: build the ClassSpecifier node.
510-
if (C->isFreeStanding()) {
511-
// Class is a declaration specifier and needs a spanning declaration node.
512-
Builder.foldNode(Builder.getRange(C),
513-
new (allocator()) syntax::SimpleDeclaration);
566+
if (!C->isFreeStanding()) {
567+
assert(C->getNumTemplateParameterLists() == 0);
514568
return true;
515569
}
570+
// Class is a declaration specifier and needs a spanning declaration node.
571+
auto DeclarationRange = Builder.getDeclRange(C);
572+
Builder.foldNode(DeclarationRange,
573+
new (allocator()) syntax::SimpleDeclaration);
574+
575+
// Build TemplateDeclaration nodes if we had template parameters.
576+
auto ConsumeTemplateParameters = [&](const TemplateParameterList &L) {
577+
const auto *TemplateKW = Builder.findToken(L.getTemplateLoc());
578+
auto R = llvm::makeArrayRef(TemplateKW, DeclarationRange.end());
579+
foldTemplateDeclaration(R, TemplateKW, DeclarationRange);
580+
581+
DeclarationRange = R;
582+
};
583+
if (auto *S = llvm::dyn_cast<ClassTemplatePartialSpecializationDecl>(C))
584+
ConsumeTemplateParameters(*S->getTemplateParameters());
585+
for (unsigned I = C->getNumTemplateParameterLists(); 0 < I; --I)
586+
ConsumeTemplateParameters(*C->getTemplateParameterList(I - 1));
516587
return true;
517588
}
518589

@@ -581,7 +652,7 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
581652
}
582653

583654
bool WalkUpFromNamespaceDecl(NamespaceDecl *S) {
584-
auto Tokens = Builder.getRange(S);
655+
auto Tokens = Builder.getDeclRange(S);
585656
if (Tokens.front().kind() == tok::coloncolon) {
586657
// Handle nested namespace definitions. Those start at '::' token, e.g.
587658
// namespace a^::b {}
@@ -622,7 +693,7 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
622693
Builder.markChildToken(L.getLParenLoc(), syntax::NodeRole::OpenParen);
623694
for (auto *P : L.getParams())
624695
Builder.markDelayedChild(
625-
Builder.getRange(P),
696+
Builder.getDeclRange(P),
626697
syntax::NodeRole::ParametersAndQualifiers_parameter);
627698
Builder.markChildToken(L.getRParenLoc(), syntax::NodeRole::CloseParen);
628699
Builder.foldNode(Builder.getRange(L.getLParenLoc(), L.getEndLoc()),
@@ -756,7 +827,7 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
756827
}
757828

758829
bool WalkUpFromEmptyDecl(EmptyDecl *S) {
759-
Builder.foldNode(Builder.getRange(S),
830+
Builder.foldNode(Builder.getDeclRange(S),
760831
new (allocator()) syntax::EmptyDeclaration);
761832
return true;
762833
}
@@ -766,49 +837,49 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
766837
syntax::NodeRole::StaticAssertDeclaration_condition);
767838
Builder.markExprChild(S->getMessage(),
768839
syntax::NodeRole::StaticAssertDeclaration_message);
769-
Builder.foldNode(Builder.getRange(S),
840+
Builder.foldNode(Builder.getDeclRange(S),
770841
new (allocator()) syntax::StaticAssertDeclaration);
771842
return true;
772843
}
773844

774845
bool WalkUpFromLinkageSpecDecl(LinkageSpecDecl *S) {
775-
Builder.foldNode(Builder.getRange(S),
846+
Builder.foldNode(Builder.getDeclRange(S),
776847
new (allocator()) syntax::LinkageSpecificationDeclaration);
777848
return true;
778849
}
779850

780851
bool WalkUpFromNamespaceAliasDecl(NamespaceAliasDecl *S) {
781-
Builder.foldNode(Builder.getRange(S),
852+
Builder.foldNode(Builder.getDeclRange(S),
782853
new (allocator()) syntax::NamespaceAliasDefinition);
783854
return true;
784855
}
785856

786857
bool WalkUpFromUsingDirectiveDecl(UsingDirectiveDecl *S) {
787-
Builder.foldNode(Builder.getRange(S),
858+
Builder.foldNode(Builder.getDeclRange(S),
788859
new (allocator()) syntax::UsingNamespaceDirective);
789860
return true;
790861
}
791862

792863
bool WalkUpFromUsingDecl(UsingDecl *S) {
793-
Builder.foldNode(Builder.getRange(S),
864+
Builder.foldNode(Builder.getDeclRange(S),
794865
new (allocator()) syntax::UsingDeclaration);
795866
return true;
796867
}
797868

798869
bool WalkUpFromUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *S) {
799-
Builder.foldNode(Builder.getRange(S),
870+
Builder.foldNode(Builder.getDeclRange(S),
800871
new (allocator()) syntax::UsingDeclaration);
801872
return true;
802873
}
803874

804875
bool WalkUpFromUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *S) {
805-
Builder.foldNode(Builder.getRange(S),
876+
Builder.foldNode(Builder.getDeclRange(S),
806877
new (allocator()) syntax::UsingDeclaration);
807878
return true;
808879
}
809880

810881
bool WalkUpFromTypeAliasDecl(TypeAliasDecl *S) {
811-
Builder.foldNode(Builder.getRange(S),
882+
Builder.foldNode(Builder.getDeclRange(S),
812883
new (allocator()) syntax::TypeAliasDeclaration);
813884
return true;
814885
}
@@ -845,6 +916,36 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
845916
Builder.foldNode(Tokens, new (allocator()) syntax::TrailingReturnType);
846917
return Tokens;
847918
}
919+
920+
void
921+
foldExplicitTemplateInstantiation(ArrayRef<syntax::Token> Range,
922+
const syntax::Token *ExternKW,
923+
const syntax::Token *TemplateKW,
924+
ArrayRef<syntax::Token> InnerDeclaration) {
925+
assert(!ExternKW || ExternKW->kind() == tok::kw_extern);
926+
assert(TemplateKW && TemplateKW->kind() == tok::kw_template);
927+
Builder.markChildToken(
928+
ExternKW,
929+
syntax::NodeRole::ExplicitTemplateInstantiation_externKeyword);
930+
Builder.markChildToken(TemplateKW, syntax::NodeRole::IntroducerKeyword);
931+
Builder.markChild(
932+
InnerDeclaration,
933+
syntax::NodeRole::ExplicitTemplateInstantiation_declaration);
934+
Builder.foldNode(Range,
935+
new (allocator()) syntax::ExplicitTemplateInstantiation);
936+
}
937+
938+
void foldTemplateDeclaration(ArrayRef<syntax::Token> Range,
939+
const syntax::Token *TemplateKW,
940+
ArrayRef<syntax::Token> TemplatedDeclaration) {
941+
assert(TemplateKW && TemplateKW->kind() == tok::kw_template);
942+
Builder.markChildToken(TemplateKW, syntax::NodeRole::IntroducerKeyword);
943+
Builder.markMaybeDelayedChild(
944+
TemplatedDeclaration,
945+
syntax::NodeRole::TemplateDeclaration_declaration);
946+
Builder.foldNode(Range, new (allocator()) syntax::TemplateDeclaration);
947+
}
948+
848949
/// A small helper to save some typing.
849950
llvm::BumpPtrAllocator &allocator() { return Builder.allocator(); }
850951

@@ -891,6 +992,11 @@ void syntax::TreeBuilder::markDelayedChild(llvm::ArrayRef<syntax::Token> Range,
891992
Pending.assignRoleDelayed(Range, R);
892993
}
893994

995+
void syntax::TreeBuilder::markMaybeDelayedChild(
996+
llvm::ArrayRef<syntax::Token> Range, NodeRole R) {
997+
Pending.assignRoleMaybeDelayed(Range, R);
998+
}
999+
8941000
void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) {
8951001
if (!Child)
8961002
return;
@@ -916,6 +1022,8 @@ void syntax::TreeBuilder::markExprChild(Expr *Child, NodeRole Role) {
9161022
}
9171023

9181024
const syntax::Token *syntax::TreeBuilder::findToken(SourceLocation L) const {
1025+
if (L.isInvalid())
1026+
return nullptr;
9191027
auto It = LocationToToken.find(L.getRawEncoding());
9201028
assert(It != LocationToToken.end());
9211029
return It->second;

0 commit comments

Comments
 (0)