r360622 - Introduce the ability to dump the AST to JSON.

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Mon May 13 14:39:55 PDT 2019


Author: aaronballman
Date: Mon May 13 14:39:55 2019
New Revision: 360622

URL: http://llvm.org/viewvc/llvm-project?rev=360622&view=rev
Log:
Introduce the ability to dump the AST to JSON.

This adds the -ast-dump=json cc1 flag (in addition to -ast-dump=default, which is the default if no dump format is specified), as well as some initial AST dumping functionality and tests.

Added:
    cfe/trunk/include/clang/AST/JSONNodeDumper.h
    cfe/trunk/lib/AST/JSONNodeDumper.cpp
    cfe/trunk/test/AST/ast-dump-enum-json.cpp
    cfe/trunk/test/AST/ast-dump-if-json.cpp
    cfe/trunk/test/AST/ast-dump-namespace-json.cpp
Modified:
    cfe/trunk/include/clang/AST/ASTDumperUtils.h
    cfe/trunk/include/clang/AST/DeclBase.h
    cfe/trunk/include/clang/Driver/CC1Options.td
    cfe/trunk/include/clang/Frontend/ASTConsumers.h
    cfe/trunk/include/clang/Frontend/FrontendOptions.h
    cfe/trunk/lib/AST/ASTDumper.cpp
    cfe/trunk/lib/AST/CMakeLists.txt
    cfe/trunk/lib/Frontend/ASTConsumers.cpp
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Frontend/FrontendActions.cpp
    cfe/trunk/tools/clang-check/ClangCheck.cpp
    cfe/trunk/tools/clang-import-test/clang-import-test.cpp

Modified: cfe/trunk/include/clang/AST/ASTDumperUtils.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTDumperUtils.h?rev=360622&r1=360621&r2=360622&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTDumperUtils.h (original)
+++ cfe/trunk/include/clang/AST/ASTDumperUtils.h Mon May 13 14:39:55 2019
@@ -17,6 +17,12 @@
 
 namespace clang {
 
+/// Used to specify the format for printing AST dump information.
+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.
 

Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=360622&r1=360621&r2=360622&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Mon May 13 14:39:55 2019
@@ -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"
@@ -1134,7 +1135,8 @@ public:
   // 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;

Added: cfe/trunk/include/clang/AST/JSONNodeDumper.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/JSONNodeDumper.h?rev=360622&view=auto
==============================================================================
--- cfe/trunk/include/clang/AST/JSONNodeDumper.h (added)
+++ cfe/trunk/include/clang/AST/JSONNodeDumper.h Mon May 13 14:39:55 2019
@@ -0,0 +1,330 @@
+//===--- 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 ConstTemplateArgumentVisitor<JSONNodeDumper>,
+      public ConstStmtVisitor<JSONNodeDumper>,
+      public TypeVisitor<JSONNodeDumper>,
+      public ConstDeclVisitor<JSONNodeDumper>,
+      public NodeStreamer {
+  friend class JSONDumper;
+
+  raw_ostream &OS;
+  const SourceManager &SM;
+  PrintingPolicy PrintPolicy;
+
+  using InnerAttrVisitor = ConstAttrVisitor<JSONNodeDumper>;
+  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);
+  }
+
+  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);
+  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);
+
+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 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 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 VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *ULE);
+  void VisitAddrLabelExpr(const AddrLabelExpr *ALE);
+
+  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);
+};
+
+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.JOS.value(NodeDumper.createBareDeclRef(Redecl));
+        else
+          // FIXME: this isn't quite right -- we want to call Visit() rather
+          // than NodeDumper.Visit() but that causes issues because it attempts
+          // to create a new array of child objects due to calling AddChild(),
+          // which messes up the JSON creation.
+          NodeDumper.JOS.object([this, Redecl] { NodeDumper.Visit(Redecl); });
+        DumpedAny = true;
+        break;
+      case TSK_ExplicitSpecialization:
+        break;
+      }
+    }
+
+    // Ensure we dump at least one decl for each specialization.
+    if (!DumpedAny)
+      NodeDumper.JOS.value(NodeDumper.createBareDeclRef(SD));
+  }
+
+  template <typename TemplateDecl>
+  void writeTemplateDecl(const TemplateDecl *TD, bool DumpExplicitInst) {
+    if (const TemplateParameterList *TPL = TD->getTemplateParameters()) {
+      NodeDumper.JOS.attributeArray("templateParams", [this, TPL] {
+        for (const auto &TP : *TPL) {
+          NodeDumper.JOS.object([this, TP] { NodeDumper.Visit(TP); });
+        }
+      });
+    }
+
+    Visit(TD->getTemplatedDecl());
+
+    auto spec_range = TD->specializations();
+    if (!llvm::empty(spec_range)) {
+      NodeDumper.JOS.attributeArray(
+          "specializations", [this, spec_range, TD, DumpExplicitInst] {
+            for (const auto *Child : spec_range)
+              writeTemplateDeclSpecialization(Child, DumpExplicitInst,
+                                              !TD->isCanonicalDecl());
+          });
+    }
+  }
+
+public:
+  JSONDumper(raw_ostream &OS, const SourceManager &SrcMgr,
+             const PrintingPolicy &PrintPolicy)
+      : NodeDumper(OS, SrcMgr, PrintPolicy) {}
+
+  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

Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=360622&r1=360621&r2=360622&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Mon May 13 14:39:55 2019
@@ -557,8 +557,14 @@ def ast_list : Flag<["-"], "ast-list">,
   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">,

Modified: cfe/trunk/include/clang/Frontend/ASTConsumers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/ASTConsumers.h?rev=360622&r1=360621&r2=360622&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/ASTConsumers.h (original)
+++ cfe/trunk/include/clang/Frontend/ASTConsumers.h Mon May 13 14:39:55 2019
@@ -13,6 +13,7 @@
 #ifndef LLVM_CLANG_FRONTEND_ASTCONSUMERS_H
 #define LLVM_CLANG_FRONTEND_ASTCONSUMERS_H
 
+#include "clang/AST/ASTDumperUtils.h"
 #include "clang/Basic/LLVM.h"
 #include <memory>
 
@@ -35,10 +36,10 @@ std::unique_ptr<ASTConsumer> CreateASTPr
 
 // AST dumper: dumps the raw AST in human-readable form to the given output
 // stream, or stdout if OS is nullptr.
