1 //===--- DumpAST.cpp - Serialize clang AST to LSP -------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "DumpAST.h"
10 #include "Protocol.h"
11 #include "SourceCode.h"
12 #include "support/Logger.h"
13 #include "clang/AST/ASTTypeTraits.h"
14 #include "clang/AST/Expr.h"
15 #include "clang/AST/ExprCXX.h"
16 #include "clang/AST/NestedNameSpecifier.h"
17 #include "clang/AST/PrettyPrinter.h"
18 #include "clang/AST/RecursiveASTVisitor.h"
19 #include "clang/AST/TextNodeDumper.h"
20 #include "clang/AST/Type.h"
21 #include "clang/AST/TypeLoc.h"
22 #include "clang/Basic/Specifiers.h"
23 #include "clang/Tooling/Syntax/Tokens.h"
24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/Support/raw_ostream.h"
26 
27 namespace clang {
28 namespace clangd {
29 namespace {
30 
31 using llvm::raw_ostream;
32 template <typename Print> std::string toString(const Print &C) {
33   std::string Result;
34   llvm::raw_string_ostream OS(Result);
35   C(OS);
36   return std::move(OS.str());
37 }
38 
39 bool isInjectedClassName(Decl *D) {
40   if (const auto *CRD = llvm::dyn_cast<CXXRecordDecl>(D))
41     return CRD->isInjectedClassName();
42   return false;
43 }
44 
45 class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
46   using Base = RecursiveASTVisitor<DumpVisitor>;
47 
48   const syntax::TokenBuffer &Tokens;
49   const ASTContext &Ctx;
50 
51   // Pointers are into 'children' vector.
52   // They remain valid because while a node is on the stack we only add
53   // descendants, not siblings.
54   std::vector<ASTNode *> Stack;
55 
56   // Generic logic used to handle traversal of all node kinds.
57 
58   template <typename T>
59   bool traverseNodePre(llvm::StringRef Role, const T &Node) {
60     if (Stack.empty()) {
61       assert(Root.role.empty());
62       Stack.push_back(&Root);
63     } else {
64       Stack.back()->children.emplace_back();
65       Stack.push_back(&Stack.back()->children.back());
66     }
67     auto &N = *Stack.back();
68     N.role = Role.str();
69     N.kind = getKind(Node);
70     N.detail = getDetail(Node);
71     N.range = getRange(Node);
72     N.arcana = getArcana(Node);
73     return true;
74   }
75   bool traverseNodePost() {
76     assert(!Stack.empty());
77     Stack.pop_back();
78     return true;
79   }
80   template <typename T, typename Callable>
81   bool traverseNode(llvm::StringRef Role, const T &Node, const Callable &Body) {
82     traverseNodePre(Role, Node);
83     Body();
84     return traverseNodePost();
85   }
86 
87   // Range: most nodes have getSourceRange(), with a couple of exceptions.
88   // We only return it if it's valid at both ends and there are no macros.
89 
90   template <typename T> llvm::Optional<Range> getRange(const T &Node) {
91     SourceRange SR = getSourceRange(Node);
92     auto Spelled = Tokens.spelledForExpanded(Tokens.expandedTokens(SR));
93     if (!Spelled)
94       return llvm::None;
95     return halfOpenToRange(
96         Tokens.sourceManager(),
97         CharSourceRange::getCharRange(Spelled->front().location(),
98                                       Spelled->back().endLocation()));
99   }
100   template <typename T, typename = decltype(std::declval<T>().getSourceRange())>
101   SourceRange getSourceRange(const T &Node) {
102     return Node.getSourceRange();
103   }
104   template <typename T,
105             typename = decltype(std::declval<T *>()->getSourceRange())>
106   SourceRange getSourceRange(const T *Node) {
107     return Node->getSourceRange();
108   }
109   // TemplateName doesn't have a real Loc node type.
110   SourceRange getSourceRange(const TemplateName &Node) { return SourceRange(); }
111   // Attr just uses a weird method name. Maybe we should fix it instead?
112   SourceRange getSourceRange(const Attr *Node) { return Node->getRange(); }
113 
114   // Kind is usualy the class name, without the suffix ("Type" etc).
115   // Where there's a set of variants instead, we use the 'Kind' enum values.
116 
117   std::string getKind(const Decl *D) { return D->getDeclKindName(); }
118   std::string getKind(const Stmt *S) {
119     std::string Result = S->getStmtClassName();
120     if (llvm::StringRef(Result).endswith("Stmt") ||
121         llvm::StringRef(Result).endswith("Expr"))
122       Result.resize(Result.size() - 4);
123     return Result;
124   }
125   std::string getKind(const TypeLoc &TL) {
126     std::string Result;
127     if (TL.getTypeLocClass() == TypeLoc::Qualified)
128       return "Qualified";
129     return TL.getType()->getTypeClassName();
130   }
131   std::string getKind(const TemplateArgumentLoc &TAL) {
132     switch (TAL.getArgument().getKind()) {
133 #define TEMPLATE_ARGUMENT_KIND(X)                                              \
134   case TemplateArgument::X:                                                    \
135     return #X
136       TEMPLATE_ARGUMENT_KIND(Null);
137       TEMPLATE_ARGUMENT_KIND(NullPtr);
138       TEMPLATE_ARGUMENT_KIND(Expression);
139       TEMPLATE_ARGUMENT_KIND(Integral);
140       TEMPLATE_ARGUMENT_KIND(Pack);
141       TEMPLATE_ARGUMENT_KIND(Type);
142       TEMPLATE_ARGUMENT_KIND(Declaration);
143       TEMPLATE_ARGUMENT_KIND(Template);
144       TEMPLATE_ARGUMENT_KIND(TemplateExpansion);
145 #undef TEMPLATE_ARGUMENT_KIND
146     }
147     llvm_unreachable("Unhandled ArgKind enum");
148   }
149   std::string getKind(const NestedNameSpecifierLoc &NNSL) {
150     assert(NNSL.getNestedNameSpecifier());
151     switch (NNSL.getNestedNameSpecifier()->getKind()) {
152 #define NNS_KIND(X)                                                            \
153   case NestedNameSpecifier::X:                                                 \
154     return #X
155       NNS_KIND(Identifier);
156       NNS_KIND(Namespace);
157       NNS_KIND(TypeSpec);
158       NNS_KIND(TypeSpecWithTemplate);
159       NNS_KIND(Global);
160       NNS_KIND(Super);
161       NNS_KIND(NamespaceAlias);
162 #undef NNS_KIND
163     }
164     llvm_unreachable("Unhandled SpecifierKind enum");
165   }
166   std::string getKind(const CXXCtorInitializer *CCI) {
167     if (CCI->isBaseInitializer())
168       return "BaseInitializer";
169     if (CCI->isDelegatingInitializer())
170       return "DelegatingInitializer";
171     if (CCI->isAnyMemberInitializer())
172       return "MemberInitializer";
173     llvm_unreachable("Unhandled CXXCtorInitializer type");
174   }
175   std::string getKind(const TemplateName &TN) {
176     switch (TN.getKind()) {
177 #define TEMPLATE_KIND(X)                                                       \
178   case TemplateName::X:                                                        \
179     return #X;
180       TEMPLATE_KIND(Template);
181       TEMPLATE_KIND(OverloadedTemplate);
182       TEMPLATE_KIND(AssumedTemplate);
183       TEMPLATE_KIND(QualifiedTemplate);
184       TEMPLATE_KIND(DependentTemplate);
185       TEMPLATE_KIND(SubstTemplateTemplateParm);
186       TEMPLATE_KIND(SubstTemplateTemplateParmPack);
187 #undef TEMPLATE_KIND
188     }
189     llvm_unreachable("Unhandled NameKind enum");
190   }
191   std::string getKind(const Attr *A) {
192     switch (A->getKind()) {
193 #define ATTR(X)                                                                \
194   case attr::X:                                                                \
195     return #X;
196 #include "clang/Basic/AttrList.inc"
197 #undef ATTR
198     }
199     llvm_unreachable("Unhandled attr::Kind enum");
200   }
201   std::string getKind(const CXXBaseSpecifier &CBS) {
202     // There aren't really any variants of CXXBaseSpecifier.
203     // To avoid special cases in the API/UI, use public/private as the kind.
204     return getAccessSpelling(CBS.getAccessSpecifier()).str();
205   }
206 
207   // Detail is the single most important fact about the node.
208   // Often this is the name, sometimes a "kind" enum like operators or casts.
209   // We should avoid unbounded text, like dumping parameter lists.
210 
211   std::string getDetail(const Decl *D) {
212     const auto *ND = dyn_cast<NamedDecl>(D);
213     if (!ND || llvm::isa_and_nonnull<CXXConstructorDecl>(ND->getAsFunction()) ||
214         isa<CXXDestructorDecl>(ND))
215       return "";
216     std::string Name = toString([&](raw_ostream &OS) { ND->printName(OS); });
217     if (Name.empty())
218       return "(anonymous)";
219     return Name;
220   }
221   std::string getDetail(const Stmt *S) {
222     if (const auto *DRE = dyn_cast<DeclRefExpr>(S))
223       return DRE->getNameInfo().getAsString();
224     if (const auto *DSDRE = dyn_cast<DependentScopeDeclRefExpr>(S))
225       return DSDRE->getNameInfo().getAsString();
226     if (const auto *ME = dyn_cast<MemberExpr>(S))
227       return ME->getMemberNameInfo().getAsString();
228     if (const auto *CE = dyn_cast<CastExpr>(S))
229       return CE->getCastKindName();
230     if (const auto *BO = dyn_cast<BinaryOperator>(S))
231       return BO->getOpcodeStr().str();
232     if (const auto *UO = dyn_cast<UnaryOperator>(S))
233       return UnaryOperator::getOpcodeStr(UO->getOpcode()).str();
234     if (const auto *CCO = dyn_cast<CXXConstructExpr>(S))
235       return CCO->getConstructor()->getNameAsString();
236     if (const auto *CTE = dyn_cast<CXXThisExpr>(S)) {
237       bool Const = CTE->getType()->getPointeeType().isLocalConstQualified();
238       if (CTE->isImplicit())
239         return Const ? "const, implicit" : "implicit";
240       if (Const)
241         return "const";
242       return "";
243     }
244     if (isa<IntegerLiteral, FloatingLiteral, FixedPointLiteral,
245             CharacterLiteral, ImaginaryLiteral, CXXBoolLiteralExpr>(S))
246       return toString([&](raw_ostream &OS) {
247         S->printPretty(OS, nullptr, Ctx.getPrintingPolicy());
248       });
249     if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(S))
250       return MTE->isBoundToLvalueReference() ? "lvalue" : "rvalue";
251     return "";
252   }
253   std::string getDetail(const TypeLoc &TL) {
254     if (TL.getType().hasLocalQualifiers())
255       return TL.getType().getLocalQualifiers().getAsString(
256           Ctx.getPrintingPolicy());
257     if (const auto *TT = dyn_cast<TagType>(TL.getTypePtr()))
258       return getDetail(TT->getDecl());
259     if (const auto *DT = dyn_cast<DeducedType>(TL.getTypePtr()))
260       if (DT->isDeduced())
261         return DT->getDeducedType().getAsString(Ctx.getPrintingPolicy());
262     if (const auto *BT = dyn_cast<BuiltinType>(TL.getTypePtr()))
263       return BT->getName(Ctx.getPrintingPolicy()).str();
264     if (const auto *TTPT = dyn_cast<TemplateTypeParmType>(TL.getTypePtr()))
265       return getDetail(TTPT->getDecl());
266     if (const auto *TT = dyn_cast<TypedefType>(TL.getTypePtr()))
267       return getDetail(TT->getDecl());
268     return "";
269   }
270   std::string getDetail(const NestedNameSpecifierLoc &NNSL) {
271     const auto &NNS = *NNSL.getNestedNameSpecifier();
272     switch (NNS.getKind()) {
273     case NestedNameSpecifier::Identifier:
274       return NNS.getAsIdentifier()->getName().str() + "::";
275     case NestedNameSpecifier::Namespace:
276       return NNS.getAsNamespace()->getNameAsString() + "::";
277     case NestedNameSpecifier::NamespaceAlias:
278       return NNS.getAsNamespaceAlias()->getNameAsString() + "::";
279     default:
280       return "";
281     }
282   }
283   std::string getDetail(const CXXCtorInitializer *CCI) {
284     if (FieldDecl *FD = CCI->getAnyMember())
285       return getDetail(FD);
286     if (TypeLoc TL = CCI->getBaseClassLoc())
287       return getDetail(TL);
288     return "";
289   }
290   std::string getDetail(const TemplateArgumentLoc &TAL) {
291     if (TAL.getArgument().getKind() == TemplateArgument::Integral)
292       return toString(TAL.getArgument().getAsIntegral(), 10);
293     return "";
294   }
295   std::string getDetail(const TemplateName &TN) {
296     return toString([&](raw_ostream &OS) {
297       TN.print(OS, Ctx.getPrintingPolicy(), TemplateName::Qualified::None);
298     });
299   }
300   std::string getDetail(const Attr *A) {
301     return A->getAttrName() ? A->getNormalizedFullName() : A->getSpelling();
302   }
303   std::string getDetail(const CXXBaseSpecifier &CBS) {
304     return CBS.isVirtual() ? "virtual" : "";
305   }
306 
307   /// Arcana is produced by TextNodeDumper, for the types it supports.
308 
309   template <typename Dump> std::string dump(const Dump &D) {
310     return toString([&](raw_ostream &OS) {
311       TextNodeDumper Dumper(OS, Ctx, /*ShowColors=*/false);
312       D(Dumper);
313     });
314   }
315   template <typename T> std::string getArcana(const T &N) {
316     return dump([&](TextNodeDumper &D) { D.Visit(N); });
317   }
318   std::string getArcana(const NestedNameSpecifierLoc &NNS) { return ""; }
319   std::string getArcana(const TemplateName &NNS) { return ""; }
320   std::string getArcana(const CXXBaseSpecifier &CBS) { return ""; }
321   std::string getArcana(const TemplateArgumentLoc &TAL) {
322     return dump([&](TextNodeDumper &D) {
323       D.Visit(TAL.getArgument(), TAL.getSourceRange());
324     });
325   }
326   std::string getArcana(const TypeLoc &TL) {
327     return dump([&](TextNodeDumper &D) { D.Visit(TL.getType()); });
328   }
329 
330 public:
331   ASTNode Root;
332   DumpVisitor(const syntax::TokenBuffer &Tokens, const ASTContext &Ctx)
333       : Tokens(Tokens), Ctx(Ctx) {}
334 
335   // Override traversal to record the nodes we care about.
336   // Generally, these are nodes with position information (TypeLoc, not Type).
337 
338   bool TraverseDecl(Decl *D) {
339     return !D || isInjectedClassName(D) ||
340            traverseNode("declaration", D, [&] { Base::TraverseDecl(D); });
341   }
342   bool TraverseTypeLoc(TypeLoc TL) {
343     return !TL || traverseNode("type", TL, [&] { Base::TraverseTypeLoc(TL); });
344   }
345   bool TraverseTemplateName(const TemplateName &TN) {
346     return traverseNode("template name", TN,
347                         [&] { Base::TraverseTemplateName(TN); });
348   }
349   bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &TAL) {
350     return traverseNode("template argument", TAL,
351                         [&] { Base::TraverseTemplateArgumentLoc(TAL); });
352   }
353   bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSL) {
354     return !NNSL || traverseNode("specifier", NNSL, [&] {
355       Base::TraverseNestedNameSpecifierLoc(NNSL);
356     });
357   }
358   bool TraverseConstructorInitializer(CXXCtorInitializer *CCI) {
359     return !CCI || traverseNode("constructor initializer", CCI, [&] {
360       Base::TraverseConstructorInitializer(CCI);
361     });
362   }
363   bool TraverseAttr(Attr *A) {
364     return !A || traverseNode("attribute", A, [&] { Base::TraverseAttr(A); });
365   }
366   bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier &CBS) {
367     return traverseNode("base", CBS,
368                         [&] { Base::TraverseCXXBaseSpecifier(CBS); });
369   }
370   // Stmt is the same, but this form allows the data recursion optimization.
371   bool dataTraverseStmtPre(Stmt *S) {
372     return S && traverseNodePre(isa<Expr>(S) ? "expression" : "statement", S);
373   }
374   bool dataTraverseStmtPost(Stmt *X) { return traverseNodePost(); }
375 
376   // QualifiedTypeLoc is handled strangely in RecursiveASTVisitor: the derived
377   // TraverseTypeLoc is not called for the inner UnqualTypeLoc.
378   // This means we'd never see 'int' in 'const int'! Work around that here.
379   // (The reason for the behavior is to avoid traversing the nested Type twice,
380   // but we ignore TraverseType anyway).
381   bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QTL) {
382     return TraverseTypeLoc(QTL.getUnqualifiedLoc());
383   }
384   // Uninteresting parts of the AST that don't have locations within them.
385   bool TraverseNestedNameSpecifier(NestedNameSpecifier *) { return true; }
386   bool TraverseType(QualType) { return true; }
387 
388   // OpaqueValueExpr blocks traversal, we must explicitly traverse it.
389   bool TraverseOpaqueValueExpr(OpaqueValueExpr *E) {
390     return TraverseStmt(E->getSourceExpr());
391   }
392   // We only want to traverse the *syntactic form* to understand the selection.
393   bool TraversePseudoObjectExpr(PseudoObjectExpr *E) {
394     return TraverseStmt(E->getSyntacticForm());
395   }
396 };
397 
398 } // namespace
399 
400 ASTNode dumpAST(const DynTypedNode &N, const syntax::TokenBuffer &Tokens,
401                 const ASTContext &Ctx) {
402   DumpVisitor V(Tokens, Ctx);
403   // DynTypedNode only works with const, RecursiveASTVisitor only non-const :-(
404   if (const auto *D = N.get<Decl>())
405     V.TraverseDecl(const_cast<Decl *>(D));
406   else if (const auto *S = N.get<Stmt>())
407     V.TraverseStmt(const_cast<Stmt *>(S));
408   else if (const auto *NNSL = N.get<NestedNameSpecifierLoc>())
409     V.TraverseNestedNameSpecifierLoc(
410         *const_cast<NestedNameSpecifierLoc *>(NNSL));
411   else if (const auto *NNS = N.get<NestedNameSpecifier>())
412     V.TraverseNestedNameSpecifier(const_cast<NestedNameSpecifier *>(NNS));
413   else if (const auto *TL = N.get<TypeLoc>())
414     V.TraverseTypeLoc(*const_cast<TypeLoc *>(TL));
415   else if (const auto *QT = N.get<QualType>())
416     V.TraverseType(*const_cast<QualType *>(QT));
417   else if (const auto *CCI = N.get<CXXCtorInitializer>())
418     V.TraverseConstructorInitializer(const_cast<CXXCtorInitializer *>(CCI));
419   else if (const auto *TAL = N.get<TemplateArgumentLoc>())
420     V.TraverseTemplateArgumentLoc(*const_cast<TemplateArgumentLoc *>(TAL));
421   else if (const auto *CBS = N.get<CXXBaseSpecifier>())
422     V.TraverseCXXBaseSpecifier(*const_cast<CXXBaseSpecifier *>(CBS));
423   else
424     elog("dumpAST: unhandled DynTypedNode kind {0}",
425          N.getNodeKind().asStringRef());
426   return std::move(V.Root);
427 }
428 
429 } // namespace clangd
430 } // namespace clang
431