Index: include/clang/AST/ASTDumperUtils.h =================================================================== --- include/clang/AST/ASTDumperUtils.h +++ include/clang/AST/ASTDumperUtils.h @@ -17,6 +17,14 @@ namespace clang { +/// Used to specify the format for printing AST dump information. The values +/// in this enumeration should match the ones in +/// clang::FrontendOptions::ASTOutputFormat. +enum ASTDumpOutputFormat { + ADOF_Default, + ADOF_JSON +}; + // Colors used for various parts of the AST dump // Do not use bold yellow for any text. It is hard to read on white screens. Index: include/clang/AST/DeclBase.h =================================================================== --- include/clang/AST/DeclBase.h +++ include/clang/AST/DeclBase.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_AST_DECLBASE_H #define LLVM_CLANG_AST_DECLBASE_H +#include "clang/AST/ASTDumperUtils.h" #include "clang/AST/AttrIterator.h" #include "clang/AST/DeclarationName.h" #include "clang/Basic/IdentifierTable.h" @@ -1138,7 +1139,8 @@ // Same as dump(), but forces color printing. void dumpColor() const; - void dump(raw_ostream &Out, bool Deserialize = false) const; + void dump(raw_ostream &Out, bool Deserialize = false, + ASTDumpOutputFormat OutputFormat = ADOF_Default) const; /// \return Unique reproducible object identifier int64_t getID() const; Index: include/clang/AST/JSONNodeDumper.h =================================================================== --- include/clang/AST/JSONNodeDumper.h +++ include/clang/AST/JSONNodeDumper.h @@ -0,0 +1,255 @@ +//===--- 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 { + raw_ostream &OS; + + /// Pending[i] is an action to dump an entity at level i. + llvm::SmallVector, 32> Pending; + + /// Indicates whether we're at the top level. + bool TopLevel = true; + + /// Indicates if we're handling the first child after entering a new depth. + bool FirstChild = true; + +protected: + + /// Used for determining intra-object comma placement; inter-object comma + /// placement is determined by FirstChild. + bool FirstChildField = true; + + /// The current indentation level. + std::string Indentation; + +public: + /// Add a child of the current node. Calls DoAddChild without arguments + template void AddChild(Fn DoAddChild) { + return AddChild("", DoAddChild); + } + + /// Add a child of the current node with an optional label. + /// Calls DoAddChild without arguments. + template 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; + OS << Indentation << "{\n"; + FirstChildField = true; + Indentation += " "; + DoAddChild(); + + while (!Pending.empty()) { + Pending.back()(true); + Pending.pop_back(); + } + Indentation.clear(); + OS << "\n" << Indentation << "}\n"; + TopLevel = true; + return; + } + + bool WasFirstChild = FirstChild; + // We need to capture an owning-string in the lambda because the lambda + // is invoked in a deferred manner. + auto DumpWithIndent = [this, DoAddChild, WasFirstChild](bool IsLastChild) { + if (WasFirstChild) { + if (!FirstChildField) + OS << ",\n"; + OS << Indentation << "\"inner\": [\n"; + } + + FirstChild = true; + unsigned Depth = Pending.size(); + OS << Indentation << "{\n"; + + Indentation += " "; + + FirstChildField = true; + 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(); + } + + // Restore the old prefix. + this->Indentation.resize(Indentation.size() - 2); + + OS << "\n" << Indentation << "}"; + + if (!IsLastChild) + OS << ",\n"; + else + OS << "\n" << Indentation << "]"; + }; + + if (FirstChild) { + Pending.push_back(std::move(DumpWithIndent)); + } else { + Pending.back()(false); + Pending.back() = std::move(DumpWithIndent); + } + FirstChild = false; + } + + NodeStreamer(raw_ostream &OS) : OS(OS) {} +}; + +// Dumps AST nodes in JSON format. Note that we cannot serialize the AST into +// JSON and then dump to a file because the AST is an ordered collection of +// nodes but our JSON objects are modelled as an unordered container. We can +// use JSON facilities for constructing the terminal fields in a node because +// the field order is unimportant there, but we cannot use those same facilities +// for dumping the entire tree because AST nodes could get out of order in ways +// that alter the meaning of the AST. +class JSONNodeDumper + : public ConstAttrVisitor, + public ConstStmtVisitor, + public TypeVisitor, + public ConstDeclVisitor, + public NodeStreamer { + raw_ostream &OS; + const SourceManager &SM; + PrintingPolicy PrintPolicy; + + using InnerAttrVisitor = ConstAttrVisitor; + using InnerStmtVisitor = ConstStmtVisitor; + using InnerTypeVisitor = TypeVisitor; + using InnerDeclVisitor = ConstDeclVisitor; + + void writeToOutput(llvm::json::Object Obj); + void writeKVPair(StringRef Key, llvm::json::Value Value); + void writeKVPairOnlyIfTrue(StringRef Key, bool Value) { + if (Value) + writeKVPair(Key, true); + } + + llvm::json::Object createSourceLocation(SourceLocation Loc); + llvm::json::Object createSourceRange(SourceRange R); + std::string createPointerRepresentation(const void *Ptr); + llvm::json::Object createQualType(QualType QT, bool Desugar = true); + llvm::json::Object createBareDeclRef(const Decl *D); + llvm::json::Object createCXXRecordDefinitionData(const CXXRecordDecl *RD); + llvm::json::Object createCXXBaseSpecifier(const CXXBaseSpecifier &BS); + std::string createAccessSpecifier(AccessSpecifier AS); + + void writePreviousDeclImpl(...) {} + + template void writePreviousDeclImpl(const Mergeable *D) { + const T *First = D->getFirstDecl(); + if (First != D) + writeKVPair("firstRedecl", createPointerRepresentation(First)); + } + + template void writePreviousDeclImpl(const Redeclarable *D) { + const T *Prev = D->getPreviousDecl(); + if (Prev) + writeKVPair("previousDecl", createPointerRepresentation(Prev)); + } + void addPreviousDeclaration(const Decl *D); + +public: + JSONNodeDumper(raw_ostream &OS, const SourceManager &SrcMgr, + const PrintingPolicy &PrintPolicy) + : NodeStreamer(OS), OS(OS), SM(SrcMgr), PrintPolicy(PrintPolicy) {} + + 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 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 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 VisitUnaryOperator(const UnaryOperator *UO); + void VisitBinaryOperator(const BinaryOperator *BO); + void VisitMemberExpr(const MemberExpr *ME); + + 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 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); +}; + +class JSONDumper : public ASTNodeTraverser { + JSONNodeDumper NodeDumper; + +public: + JSONDumper(raw_ostream &OS, const SourceManager &SrcMgr, + const PrintingPolicy &PrintPolicy) + : NodeDumper(OS, SrcMgr, PrintPolicy) {} + + JSONNodeDumper &doGetNodeDelegate() { return NodeDumper; } +}; + +} // namespace clang + +#endif // LLVM_CLANG_AST_JSONNODEDUMPER_H Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -553,8 +553,14 @@ HelpText<"Build ASTs and print the list of declaration node qualified names">; def ast_dump : Flag<["-"], "ast-dump">, HelpText<"Build ASTs and then debug dump them">; +def ast_dump_EQ : Joined<["-"], "ast-dump=">, + HelpText<"Build ASTs and then debug dump them in the specified format. " + "Supported formats include: default, json">; def ast_dump_all : Flag<["-"], "ast-dump-all">, HelpText<"Build ASTs and then debug dump them, forcing deserialization">; +def ast_dump_all_EQ : Joined<["-"], "ast-dump-all=">, + HelpText<"Build ASTs and then debug dump them in the specified format, " + "forcing deserialization. Supported formats include: default, json">; def templight_dump : Flag<["-"], "templight-dump">, HelpText<"Dump templight information to stdout">; def ast_dump_lookups : Flag<["-"], "ast-dump-lookups">, Index: include/clang/Frontend/ASTConsumers.h =================================================================== --- include/clang/Frontend/ASTConsumers.h +++ include/clang/Frontend/ASTConsumers.h @@ -14,6 +14,7 @@ #define LLVM_CLANG_FRONTEND_ASTCONSUMERS_H #include "clang/Basic/LLVM.h" +#include "clang/Frontend/FrontendOptions.h" #include namespace clang { @@ -35,10 +36,10 @@ // AST dumper: dumps the raw AST in human-readable form to the given output // stream, or stdout if OS is nullptr. -std::unique_ptr CreateASTDumper(std::unique_ptr OS, - StringRef FilterString, - bool DumpDecls, bool Deserialize, - bool DumpLookups); +std::unique_ptr +CreateASTDumper(std::unique_ptr OS, StringRef FilterString, + bool DumpDecls, bool Deserialize, bool DumpLookups, + FrontendOptions::ASTOutputFormat Format); // AST Decl node lister: prints qualified names of all filterable AST Decl // nodes. Index: include/clang/Frontend/FrontendOptions.h =================================================================== --- include/clang/Frontend/FrontendOptions.h +++ include/clang/Frontend/FrontendOptions.h @@ -307,6 +307,12 @@ CodeCompleteOptions CodeCompleteOpts; + /// Specifies the output format of the AST. + enum ASTOutputFormat { + AOF_Default, + AOF_JSON, + } ASTDumpFormat = AOF_Default; + enum { ARCMT_None, ARCMT_Check, Index: lib/AST/ASTDumper.cpp =================================================================== --- lib/AST/ASTDumper.cpp +++ lib/AST/ASTDumper.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTNodeTraverser.h" #include "clang/AST/DeclLookups.h" +#include "clang/AST/JSONNodeDumper.h" #include "clang/AST/TextNodeDumper.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/Module.h" @@ -222,13 +223,21 @@ LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); } -LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize) const { +LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize, + ASTDumpOutputFormat Format) const { const ASTContext &Ctx = getASTContext(); const SourceManager &SM = Ctx.getSourceManager(); - ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &SM, - SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy()); - P.setDeserialize(Deserialize); - P.Visit(this); + + if (ADOF_JSON == Format) { + JSONDumper P(OS, SM, Ctx.getPrintingPolicy()); + (void)Deserialize; // FIXME? + P.Visit(this); + } else { + ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &SM, + SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy()); + P.setDeserialize(Deserialize); + P.Visit(this); + } } LLVM_DUMP_METHOD void Decl::dumpColor() const { Index: lib/AST/CMakeLists.txt =================================================================== --- lib/AST/CMakeLists.txt +++ lib/AST/CMakeLists.txt @@ -44,6 +44,7 @@ InheritViz.cpp ItaniumCXXABI.cpp ItaniumMangle.cpp + JSONNodeDumper.cpp Mangle.cpp MicrosoftCXXABI.cpp MicrosoftMangle.cpp Index: lib/AST/JSONNodeDumper.cpp =================================================================== --- lib/AST/JSONNodeDumper.cpp +++ lib/AST/JSONNodeDumper.cpp @@ -0,0 +1,593 @@ +#include "clang/AST/JSONNodeDumper.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; + +void JSONNodeDumper::addPreviousDeclaration(const Decl *D) { + switch (D->getKind()) { +#define DECL(DERIVED, BASE) \ + case Decl::DERIVED: \ + return writePreviousDeclImpl(cast(D)); +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" +#undef ABSTRACT_DECL +#undef DECL + } + llvm_unreachable("Decl that isn't part of DeclNodes.inc!"); +} + + +void JSONNodeDumper::Visit(const Attr *A) { + const char *AttrName = nullptr; + switch (A->getKind()) { +#define ATTR(X) \ + case attr::X: \ + AttrName = #X##"Attr"; \ + break; +#include "clang/Basic/AttrList.inc" +#undef ATTR + } + writeKVPair("id", createPointerRepresentation(A)); + writeKVPair("kind", AttrName); + writeKVPair("range", createSourceRange(A->getRange())); + writeKVPairOnlyIfTrue("inherited", A->isInherited()); + writeKVPairOnlyIfTrue("implicit", A->isImplicit()); + + // FIXME: it would be useful for us to output the spelling kind as well as + // the actual spelling. This would allow us to distinguish between the + // various attribute syntaxes, but we don't currently track that information + // within the AST. + writeKVPair("spelling", A->getSpelling()); + + InnerAttrVisitor::Visit(A); +} + +void JSONNodeDumper::Visit(const Stmt *S) { + if (!S) + return; + + writeKVPair("id", createPointerRepresentation(S)); + writeKVPair("kind", S->getStmtClassName()); + writeKVPair("range", createSourceRange(S->getSourceRange())); + + if (const auto *E = dyn_cast(S)) { + writeKVPair("type", createQualType(E->getType())); + const char *Category = nullptr; + switch (E->getValueKind()) { + case VK_LValue: Category = "lvalue"; break; + case VK_XValue: Category = "xvalue"; break; + case VK_RValue: Category = "rvalue"; break; + } + writeKVPair("valueCategory", Category); + } + InnerStmtVisitor::Visit(S); +} + +void JSONNodeDumper::Visit(const Type *T) { + writeKVPair("id", createPointerRepresentation(T)); + writeKVPair("kind", (llvm::Twine(T->getTypeClassName()) + "Type").str()); + writeKVPair("type", createQualType(QualType(T, 0), /*Desugar*/ false)); + writeKVPairOnlyIfTrue("isDependent", T->isDependentType()); + writeKVPairOnlyIfTrue("isInstantiationDependent", + T->isInstantiationDependentType()); + writeKVPairOnlyIfTrue("isVariablyModified", T->isVariablyModifiedType()); + writeKVPairOnlyIfTrue("containsUnexpandedPack", + T->containsUnexpandedParameterPack()); + writeKVPairOnlyIfTrue("isImported", T->isFromAST()); + InnerTypeVisitor::Visit(T); +} + +void JSONNodeDumper::Visit(QualType T) { + writeKVPair("id", createPointerRepresentation(T.getAsOpaquePtr())); + writeKVPair("type", createQualType(T)); + writeKVPair("qualifiers", T.split().Quals.getAsString()); +} + +void JSONNodeDumper::Visit(const Decl *D) { + writeKVPair("id", createPointerRepresentation(D)); + writeKVPair("kind", (llvm::Twine(D->getDeclKindName()) + "Decl").str()); + writeKVPair("loc", createSourceLocation(D->getLocation())); + writeKVPair("range", createSourceRange(D->getSourceRange())); + writeKVPairOnlyIfTrue("isImplicit", D->isImplicit()); + writeKVPairOnlyIfTrue("isInvalid", D->isInvalidDecl()); + + if (D->isUsed()) + writeKVPair("isUsed", true); + else if (D->isThisDeclarationReferenced()) + writeKVPair("isReferenced", true); + + if (const auto *ND = dyn_cast(D)) + writeKVPairOnlyIfTrue("isHidden", ND->isHidden()); + + if (D->getLexicalDeclContext() != D->getDeclContext()) + writeKVPair("parentDeclContext", createPointerRepresentation(D->getDeclContext())); + + addPreviousDeclaration(D); + InnerDeclVisitor::Visit(D); +} + +void JSONNodeDumper::Visit(const comments::Comment *C, + const comments::FullComment *FC) {} +void JSONNodeDumper::Visit(const TemplateArgument &TA, SourceRange R, + const Decl *From, StringRef Label) {} +void JSONNodeDumper::Visit(const CXXCtorInitializer *Init) {} +void JSONNodeDumper::Visit(const OMPClause *C) {} +void JSONNodeDumper::Visit(const BlockDecl::Capture &C) {} +void JSONNodeDumper::Visit(const GenericSelectionExpr::ConstAssociation &A) {} + +void JSONNodeDumper::writeToOutput(llvm::json::Object Obj) { + OS << Indentation << llvm::formatv("{0:2}", llvm::json::Value(std::move(Obj))); +} + +void JSONNodeDumper::writeKVPair(StringRef Key, llvm::json::Value Value) { + if (!FirstChildField) + OS << ",\n"; + OS << Indentation << "\"" << Key << "\": " << Value; + FirstChildField = false; +} + +llvm::json::Object JSONNodeDumper::createSourceLocation(SourceLocation Loc) { + SourceLocation Spelling = SM.getSpellingLoc(Loc); + PresumedLoc Presumed = SM.getPresumedLoc(Spelling); + + if (Presumed.isInvalid()) + return llvm::json::Object{}; + + return llvm::json::Object{{"file", Presumed.getFilename()}, + {"line", Presumed.getLine()}, + {"col", Presumed.getColumn()}}; +} + +llvm::json::Object JSONNodeDumper::createSourceRange(SourceRange R) { + return llvm::json::Object{{"begin", createSourceLocation(R.getBegin())}, + {"end", createSourceLocation(R.getEnd())}}; +} + +std::string JSONNodeDumper::createPointerRepresentation(const void *Ptr) { + // Because JSON stores integer values as signed 64-bit integers, trying to + // represent them as such makes for very ugly pointer values in the resulting + // output. Instead, we convert the value to hex and treat it as a string. + return "0x" + llvm::utohexstr(reinterpret_cast(Ptr), true); +} + +llvm::json::Object JSONNodeDumper::createQualType(QualType QT, bool Desugar) { + SplitQualType SQT = QT.split(); + llvm::json::Object Ret{{"qualType", QualType::getAsString(SQT, PrintPolicy)}}; + + if (Desugar && !QT.isNull()) { + SplitQualType DSQT = QT.getSplitDesugaredType(); + if (DSQT != SQT) + Ret["desugaredQualType"] = QualType::getAsString(DSQT, PrintPolicy); + } + return Ret; +} + +llvm::json::Object JSONNodeDumper::createBareDeclRef(const Decl *D) { + llvm::json::Object Ret{ + {"id", createPointerRepresentation(D)}, + {"kind", (llvm::Twine(D->getDeclKindName()) + "Decl").str()}}; + if (const auto *ND = dyn_cast(D)) + Ret["name"] = ND->getDeclName().getAsString(); + if (const auto *VD = dyn_cast(D)) + Ret["type"] = createQualType(VD->getType()); + return Ret; +} + +#define FIELD2(Name, Flag) if (RD->Flag()) Ret[Name] = true +#define FIELD1(Flag) FIELD2(#Flag, Flag) + +static llvm::json::Object +createDefaultConstructorDefinitionData(const CXXRecordDecl *RD) { + llvm::json::Object Ret; + + FIELD2("exists", hasDefaultConstructor); + FIELD2("trivial", hasTrivialDefaultConstructor); + FIELD2("nonTrivial", hasNonTrivialDefaultConstructor); + FIELD2("userProvided", hasUserProvidedDefaultConstructor); + FIELD2("isConstexpr", hasConstexprDefaultConstructor); + FIELD2("needsImplicit", needsImplicitDefaultConstructor); + FIELD2("defaultedIsConstexpr", defaultedDefaultConstructorIsConstexpr); + + return Ret; +} + +static llvm::json::Object +createCopyConstructorDefinitionData(const CXXRecordDecl *RD) { + llvm::json::Object Ret; + + FIELD2("simple", hasSimpleCopyConstructor); + FIELD2("trivial", hasTrivialCopyConstructor); + FIELD2("nonTrivial", hasNonTrivialCopyConstructor); + FIELD2("userDeclared", hasUserDeclaredCopyConstructor); + FIELD2("hasConstParam", hasCopyConstructorWithConstParam); + FIELD2("implicitHasConstParam", implicitCopyConstructorHasConstParam); + FIELD2("needsImplicit", needsImplicitCopyConstructor); + FIELD2("needsOverloadResolution", needsOverloadResolutionForCopyConstructor); + if (!RD->needsOverloadResolutionForCopyConstructor()) + FIELD2("defaultedIsDeleted", defaultedCopyConstructorIsDeleted); + + return Ret; +} + +static llvm::json::Object +createMoveConstructorDefinitionData(const CXXRecordDecl *RD) { + llvm::json::Object Ret; + + FIELD2("exists", hasMoveConstructor); + FIELD2("simple", hasSimpleMoveConstructor); + FIELD2("trivial", hasTrivialMoveConstructor); + FIELD2("nonTrivial", hasNonTrivialMoveConstructor); + FIELD2("userDeclared", hasUserDeclaredMoveConstructor); + FIELD2("needsImplicit", needsImplicitMoveConstructor); + FIELD2("needsOverloadResolution", needsOverloadResolutionForMoveConstructor); + if (!RD->needsOverloadResolutionForMoveConstructor()) + FIELD2("defaultedIsDeleted", defaultedMoveConstructorIsDeleted); + + return Ret; +} + +static llvm::json::Object +createCopyAssignmentDefinitionData(const CXXRecordDecl *RD) { + llvm::json::Object Ret; + + FIELD2("trivial", hasTrivialCopyAssignment); + FIELD2("nonTrivial", hasNonTrivialCopyAssignment); + FIELD2("hasConstParam", hasCopyAssignmentWithConstParam); + FIELD2("implicitHasConstParam", implicitCopyAssignmentHasConstParam); + FIELD2("userDeclared", hasUserDeclaredCopyAssignment); + FIELD2("needsImplicit", needsImplicitCopyAssignment); + FIELD2("needsOverloadResolution", needsOverloadResolutionForCopyAssignment); + + return Ret; +} + +static llvm::json::Object +createMoveAssignmentDefinitionData(const CXXRecordDecl *RD) { + llvm::json::Object Ret; + + FIELD2("exists", hasMoveAssignment); + FIELD2("simple", hasSimpleMoveAssignment); + FIELD2("trivial", hasTrivialMoveAssignment); + FIELD2("nonTrivial", hasNonTrivialMoveAssignment); + FIELD2("userDeclared", hasUserDeclaredMoveAssignment); + FIELD2("needsImplicit", needsImplicitMoveAssignment); + FIELD2("needsOverloadResolution", needsOverloadResolutionForMoveAssignment); + + return Ret; +} + +static llvm::json::Object +createDestructorDefinitionData(const CXXRecordDecl *RD) { + llvm::json::Object Ret; + + FIELD2("simple", hasSimpleDestructor); + FIELD2("irrelevant", hasIrrelevantDestructor); + FIELD2("trivial", hasTrivialDestructor); + FIELD2("nonTrivial", hasNonTrivialDestructor); + FIELD2("userDeclared", hasUserDeclaredDestructor); + FIELD2("needsImplicit", needsImplicitDestructor); + FIELD2("needsOverloadResolution", needsOverloadResolutionForDestructor); + if (!RD->needsOverloadResolutionForDestructor()) + FIELD2("defaultedIsDeleted", defaultedDestructorIsDeleted); + + return Ret; +} + +llvm::json::Object +JSONNodeDumper::createCXXRecordDefinitionData(const CXXRecordDecl *RD) { + llvm::json::Object Ret; + + // This data is common to all C++ classes. + FIELD1(isGenericLambda); + FIELD1(isLambda); + FIELD1(isEmpty); + FIELD1(isAggregate); + FIELD1(isStandardLayout); + FIELD1(isTriviallyCopyable); + FIELD1(isPOD); + FIELD1(isTrivial); + FIELD1(isPolymorphic); + FIELD1(isAbstract); + FIELD1(isLiteral); + FIELD1(canPassInRegisters); + FIELD1(hasUserDeclaredConstructor); + FIELD1(hasConstexprNonCopyMoveConstructor); + FIELD1(hasMutableFields); + FIELD1(hasVariantMembers); + FIELD2("canConstDefaultInit", allowConstDefaultInit); + + Ret["defaultCtor"] = createDefaultConstructorDefinitionData(RD); + Ret["copyCtor"] = createCopyConstructorDefinitionData(RD); + Ret["moveCtor"] = createMoveConstructorDefinitionData(RD); + Ret["copyAssign"] = createCopyAssignmentDefinitionData(RD); + Ret["moveAssign"] = createMoveAssignmentDefinitionData(RD); + Ret["dtor"] = createDestructorDefinitionData(RD); + + return Ret; +} + +#undef FIELD1 +#undef FIELD2 + +std::string JSONNodeDumper::createAccessSpecifier(AccessSpecifier AS) { + switch (AS) { + case AS_none: return "none"; + case AS_private: return "private"; + case AS_protected: return "protected"; + case AS_public: return "public"; + } + llvm_unreachable("Unknown access specifier"); +} + +llvm::json::Object +JSONNodeDumper::createCXXBaseSpecifier(const CXXBaseSpecifier &BS) { + llvm::json::Object Ret; + + Ret["type"] = createQualType(BS.getType()); + Ret["access"] = createAccessSpecifier(BS.getAccessSpecifier()); + Ret["writtenAccess"] = + createAccessSpecifier(BS.getAccessSpecifierAsWritten()); + if (BS.isVirtual()) + Ret["isVirtual"] = true; + if (BS.isPackExpansion()) + Ret["isPackExpansion"] = true; + + return Ret; +} + +void JSONNodeDumper::VisitTypedefType(const TypedefType *TT) { + writeKVPair("decl", createBareDeclRef(TT->getDecl())); +} + +void JSONNodeDumper::VisitFunctionType(const FunctionType *T) { + FunctionType::ExtInfo E = T->getExtInfo(); + writeKVPairOnlyIfTrue("noreturn", E.getNoReturn()); + writeKVPairOnlyIfTrue("producesResult", E.getProducesResult()); + if (E.getHasRegParm()) + writeKVPair("regParm", E.getRegParm()); + writeKVPair("cc", FunctionType::getNameForCallConv(E.getCC())); +} + +void JSONNodeDumper::VisitFunctionProtoType(const FunctionProtoType *T) { + FunctionProtoType::ExtProtoInfo E = T->getExtProtoInfo(); + writeKVPairOnlyIfTrue("trailingReturn", E.HasTrailingReturn); + writeKVPairOnlyIfTrue("const", T->isConst()); + writeKVPairOnlyIfTrue("volatile", T->isVolatile()); + writeKVPairOnlyIfTrue("restrict", T->isRestrict()); + writeKVPairOnlyIfTrue("variadic", E.Variadic); + switch (E.RefQualifier) { + case RQ_LValue: writeKVPair("refQualifier", "&"); break; + case RQ_RValue: writeKVPair("refQualifier", "&&"); break; + case RQ_None: break; + } + VisitFunctionType(T); +} + +void JSONNodeDumper::VisitNamedDecl(const NamedDecl *ND) { + if (ND && ND->getDeclName()) + writeKVPair("name", ND->getNameAsString()); +} + +void JSONNodeDumper::VisitTypedefDecl(const TypedefDecl *TD) { + VisitNamedDecl(TD); + writeKVPair("type", createQualType(TD->getUnderlyingType())); +} + +void JSONNodeDumper::VisitTypeAliasDecl(const TypeAliasDecl *TAD) { + VisitNamedDecl(TAD); + writeKVPair("type", createQualType(TAD->getUnderlyingType())); +} + +void JSONNodeDumper::VisitNamespaceDecl(const NamespaceDecl *ND) { + VisitNamedDecl(ND); + writeKVPairOnlyIfTrue("isInline", ND->isInline()); + if (!ND->isOriginalNamespace()) + writeKVPair("originalNamespace", + createBareDeclRef(ND->getOriginalNamespace())); +} + +void JSONNodeDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *UDD) { + writeKVPair("nominatedNamespace", + createBareDeclRef(UDD->getNominatedNamespace())); +} + +void JSONNodeDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD) { + VisitNamedDecl(NAD); + writeKVPair("aliasedNamespace", + createBareDeclRef(NAD->getAliasedNamespace())); +} + +void JSONNodeDumper::VisitUsingDecl(const UsingDecl *UD) { + std::string Name; + if (const NestedNameSpecifier *NNS = UD->getQualifier()) { + llvm::raw_string_ostream SOS(Name); + NNS->print(SOS, UD->getASTContext().getPrintingPolicy()); + } + Name += UD->getNameAsString(); + writeKVPair("name", Name); +} + +void JSONNodeDumper::VisitUsingShadowDecl(const UsingShadowDecl *USD) { + writeKVPair("target", createBareDeclRef(USD->getTargetDecl())); +} + +void JSONNodeDumper::VisitVarDecl(const VarDecl *VD) { + VisitNamedDecl(VD); + writeKVPair("type", createQualType(VD->getType())); + + StorageClass SC = VD->getStorageClass(); + if (SC != SC_None) + writeKVPair("storageClass", VarDecl::getStorageClassSpecifierString(SC)); + switch (VD->getTLSKind()) { + case VarDecl::TLS_Dynamic: writeKVPair("tls", "dynamic"); break; + case VarDecl::TLS_Static: writeKVPair("tls", "static"); break; + case VarDecl::TLS_None: break; + } + writeKVPairOnlyIfTrue("nrvo", VD->isNRVOVariable()); + writeKVPairOnlyIfTrue("inline", VD->isInline()); + writeKVPairOnlyIfTrue("constexpr", VD->isConstexpr()); + if (VD->hasInit()) { + switch (VD->getInitStyle()) { + case VarDecl::CInit: writeKVPair("init", "c"); break; + case VarDecl::CallInit: writeKVPair("init", "call"); break; + case VarDecl::ListInit: writeKVPair("init", "list"); break; + } + } +} + +void JSONNodeDumper::VisitFunctionDecl(const FunctionDecl *FD) { + VisitNamedDecl(FD); + writeKVPair("type", createQualType(FD->getType())); + StorageClass SC = FD->getStorageClass(); + if (SC != SC_None) + writeKVPair("storageClass", VarDecl::getStorageClassSpecifierString(SC)); + writeKVPairOnlyIfTrue("inline", FD->isInlineSpecified()); + writeKVPairOnlyIfTrue("virtual", FD->isVirtualAsWritten()); + writeKVPairOnlyIfTrue("pure", FD->isPure()); + writeKVPairOnlyIfTrue("explicitlyDeleted", FD->isDeletedAsWritten()); + writeKVPairOnlyIfTrue("constexpr", FD->isConstexpr()); + if (FD->isDefaulted()) + writeKVPair("explicitlyDefaulted", FD->isDeleted() ? "deleted" : "default"); +} + +void JSONNodeDumper::VisitEnumDecl(const EnumDecl *ED) { + VisitNamedDecl(ED); + if (ED->isFixed()) + writeKVPair("fixedUnderlyingType", createQualType(ED->getIntegerType())); + if (ED->isScoped()) + writeKVPair("scopedEnumTag", + ED->isScopedUsingClassTag() ? "class" : "struct"); +} +void JSONNodeDumper::VisitEnumConstantDecl(const EnumConstantDecl *ECD) { + VisitNamedDecl(ECD); + writeKVPair("type", createQualType(ECD->getType())); +} + +void JSONNodeDumper::VisitRecordDecl(const RecordDecl *RD) { + VisitNamedDecl(RD); + writeKVPair("tagUsed", RD->getKindName()); + writeKVPairOnlyIfTrue("completeDefinition", RD->isCompleteDefinition()); +} +void JSONNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *RD) { + VisitRecordDecl(RD); + + // All other information requires a complete definition. + if (!RD->isCompleteDefinition()) + return; + + writeKVPair("definitionData", createCXXRecordDefinitionData(RD)); + + llvm::json::Array Bases; + for (const auto &Spec : RD->bases()) { + Bases.push_back(createCXXBaseSpecifier(Spec)); + } + if (!Bases.empty()) + writeKVPair("bases", std::move(Bases)); +} + +void JSONNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { + VisitNamedDecl(D); + writeKVPair("tagUsed", D->wasDeclaredWithTypename() ? "typename" : "class"); + writeKVPair("depth", D->getDepth()); + writeKVPair("index", D->getIndex()); + writeKVPairOnlyIfTrue("isParameterPack", D->isParameterPack()); +} + +void JSONNodeDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { + VisitNamedDecl(D); + writeKVPair("type", createQualType(D->getType())); + writeKVPair("depth", D->getDepth()); + writeKVPair("index", D->getIndex()); + writeKVPairOnlyIfTrue("isParameterPack", D->isParameterPack()); +} + +void JSONNodeDumper::VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) { + VisitNamedDecl(D); + writeKVPair("depth", D->getDepth()); + writeKVPair("index", D->getIndex()); + writeKVPairOnlyIfTrue("isParameterPack", D->isParameterPack()); +} + +void JSONNodeDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *LSD) { + std::string Lang; + switch (LSD->getLanguage()) { + case LinkageSpecDecl::lang_c: Lang = "C"; break; + case LinkageSpecDecl::lang_cxx: Lang = "C++"; break; + } + writeKVPair("language", Lang); + writeKVPairOnlyIfTrue("hasBraces", LSD->hasBraces()); +} + +void JSONNodeDumper::VisitAccessSpecDecl(const AccessSpecDecl *ASD) { + writeKVPair("access", createAccessSpecifier(ASD->getAccess())); +} + +void JSONNodeDumper::VisitFriendDecl(const FriendDecl *FD) { + if (const TypeSourceInfo *T = FD->getFriendType()) + writeKVPair("type", createQualType(T->getType())); +} + +void JSONNodeDumper::VisitUnaryOperator(const UnaryOperator *UO) { + writeKVPair("isPostfix", UO->isPostfix()); + writeKVPair("opcode", UnaryOperator::getOpcodeStr(UO->getOpcode())); + if (!UO->canOverflow()) + writeKVPair("canOverflow", false); +} + +void JSONNodeDumper::VisitBinaryOperator(const BinaryOperator *BO) { + writeKVPair("opcode", BinaryOperator::getOpcodeStr(BO->getOpcode())); +} + +void JSONNodeDumper::VisitMemberExpr(const MemberExpr *ME) { + // Note, we always write this Boolean field because the information it conveys + // is critical to understanding the AST node. + writeKVPair("isArrow", ME->isArrow()); + writeKVPair("referencedMemberDecl", + createPointerRepresentation(ME->getMemberDecl())); +} + +void JSONNodeDumper::VisitIntegerLiteral(const IntegerLiteral *IL) { + writeKVPair("value", IL->getValue().toString( + /*Radix=*/10, IL->getType()->isSignedIntegerType())); +} +void JSONNodeDumper::VisitCharacterLiteral(const CharacterLiteral *CL) { + // FIXME: This should probably print the character literal as a string, + // rather than as a numerical value. + writeKVPair("value", CL->getValue()); +} +void JSONNodeDumper::VisitFixedPointLiteral(const FixedPointLiteral *FPL) { + writeKVPair("value", FPL->getValueAsString(/*Radix=*/10)); +} +void JSONNodeDumper::VisitFloatingLiteral(const FloatingLiteral *FL) { + writeKVPair("value", FL->getValueAsApproximateDouble()); +} +void JSONNodeDumper::VisitStringLiteral(const StringLiteral *SL) { + writeKVPair("value", SL->getString()); +} + +void JSONNodeDumper::VisitIfStmt(const IfStmt *IS) { + writeKVPairOnlyIfTrue("hasInit", IS->hasInitStorage()); + writeKVPairOnlyIfTrue("hasVar", IS->hasVarStorage()); + writeKVPairOnlyIfTrue("hasElse", IS->hasElseStorage()); + writeKVPairOnlyIfTrue("isConstexpr", IS->isConstexpr()); +} + +void JSONNodeDumper::VisitSwitchStmt(const SwitchStmt *SS) { + writeKVPairOnlyIfTrue("hasInit", SS->hasInitStorage()); + writeKVPairOnlyIfTrue("hasVar", SS->hasVarStorage()); +} +void JSONNodeDumper::VisitCaseStmt(const CaseStmt *CS) { + writeKVPairOnlyIfTrue("isGNURange", CS->caseStmtIsGNURange()); +} + +void JSONNodeDumper::VisitLabelStmt(const LabelStmt *LS) { + writeKVPair("name", LS->getName()); + writeKVPair("declId", createPointerRepresentation(LS->getDecl())); +} +void JSONNodeDumper::VisitGotoStmt(const GotoStmt *GS) { + writeKVPair("targetLabelDeclId", createPointerRepresentation(GS->getLabel())); +} + +void JSONNodeDumper::VisitWhileStmt(const WhileStmt *WS) { + writeKVPairOnlyIfTrue("hasVar", WS->hasVarStorage()); +} Index: lib/Frontend/ASTConsumers.cpp =================================================================== --- lib/Frontend/ASTConsumers.cpp +++ lib/Frontend/ASTConsumers.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/FrontendOptions.h" #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -34,10 +35,12 @@ public: enum Kind { DumpFull, Dump, Print, None }; - ASTPrinter(std::unique_ptr Out, Kind K, StringRef FilterString, + ASTPrinter(std::unique_ptr Out, Kind K, + FrontendOptions::ASTOutputFormat Format, StringRef FilterString, bool DumpLookups = false) : Out(Out ? *Out : llvm::outs()), OwnedOut(std::move(Out)), - OutputKind(K), FilterString(FilterString), DumpLookups(DumpLookups) {} + OutputKind(K), OutputFormat(Format), FilterString(FilterString), + DumpLookups(DumpLookups) {} void HandleTranslationUnit(ASTContext &Context) override { TranslationUnitDecl *D = Context.getTranslationUnitDecl(); @@ -90,7 +93,10 @@ PrintingPolicy Policy(D->getASTContext().getLangOpts()); D->print(Out, Policy, /*Indentation=*/0, /*PrintInstantiation=*/true); } else if (OutputKind != None) - D->dump(Out, OutputKind == DumpFull); + D->dump(Out, OutputKind == DumpFull, + OutputFormat == FrontendOptions::ASTOutputFormat::AOF_JSON + ? ADOF_JSON + : ADOF_Default); } raw_ostream &Out; @@ -99,6 +105,9 @@ /// How to output individual declarations. Kind OutputKind; + /// What format should the output take? + FrontendOptions::ASTOutputFormat OutputFormat; + /// Which declarations or DeclContexts to display. std::string FilterString; @@ -135,20 +144,19 @@ clang::CreateASTPrinter(std::unique_ptr Out, StringRef FilterString) { return llvm::make_unique(std::move(Out), ASTPrinter::Print, + FrontendOptions::AOF_Default, FilterString); } std::unique_ptr -clang::CreateASTDumper(std::unique_ptr Out, - StringRef FilterString, - bool DumpDecls, - bool Deserialize, - bool DumpLookups) { +clang::CreateASTDumper(std::unique_ptr Out, StringRef FilterString, + bool DumpDecls, bool Deserialize, bool DumpLookups, + FrontendOptions::ASTOutputFormat Format) { assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump"); return llvm::make_unique(std::move(Out), Deserialize ? ASTPrinter::DumpFull : DumpDecls ? ASTPrinter::Dump : - ASTPrinter::None, + ASTPrinter::None, Format, FilterString, DumpLookups); } Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -1603,6 +1603,22 @@ llvm_unreachable("Invalid option in group!"); case OPT_ast_list: Opts.ProgramAction = frontend::ASTDeclList; break; + case OPT_ast_dump_all_EQ: + case OPT_ast_dump_EQ: { + unsigned Val = llvm::StringSwitch(A->getValue()) + .CaseLower("default", FrontendOptions::AOF_Default) + .CaseLower("json", FrontendOptions::AOF_JSON) + .Default(std::numeric_limits::max()); + + if (Val != std::numeric_limits::max()) + Opts.ASTDumpFormat = static_cast(Val); + else { + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(); + Opts.ASTDumpFormat = FrontendOptions::AOF_Default; + } + LLVM_FALLTHROUGH; + } case OPT_ast_dump: case OPT_ast_dump_all: case OPT_ast_dump_lookups: @@ -1725,8 +1741,8 @@ Opts.FixOnlyWarnings = Args.hasArg(OPT_fix_only_warnings); Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile); Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp); - Opts.ASTDumpDecls = Args.hasArg(OPT_ast_dump); - Opts.ASTDumpAll = Args.hasArg(OPT_ast_dump_all); + Opts.ASTDumpDecls = Args.hasArg(OPT_ast_dump, OPT_ast_dump_EQ); + Opts.ASTDumpAll = Args.hasArg(OPT_ast_dump_all, OPT_ast_dump_all_EQ); Opts.ASTDumpFilter = Args.getLastArgValue(OPT_ast_dump_filter); Opts.ASTDumpLookups = Args.hasArg(OPT_ast_dump_lookups); Opts.UseGlobalModuleIndex = !Args.hasArg(OPT_fno_modules_global_index); Index: lib/Frontend/FrontendActions.cpp =================================================================== --- lib/Frontend/FrontendActions.cpp +++ lib/Frontend/FrontendActions.cpp @@ -73,11 +73,10 @@ std::unique_ptr ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { - return CreateASTDumper(nullptr /*Dump to stdout.*/, - CI.getFrontendOpts().ASTDumpFilter, - CI.getFrontendOpts().ASTDumpDecls, - CI.getFrontendOpts().ASTDumpAll, - CI.getFrontendOpts().ASTDumpLookups); + const FrontendOptions &Opts = CI.getFrontendOpts(); + return CreateASTDumper(nullptr /*Dump to stdout.*/, Opts.ASTDumpFilter, + Opts.ASTDumpDecls, Opts.ASTDumpAll, + Opts.ASTDumpLookups, Opts.ASTDumpFormat); } std::unique_ptr Index: test/AST/ast-dump-enum-json.cpp =================================================================== --- test/AST/ast-dump-enum-json.cpp +++ test/AST/ast-dump-enum-json.cpp @@ -0,0 +1,182 @@ +// RUN: %clang_cc1 -triple x86_64-pc-linux -std=c++17 -ast-dump=json %s | FileCheck %s + +enum { + One, + Two +}; + +// CHECK: "kind": "EnumDecl", +// CHECK-NEXT: "loc": {"col":1,"file":"{{.*}}","line":3}, +// CHECK-NEXT: "range": {"begin":{"col":1,"file":"{{.*}}","line":3},"end":{"col":1,"file":"{{.*}}","line":6}}, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "EnumConstantDecl", +// CHECK-NEXT: "loc": {"col":3,"file":"{{.*}}","line":4}, +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":4},"end":{"col":3,"file":"{{.*}}","line":4}}, +// CHECK-NEXT: "name": "One", +// CHECK-NEXT: "type": {"qualType":"(anonymous enum at {{.*}}:3:1)"} +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "EnumConstantDecl", +// CHECK-NEXT: "loc": {"col":3,"file":"{{.*}}","line":5}, +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":5},"end":{"col":3,"file":"{{.*}}","line":5}}, +// CHECK-NEXT: "name": "Two", +// CHECK-NEXT: "type": {"qualType":"(anonymous enum at {{.*}}:3:1)"} +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, + +enum E { + Three, + Four +}; + +// CHECK: "kind": "EnumDecl", +// CHECK-NEXT: "loc": {"col":6,"file":"{{.*}}","line":31}, +// CHECK-NEXT: "range": {"begin":{"col":1,"file":"{{.*}}","line":31},"end":{"col":1,"file":"{{.*}}","line":34}}, +// CHECK-NEXT: "name": "E", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "EnumConstantDecl", +// CHECK-NEXT: "loc": {"col":3,"file":"{{.*}}","line":32}, +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":32},"end":{"col":3,"file":"{{.*}}","line":32}}, +// CHECK-NEXT: "name": "Three", +// CHECK-NEXT: "type": {"qualType":"E"} +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "EnumConstantDecl", +// CHECK-NEXT: "loc": {"col":3,"file":"{{.*}}","line":33}, +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":33},"end":{"col":3,"file":"{{.*}}","line":33}}, +// CHECK-NEXT: "name": "Four", +// CHECK-NEXT: "type": {"qualType":"E"} +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, + +enum F : short { + Five, + Six +}; + +// CHECK: "kind": "EnumDecl", +// CHECK-NEXT: "loc": {"col":6,"file":"{{.*}}","line":60}, +// CHECK-NEXT: "range": {"begin":{"col":1,"file":"{{.*}}","line":60},"end":{"col":1,"file":"{{.*}}","line":63}}, +// CHECK-NEXT: "name": "F", +// CHECK-NEXT: "fixedUnderlyingType": {"qualType":"short"}, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "EnumConstantDecl", +// CHECK-NEXT: "loc": {"col":3,"file":"{{.*}}","line":61}, +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":61},"end":{"col":3,"file":"{{.*}}","line":61}}, +// CHECK-NEXT: "name": "Five", +// CHECK-NEXT: "type": {"qualType":"F"} +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "EnumConstantDecl", +// CHECK-NEXT: "loc": {"col":3,"file":"{{.*}}","line":62}, +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":62},"end":{"col":3,"file":"{{.*}}","line":62}}, +// CHECK-NEXT: "name": "Six", +// CHECK-NEXT: "type": {"qualType":"F"} +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, + +enum struct G { + Seven, + Eight +}; + +// CHECK: "kind": "EnumDecl", +// CHECK-NEXT: "loc": {"col":13,"file":"{{.*}}","line":90}, +// CHECK-NEXT: "range": {"begin":{"col":1,"file":"{{.*}}","line":90},"end":{"col":1,"file":"{{.*}}","line":93}}, +// CHECK-NEXT: "name": "G", +// CHECK-NEXT: "fixedUnderlyingType": {"qualType":"int"}, +// CHECK-NEXT: "scopedEnumTag": "struct", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "EnumConstantDecl", +// CHECK-NEXT: "loc": {"col":3,"file":"{{.*}}","line":91}, +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":91},"end":{"col":3,"file":"{{.*}}","line":91}}, +// CHECK-NEXT: "name": "Seven", +// CHECK-NEXT: "type": {"qualType":"G"} +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "EnumConstantDecl", +// CHECK-NEXT: "loc": {"col":3,"file":"{{.*}}","line":92}, +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":92},"end":{"col":3,"file":"{{.*}}","line":92}}, +// CHECK-NEXT: "name": "Eight", +// CHECK-NEXT: "type": {"qualType":"G"} +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, + +enum class H { + Nine, + Ten +}; + +// CHECK: "kind": "EnumDecl", +// CHECK-NEXT: "loc": {"col":12,"file":"{{.*}}","line":121}, +// CHECK-NEXT: "range": {"begin":{"col":1,"file":"{{.*}}","line":121},"end":{"col":1,"file":"{{.*}}","line":124}}, +// CHECK-NEXT: "name": "H", +// CHECK-NEXT: "fixedUnderlyingType": {"qualType":"int"}, +// CHECK-NEXT: "scopedEnumTag": "class", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "EnumConstantDecl", +// CHECK-NEXT: "loc": {"col":3,"file":"{{.*}}","line":122}, +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":122},"end":{"col":3,"file":"{{.*}}","line":122}}, +// CHECK-NEXT: "name": "Nine", +// CHECK-NEXT: "type": {"qualType":"H"} +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "EnumConstantDecl", +// CHECK-NEXT: "loc": {"col":3,"file":"{{.*}}","line":123}, +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":123},"end":{"col":3,"file":"{{.*}}","line":123}}, +// CHECK-NEXT: "name": "Ten", +// CHECK-NEXT: "type": {"qualType":"H"} +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, + +enum class I : int { + Eleven, + Twelve +}; + +// CHECK: "kind": "EnumDecl", +// CHECK-NEXT: "loc": {"col":12,"file":"{{.*}}","line":152}, +// CHECK-NEXT: "range": {"begin":{"col":1,"file":"{{.*}}","line":152},"end":{"col":1,"file":"{{.*}}","line":155}}, +// CHECK-NEXT: "name": "I", +// CHECK-NEXT: "fixedUnderlyingType": {"qualType":"int"}, +// CHECK-NEXT: "scopedEnumTag": "class", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "EnumConstantDecl", +// CHECK-NEXT: "loc": {"col":3,"file":"{{.*}}","line":153}, +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":153},"end":{"col":3,"file":"{{.*}}","line":153}}, +// CHECK-NEXT: "name": "Eleven", +// CHECK-NEXT: "type": {"qualType":"I"} +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "EnumConstantDecl", +// CHECK-NEXT: "loc": {"col":3,"file":"{{.*}}","line":154}, +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":154},"end":{"col":3,"file":"{{.*}}","line":154}}, +// CHECK-NEXT: "name": "Twelve", +// CHECK-NEXT: "type": {"qualType":"I"} +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] Index: test/AST/ast-dump-if-json.cpp =================================================================== --- test/AST/ast-dump-if-json.cpp +++ test/AST/ast-dump-if-json.cpp @@ -0,0 +1,360 @@ +// RUN: %clang_cc1 -triple x86_64-pc-linux -std=c++17 -ast-dump=json %s | FileCheck %s + +void func(int val) { + if (val) + ; + +// CHECK: "kind": "IfStmt", +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":4},"end":{"col":5,"file":"{{.*}}","line":5}}, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ImplicitCastExpr", +// CHECK-NEXT: "range": {"begin":{"col":7,"file":"{{.*}}","line":4},"end":{"col":7,"file":"{{.*}}","line":4}}, +// CHECK-NEXT: "type": {"qualType":"bool"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ImplicitCastExpr", +// CHECK-NEXT: "range": {"begin":{"col":7,"file":"{{.*}}","line":4},"end":{"col":7,"file":"{{.*}}","line":4}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "DeclRefExpr", +// CHECK-NEXT: "range": {"begin":{"col":7,"file":"{{.*}}","line":4},"end":{"col":7,"file":"{{.*}}","line":4}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "lvalue" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "NullStmt", +// CHECK-NEXT: "range": {"begin":{"col":5,"file":"{{.*}}","line":5},"end":{"col":5,"file":"{{.*}}","line":5}} +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, + + if (val) + ; + else + ; + +// CHECK: "kind": "IfStmt", +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":43},"end":{"col":5,"file":"{{.*}}","line":46}}, +// CHECK-NEXT: "hasElse": true, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ImplicitCastExpr", +// CHECK-NEXT: "range": {"begin":{"col":7,"file":"{{.*}}","line":43},"end":{"col":7,"file":"{{.*}}","line":43}}, +// CHECK-NEXT: "type": {"qualType":"bool"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ImplicitCastExpr", +// CHECK-NEXT: "range": {"begin":{"col":7,"file":"{{.*}}","line":43},"end":{"col":7,"file":"{{.*}}","line":43}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "DeclRefExpr", +// CHECK-NEXT: "range": {"begin":{"col":7,"file":"{{.*}}","line":43},"end":{"col":7,"file":"{{.*}}","line":43}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "lvalue" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "NullStmt", +// CHECK-NEXT: "range": {"begin":{"col":5,"file":"{{.*}}","line":44},"end":{"col":5,"file":"{{.*}}","line":44}} +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "NullStmt", +// CHECK-NEXT: "range": {"begin":{"col":5,"file":"{{.*}}","line":46},"end":{"col":5,"file":"{{.*}}","line":46}} +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, + + if (val) + ; + else if (val) + ; + else + ; + +// CHECK: "kind": "IfStmt", +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":90},"end":{"col":5,"file":"{{.*}}","line":95}}, +// CHECK-NEXT: "hasElse": true, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ImplicitCastExpr", +// CHECK-NEXT: "range": {"begin":{"col":7,"file":"{{.*}}","line":90},"end":{"col":7,"file":"{{.*}}","line":90}}, +// CHECK-NEXT: "type": {"qualType":"bool"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ImplicitCastExpr", +// CHECK-NEXT: "range": {"begin":{"col":7,"file":"{{.*}}","line":90},"end":{"col":7,"file":"{{.*}}","line":90}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "DeclRefExpr", +// CHECK-NEXT: "range": {"begin":{"col":7,"file":"{{.*}}","line":90},"end":{"col":7,"file":"{{.*}}","line":90}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "lvalue" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "NullStmt", +// CHECK-NEXT: "range": {"begin":{"col":5,"file":"{{.*}}","line":91},"end":{"col":5,"file":"{{.*}}","line":91}} +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "IfStmt", +// CHECK-NEXT: "range": {"begin":{"col":8,"file":"{{.*}}","line":92},"end":{"col":5,"file":"{{.*}}","line":95}}, +// CHECK-NEXT: "hasElse": true, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ImplicitCastExpr", +// CHECK-NEXT: "range": {"begin":{"col":12,"file":"{{.*}}","line":92},"end":{"col":12,"file":"{{.*}}","line":92}}, +// CHECK-NEXT: "type": {"qualType":"bool"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ImplicitCastExpr", +// CHECK-NEXT: "range": {"begin":{"col":12,"file":"{{.*}}","line":92},"end":{"col":12,"file":"{{.*}}","line":92}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "DeclRefExpr", +// CHECK-NEXT: "range": {"begin":{"col":12,"file":"{{.*}}","line":92},"end":{"col":12,"file":"{{.*}}","line":92}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "lvalue" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "NullStmt", +// CHECK-NEXT: "range": {"begin":{"col":5,"file":"{{.*}}","line":93},"end":{"col":5,"file":"{{.*}}","line":93}} +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "NullStmt", +// CHECK-NEXT: "range": {"begin":{"col":5,"file":"{{.*}}","line":95},"end":{"col":5,"file":"{{.*}}","line":95}} +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, + + if constexpr(10 == 10) + ; + +// CHECK: "kind": "IfStmt", +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":177},"end":{"col":5,"file":"{{.*}}","line":178}}, +// CHECK-NEXT: "isConstexpr": true, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ConstantExpr", +// CHECK-NEXT: "range": {"begin":{"col":16,"file":"{{.*}}","line":177},"end":{"col":22,"file":"{{.*}}","line":177}}, +// CHECK-NEXT: "type": {"qualType":"bool"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "BinaryOperator", +// CHECK-NEXT: "range": {"begin":{"col":16,"file":"{{.*}}","line":177},"end":{"col":22,"file":"{{.*}}","line":177}}, +// CHECK-NEXT: "type": {"qualType":"bool"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "opcode": "==", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "IntegerLiteral", +// CHECK-NEXT: "range": {"begin":{"col":16,"file":"{{.*}}","line":177},"end":{"col":16,"file":"{{.*}}","line":177}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "value": "10" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "IntegerLiteral", +// CHECK-NEXT: "range": {"begin":{"col":22,"file":"{{.*}}","line":177},"end":{"col":22,"file":"{{.*}}","line":177}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "value": "10" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "NullStmt", +// CHECK-NEXT: "range": {"begin":{"col":5,"file":"{{.*}}","line":178},"end":{"col":5,"file":"{{.*}}","line":178}} +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, + + if (int i = 12) + ; + +// CHECK: "kind": "IfStmt", +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":227},"end":{"col":5,"file":"{{.*}}","line":228}}, +// CHECK-NEXT: "hasVar": true, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "DeclStmt", +// CHECK-NEXT: "range": {"begin":{"col":7,"file":"{{.*}}","line":227},"end":{"col":15,"file":"{{.*}}","line":227}}, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "VarDecl", +// CHECK-NEXT: "loc": {"col":11,"file":"{{.*}}","line":227}, +// CHECK-NEXT: "range": {"begin":{"col":7,"file":"{{.*}}","line":227},"end":{"col":15,"file":"{{.*}}","line":227}}, +// CHECK-NEXT: "isUsed": true, +// CHECK-NEXT: "name": "i", +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "init": "c", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "IntegerLiteral", +// CHECK-NEXT: "range": {"begin":{"col":15,"file":"{{.*}}","line":227},"end":{"col":15,"file":"{{.*}}","line":227}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "value": "12" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ImplicitCastExpr", +// CHECK-NEXT: "range": {"begin":{"col":11,"file":"{{.*}}","line":227},"end":{"col":11,"file":"{{.*}}","line":227}}, +// CHECK-NEXT: "type": {"qualType":"bool"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ImplicitCastExpr", +// CHECK-NEXT: "range": {"begin":{"col":11,"file":"{{.*}}","line":227},"end":{"col":11,"file":"{{.*}}","line":227}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "DeclRefExpr", +// CHECK-NEXT: "range": {"begin":{"col":11,"file":"{{.*}}","line":227},"end":{"col":11,"file":"{{.*}}","line":227}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "lvalue" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "NullStmt", +// CHECK-NEXT: "range": {"begin":{"col":5,"file":"{{.*}}","line":228},"end":{"col":5,"file":"{{.*}}","line":228}} +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, + + if (int i = 12; i) + ; + +// CHECK: "kind": "IfStmt", +// CHECK-NEXT: "range": {"begin":{"col":3,"file":"{{.*}}","line":294},"end":{"col":5,"file":"{{.*}}","line":295}}, +// CHECK-NEXT: "hasInit": true, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "DeclStmt", +// CHECK-NEXT: "range": {"begin":{"col":7,"file":"{{.*}}","line":294},"end":{"col":17,"file":"{{.*}}","line":294}}, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "VarDecl", +// CHECK-NEXT: "loc": {"col":11,"file":"{{.*}}","line":294}, +// CHECK-NEXT: "range": {"begin":{"col":7,"file":"{{.*}}","line":294},"end":{"col":15,"file":"{{.*}}","line":294}}, +// CHECK-NEXT: "isUsed": true, +// CHECK-NEXT: "name": "i", +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "init": "c", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "IntegerLiteral", +// CHECK-NEXT: "range": {"begin":{"col":15,"file":"{{.*}}","line":294},"end":{"col":15,"file":"{{.*}}","line":294}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "value": "12" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ImplicitCastExpr", +// CHECK-NEXT: "range": {"begin":{"col":19,"file":"{{.*}}","line":294},"end":{"col":19,"file":"{{.*}}","line":294}}, +// CHECK-NEXT: "type": {"qualType":"bool"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ImplicitCastExpr", +// CHECK-NEXT: "range": {"begin":{"col":19,"file":"{{.*}}","line":294},"end":{"col":19,"file":"{{.*}}","line":294}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "DeclRefExpr", +// CHECK-NEXT: "range": {"begin":{"col":19,"file":"{{.*}}","line":294},"end":{"col":19,"file":"{{.*}}","line":294}}, +// CHECK-NEXT: "type": {"qualType":"int"}, +// CHECK-NEXT: "valueCategory": "lvalue" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "NullStmt", +// CHECK-NEXT: "range": {"begin":{"col":5,"file":"{{.*}}","line":295},"end":{"col":5,"file":"{{.*}}","line":295}} +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +} Index: tools/clang-check/ClangCheck.cpp =================================================================== --- tools/clang-check/ClangCheck.cpp +++ tools/clang-check/ClangCheck.cpp @@ -134,11 +134,11 @@ if (ASTList) return clang::CreateASTDeclNodeLister(); if (ASTDump) - return clang::CreateASTDumper(nullptr /*Dump to stdout.*/, - ASTDumpFilter, + return clang::CreateASTDumper(nullptr /*Dump to stdout.*/, ASTDumpFilter, /*DumpDecls=*/true, /*Deserialize=*/false, - /*DumpLookups=*/false); + /*DumpLookups=*/false, + clang::FrontendOptions::AOF_Default); if (ASTPrint) return clang::CreateASTPrinter(nullptr, ASTDumpFilter); return llvm::make_unique(); Index: tools/clang-import-test/clang-import-test.cpp =================================================================== --- tools/clang-import-test/clang-import-test.cpp +++ tools/clang-import-test/clang-import-test.cpp @@ -316,8 +316,9 @@ auto &CG = *static_cast(ASTConsumers.back().get()); if (ShouldDumpAST) - ASTConsumers.push_back(CreateASTDumper(nullptr /*Dump to stdout.*/, - "", true, false, false)); + ASTConsumers.push_back( + CreateASTDumper(nullptr /*Dump to stdout.*/, "", true, false, false, + clang::FrontendOptions::AOF_Default)); CI.getDiagnosticClient().BeginSourceFile( CI.getCompilerInstance().getLangOpts(),