-std::unique_ptr<ASTConsumer> CreateASTDumper(std::unique_ptr<raw_ostream> OS,
-                                             StringRef FilterString,
-                                             bool DumpDecls, bool Deserialize,
-                                             bool DumpLookups);
+std::unique_ptr<ASTConsumer>
+CreateASTDumper(std::unique_ptr<raw_ostream> OS, StringRef FilterString,
+                bool DumpDecls, bool Deserialize, bool DumpLookups,
+                ASTDumpOutputFormat Format);
 
 // AST Decl node lister: prints qualified names of all filterable AST Decl
 // nodes.

Modified: cfe/trunk/include/clang/Frontend/FrontendOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendOptions.h?rev=360622&r1=360621&r2=360622&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendOptions.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendOptions.h Mon May 13 14:39:55 2019
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_FRONTEND_FRONTENDOPTIONS_H
 #define LLVM_CLANG_FRONTEND_FRONTENDOPTIONS_H
 
+#include "clang/AST/ASTDumperUtils.h"
 #include "clang/Frontend/CommandLineSourceLoc.h"
 #include "clang/Serialization/ModuleFileExtension.h"
 #include "clang/Sema/CodeCompleteOptions.h"
@@ -307,6 +308,9 @@ public:
 
   CodeCompleteOptions CodeCompleteOpts;
 
