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