diff options
Diffstat (limited to 'include/clang/AST/JSONNodeDumper.h')
-rw-r--r-- | include/clang/AST/JSONNodeDumper.h | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/include/clang/AST/JSONNodeDumper.h b/include/clang/AST/JSONNodeDumper.h new file mode 100644 index 000000000000..238e43aad78b --- /dev/null +++ b/include/clang/AST/JSONNodeDumper.h @@ -0,0 +1,425 @@ +//===--- JSONNodeDumper.h - Printing of AST nodes to JSON -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements AST dumping of components of individual AST nodes to +// a JSON. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_JSONNODEDUMPER_H +#define LLVM_CLANG_AST_JSONNODEDUMPER_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTNodeTraverser.h" +#include "clang/AST/ASTDumperUtils.h" +#include "clang/AST/AttrVisitor.h" +#include "clang/AST/CommentCommandTraits.h" +#include "clang/AST/CommentVisitor.h" +#include "clang/AST/ExprCXX.h" +#include "llvm/Support/JSON.h" + +namespace clang { + +class NodeStreamer { + bool FirstChild = true; + bool TopLevel = true; + llvm::SmallVector<std::function<void(bool IsLastChild)>, 32> Pending; + +protected: + llvm::json::OStream JOS; + +public: + /// Add a child of the current node. Calls DoAddChild without arguments + template <typename Fn> void AddChild(Fn DoAddChild) { + return AddChild("", DoAddChild); + } + + /// Add a child of the current node with an optional label. + /// Calls DoAddChild without arguments. + template <typename Fn> void AddChild(StringRef Label, Fn DoAddChild) { + // If we're at the top level, there's nothing interesting to do; just + // run the dumper. + if (TopLevel) { + TopLevel = false; + JOS.objectBegin(); + + DoAddChild(); + + while (!Pending.empty()) { + Pending.back()(true); + Pending.pop_back(); + } + + JOS.objectEnd(); + TopLevel = true; + return; + } + + // We need to capture an owning-string in the lambda because the lambda + // is invoked in a deferred manner. + std::string LabelStr = !Label.empty() ? Label : "inner"; + bool WasFirstChild = FirstChild; + auto DumpWithIndent = [=](bool IsLastChild) { + if (WasFirstChild) { + JOS.attributeBegin(LabelStr); + JOS.arrayBegin(); + } + + FirstChild = true; + unsigned Depth = Pending.size(); + JOS.objectBegin(); + + DoAddChild(); + + // If any children are left, they're the last at their nesting level. + // Dump those ones out now. + while (Depth < Pending.size()) { + Pending.back()(true); + this->Pending.pop_back(); + } + + JOS.objectEnd(); + + if (IsLastChild) { + JOS.arrayEnd(); + JOS.attributeEnd(); + } + }; + + if (FirstChild) { + Pending.push_back(std::move(DumpWithIndent)); + } else { + Pending.back()(false); + Pending.back() = std::move(DumpWithIndent); + } + FirstChild = false; + } + + NodeStreamer(raw_ostream &OS) : JOS(OS, 2) {} +}; + +// Dumps AST nodes in JSON format. There is no implied stability for the +// content or format of the dump between major releases of Clang, other than it +// being valid JSON output. Further, there is no requirement that the +// information dumped is a complete representation of the AST, only that the +// information presented is correct. +class JSONNodeDumper + : public ConstAttrVisitor<JSONNodeDumper>, + public comments::ConstCommentVisitor<JSONNodeDumper, void, + const comments::FullComment *>, + public ConstTemplateArgumentVisitor<JSONNodeDumper>, + public ConstStmtVisitor<JSONNodeDumper>, + public TypeVisitor<JSONNodeDumper>, + public ConstDeclVisitor<JSONNodeDumper>, + public NodeStreamer { + friend class JSONDumper; + + const SourceManager &SM; + ASTContext& Ctx; + PrintingPolicy PrintPolicy; + const comments::CommandTraits *Traits; + StringRef LastLocFilename; + unsigned LastLocLine, LastLocPresumedLine; + + using InnerAttrVisitor = ConstAttrVisitor<JSONNodeDumper>; + using InnerCommentVisitor = + comments::ConstCommentVisitor<JSONNodeDumper, void, + const comments::FullComment *>; + using InnerTemplateArgVisitor = ConstTemplateArgumentVisitor<JSONNodeDumper>; + using InnerStmtVisitor = ConstStmtVisitor<JSONNodeDumper>; + using InnerTypeVisitor = TypeVisitor<JSONNodeDumper>; + using InnerDeclVisitor = ConstDeclVisitor<JSONNodeDumper>; + + void attributeOnlyIfTrue(StringRef Key, bool Value) { + if (Value) + JOS.attribute(Key, Value); + } + + // Writes the attributes of a SourceLocation object without. + void writeBareSourceLocation(SourceLocation Loc, bool IsSpelling); + + // Writes the attributes of a SourceLocation to JSON based on its presumed + // spelling location. If the given location represents a macro invocation, + // this outputs two sub-objects: one for the spelling and one for the + // expansion location. + void writeSourceLocation(SourceLocation Loc); + void writeSourceRange(SourceRange R); + std::string createPointerRepresentation(const void *Ptr); + llvm::json::Object createQualType(QualType QT, bool Desugar = true); + llvm::json::Object createBareDeclRef(const Decl *D); + void writeBareDeclRef(const Decl *D); + llvm::json::Object createCXXRecordDefinitionData(const CXXRecordDecl *RD); + llvm::json::Object createCXXBaseSpecifier(const CXXBaseSpecifier &BS); + std::string createAccessSpecifier(AccessSpecifier AS); + llvm::json::Array createCastPath(const CastExpr *C); + + void writePreviousDeclImpl(...) {} + + template <typename T> void writePreviousDeclImpl(const Mergeable<T> *D) { + const T *First = D->getFirstDecl(); + if (First != D) + JOS.attribute("firstRedecl", createPointerRepresentation(First)); + } + + template <typename T> void writePreviousDeclImpl(const Redeclarable<T> *D) { + const T *Prev = D->getPreviousDecl(); + if (Prev) + JOS.attribute("previousDecl", createPointerRepresentation(Prev)); + } + void addPreviousDeclaration(const Decl *D); + + StringRef getCommentCommandName(unsigned CommandID) const; + +public: + JSONNodeDumper(raw_ostream &OS, const SourceManager &SrcMgr, ASTContext &Ctx, + const PrintingPolicy &PrintPolicy, + const comments::CommandTraits *Traits) + : NodeStreamer(OS), SM(SrcMgr), Ctx(Ctx), PrintPolicy(PrintPolicy), + Traits(Traits), LastLocLine(0), LastLocPresumedLine(0) {} + + void Visit(const Attr *A); + void Visit(const Stmt *Node); + void Visit(const Type *T); + void Visit(QualType T); + void Visit(const Decl *D); + + void Visit(const comments::Comment *C, const comments::FullComment *FC); + void Visit(const TemplateArgument &TA, SourceRange R = {}, + const Decl *From = nullptr, StringRef Label = {}); + void Visit(const CXXCtorInitializer *Init); + void Visit(const OMPClause *C); + void Visit(const BlockDecl::Capture &C); + void Visit(const GenericSelectionExpr::ConstAssociation &A); + + void VisitTypedefType(const TypedefType *TT); + void VisitFunctionType(const FunctionType *T); + void VisitFunctionProtoType(const FunctionProtoType *T); + void VisitRValueReferenceType(const ReferenceType *RT); + void VisitArrayType(const ArrayType *AT); + void VisitConstantArrayType(const ConstantArrayType *CAT); + void VisitDependentSizedExtVectorType(const DependentSizedExtVectorType *VT); + void VisitVectorType(const VectorType *VT); + void VisitUnresolvedUsingType(const UnresolvedUsingType *UUT); + void VisitUnaryTransformType(const UnaryTransformType *UTT); + void VisitTagType(const TagType *TT); + void VisitTemplateTypeParmType(const TemplateTypeParmType *TTPT); + void VisitAutoType(const AutoType *AT); + void VisitTemplateSpecializationType(const TemplateSpecializationType *TST); + void VisitInjectedClassNameType(const InjectedClassNameType *ICNT); + void VisitObjCInterfaceType(const ObjCInterfaceType *OIT); + void VisitPackExpansionType(const PackExpansionType *PET); + void VisitElaboratedType(const ElaboratedType *ET); + void VisitMacroQualifiedType(const MacroQualifiedType *MQT); + void VisitMemberPointerType(const MemberPointerType *MPT); + + void VisitNamedDecl(const NamedDecl *ND); + void VisitTypedefDecl(const TypedefDecl *TD); + void VisitTypeAliasDecl(const TypeAliasDecl *TAD); + void VisitNamespaceDecl(const NamespaceDecl *ND); + void VisitUsingDirectiveDecl(const UsingDirectiveDecl *UDD); + void VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD); + void VisitUsingDecl(const UsingDecl *UD); + void VisitUsingShadowDecl(const UsingShadowDecl *USD); + void VisitVarDecl(const VarDecl *VD); + void VisitFieldDecl(const FieldDecl *FD); + void VisitFunctionDecl(const FunctionDecl *FD); + void VisitEnumDecl(const EnumDecl *ED); + void VisitEnumConstantDecl(const EnumConstantDecl *ECD); + void VisitRecordDecl(const RecordDecl *RD); + void VisitCXXRecordDecl(const CXXRecordDecl *RD); + void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D); + void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D); + void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D); + void VisitLinkageSpecDecl(const LinkageSpecDecl *LSD); + void VisitAccessSpecDecl(const AccessSpecDecl *ASD); + void VisitFriendDecl(const FriendDecl *FD); + + void VisitObjCIvarDecl(const ObjCIvarDecl *D); + void VisitObjCMethodDecl(const ObjCMethodDecl *D); + void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D); + void VisitObjCCategoryDecl(const ObjCCategoryDecl *D); + void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D); + void VisitObjCProtocolDecl(const ObjCProtocolDecl *D); + void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D); + void VisitObjCImplementationDecl(const ObjCImplementationDecl *D); + void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D); + void VisitObjCPropertyDecl(const ObjCPropertyDecl *D); + void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D); + void VisitBlockDecl(const BlockDecl *D); + + void VisitDeclRefExpr(const DeclRefExpr *DRE); + void VisitPredefinedExpr(const PredefinedExpr *PE); + void VisitUnaryOperator(const UnaryOperator *UO); + void VisitBinaryOperator(const BinaryOperator *BO); + void VisitCompoundAssignOperator(const CompoundAssignOperator *CAO); + void VisitMemberExpr(const MemberExpr *ME); + void VisitCXXNewExpr(const CXXNewExpr *NE); + void VisitCXXDeleteExpr(const CXXDeleteExpr *DE); + void VisitCXXThisExpr(const CXXThisExpr *TE); + void VisitCastExpr(const CastExpr *CE); + void VisitImplicitCastExpr(const ImplicitCastExpr *ICE); + void VisitCallExpr(const CallExpr *CE); + void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *TTE); + void VisitSizeOfPackExpr(const SizeOfPackExpr *SOPE); + void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *ULE); + void VisitAddrLabelExpr(const AddrLabelExpr *ALE); + void VisitCXXTypeidExpr(const CXXTypeidExpr *CTE); + void VisitConstantExpr(const ConstantExpr *CE); + void VisitInitListExpr(const InitListExpr *ILE); + void VisitGenericSelectionExpr(const GenericSelectionExpr *GSE); + void VisitCXXUnresolvedConstructExpr(const CXXUnresolvedConstructExpr *UCE); + void VisitCXXConstructExpr(const CXXConstructExpr *CE); + void VisitExprWithCleanups(const ExprWithCleanups *EWC); + void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE); + void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE); + void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *ME); + + void VisitObjCEncodeExpr(const ObjCEncodeExpr *OEE); + void VisitObjCMessageExpr(const ObjCMessageExpr *OME); + void VisitObjCBoxedExpr(const ObjCBoxedExpr *OBE); + void VisitObjCSelectorExpr(const ObjCSelectorExpr *OSE); + void VisitObjCProtocolExpr(const ObjCProtocolExpr *OPE); + void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *OPRE); + void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *OSRE); + void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *OIRE); + void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *OBLE); + + void VisitIntegerLiteral(const IntegerLiteral *IL); + void VisitCharacterLiteral(const CharacterLiteral *CL); + void VisitFixedPointLiteral(const FixedPointLiteral *FPL); + void VisitFloatingLiteral(const FloatingLiteral *FL); + void VisitStringLiteral(const StringLiteral *SL); + void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *BLE); + + void VisitIfStmt(const IfStmt *IS); + void VisitSwitchStmt(const SwitchStmt *SS); + void VisitCaseStmt(const CaseStmt *CS); + void VisitLabelStmt(const LabelStmt *LS); + void VisitGotoStmt(const GotoStmt *GS); + void VisitWhileStmt(const WhileStmt *WS); + void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *OACS); + + void VisitNullTemplateArgument(const TemplateArgument &TA); + void VisitTypeTemplateArgument(const TemplateArgument &TA); + void VisitDeclarationTemplateArgument(const TemplateArgument &TA); + void VisitNullPtrTemplateArgument(const TemplateArgument &TA); + void VisitIntegralTemplateArgument(const TemplateArgument &TA); + void VisitTemplateTemplateArgument(const TemplateArgument &TA); + void VisitTemplateExpansionTemplateArgument(const TemplateArgument &TA); + void VisitExpressionTemplateArgument(const TemplateArgument &TA); + void VisitPackTemplateArgument(const TemplateArgument &TA); + + void visitTextComment(const comments::TextComment *C, + const comments::FullComment *); + void visitInlineCommandComment(const comments::InlineCommandComment *C, + const comments::FullComment *); + void visitHTMLStartTagComment(const comments::HTMLStartTagComment *C, + const comments::FullComment *); + void visitHTMLEndTagComment(const comments::HTMLEndTagComment *C, + const comments::FullComment *); + void visitBlockCommandComment(const comments::BlockCommandComment *C, + const comments::FullComment *); + void visitParamCommandComment(const comments::ParamCommandComment *C, + const comments::FullComment *FC); + void visitTParamCommandComment(const comments::TParamCommandComment *C, + const comments::FullComment *FC); + void visitVerbatimBlockComment(const comments::VerbatimBlockComment *C, + const comments::FullComment *); + void + visitVerbatimBlockLineComment(const comments::VerbatimBlockLineComment *C, + const comments::FullComment *); + void visitVerbatimLineComment(const comments::VerbatimLineComment *C, + const comments::FullComment *); +}; + +class JSONDumper : public ASTNodeTraverser<JSONDumper, JSONNodeDumper> { + JSONNodeDumper NodeDumper; + + template <typename SpecializationDecl> + void writeTemplateDeclSpecialization(const SpecializationDecl *SD, + bool DumpExplicitInst, + bool DumpRefOnly) { + bool DumpedAny = false; + for (const auto *RedeclWithBadType : SD->redecls()) { + // FIXME: The redecls() range sometimes has elements of a less-specific + // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives + // us TagDecls, and should give CXXRecordDecls). + const auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType); + if (!Redecl) { + // Found the injected-class-name for a class template. This will be + // dumped as part of its surrounding class so we don't need to dump it + // here. + assert(isa<CXXRecordDecl>(RedeclWithBadType) && + "expected an injected-class-name"); + continue; + } + + switch (Redecl->getTemplateSpecializationKind()) { + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + if (!DumpExplicitInst) + break; + LLVM_FALLTHROUGH; + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + if (DumpRefOnly) + NodeDumper.AddChild([=] { NodeDumper.writeBareDeclRef(Redecl); }); + else + Visit(Redecl); + DumpedAny = true; + break; + case TSK_ExplicitSpecialization: + break; + } + } + + // Ensure we dump at least one decl for each specialization. + if (!DumpedAny) + NodeDumper.AddChild([=] { NodeDumper.writeBareDeclRef(SD); }); + } + + template <typename TemplateDecl> + void writeTemplateDecl(const TemplateDecl *TD, bool DumpExplicitInst) { + // FIXME: it would be nice to dump template parameters and specializations + // to their own named arrays rather than shoving them into the "inner" + // array. However, template declarations are currently being handled at the + // wrong "level" of the traversal hierarchy and so it is difficult to + // achieve without losing information elsewhere. + + dumpTemplateParameters(TD->getTemplateParameters()); + + Visit(TD->getTemplatedDecl()); + + for (const auto *Child : TD->specializations()) + writeTemplateDeclSpecialization(Child, DumpExplicitInst, + !TD->isCanonicalDecl()); + } + +public: + JSONDumper(raw_ostream &OS, const SourceManager &SrcMgr, ASTContext &Ctx, + const PrintingPolicy &PrintPolicy, + const comments::CommandTraits *Traits) + : NodeDumper(OS, SrcMgr, Ctx, PrintPolicy, Traits) {} + + JSONNodeDumper &doGetNodeDelegate() { return NodeDumper; } + + void VisitFunctionTemplateDecl(const FunctionTemplateDecl *FTD) { + writeTemplateDecl(FTD, true); + } + void VisitClassTemplateDecl(const ClassTemplateDecl *CTD) { + writeTemplateDecl(CTD, false); + } + void VisitVarTemplateDecl(const VarTemplateDecl *VTD) { + writeTemplateDecl(VTD, false); + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_AST_JSONNODEDUMPER_H |