+  /// Specifies the output format of the AST.
+  ASTDumpOutputFormat ASTDumpFormat = ADOF_Default;
+
   enum {
     ARCMT_None,
     ARCMT_Check,

Modified: cfe/trunk/lib/AST/ASTDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=360622&r1=360621&r2=360622&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTDumper.cpp (original)
+++ cfe/trunk/lib/AST/ASTDumper.cpp Mon May 13 14:39:55 2019
@@ -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 Type::dump(llvm::r
 
 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 {

Modified: cfe/trunk/lib/AST/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CMakeLists.txt?rev=360622&r1=360621&r2=360622&view=diff
==============================================================================
--- cfe/trunk/lib/AST/CMakeLists.txt (original)
+++ cfe/trunk/lib/AST/CMakeLists.txt Mon May 13 14:39:55 2019
@@ -44,6 +44,7 @@ add_clang_library(clangAST
   InheritViz.cpp
   ItaniumCXXABI.cpp
   ItaniumMangle.cpp
+  JSONNodeDumper.cpp
   Mangle.cpp
   MicrosoftCXXABI.cpp
   MicrosoftMangle.cpp

Added: cfe/trunk/lib/AST/JSONNodeDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/JSONNodeDumper.cpp?rev=360622&view=auto
==============================================================================
--- cfe/trunk/lib/AST/JSONNodeDumper.cpp (added)
+++ cfe/trunk/lib/AST/JSONNodeDumper.cpp Mon May 13 14:39:55 2019
@@ -0,0 +1,781 @@
+#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<DERIVED##Decl>(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
+  }
+  JOS.attribute("id", createPointerRepresentation(A));
+  JOS.attribute("kind", AttrName);
+  JOS.attribute("range", createSourceRange(A->getRange()));
+  attributeOnlyIfTrue("inherited", A->isInherited());
+  attributeOnlyIfTrue("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.
+  //JOS.attribute("spelling", A->getSpelling());
+
+  InnerAttrVisitor::Visit(A);
+}
+
+void JSONNodeDumper::Visit(const Stmt *S) {
+  if (!S)
+    return;
+
+  JOS.attribute("id", createPointerRepresentation(S));
+  JOS.attribute("kind", S->getStmtClassName());
+  JOS.attribute("range", createSourceRange(S->getSourceRange()));
+
+  if (const auto *E = dyn_cast<Expr>(S)) {
+    JOS.attribute("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;
+    }
+    JOS.attribute("valueCategory", Category);
+  }
+  InnerStmtVisitor::Visit(S);
+}
+
+void JSONNodeDumper::Visit(const Type *T) {
+  JOS.attribute("id", createPointerRepresentation(T));
+  JOS.attribute("kind", (llvm::Twine(T->getTypeClassName()) + "Type").str());
+  JOS.attribute("type", createQualType(QualType(T, 0), /*Desugar*/ false));
+  attributeOnlyIfTrue("isDependent", T->isDependentType());
+  attributeOnlyIfTrue("isInstantiationDependent",
+                      T->isInstantiationDependentType());
+  attributeOnlyIfTrue("isVariablyModified", T->isVariablyModifiedType());
+  attributeOnlyIfTrue("containsUnexpandedPack",
+                      T->containsUnexpandedParameterPack());
+  attributeOnlyIfTrue("isImported", T->isFromAST());
+  InnerTypeVisitor::Visit(T);
+}
+
+void JSONNodeDumper::Visit(QualType T) {
+  JOS.attribute("id", createPointerRepresentation(T.getAsOpaquePtr()));
+  JOS.attribute("type", createQualType(T));
+  JOS.attribute("qualifiers", T.split().Quals.getAsString());
+}
+
+void JSONNodeDumper::Visit(const Decl *D) {
+  JOS.attribute("id", createPointerRepresentation(D));
+
+  if (!D)
+    return;
+
+  JOS.attribute("kind", (llvm::Twine(D->getDeclKindName()) + "Decl").str());
+  JOS.attribute("loc", createSourceLocation(D->getLocation()));
+  JOS.attribute("range", createSourceRange(D->getSourceRange()));
+  attributeOnlyIfTrue("isImplicit", D->isImplicit());
+  attributeOnlyIfTrue("isInvalid", D->isInvalidDecl());
+
+  if (D->isUsed())
+    JOS.attribute("isUsed", true);
+  else if (D->isThisDeclarationReferenced())
+    JOS.attribute("isReferenced", true);
+
+  if (const auto *ND = dyn_cast<NamedDecl>(D))
+    attributeOnlyIfTrue("isHidden", ND->isHidden());
+
+  if (D->getLexicalDeclContext() != D->getDeclContext())
+    JOS.attribute("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) {
+  JOS.attribute("kind", "TemplateArgument");
+  if (R.isValid())
+    JOS.attribute("range", createSourceRange(R));
+
+  if (From)
+    JOS.attribute(Label.empty() ? "fromDecl" : Label, createBareDeclRef(From));
+
+  InnerTemplateArgVisitor::Visit(TA);
+}
+
+void JSONNodeDumper::Visit(const CXXCtorInitializer *Init) {
+  JOS.attribute("kind", "CXXCtorInitializer");
+  if (Init->isAnyMemberInitializer())
+    JOS.attribute("anyInit", createBareDeclRef(Init->getAnyMember()));
+  else if (Init->isBaseInitializer())
+    JOS.attribute("baseInit",
+                  createQualType(QualType(Init->getBaseClass(), 0)));
+  else if (Init->isDelegatingInitializer())
+    JOS.attribute("delegatingInit",
+                  createQualType(Init->getTypeSourceInfo()->getType()));
+  else
+    llvm_unreachable("Unknown initializer type");
+}
+
+void JSONNodeDumper::Visit(const OMPClause *C) {}
+void JSONNodeDumper::Visit(const BlockDecl::Capture &C) {}
+void JSONNodeDumper::Visit(const GenericSelectionExpr::ConstAssociation &A) {
+  JOS.attribute("associationKind", A.getTypeSourceInfo() ? "case" : "default");
+  attributeOnlyIfTrue("selected", A.isSelected());
+}
+
+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<uint64_t>(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<NamedDecl>(D))
+    Ret["name"] = ND->getDeclName().getAsString();
+  if (const auto *VD = dyn_cast<ValueDecl>(D))
+    Ret["type"] = createQualType(VD->getType());
+  return Ret;
+}
+
+llvm::json::Array JSONNodeDumper::createCastPath(const CastExpr *C) {
+  llvm::json::Array Ret;
+  if (C->path_empty())
+    return Ret;
+
+  for (auto I = C->path_begin(), E = C->path_end(); I != E; ++I) {
+    const CXXBaseSpecifier *Base = *I;
+    const auto *RD =
+        cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+
+    llvm::json::Object Val{{"name", RD->getName()}};
+    if (Base->isVirtual())
+      Val["isVirtual"] = true;
+    Ret.push_back(std::move(Val));
+  }
+  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) {
+  JOS.attribute("decl", createBareDeclRef(TT->getDecl()));
+}
+
+void JSONNodeDumper::VisitFunctionType(const FunctionType *T) {
+  FunctionType::ExtInfo E = T->getExtInfo();
+  attributeOnlyIfTrue("noreturn", E.getNoReturn());
+  attributeOnlyIfTrue("producesResult", E.getProducesResult());
+  if (E.getHasRegParm())
+    JOS.attribute("regParm", E.getRegParm());
+  JOS.attribute("cc", FunctionType::getNameForCallConv(E.getCC()));
+}
+
+void JSONNodeDumper::VisitFunctionProtoType(const FunctionProtoType *T) {
+  FunctionProtoType::ExtProtoInfo E = T->getExtProtoInfo();
+  attributeOnlyIfTrue("trailingReturn", E.HasTrailingReturn);
+  attributeOnlyIfTrue("const", T->isConst());
+  attributeOnlyIfTrue("volatile", T->isVolatile());
+  attributeOnlyIfTrue("restrict", T->isRestrict());
+  attributeOnlyIfTrue("variadic", E.Variadic);
+  switch (E.RefQualifier) {
+  case RQ_LValue: JOS.attribute("refQualifier", "&"); break;
+  case RQ_RValue: JOS.attribute("refQualifier", "&&"); break;
+  case RQ_None: break;
+  }
+  switch (E.ExceptionSpec.Type) {
+  case EST_DynamicNone:
+  case EST_Dynamic: {
+    JOS.attribute("exceptionSpec", "throw");
+    llvm::json::Array Types;
+    for (QualType QT : E.ExceptionSpec.Exceptions)
+      Types.push_back(createQualType(QT));
+    JOS.attribute("exceptionTypes", std::move(Types));
+  } break;
+  case EST_MSAny:
+    JOS.attribute("exceptionSpec", "throw");
+    JOS.attribute("throwsAny", true);
+    break;
+  case EST_BasicNoexcept:
+    JOS.attribute("exceptionSpec", "noexcept");
+    break;
+  case EST_NoexceptTrue:
+  case EST_NoexceptFalse:
+    JOS.attribute("exceptionSpec", "noexcept");
+    JOS.attribute("conditionEvaluatesTo",
+                E.ExceptionSpec.Type == EST_NoexceptTrue);
+    //JOS.attributeWithCall("exceptionSpecExpr",
+    //                    [this, E]() { Visit(E.ExceptionSpec.NoexceptExpr); });
+    break;
+
+  // FIXME: I cannot find a way to trigger these cases while dumping the AST. I
+  // suspect you can only run into them when executing an AST dump from within
+  // the debugger, which is not a use case we worry about for the JSON dumping
+  // feature.
+  case EST_DependentNoexcept:
+  case EST_Unevaluated:
+  case EST_Uninstantiated:
+  case EST_Unparsed:
+  case EST_None: break;
+  }
+  VisitFunctionType(T);
+}
+
+void JSONNodeDumper::VisitNamedDecl(const NamedDecl *ND) {
+  if (ND && ND->getDeclName())
+    JOS.attribute("name", ND->getNameAsString());
+}
+
+void JSONNodeDumper::VisitTypedefDecl(const TypedefDecl *TD) {
+  VisitNamedDecl(TD);
+  JOS.attribute("type", createQualType(TD->getUnderlyingType()));
+}
+
+void JSONNodeDumper::VisitTypeAliasDecl(const TypeAliasDecl *TAD) {
+  VisitNamedDecl(TAD);
+  JOS.attribute("type", createQualType(TAD->getUnderlyingType()));
+}
+
+void JSONNodeDumper::VisitNamespaceDecl(const NamespaceDecl *ND) {
+  VisitNamedDecl(ND);
+  attributeOnlyIfTrue("isInline", ND->isInline());
+  if (!ND->isOriginalNamespace())
+    JOS.attribute("originalNamespace",
+                  createBareDeclRef(ND->getOriginalNamespace()));
+}
+
+void JSONNodeDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *UDD) {
+  JOS.attribute("nominatedNamespace",
+                createBareDeclRef(UDD->getNominatedNamespace()));
+}
+
+void JSONNodeDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD) {
+  VisitNamedDecl(NAD);
+  JOS.attribute("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();
+  JOS.attribute("name", Name);
+}
+
+void JSONNodeDumper::VisitUsingShadowDecl(const UsingShadowDecl *USD) {
+  JOS.attribute("target", createBareDeclRef(USD->getTargetDecl()));
+}
+
+void JSONNodeDumper::VisitVarDecl(const VarDecl *VD) {
+  VisitNamedDecl(VD);
+  JOS.attribute("type", createQualType(VD->getType()));
+
+  StorageClass SC = VD->getStorageClass();
+  if (SC != SC_None)
+    JOS.attribute("storageClass", VarDecl::getStorageClassSpecifierString(SC));
+  switch (VD->getTLSKind()) {
+  case VarDecl::TLS_Dynamic: JOS.attribute("tls", "dynamic"); break;
+  case VarDecl::TLS_Static: JOS.attribute("tls", "static"); break;
+  case VarDecl::TLS_None: break;
+  }
+  attributeOnlyIfTrue("nrvo", VD->isNRVOVariable());
+  attributeOnlyIfTrue("inline", VD->isInline());
+  attributeOnlyIfTrue("constexpr", VD->isConstexpr());
+  attributeOnlyIfTrue("modulePrivate", VD->isModulePrivate());
+  if (VD->hasInit()) {
+    switch (VD->getInitStyle()) {
+    case VarDecl::CInit: JOS.attribute("init", "c");  break;
+    case VarDecl::CallInit: JOS.attribute("init", "call"); break;
+    case VarDecl::ListInit: JOS.attribute("init", "list"); break;
+    }
+  }
+}
+
+void JSONNodeDumper::VisitFieldDecl(const FieldDecl *FD) {
+  VisitNamedDecl(FD);
+  JOS.attribute("type", createQualType(FD->getType()));
+  attributeOnlyIfTrue("mutable", FD->isMutable());
+  attributeOnlyIfTrue("modulePrivate", FD->isModulePrivate());
+  attributeOnlyIfTrue("isBitfield", FD->isBitField());
+  attributeOnlyIfTrue("hasInClassInitializer", FD->hasInClassInitializer());
+}
+
+void JSONNodeDumper::VisitFunctionDecl(const FunctionDecl *FD) {
+  VisitNamedDecl(FD);
+  JOS.attribute("type", createQualType(FD->getType()));
+  StorageClass SC = FD->getStorageClass();
+  if (SC != SC_None)
+    JOS.attribute("storageClass", VarDecl::getStorageClassSpecifierString(SC));
+  attributeOnlyIfTrue("inline", FD->isInlineSpecified());
+  attributeOnlyIfTrue("virtual", FD->isVirtualAsWritten());
+  attributeOnlyIfTrue("pure", FD->isPure());
+  attributeOnlyIfTrue("explicitlyDeleted", FD->isDeletedAsWritten());
+  attributeOnlyIfTrue("constexpr", FD->isConstexpr());
+  if (FD->isDefaulted())
+    JOS.attribute("explicitlyDefaulted",
+                  FD->isDeleted() ? "deleted" : "default");
+}
+
+void JSONNodeDumper::VisitEnumDecl(const EnumDecl *ED) {
+  VisitNamedDecl(ED);
+  if (ED->isFixed())
+    JOS.attribute("fixedUnderlyingType", createQualType(ED->getIntegerType()));
+  if (ED->isScoped())
+    JOS.attribute("scopedEnumTag",
+                  ED->isScopedUsingClassTag() ? "class" : "struct");
+}
+void JSONNodeDumper::VisitEnumConstantDecl(const EnumConstantDecl *ECD) {
+  VisitNamedDecl(ECD);
+  JOS.attribute("type", createQualType(ECD->getType()));
+}
+
+void JSONNodeDumper::VisitRecordDecl(const RecordDecl *RD) {
+  VisitNamedDecl(RD);
+  JOS.attribute("tagUsed", RD->getKindName());
+  attributeOnlyIfTrue("completeDefinition", RD->isCompleteDefinition());
+}
+void JSONNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *RD) {
+  VisitRecordDecl(RD);
+
+  // All other information requires a complete definition.
+  if (!RD->isCompleteDefinition())
+    return;
+
+  JOS.attribute("definitionData", createCXXRecordDefinitionData(RD));
+  if (RD->getNumBases()) {
+    JOS.attributeArray("bases", [this, RD] {
+      for (const auto &Spec : RD->bases())
+        JOS.value(createCXXBaseSpecifier(Spec));
+    });
+  }
+}
+
+void JSONNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
+  VisitNamedDecl(D);
+  JOS.attribute("tagUsed", D->wasDeclaredWithTypename() ? "typename" : "class");
+  JOS.attribute("depth", D->getDepth());
+  JOS.attribute("index", D->getIndex());
+  attributeOnlyIfTrue("isParameterPack", D->isParameterPack());
+}
+
+void JSONNodeDumper::VisitNonTypeTemplateParmDecl(
+    const NonTypeTemplateParmDecl *D) {
+  VisitNamedDecl(D);
+  JOS.attribute("type", createQualType(D->getType()));
+  JOS.attribute("depth", D->getDepth());
+  JOS.attribute("index", D->getIndex());
+  attributeOnlyIfTrue("isParameterPack", D->isParameterPack());
+}
+
+void JSONNodeDumper::VisitTemplateTemplateParmDecl(
+    const TemplateTemplateParmDecl *D) {
+  VisitNamedDecl(D);
+  JOS.attribute("depth", D->getDepth());
+  JOS.attribute("index", D->getIndex());
+  attributeOnlyIfTrue("isParameterPack", D->isParameterPack());
+}
+
+void JSONNodeDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *LSD) {
+  StringRef Lang;
+  switch (LSD->getLanguage()) {
+  case LinkageSpecDecl::lang_c: Lang = "C"; break;
+  case LinkageSpecDecl::lang_cxx: Lang = "C++"; break;
+  }
+  JOS.attribute("language", Lang);
+  attributeOnlyIfTrue("hasBraces", LSD->hasBraces());
+}
+
+void JSONNodeDumper::VisitAccessSpecDecl(const AccessSpecDecl *ASD) {
+  JOS.attribute("access", createAccessSpecifier(ASD->getAccess()));
+}
+
+void JSONNodeDumper::VisitFriendDecl(const FriendDecl *FD) {
+  if (const TypeSourceInfo *T = FD->getFriendType())
+    JOS.attribute("type", createQualType(T->getType()));
+}
+
+void JSONNodeDumper::VisitDeclRefExpr(const DeclRefExpr *DRE) {
+  JOS.attribute("referencedDecl", createBareDeclRef(DRE->getDecl()));
+  if (DRE->getDecl() != DRE->getFoundDecl())
+    JOS.attribute("foundReferencedDecl",
+                  createBareDeclRef(DRE->getFoundDecl()));
+}
+
+void JSONNodeDumper::VisitPredefinedExpr(const PredefinedExpr *PE) {
+  JOS.attribute("name", PredefinedExpr::getIdentKindName(PE->getIdentKind()));
+}
+
+void JSONNodeDumper::VisitUnaryOperator(const UnaryOperator *UO) {
+  JOS.attribute("isPostfix", UO->isPostfix());
+  JOS.attribute("opcode", UnaryOperator::getOpcodeStr(UO->getOpcode()));
+  if (!UO->canOverflow())
+    JOS.attribute("canOverflow", false);
+}
+
+void JSONNodeDumper::VisitBinaryOperator(const BinaryOperator *BO) {
+  JOS.attribute("opcode", BinaryOperator::getOpcodeStr(BO->getOpcode()));
+}
+
+void JSONNodeDumper::VisitCompoundAssignOperator(
+    const CompoundAssignOperator *CAO) {
+  VisitBinaryOperator(CAO);
+  JOS.attribute("computeLHSType", createQualType(CAO->getComputationLHSType()));
+  JOS.attribute("computeResultType",
+                createQualType(CAO->getComputationResultType()));
+}
+
+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.
+  JOS.attribute("isArrow", ME->isArrow());
+  JOS.attribute("referencedMemberDecl",
+                createPointerRepresentation(ME->getMemberDecl()));
+}
+
+void JSONNodeDumper::VisitCXXNewExpr(const CXXNewExpr *NE) {
+  attributeOnlyIfTrue("isGlobal", NE->isGlobalNew());
+  attributeOnlyIfTrue("isArray", NE->isArray());
+  attributeOnlyIfTrue("isPlacement", NE->getNumPlacementArgs() != 0);
+  switch (NE->getInitializationStyle()) {
+  case CXXNewExpr::NoInit: break;
+  case CXXNewExpr::CallInit: JOS.attribute("initStyle", "call"); break;
+  case CXXNewExpr::ListInit: JOS.attribute("initStyle", "list"); break;
+  }
+  if (const FunctionDecl *FD = NE->getOperatorNew())
+    JOS.attribute("operatorNewDecl", createBareDeclRef(FD));
+  if (const FunctionDecl *FD = NE->getOperatorDelete())
+    JOS.attribute("operatorDeleteDecl", createBareDeclRef(FD));
+}
+void JSONNodeDumper::VisitCXXDeleteExpr(const CXXDeleteExpr *DE) {
+  attributeOnlyIfTrue("isGlobal", DE->isGlobalDelete());
+  attributeOnlyIfTrue("isArray", DE->isArrayForm());
+  attributeOnlyIfTrue("isArrayAsWritten", DE->isArrayFormAsWritten());
+  if (const FunctionDecl *FD = DE->getOperatorDelete())
+    JOS.attribute("operatorDeleteDecl", createBareDeclRef(FD));
+}
+
+void JSONNodeDumper::VisitCXXThisExpr(const CXXThisExpr *TE) {
+  attributeOnlyIfTrue("implicit", TE->isImplicit());
+}
+
+void JSONNodeDumper::VisitCastExpr(const CastExpr *CE) {
+  JOS.attribute("castKind", CE->getCastKindName());
+  llvm::json::Array Path = createCastPath(CE);
+  if (!Path.empty())
+    JOS.attribute("path", std::move(Path));
+  // FIXME: This may not be useful information as it can be obtusely gleaned
+  // from the inner[] array.
+  if (const NamedDecl *ND = CE->getConversionFunction())
+    JOS.attribute("conversionFunc", createBareDeclRef(ND));
+}
+
+void JSONNodeDumper::VisitImplicitCastExpr(const ImplicitCastExpr *ICE) {
+  VisitCastExpr(ICE);
+  attributeOnlyIfTrue("isPartOfExplicitCast", ICE->isPartOfExplicitCast());
+}
+
+void JSONNodeDumper::VisitCallExpr(const CallExpr *CE) {
+  attributeOnlyIfTrue("adl", CE->usesADL());
+}
+
+void JSONNodeDumper::VisitUnaryExprOrTypeTraitExpr(
+    const UnaryExprOrTypeTraitExpr *TTE) {
+  switch (TTE->getKind()) {
+  case UETT_SizeOf: JOS.attribute("name", "sizeof"); break;
+  case UETT_AlignOf: JOS.attribute("name", "alignof"); break;
+  case UETT_VecStep:  JOS.attribute("name", "vec_step"); break;
+  case UETT_PreferredAlignOf:  JOS.attribute("name", "__alignof"); break;
+  case UETT_OpenMPRequiredSimdAlign:
+    JOS.attribute("name", "__builtin_omp_required_simd_align"); break;
+  }
+  if (TTE->isArgumentType())
+    JOS.attribute("argType", createQualType(TTE->getArgumentType()));
+}
+
+void JSONNodeDumper::VisitUnresolvedLookupExpr(
+    const UnresolvedLookupExpr *ULE) {
+  JOS.attribute("usesADL", ULE->requiresADL());
+  JOS.attribute("name", ULE->getName().getAsString());
+
+  JOS.attributeArray("lookups", [this, ULE] {
+    for (const NamedDecl *D : ULE->decls())
+      JOS.value(createBareDeclRef(D));
+  });
+}
+
+void JSONNodeDumper::VisitAddrLabelExpr(const AddrLabelExpr *ALE) {
+  JOS.attribute("name", ALE->getLabel()->getName());
+  JOS.attribute("labelDeclId", createPointerRepresentation(ALE->getLabel()));
+}
+
+void JSONNodeDumper::VisitIntegerLiteral(const IntegerLiteral *IL) {
+  JOS.attribute("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.
+  JOS.attribute("value", CL->getValue());
+}
+void JSONNodeDumper::VisitFixedPointLiteral(const FixedPointLiteral *FPL) {
+  JOS.attribute("value", FPL->getValueAsString(/*Radix=*/10));
+}
+void JSONNodeDumper::VisitFloatingLiteral(const FloatingLiteral *FL) {
+  JOS.attribute("value", FL->getValueAsApproximateDouble());
+}
+void JSONNodeDumper::VisitStringLiteral(const StringLiteral *SL) {
+  std::string Buffer;
+  llvm::raw_string_ostream SS(Buffer);
+  SL->outputString(SS);
+  JOS.attribute("value", SS.str());
+}
+void JSONNodeDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *BLE) {
+  JOS.attribute("value", BLE->getValue());
+}
+
+void JSONNodeDumper::VisitIfStmt(const IfStmt *IS) {
+  attributeOnlyIfTrue("hasInit", IS->hasInitStorage());
+  attributeOnlyIfTrue("hasVar", IS->hasVarStorage());
+  attributeOnlyIfTrue("hasElse", IS->hasElseStorage());
+  attributeOnlyIfTrue("isConstexpr", IS->isConstexpr());
+}
+
+void JSONNodeDumper::VisitSwitchStmt(const SwitchStmt *SS) {
+  attributeOnlyIfTrue("hasInit", SS->hasInitStorage());
+  attributeOnlyIfTrue("hasVar", SS->hasVarStorage());
+}
+void JSONNodeDumper::VisitCaseStmt(const CaseStmt *CS) {
+  attributeOnlyIfTrue("isGNURange", CS->caseStmtIsGNURange());
+}
+
+void JSONNodeDumper::VisitLabelStmt(const LabelStmt *LS) {
+  JOS.attribute("name", LS->getName());
+  JOS.attribute("declId", createPointerRepresentation(LS->getDecl()));
+}
+void JSONNodeDumper::VisitGotoStmt(const GotoStmt *GS) {
+  JOS.attribute("targetLabelDeclId",
+                createPointerRepresentation(GS->getLabel()));
+}
+
+void JSONNodeDumper::VisitWhileStmt(const WhileStmt *WS) {
+  attributeOnlyIfTrue("hasVar", WS->hasVarStorage());
+}

