Skip to content

Commit 8d1b1c9

Browse files
authored
[AST] Add dump() method to TypeLoc (#65484)
The ability to dump AST nodes is important to ad-hoc debugging, and the fact this doesn't work with TypeLoc nodes is an obvious missing feature in e.g. clang-query (`set output dump` simply does nothing). Having TypeLoc::dump(), and enabling DynTypedNode::dump() for such nodes seems like a clear win. It looks like this: ``` int main(int argc, char **argv); FunctionProtoTypeLoc <test.cc:3:1, col:31> 'int (int, char **)' cdecl |-ParmVarDecl 0x30071a8 <col:10, col:14> col:14 argc 'int' | `-BuiltinTypeLoc <col:10> 'int' |-ParmVarDecl 0x3007250 <col:20, col:27> col:27 argv 'char **' | `-PointerTypeLoc <col:20, col:26> 'char **' | `-PointerTypeLoc <col:20, col:25> 'char *' | `-BuiltinTypeLoc <col:20> 'char' `-BuiltinTypeLoc <col:1> 'int' ``` It dumps the lexically nested tree of type locs. This often looks similar to how types are dumped, but unlike types we don't look at desugaring e.g. typedefs, as their underlying types are not lexically spelled here. --- Less clear is exactly when to include these nodes in existing text AST dumps rooted at (TranslationUnit)Decls. These already omit supported nodes sometimes, e.g. NestedNameSpecifiers are often mentioned but not recursively dumped. TypeLocs are a more extreme case: they're ~always more verbose than the current AST dump. So this patch punts on that, TypeLocs are only ever printed recursively as part of a TypeLoc::dump() call. It would also be nice to be able to invoke `clang` to dump a typeloc somehow, like `clang -cc1 -ast-dump`. But I don't know exactly what the best verison of that is, so this patch doesn't do it. --- There are similar (less critical!) nodes: TemplateArgumentLoc etc, these also don't have dump() functions today and are obvious extensions. I suspect that we should add these, and Loc nodes should dump each other (e.g. the ElaboratedTypeLoc `vector<int>::iterator` should dump the NestedNameSpecifierLoc `vector<int>::`, which dumps the TemplateSpecializationTypeLoc `vector<int>::` etc). Maybe this generalizes further to a "full syntactic dump" mode, where even Decls and Stmts would print the TypeLocs they lexically contain. But this may be more complex than useful. --- While here, ConceptReference JSON dumping must be implemented. It's not totally clear to me why this implementation wasn't required before but is now...
1 parent c651b2b commit 8d1b1c9

File tree

10 files changed

+314
-8
lines changed

10 files changed

+314
-8
lines changed

clang/include/clang/AST/ASTNodeTraverser.h

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
#include "clang/AST/StmtVisitor.h"
2424
#include "clang/AST/TemplateArgumentVisitor.h"
2525
#include "clang/AST/Type.h"
26+
#include "clang/AST/TypeLocVisitor.h"
2627
#include "clang/AST/TypeVisitor.h"
28+
#include "llvm/Support/SaveAndRestore.h"
2729

2830
namespace clang {
2931

@@ -48,6 +50,7 @@ struct {
4850
void Visit(const Stmt *Node);
4951
void Visit(const Type *T);
5052
void Visit(QualType T);
53+
void Visit(TypeLoc);
5154
void Visit(const Decl *D);
5255
void Visit(const CXXCtorInitializer *Init);
5356
void Visit(const OMPClause *C);
@@ -64,13 +67,22 @@ class ASTNodeTraverser
6467
public comments::ConstCommentVisitor<Derived, void,
6568
const comments::FullComment *>,
6669
public TypeVisitor<Derived>,
70+
public TypeLocVisitor<Derived>,
6771
public ConstAttrVisitor<Derived>,
6872
public ConstTemplateArgumentVisitor<Derived> {
6973

7074
/// Indicates whether we should trigger deserialization of nodes that had
7175
/// not already been loaded.
7276
bool Deserialize = false;
7377

78+
/// Tracks whether we should dump TypeLocs etc.
79+
///
80+
/// Detailed location information such as TypeLoc nodes is not usually
81+
/// included in the dump (too verbose).
82+
/// But when explicitly asked to dump a Loc node, we do so recursively,
83+
/// including e.g. FunctionTypeLoc => ParmVarDecl => TypeLoc.
84+
bool VisitLocs = false;
85+
7486
TraversalKind Traversal = TraversalKind::TK_AsIs;
7587

7688
NodeDelegateType &getNodeDelegate() {
@@ -85,7 +97,7 @@ class ASTNodeTraverser
8597
void SetTraversalKind(TraversalKind TK) { Traversal = TK; }
8698
TraversalKind GetTraversalKind() const { return Traversal; }
8799

88-
void Visit(const Decl *D) {
100+
void Visit(const Decl *D, bool VisitLocs = false) {
89101
if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isImplicit())
90102
return;
91103

@@ -94,7 +106,10 @@ class ASTNodeTraverser
94106
if (!D)
95107
return;
96108

97-
ConstDeclVisitor<Derived>::Visit(D);
109+
{
110+
llvm::SaveAndRestore RestoreVisitLocs(this->VisitLocs, VisitLocs);
111+
ConstDeclVisitor<Derived>::Visit(D);
112+
}
98113

99114
for (const auto &A : D->attrs())
100115
Visit(A);
@@ -181,6 +196,17 @@ class ASTNodeTraverser
181196
});
182197
}
183198

199+
void Visit(TypeLoc T) {
200+
getNodeDelegate().AddChild([=] {
201+
getNodeDelegate().Visit(T);
202+
if (T.isNull())
203+
return;
204+
TypeLocVisitor<Derived>::Visit(T);
205+
if (auto Inner = T.getNextTypeLoc())
206+
Visit(Inner);
207+
});
208+
}
209+
184210
void Visit(const Attr *A) {
185211
getNodeDelegate().AddChild([=] {
186212
getNodeDelegate().Visit(A);
@@ -286,6 +312,8 @@ class ASTNodeTraverser
286312
Visit(*QT);
287313
else if (const auto *T = N.get<Type>())
288314
Visit(T);
315+
else if (const auto *TL = N.get<TypeLoc>())
316+
Visit(*TL);
289317
else if (const auto *C = N.get<CXXCtorInitializer>())
290318
Visit(C);
291319
else if (const auto *C = N.get<OMPClause>())
@@ -346,7 +374,7 @@ class ASTNodeTraverser
346374

347375
void VisitComplexType(const ComplexType *T) { Visit(T->getElementType()); }
348376
void VisitLocInfoType(const LocInfoType *T) {
349-
Visit(T->getTypeSourceInfo()->getType());
377+
Visit(T->getTypeSourceInfo()->getTypeLoc());
350378
}
351379
void VisitPointerType(const PointerType *T) { Visit(T->getPointeeType()); }
352380
void VisitBlockPointerType(const BlockPointerType *T) {
@@ -421,9 +449,55 @@ class ASTNodeTraverser
421449
if (!T->isSugared())
422450
Visit(T->getPattern());
423451
}
452+
void VisitAutoType(const AutoType *T) {
453+
for (const auto &Arg : T->getTypeConstraintArguments())
454+
Visit(Arg);
455+
}
424456
// FIXME: ElaboratedType, DependentNameType,
425457
// DependentTemplateSpecializationType, ObjCObjectType
426458

459+
// For TypeLocs, we automatically visit the inner type loc (pointee type etc).
460+
// We must explicitly visit other lexically-nested nodes.
461+
void VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
462+
TypeLocVisitor<Derived>::VisitFunctionTypeLoc(TL);
463+
for (const auto *Param : TL.getParams())
464+
Visit(Param, /*VisitTypeLocs=*/true);
465+
}
466+
void VisitAutoTypeLoc(AutoTypeLoc TL) {
467+
if (const auto *CR = TL.getConceptReference()) {
468+
if (auto *Args = CR->getTemplateArgsAsWritten())
469+
for (const auto &Arg : Args->arguments())
470+
dumpTemplateArgumentLoc(Arg);
471+
}
472+
}
473+
void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
474+
Visit(TL.getClassTInfo()->getTypeLoc());
475+
}
476+
void VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
477+
Visit(TL.getSizeExpr());
478+
}
479+
void VisitDependentSizedArrayTypeLoc(DependentSizedArrayTypeLoc TL) {
480+
Visit(TL.getSizeExpr());
481+
}
482+
void VisitDependentSizedExtVectorTypeLoc(DependentSizedExtVectorTypeLoc TL) {
483+
Visit(cast<DependentSizedExtVectorType>(TL.getType())->getSizeExpr());
484+
}
485+
void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
486+
Visit(TL.getUnderlyingExpr());
487+
}
488+
void VisitDecltypeType(DecltypeType TL) {
489+
Visit(TL.getUnderlyingExpr());
490+
}
491+
void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
492+
for (unsigned I=0, N=TL.getNumArgs(); I < N; ++I)
493+
dumpTemplateArgumentLoc(TL.getArgLoc(I));
494+
}
495+
void VisitDependentTemplateSpecializationTypeLoc(
496+
DependentTemplateSpecializationTypeLoc TL) {
497+
for (unsigned I=0, N=TL.getNumArgs(); I < N; ++I)
498+
dumpTemplateArgumentLoc(TL.getArgLoc(I));
499+
}
500+
427501
void VisitTypedefDecl(const TypedefDecl *D) { Visit(D->getUnderlyingType()); }
428502

429503
void VisitEnumConstantDecl(const EnumConstantDecl *D) {
@@ -468,6 +542,8 @@ class ASTNodeTraverser
468542
if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isCXXForRangeDecl())
469543
return;
470544

545+
if (const auto *TSI = D->getTypeSourceInfo(); VisitLocs && TSI)
546+
Visit(TSI->getTypeLoc());
471547
if (D->hasInit())
472548
Visit(D->getInit());
473549
}