Modified: cfe/trunk/lib/Frontend/ASTConsumers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTConsumers.cpp?rev=360622&r1=360621&r2=360622&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/ASTConsumers.cpp (original)
+++ cfe/trunk/lib/Frontend/ASTConsumers.cpp Mon May 13 14:39:55 2019
@@ -34,10 +34,12 @@ namespace {
 
   public:
     enum Kind { DumpFull, Dump, Print, None };
-    ASTPrinter(std::unique_ptr<raw_ostream> Out, Kind K, StringRef FilterString,
+    ASTPrinter(std::unique_ptr<raw_ostream> Out, Kind K,
+               ASTDumpOutputFormat 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 +92,7 @@ namespace {
         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);
     }
 
     raw_ostream &Out;
@@ -99,6 +101,9 @@ namespace {
     /// How to output individual declarations.
     Kind OutputKind;
 
+    /// What format should the output take?
+    ASTDumpOutputFormat OutputFormat;
+
     /// Which declarations or DeclContexts to display.
     std::string FilterString;
 
@@ -135,20 +140,18 @@ std::unique_ptr<ASTConsumer>
 clang::CreateASTPrinter(std::unique_ptr<raw_ostream> Out,
                         StringRef FilterString) {
   return llvm::make_unique<ASTPrinter>(std::move(Out), ASTPrinter::Print,
-                                       FilterString);
+                                       ADOF_Default, FilterString);
 }
 
 std::unique_ptr<ASTConsumer>
-clang::CreateASTDumper(std::unique_ptr<raw_ostream> Out,
-                       StringRef FilterString,
-                       bool DumpDecls,
-                       bool Deserialize,
-                       bool DumpLookups) {
+clang::CreateASTDumper(std::unique_ptr<raw_ostream> Out, StringRef FilterString,
+                       bool DumpDecls, bool Deserialize, bool DumpLookups,
+                       ASTDumpOutputFormat Format) {
   assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump");
   return llvm::make_unique<ASTPrinter>(std::move(Out),
                                        Deserialize ? ASTPrinter::DumpFull :
                                        DumpDecls ? ASTPrinter::Dump :
-                                       ASTPrinter::None,
+                                       ASTPrinter::None, Format,
                                        FilterString, DumpLookups);
 }
 

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=360622&r1=360621&r2=360622&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Mon May 13 14:39:55 2019
@@ -1603,6 +1603,22 @@ static InputKind ParseFrontendArgs(Front
       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<unsigned>(A->getValue())
+                         .CaseLower("default", ADOF_Default)
+                         .CaseLower("json", ADOF_JSON)
+                         .Default(std::numeric_limits<unsigned>::max());
+
+      if (Val != std::numeric_limits<unsigned>::max())
+        Opts.ASTDumpFormat = static_cast<ASTDumpOutputFormat>(Val);
+      else {
+        Diags.Report(diag::err_drv_invalid_value)
+            << A->getAsString(Args) << A->getValue();
+        Opts.ASTDumpFormat = ADOF_Default;
+      }
+      LLVM_FALLTHROUGH;
+    }
     case OPT_ast_dump:
     case OPT_ast_dump_all:
     case OPT_ast_dump_lookups:
@@ -1725,8 +1741,8 @@ static InputKind ParseFrontendArgs(Front
   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);

Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=360622&r1=360621&r2=360622&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendActions.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendActions.cpp Mon May 13 14:39:55 2019
@@ -73,11 +73,10 @@ ASTPrintAction::CreateASTConsumer(Compil
 
 std::unique_ptr<ASTConsumer>
 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<ASTConsumer>

Added: cfe/trunk/test/AST/ast-dump-enum-json.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/AST/ast-dump-enum-json.cpp?rev=360622&view=auto
==============================================================================
--- cfe/trunk/test/AST/ast-dump-enum-json.cpp (added)
+++ cfe/trunk/test/AST/ast-dump-enum-json.cpp Mon May 13 14:39:55 2019
@@ -0,0 +1,484 @@
+// 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": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 3
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 3
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 6
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "EnumConstantDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 4
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 4
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 4
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "One",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "(anonymous enum at {{.*}}:3:1)"
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "EnumConstantDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 5
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 5
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 5
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "Two",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "(anonymous enum at {{.*}}:3:1)"
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+
+enum E {
+  Three,
+  Four
+};
+
+// CHECK: "kind": "EnumDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 6,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 80
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 80
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 83
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "E",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "EnumConstantDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 81
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 81
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 81
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "Three",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "E"
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "EnumConstantDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 82
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 82
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 82
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "Four",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "E"
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+
+enum F : short {
+  Five,
+  Six
+};
+
+// CHECK: "kind": "EnumDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 6,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 158
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 158
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 161
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "F",
+// CHECK-NEXT: "fixedUnderlyingType": {
+// CHECK-NEXT: "qualType": "short"
+// CHECK-NEXT: },
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "EnumConstantDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 159
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 159
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 159
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "Five",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "F"
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "EnumConstantDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 160
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 160
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 160
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "Six",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "F"
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+
+enum struct G {
+  Seven,
+  Eight
+};
+
+// CHECK: "kind": "EnumDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 13,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 239
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 239
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 242
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "G",
+// CHECK-NEXT: "fixedUnderlyingType": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "scopedEnumTag": "struct",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "EnumConstantDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 240
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 240
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 240
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "Seven",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "G"
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "EnumConstantDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 241
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 241
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 241
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "Eight",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "G"
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+
+enum class H {
+  Nine,
+  Ten
+};
+
+// CHECK: "kind": "EnumDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 12,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 321
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 321
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 324
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "H",
+// CHECK-NEXT: "fixedUnderlyingType": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "scopedEnumTag": "class",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "EnumConstantDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 322
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 322
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 322
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "Nine",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "H"
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "EnumConstantDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 323
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 323
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 323
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "Ten",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "H"
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+
+enum class I : int {
+  Eleven,
+  Twelve
+};
+
+// CHECK: "kind": "EnumDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 12,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 403
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 403
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 406
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "I",
+// CHECK-NEXT: "fixedUnderlyingType": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "scopedEnumTag": "class",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "EnumConstantDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 404
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 404
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 404
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "Eleven",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "I"
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "EnumConstantDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 405
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 405
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 405
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "Twelve",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "I"
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: }
+// CHECK-NEXT: ]

Added: cfe/trunk/test/AST/ast-dump-if-json.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/AST/ast-dump-if-json.cpp?rev=360622&view=auto
==============================================================================
--- cfe/trunk/test/AST/ast-dump-if-json.cpp (added)
+++ cfe/trunk/test/AST/ast-dump-if-json.cpp Mon May 13 14:39:55 2019
@@ -0,0 +1,964 @@
+// 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": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 4
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 5
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ImplicitCastExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 4
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 4
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "bool"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "castKind": "IntegralToBoolean",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ImplicitCastExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 4
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 4
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "castKind": "LValueToRValue",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "DeclRefExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 4
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 4
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "lvalue",
+// CHECK-NEXT: "referencedDecl": {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ParmVarDecl",
+// CHECK-NEXT: "name": "val",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "NullStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 5
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 5
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+
+  if (val)
+    ;
+  else
+    ;
+
+// CHECK: "kind": "IfStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 114
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 117
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "hasElse": true,
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ImplicitCastExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 114
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 114
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "bool"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "castKind": "IntegralToBoolean",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ImplicitCastExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 114
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 114
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "castKind": "LValueToRValue",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "DeclRefExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 114
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 114
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "lvalue"
+// CHECK-NEXT: "referencedDecl": {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ParmVarDecl",
+// CHECK-NEXT: "name": "val",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "NullStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 115
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 115
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "NullStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 117
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 117
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+
+  if (val)
+    ;
+  else if (val)
+    ;
+  else
+    ;
+
+// CHECK: "kind": "IfStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 243
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 248
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "hasElse": true,
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ImplicitCastExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 243
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 243
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "bool"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "castKind": "IntegralToBoolean",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ImplicitCastExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 243
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 243
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "castKind": "LValueToRValue",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "DeclRefExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 243
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 243
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "lvalue"
+// CHECK-NEXT: "referencedDecl": {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ParmVarDecl",
+// CHECK-NEXT: "name": "val",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "NullStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 244
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 244
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "IfStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 8,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 245
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 248
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "hasElse": true,
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ImplicitCastExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 12,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 245
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 12,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 245
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "bool"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "castKind": "IntegralToBoolean",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ImplicitCastExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 12,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 245
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 12,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 245
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "castKind": "LValueToRValue",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "DeclRefExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 12,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 245
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 12,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 245
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "lvalue"
+// CHECK-NEXT: "referencedDecl": {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ParmVarDecl",
+// CHECK-NEXT: "name": "val",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "NullStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 246
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 246
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "NullStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 248
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 248
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+
+  if constexpr(10 == 10)
+    ;
+
+// CHECK: "kind": "IfStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 483
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 484
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "isConstexpr": true,
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ConstantExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 16,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 483
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 22,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 483
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "bool"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "BinaryOperator",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 16,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 483
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 22,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 483
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "bool"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "opcode": "==",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "IntegerLiteral",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 16,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 483
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 16,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 483
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "value": "10"
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "IntegerLiteral",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 22,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 483
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 22,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 483
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// 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": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 484
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 484
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+
+  if (int i = 12)
+    ;
+
+// CHECK: "kind": "IfStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 607
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 608
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "hasVar": true,
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "DeclStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 607
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 15,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 607
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "VarDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 11,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 607
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 607
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 15,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 607
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "isUsed": true,
+// CHECK-NEXT: "name": "i",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "init": "c",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "IntegerLiteral",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 15,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 607
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 15,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 607
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// 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": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 11,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 607
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 11,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 607
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "bool"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "castKind": "IntegralToBoolean",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ImplicitCastExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 11,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 607
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 11,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 607
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "castKind": "LValueToRValue",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "DeclRefExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 11,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 607
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 11,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 607
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "lvalue"
+// CHECK-NEXT: "referencedDecl": {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "VarDecl",
+// CHECK-NEXT: "name": "i",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "NullStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 608
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 608
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+
+  if (int i = 12; i)
+    ;
+
+// CHECK: "kind": "IfStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 3,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 786
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 787
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "hasInit": true,
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "DeclStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 786
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 17,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 786
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "VarDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 11,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 786
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 7,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 786
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 15,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 786
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "isUsed": true,
+// CHECK-NEXT: "name": "i",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "init": "c",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "IntegerLiteral",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 15,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 786
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 15,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 786
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// 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": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 19,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 786
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 19,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 786
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "bool"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "castKind": "IntegralToBoolean",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ImplicitCastExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 19,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 786
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 19,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 786
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "castKind": "LValueToRValue",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "DeclRefExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 19,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 786
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 19,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 786
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "lvalue"
+// CHECK-NEXT: "referencedDecl": {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "VarDecl",
+// CHECK-NEXT: "name": "i",
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "int"
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "NullStmt",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 787
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 5,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 787
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: }
+}

Added: cfe/trunk/test/AST/ast-dump-namespace-json.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/AST/ast-dump-namespace-json.cpp?rev=360622&view=auto
==============================================================================
--- cfe/trunk/test/AST/ast-dump-namespace-json.cpp (added)
+++ cfe/trunk/test/AST/ast-dump-namespace-json.cpp Mon May 13 14:39:55 2019
@@ -0,0 +1,211 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux -std=c++2a -ast-dump=json %s | FileCheck %s
+
+namespace foo {
+}
+// CHECK: "kind": "NamespaceDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 11,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 3
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 3
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 4
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "foo"
+// CHECK-NEXT: },
+
+
+namespace {
+}
+// CHECK: "kind": "NamespaceDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 11,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 27
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 27
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 28
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "UsingDirectiveDecl",
+// CHECK-NEXT: "loc": {},
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 11,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 27
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {}
+// CHECK-NEXT: },
+// CHECK-NEXT: "isImplicit": true,
+// CHECK-NEXT: "nominatedNamespace": {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "NamespaceDecl",
+// CHECK-NEXT: "name": ""
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+
+namespace bar {
+inline namespace __1 {
+}
+}
+// CHECK: "kind": "NamespaceDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 11,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 68
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 68
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 71
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "bar",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT:   "id": "0x{{.*}}",
+// CHECK-NEXT:   "kind": "NamespaceDecl",
+// CHECK-NEXT:   "loc": {
+// CHECK-NEXT:     "col": 18,
+// CHECK-NEXT:     "file": "{{.*}}",
+// CHECK-NEXT:     "line": 69
+// CHECK-NEXT:   },
+// CHECK-NEXT:   "range": {
+// CHECK-NEXT:     "begin": {
+// CHECK-NEXT:       "col": 1,
+// CHECK-NEXT:       "file": "{{.*}}",
+// CHECK-NEXT:       "line": 69
+// CHECK-NEXT:     },
+// CHECK-NEXT:     "end": {
+// CHECK-NEXT:       "col": 1,
+// CHECK-NEXT:       "file": "{{.*}}",
+// CHECK-NEXT:       "line": 70
+// CHECK-NEXT:     }
+// CHECK-NEXT:   },
+// CHECK-NEXT:   "name": "__1",
+// CHECK-NEXT:   "isInline": true
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+
+namespace baz::quux {
+}
+// CHECK: "kind": "NamespaceDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 11,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 118
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 118
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 119
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "baz",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT:   "id": "0x{{.*}}",
+// CHECK-NEXT:   "kind": "NamespaceDecl",
+// CHECK-NEXT:   "loc": {
+// CHECK-NEXT:     "col": 16,
+// CHECK-NEXT:     "file": "{{.*}}",
+// CHECK-NEXT:     "line": 118
+// CHECK-NEXT:   },
+// CHECK-NEXT:   "range": {
+// CHECK-NEXT:     "begin": {
+// CHECK-NEXT:       "col": 14,
+// CHECK-NEXT:       "file": "{{.*}}",
+// CHECK-NEXT:       "line": 118
+// CHECK-NEXT:     },
+// CHECK-NEXT:     "end": {
+// CHECK-NEXT:       "col": 1,
+// CHECK-NEXT:       "file": "{{.*}}",
+// CHECK-NEXT:       "line": 119
+// CHECK-NEXT:     }
+// CHECK-NEXT:   },
+// CHECK-NEXT:   "name": "quux"
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: },
+
+namespace quux::inline frobble {
+}
+// CHECK: "kind": "NamespaceDecl",
+// CHECK-NEXT: "loc": {
+// CHECK-NEXT: "col": 11,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 165
+// CHECK-NEXT: },
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 165
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 1,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 166
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "name": "quux",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT:   "id": "0x{{.*}}",
+// CHECK-NEXT:   "kind": "NamespaceDecl",
+// CHECK-NEXT:   "loc": {
+// CHECK-NEXT:     "col": 24,
+// CHECK-NEXT:     "file": "{{.*}}",
+// CHECK-NEXT:     "line": 165
+// CHECK-NEXT:   },
+// CHECK-NEXT:   "range": {
+// CHECK-NEXT:     "begin": {
+// CHECK-NEXT:       "col": 17,
+// CHECK-NEXT:       "file": "{{.*}}",
+// CHECK-NEXT:       "line": 165
+// CHECK-NEXT:     },
+// CHECK-NEXT:     "end": {
+// CHECK-NEXT:       "col": 1,
+// CHECK-NEXT:       "file": "{{.*}}",
+// CHECK-NEXT:       "line": 166
+// CHECK-NEXT:     }
+// CHECK-NEXT:   },
+// CHECK-NEXT:   "name": "frobble",
+// CHECK-NEXT:   "isInline": true
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK-NEXT: }

Modified: cfe/trunk/tools/clang-check/ClangCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-check/ClangCheck.cpp?rev=360622&r1=360621&r2=360622&view=diff
==============================================================================
--- cfe/trunk/tools/clang-check/ClangCheck.cpp (original)
+++ cfe/trunk/tools/clang-check/ClangCheck.cpp Mon May 13 14:39:55 2019
@@ -134,11 +134,11 @@ public:
     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::ADOF_Default);
     if (ASTPrint)
       return clang::CreateASTPrinter(nullptr, ASTDumpFilter);
     return llvm::make_unique<clang::ASTConsumer>();

Modified: cfe/trunk/tools/clang-import-test/clang-import-test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-import-test/clang-import-test.cpp?rev=360622&r1=360621&r2=360622&view=diff
==============================================================================
--- cfe/trunk/tools/clang-import-test/clang-import-test.cpp (original)
+++ cfe/trunk/tools/clang-import-test/clang-import-test.cpp Mon May 13 14:39:55 2019
@@ -316,8 +316,9 @@ llvm::Expected<CIAndOrigins> Parse(const
   auto &CG = *static_cast<CodeGenerator *>(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::ADOF_Default));
 
   CI.getDiagnosticClient().BeginSourceFile(
       CI.getCompilerInstance().getLangOpts(),




More information about the cfe-commits mailing list