clang/include/clang/AST/JSONNodeDumper.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ class JSONNodeDumper
197197
void Visit(const Type *T);
198198
void Visit(QualType T);
199199
void Visit(const Decl *D);
200+
void Visit(TypeLoc TL);
200201

201202
void Visit(const comments::Comment *C, const comments::FullComment *FC);
202203
void Visit(const TemplateArgument &TA, SourceRange R = {},
@@ -207,6 +208,7 @@ class JSONNodeDumper
207208
void Visit(const GenericSelectionExpr::ConstAssociation &A);
208209
void Visit(const concepts::Requirement *R);
209210
void Visit(const APValue &Value, QualType Ty);
211+
void Visit(const ConceptReference *);
210212

211213
void VisitAliasAttr(const AliasAttr *AA);
212214
void VisitCleanupAttr(const CleanupAttr *CA);

clang/include/clang/AST/TextNodeDumper.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "clang/AST/StmtVisitor.h"
2525
#include "clang/AST/TemplateArgumentVisitor.h"
2626
#include "clang/AST/Type.h"
27+
#include "clang/AST/TypeLocVisitor.h"
2728
#include "clang/AST/TypeVisitor.h"
2829

2930
namespace clang {
@@ -132,6 +133,7 @@ class TextNodeDumper
132133
public ConstTemplateArgumentVisitor<TextNodeDumper>,
133134
public ConstStmtVisitor<TextNodeDumper>,
134135
public TypeVisitor<TextNodeDumper>,
136+
public TypeLocVisitor<TextNodeDumper>,
135137
public ConstDeclVisitor<TextNodeDumper> {
136138
raw_ostream &OS;
137139
const bool ShowColors;
@@ -179,6 +181,8 @@ class TextNodeDumper
179181

180182
void Visit(QualType T);
181183

184+
void Visit(TypeLoc);
185+
182186
void Visit(const Decl *D);
183187

184188
void Visit(const CXXCtorInitializer *Init);
@@ -339,6 +343,8 @@ class TextNodeDumper
339343
void VisitObjCInterfaceType(const ObjCInterfaceType *T);
340344
void VisitPackExpansionType(const PackExpansionType *T);
341345

346+
void VisitTypeLoc(TypeLoc TL);
347+
342348
void VisitLabelDecl(const LabelDecl *D);
343349
void VisitTypedefDecl(const TypedefDecl *D);
344350
void VisitEnumDecl(const EnumDecl *D);

clang/include/clang/AST/TypeLoc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,9 @@ class TypeLoc {
229229
/// __nullable, or __null_unspecifier), if there is one.
230230
SourceLocation findNullabilityLoc() const;
231231

232+
void dump() const;
233+
void dump(llvm::raw_ostream &, const ASTContext &) const;
234+
232235
private:
233236
static bool isKind(const TypeLoc&) {
234237
return true;

clang/lib/AST/ASTDumper.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,19 @@ LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS,
200200
QualType(this, 0).dump(OS, Context);
201201
}
202202

203+
//===----------------------------------------------------------------------===//
204+
// TypeLoc method implementations
205+
//===----------------------------------------------------------------------===//
206+
207+
LLVM_DUMP_METHOD void TypeLoc::dump() const {
208+
ASTDumper(llvm::errs(), /*ShowColors=*/false).Visit(*this);
209+
}
210+
211+
LLVM_DUMP_METHOD void TypeLoc::dump(llvm::raw_ostream &OS,
212+
const ASTContext &Context) const {
213+
ASTDumper(OS, Context, Context.getDiagnostics().getShowColors()).Visit(*this);
214+
}
215+
203216
//===----------------------------------------------------------------------===//
204217
// Decl method implementations
205218
//===----------------------------------------------------------------------===//

clang/lib/AST/ASTTypeTraits.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ void DynTypedNode::dump(llvm::raw_ostream &OS,
228228
T->dump(OS, Context);
229229
else if (const ConceptReference *C = get<ConceptReference>())
230230
C->dump(OS);
231+
else if (const TypeLoc *TL = get<TypeLoc>())
232+
TL->dump(OS, Context);
231233
else
232234
OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n";
233235
}

clang/lib/AST/JSONNodeDumper.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ void JSONNodeDumper::Visit(const Type *T) {
7777
return;
7878

7979
JOS.attribute("kind", (llvm::Twine(T->getTypeClassName()) + "Type").str());
80-
JOS.attribute("type", createQualType(QualType(T, 0), /*Desugar*/ false));
80+
JOS.attribute("type", createQualType(QualType(T, 0), /*Desugar=*/false));
8181
attributeOnlyIfTrue("containsErrors", T->containsErrors());
8282
attributeOnlyIfTrue("isDependent", T->isDependentType());
8383
attributeOnlyIfTrue("isInstantiationDependent",
@@ -96,6 +96,21 @@ void JSONNodeDumper::Visit(QualType T) {
9696
JOS.attribute("qualifiers", T.split().Quals.getAsString());
9797
}
9898

99+
void JSONNodeDumper::Visit(TypeLoc TL) {
100+
if (TL.isNull())
101+
return;
102+
JOS.attribute("kind",
103+
(llvm::Twine(TL.getTypeLocClass() == TypeLoc::Qualified
104+
? "Qualified"
105+
: TL.getTypePtr()->getTypeClassName()) +
106+
"TypeLoc")
107+
.str());
108+
JOS.attribute("type",
109+
createQualType(QualType(TL.getType()), /*Desugar=*/false));
110+
JOS.attributeObject("range",
111+
[TL, this] { writeSourceRange(TL.getSourceRange()); });
112+
}
113+
99114
void JSONNodeDumper::Visit(const Decl *D) {
100115
JOS.attribute("id", createPointerRepresentation(D));
101116

@@ -223,6 +238,22 @@ void JSONNodeDumper::Visit(const APValue &Value, QualType Ty) {
223238
JOS.attribute("value", OS.str());
224239
}
225240

241+
void JSONNodeDumper::Visit(const ConceptReference *CR) {
242+
JOS.attribute("kind", "ConceptReference");
243+
JOS.attribute("id", createPointerRepresentation(CR->getNamedConcept()));
244+
if (const auto *Args = CR->getTemplateArgsAsWritten()) {
245+
JOS.attributeArray("templateArgsAsWritten", [Args, this] {
246+
for (const TemplateArgumentLoc &TAL : Args->arguments())
247+
JOS.object(
248+
[&TAL, this] { Visit(TAL.getArgument(), TAL.getSourceRange()); });
249+
});
250+
}
251+
JOS.attributeObject("loc",
252+
[CR, this] { writeSourceLocation(CR->getLocation()); });
253+
JOS.attributeObject("range",
254+
[CR, this] { writeSourceRange(CR->getSourceRange()); });
255+
}
256+
226257
void JSONNodeDumper::writeIncludeStack(PresumedLoc Loc, bool JustFirst) {
227258
if (Loc.isInvalid())
228259
return;

clang/lib/AST/TextNodeDumper.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "clang/AST/LocInfoType.h"
1919
#include "clang/AST/NestedNameSpecifier.h"
2020
#include "clang/AST/Type.h"
21+
#include "clang/AST/TypeLocVisitor.h"
2122
#include "clang/Basic/Module.h"
2223
#include "clang/Basic/SourceManager.h"
2324
#include "clang/Basic/Specifiers.h"
@@ -240,6 +241,27 @@ void TextNodeDumper::Visit(QualType T) {
240241
OS << " " << T.split().Quals.getAsString();
241242
}
242243

244+
void TextNodeDumper::Visit(TypeLoc TL) {
245+
if (!TL) {
246+
ColorScope Color(OS, ShowColors, NullColor);
247+
OS << "<<<NULL>>>";
248+
return;
249+
}
250+
251+
{
252+
ColorScope Color(OS, ShowColors, TypeColor);
253+
OS << (TL.getTypeLocClass() == TypeLoc::Qualified
254+
? "Qualified"
255+
: TL.getType()->getTypeClassName())
256+
<< "TypeLoc";
257+
}
258+
dumpSourceRange(TL.getSourceRange());
259+
OS << ' ';
260+
dumpBareType(TL.getType(), /*Desugar=*/false);
261+
262+
TypeLocVisitor<TextNodeDumper>::Visit(TL);
263+
}
264+
243265
void TextNodeDumper::Visit(const Decl *D) {
244266
if (!D) {
245267
ColorScope Color(OS, ShowColors, NullColor);
@@ -1801,11 +1823,8 @@ void TextNodeDumper::VisitAutoType(const AutoType *T) {
18011823
OS << " decltype(auto)";
18021824
if (!T->isDeduced())
18031825
OS << " undeduced";
1804-
if (T->isConstrained()) {
1826+
if (T->isConstrained())
18051827
dumpDeclRef(T->getTypeConstraintConcept());
1806-
for (const auto &Arg : T->getTypeConstraintArguments())
1807-
VisitTemplateArgument(Arg);
1808-
}
18091828
}
18101829

18111830
void TextNodeDumper::VisitDeducedTemplateSpecializationType(
@@ -1838,6 +1857,13 @@ void TextNodeDumper::VisitPackExpansionType(const PackExpansionType *T) {
18381857
OS << " expansions " << *N;
18391858
}
18401859

1860+
void TextNodeDumper::VisitTypeLoc(TypeLoc TL) {
1861+
// By default, add extra Type details with no extra loc info.
1862+
TypeVisitor<TextNodeDumper>::Visit(TL.getTypePtr());
1863+
}
1864+
// FIXME: override behavior for TypeLocs that have interesting location
1865+
// information, such as the qualifier in ElaboratedTypeLoc.
1866+
18411867
void TextNodeDumper::VisitLabelDecl(const LabelDecl *D) { dumpName(D); }
18421868

18431869
void TextNodeDumper::VisitTypedefDecl(const TypedefDecl *D) {

0 commit comments

Comments
 (0)