You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5464 lines
171 KiB

/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2003-2014 University of Illinois at Urbana-Champaign.
* All rights reserved.
*
* This file is distributed under the University of Illinois Open Source
* License.
* See LLVM-LICENSE for details.
*
*/
/**
* Utility class to export an AST of clang into Json and Yojson (and ultimately
* Biniou)
* while conforming to the inlined ATD specifications.
*
* /!\
* '//@atd' comments are meant to be extracted and processed to generate ATD
* specifications for the Json dumper.
* Do not modify ATD comments without modifying the Json emission accordingly
* (and conversely).
* See ATD_GUIDELINES.md for more guidelines on how to write and test ATD
* annotations.
*
* This file was obtained by modifying the file ASTdumper.cpp from the
* LLVM/clang project.
* The general layout should be maintained to make future merging easier.
*/
#pragma once
#include <memory>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/ASTContext.h>
#include <clang/AST/Attr.h>
#include <clang/AST/AttrVisitor.h>
#include <clang/AST/CommentVisitor.h>
#include <clang/AST/DeclCXX.h>
#include <clang/AST/DeclLookups.h>
#include <clang/AST/DeclObjC.h>
#include <clang/AST/DeclVisitor.h>
#include <clang/AST/Mangle.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/AST/StmtVisitor.h>
#include <clang/AST/TypeVisitor.h>
#include <clang/Basic/Module.h>
#include <clang/Basic/SourceManager.h>
#include <clang/Basic/TargetInfo.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendDiagnostic.h>
#include <clang/Frontend/FrontendPluginRegistry.h>
#include <llvm/Support/raw_ostream.h>
#include "AttrParameterVectorStream.h"
#include "NamePrinter.h"
#include "SimplePluginASTAction.h"
#include "atdlib/ATDWriter.h"
//===----------------------------------------------------------------------===//
// ASTExporter Visitor
//===----------------------------------------------------------------------===//
namespace ASTLib {
struct ASTExporterOptions : ASTPluginLib::PluginASTOptionsBase {
bool withPointers = true;
bool dumpComments = false;
bool useMacroExpansionLocation = true;
ATDWriter::ATDWriterOptions atdWriterOptions = {
.useYojson = false,
.prettifyJson = true,
};
void loadValuesFromEnvAndMap(
const ASTPluginLib::PluginASTOptionsBase::argmap_t &map) {
ASTPluginLib::PluginASTOptionsBase::loadValuesFromEnvAndMap(map);
loadBool(map, "AST_WITH_POINTERS", withPointers);
loadBool(map, "USE_YOJSON", atdWriterOptions.useYojson);
loadBool(map, "PRETTIFY_JSON", atdWriterOptions.prettifyJson);
}
};
using namespace clang;
using namespace clang::comments;
template <class Impl>
struct TupleSizeBase {
// Decls
#define DECL(DERIVED, BASE) \
int DERIVED##DeclTupleSize() { \
return static_cast<Impl *>(this)->BASE##TupleSize(); \
}
#define ABSTRACT_DECL(DECL) DECL
#include <clang/AST/DeclNodes.inc>
int tupleSizeOfDeclKind(const Decl::Kind kind) {
switch (kind) {
#define DECL(DERIVED, BASE) \
case Decl::DERIVED: \
return static_cast<Impl *>(this)->DERIVED##DeclTupleSize();
#define ABSTRACT_DECL(DECL)
#include <clang/AST/DeclNodes.inc>
}
llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
}
// Stmts
#define STMT(CLASS, PARENT) \
int CLASS##TupleSize() { \
return static_cast<Impl *>(this)->PARENT##TupleSize(); \
}
#define ABSTRACT_STMT(STMT) STMT
#include <clang/AST/StmtNodes.inc>
int tupleSizeOfStmtClass(const Stmt::StmtClass stmtClass) {
switch (stmtClass) {
#define STMT(CLASS, PARENT) \
case Stmt::CLASS##Class: \
return static_cast<Impl *>(this)->CLASS##TupleSize();
#define ABSTRACT_STMT(STMT)
#include <clang/AST/StmtNodes.inc>
case Stmt::NoStmtClass:
break;
}
llvm_unreachable("Stmt that isn't part of StmtNodes.inc!");
}
// Comments
#define COMMENT(CLASS, PARENT) \
int CLASS##TupleSize() { \
return static_cast<Impl *>(this)->PARENT##TupleSize(); \
}
#define ABSTRACT_COMMENT(COMMENT) COMMENT
#include <clang/AST/CommentNodes.inc>
int tupleSizeOfCommentKind(const Comment::CommentKind kind) {
switch (kind) {
#define COMMENT(CLASS, PARENT) \
case Comment::CLASS##Kind: \
return static_cast<Impl *>(this)->CLASS##TupleSize();
#define ABSTRACT_COMMENT(COMMENT)
#include <clang/AST/CommentNodes.inc>
case Comment::NoCommentKind:
break;
}
llvm_unreachable("Comment that isn't part of CommentNodes.inc!");
}
// Types
#define TYPE(DERIVED, BASE) \
int DERIVED##TypeTupleSize() { \
return static_cast<Impl *>(this)->BASE##TupleSize(); \
}
#define ABSTRACT_TYPE(DERIVED, BASE) TYPE(DERIVED, BASE)
#include <clang/AST/TypeNodes.inc>
int tupleSizeOfTypeClass(const Type::TypeClass typeClass) {
switch (typeClass) {
#define TYPE(DERIVED, BASE) \
case Type::DERIVED: \
return static_cast<Impl *>(this)->DERIVED##TypeTupleSize();
#define ABSTRACT_TYPE(DERIVED, BASE)
#include <clang/AST/TypeNodes.inc>
}
llvm_unreachable("Type that isn't part of TypeNodes.def!");
}
// Attributes
#define ATTR(NAME) \
int NAME##AttrTupleSize() { return 1; }
#include <clang/Basic/AttrList.inc>
int tupleSizeOfAttrKind(const attr::Kind attrKind) {
switch (attrKind) {
#define ATTR(NAME) \
case attr::Kind::NAME: \
return static_cast<Impl *>(this)->NAME##AttrTupleSize();
#include <clang/Basic/AttrList.inc>
}
llvm_unreachable("Attr that isn't part of AttrList.inc!");
}
};
typedef ATDWriter::JsonWriter<raw_ostream> JsonWriter;
template <class ATDWriter = JsonWriter>
class ASTExporter : public ConstDeclVisitor<ASTExporter<ATDWriter>>,
public ConstStmtVisitor<ASTExporter<ATDWriter>>,
public ConstCommentVisitor<ASTExporter<ATDWriter>>,
public TypeVisitor<ASTExporter<ATDWriter>>,
public ConstAttrVisitor<ASTExporter<ATDWriter>>,
public TupleSizeBase<ASTExporter<ATDWriter>> {
typedef typename ATDWriter::ObjectScope ObjectScope;
typedef typename ATDWriter::ArrayScope ArrayScope;
typedef typename ATDWriter::TupleScope TupleScope;
typedef typename ATDWriter::VariantScope VariantScope;
ATDWriter OF;
ASTContext &Context;
const ASTExporterOptions &Options;
std::unique_ptr<MangleContext> Mangler;
// Encoding of NULL pointers into suitable empty nodes
// This is a hack but using option types in children lists would make the Json
// terribly verbose.
// Also these useless nodes could have occurred in the original AST anyway :)
//
// Note: We are not using std::unique_ptr because 'delete' appears to be
// protected (at least on Stmt).
const Stmt *const NullPtrStmt;
const Decl *const NullPtrDecl;
const Comment *const NullPtrComment;
// Keep track of the last location we print out so that we can
// print out deltas from then on out.
const char *LastLocFilename;
unsigned LastLocLine;
// The \c FullComment parent of the comment being dumped.
const FullComment *FC;
NamePrinter<ATDWriter> NamePrint;
public:
ASTExporter(raw_ostream &OS,
ASTContext &Context,
const ASTExporterOptions &Opts)
: OF(OS, Opts.atdWriterOptions),
Context(Context),
Options(Opts),
Mangler(
ItaniumMangleContext::create(Context, Context.getDiagnostics())),
NullPtrStmt(new (Context) NullStmt(SourceLocation())),
NullPtrDecl(EmptyDecl::Create(
Context, Context.getTranslationUnitDecl(), SourceLocation())),
NullPtrComment(new (Context) Comment(
Comment::NoCommentKind, SourceLocation(), SourceLocation())),
LastLocFilename(""),
LastLocLine(~0U),
FC(0),
NamePrint(Context.getSourceManager(), OF) {}
void dumpDecl(const Decl *D);
void dumpStmt(const Stmt *S);
void dumpFullComment(const FullComment *C);
void dumpType(const Type *T);
void dumpPointerToType(const Type *T);
void dumpQualTypeNoQuals(const QualType &qt);
void dumpClassLambdaCapture(const LambdaCapture *C);
void dumpVersionTuple(const VersionTuple &VT);
// Utilities
void dumpPointer(const void *Ptr);
void dumpSourceRange(SourceRange R);
void dumpSourceLocation(SourceLocation Loc);
void dumpQualType(const QualType &qt);
void dumpTypeOld(const Type *T);
void dumpDeclRef(const Decl &Node);
bool hasNodes(const DeclContext *DC);
void dumpLookups(const DeclContext &DC);
void dumpSelector(const Selector sel);
void dumpName(const NamedDecl &decl);
void dumpInputKind(const InputKind kind);
void dumpIntegerTypeWidths(const TargetInfo &info);
bool alwaysEmitParent(const Decl *D);
void emitAPInt(bool isSigned, const llvm::APInt &value);
// C++ Utilities
void dumpAccessSpecifier(AccessSpecifier AS);
void dumpCXXCtorInitializer(const CXXCtorInitializer &Init);
void dumpDeclarationName(const DeclarationName &Name);
void dumpNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
void dumpTemplateArgument(const TemplateArgument &Arg);
void dumpTemplateSpecialization(const TemplateDecl *D,
const TemplateArgumentList &Args);
// void dumpTemplateParameters(const TemplateParameterList *TPL);
// void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI);
// void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A);
// void dumpTemplateArgumentList(const TemplateArgumentList &TAL);
// void dumpTemplateArgument(const TemplateArgument &A,
// SourceRange R = SourceRange());
void dumpCXXBaseSpecifier(const CXXBaseSpecifier &Base);
#define DECLARE_VISITOR(NAME) \
int NAME##TupleSize(); \
void Visit##NAME(const NAME *D);
#define DECLARE_LOWERCASE_VISITOR(NAME) \
int NAME##TupleSize(); \
void visit##NAME(const NAME *D);
// Decls
DECLARE_VISITOR(Decl)
DECLARE_VISITOR(DeclContext)
DECLARE_VISITOR(BlockDecl)
DECLARE_VISITOR(CapturedDecl)
DECLARE_VISITOR(LinkageSpecDecl)
DECLARE_VISITOR(NamespaceDecl)
DECLARE_VISITOR(ObjCContainerDecl)
DECLARE_VISITOR(TagDecl)
DECLARE_VISITOR(TypeDecl)
DECLARE_VISITOR(TranslationUnitDecl)
DECLARE_VISITOR(NamedDecl)
DECLARE_VISITOR(ValueDecl)
DECLARE_VISITOR(TypedefDecl)
DECLARE_VISITOR(EnumDecl)
DECLARE_VISITOR(RecordDecl)
DECLARE_VISITOR(EnumConstantDecl)
DECLARE_VISITOR(IndirectFieldDecl)
DECLARE_VISITOR(FunctionDecl)
DECLARE_VISITOR(FieldDecl)
DECLARE_VISITOR(VarDecl)
// no use for these yet, ignore them
// DECLARE_VISITOR(FileScopeAsmDecl)
DECLARE_VISITOR(ImportDecl)
// C++ Decls
DECLARE_VISITOR(UsingDirectiveDecl)
DECLARE_VISITOR(NamespaceAliasDecl)
DECLARE_VISITOR(CXXRecordDecl)
DECLARE_VISITOR(ClassTemplateSpecializationDecl)
DECLARE_VISITOR(CXXMethodDecl)
DECLARE_VISITOR(ClassTemplateDecl)
DECLARE_VISITOR(FunctionTemplateDecl)
DECLARE_VISITOR(FriendDecl)
// void VisitTypeAliasDecl(const TypeAliasDecl *D);
// void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D);
// void VisitStaticAssertDecl(const StaticAssertDecl *D);
// template<typename SpecializationDecl>
// void VisitTemplateDeclSpecialization(ChildDumper &Children,
// const SpecializationDecl *D,
// bool DumpExplicitInst,
// bool DumpRefOnly);
// void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
// void VisitClassTemplateSpecializationDecl(
// const ClassTemplateSpecializationDecl *D);
// void VisitClassTemplatePartialSpecializationDecl(
// const ClassTemplatePartialSpecializationDecl *D);
// void VisitClassScopeFunctionSpecializationDecl(
// const ClassScopeFunctionSpecializationDecl *D);
// void VisitVarTemplateDecl(const VarTemplateDecl *D);
// void VisitVarTemplateSpecializationDecl(
// const VarTemplateSpecializationDecl *D);
// void VisitVarTemplatePartialSpecializationDecl(
// const VarTemplatePartialSpecializationDecl *D);
// void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
// void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
// void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
// void VisitUsingDecl(const UsingDecl *D);
// void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl
// *D);
// void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D);
// void VisitUsingShadowDecl(const UsingShadowDecl *D);
// void VisitLinkageSpecDecl(const LinkageSpecDecl *D);
// void VisitAccessSpecDecl(const AccessSpecDecl *D);
//
// // ObjC Decls
DECLARE_VISITOR(ObjCIvarDecl)
DECLARE_VISITOR(ObjCMethodDecl)
DECLARE_VISITOR(ObjCCategoryDecl)
DECLARE_VISITOR(ObjCCategoryImplDecl)
DECLARE_VISITOR(ObjCProtocolDecl)
DECLARE_VISITOR(ObjCInterfaceDecl)
DECLARE_VISITOR(ObjCImplementationDecl)
DECLARE_VISITOR(ObjCCompatibleAliasDecl)
DECLARE_VISITOR(ObjCPropertyDecl)
DECLARE_VISITOR(ObjCPropertyImplDecl)
// Stmts.
DECLARE_VISITOR(Stmt)
DECLARE_VISITOR(AttributedStmt)
DECLARE_VISITOR(CXXCatchStmt)
DECLARE_VISITOR(DeclStmt)
DECLARE_VISITOR(GotoStmt)
DECLARE_VISITOR(IfStmt)
DECLARE_VISITOR(LabelStmt)
DECLARE_VISITOR(SwitchStmt)
// Exprs
DECLARE_VISITOR(Expr)
DECLARE_VISITOR(CastExpr)
DECLARE_VISITOR(ExplicitCastExpr)
DECLARE_VISITOR(DeclRefExpr)
DECLARE_VISITOR(PredefinedExpr)
DECLARE_VISITOR(CharacterLiteral)
DECLARE_VISITOR(IntegerLiteral)
DECLARE_VISITOR(FixedPointLiteral)
DECLARE_VISITOR(FloatingLiteral)
DECLARE_VISITOR(StringLiteral)
// DECLARE_VISITOR(InitListExpr)
DECLARE_VISITOR(UnaryOperator)
DECLARE_VISITOR(UnaryExprOrTypeTraitExpr)
DECLARE_VISITOR(MemberExpr)
DECLARE_VISITOR(ExtVectorElementExpr)
DECLARE_VISITOR(BinaryOperator)
DECLARE_VISITOR(CompoundAssignOperator)
DECLARE_VISITOR(AddrLabelExpr)
DECLARE_VISITOR(BlockExpr)
DECLARE_VISITOR(OpaqueValueExpr)
DECLARE_VISITOR(OffsetOfExpr)
// C++
DECLARE_VISITOR(CXXNamedCastExpr)
DECLARE_VISITOR(CXXBoolLiteralExpr)
DECLARE_VISITOR(CXXConstructExpr)
DECLARE_VISITOR(CXXInheritedCtorInitExpr)
DECLARE_VISITOR(CXXBindTemporaryExpr)
DECLARE_VISITOR(MaterializeTemporaryExpr)
DECLARE_VISITOR(ExprWithCleanups)
DECLARE_VISITOR(OverloadExpr)
DECLARE_VISITOR(UnresolvedLookupExpr)
void dumpCXXTemporary(const CXXTemporary *Temporary);
DECLARE_VISITOR(LambdaExpr)
DECLARE_VISITOR(CXXNewExpr)
DECLARE_VISITOR(CXXDeleteExpr)
DECLARE_VISITOR(CXXDefaultArgExpr)
DECLARE_VISITOR(CXXDefaultInitExpr)
DECLARE_VISITOR(TypeTraitExpr)
DECLARE_VISITOR(GenericSelectionExpr)
DECLARE_VISITOR(CXXNoexceptExpr)
// ObjC
DECLARE_VISITOR(ObjCAtCatchStmt)
DECLARE_VISITOR(ObjCEncodeExpr)
DECLARE_VISITOR(ObjCMessageExpr)
DECLARE_VISITOR(ObjCBoxedExpr)
DECLARE_VISITOR(ObjCSelectorExpr)
DECLARE_VISITOR(ObjCProtocolExpr)
DECLARE_VISITOR(ObjCPropertyRefExpr)
DECLARE_VISITOR(ObjCSubscriptRefExpr)
DECLARE_VISITOR(ObjCIvarRefExpr)
DECLARE_VISITOR(ObjCBoolLiteralExpr)
DECLARE_VISITOR(ObjCAvailabilityCheckExpr)
DECLARE_VISITOR(ObjCArrayLiteral)
DECLARE_VISITOR(ObjCDictionaryLiteral)
DECLARE_VISITOR(ObjCBridgedCastExpr)
// Comments.
const char *getCommandName(unsigned CommandID);
void dumpComment(const Comment *C);
// Inline comments.
DECLARE_LOWERCASE_VISITOR(Comment)
// DECLARE_LOWERCASE_VISITOR(TextComment)
// void visitInlineCommandComment(const InlineCommandComment *C);
// void visitHTMLStartTagComment(const HTMLStartTagComment *C);
// void visitHTMLEndTagComment(const HTMLEndTagComment *C);
//
// // Block comments.
// void visitBlockCommandComment(const BlockCommandComment *C);
// void visitParamCommandComment(const ParamCommandComment *C);
// void visitTParamCommandComment(const TParamCommandComment *C);
// void visitVerbatimBlockComment(const VerbatimBlockComment *C);
// void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
// void visitVerbatimLineComment(const VerbatimLineComment *C);
// Types - no template type handling yet
int TypeWithChildInfoTupleSize();
DECLARE_VISITOR(Type)
DECLARE_VISITOR(AdjustedType)
DECLARE_VISITOR(ArrayType)
DECLARE_VISITOR(ConstantArrayType)
// DECLARE_VISITOR(DependentSizedArrayType)
// DECLARE_VISITOR(IncompleteArrayType)
DECLARE_VISITOR(VariableArrayType)
DECLARE_VISITOR(AtomicType)
DECLARE_VISITOR(AttributedType) // getEquivalentType() + getAttrKind -> string
// DECLARE_VISITOR(AutoType)
DECLARE_VISITOR(BlockPointerType)
DECLARE_VISITOR(BuiltinType)
// DECLARE_VISITOR(ComplexType)
DECLARE_VISITOR(DecltypeType)
// DECLARE_VISITOR(DependentSizedExtVectorType)
DECLARE_VISITOR(FunctionType)
// DECLARE_VISITOR(FunctionNoProtoType)
DECLARE_VISITOR(FunctionProtoType)
// DECLARE_VISITOR(InjectedClassNameType)
DECLARE_VISITOR(MemberPointerType)
DECLARE_VISITOR(ObjCObjectPointerType)
DECLARE_VISITOR(ObjCObjectType)
DECLARE_VISITOR(ObjCInterfaceType)
DECLARE_VISITOR(ParenType)
DECLARE_VISITOR(PointerType)
DECLARE_VISITOR(ReferenceType)
DECLARE_VISITOR(TagType)
DECLARE_VISITOR(TypedefType)
void dumpAttrKind(attr::Kind Kind);
void dumpAttr(const Attr *A);
DECLARE_VISITOR(Attr)
DECLARE_VISITOR(AnnotateAttr)
DECLARE_VISITOR(AvailabilityAttr)
DECLARE_VISITOR(SentinelAttr)
DECLARE_VISITOR(VisibilityAttr)
void dumpTypeAttr(AttributedType::Kind kind);
void dumpObjCLifetimeQual(Qualifiers::ObjCLifetime qual);
/* #define TYPE(CLASS, PARENT) DECLARE_VISITOR(CLASS##Type) */
/* #define ABSTRACT_TYPE(CLASS, PARENT) */
/* #include <clang/AST/TypeNodes.def> */
};
//===----------------------------------------------------------------------===//
// Utilities
//===----------------------------------------------------------------------===//
bool hasMeaningfulTypeInfo(const Type *T) {
// clang goes into an infinite loop trying to compute the TypeInfo of
// dependent types, and a width of 0 if the type doesn't have a constant size
return T && !T->isIncompleteType() && !T->isDependentType() &&
T->isConstantSizeType();
}
std::unordered_map<const void *, int> pointerMap;
int pointerCounter = 1;
//@atd type pointer = int
template <class ATDWriter>
void writePointer(ATDWriter &OF, bool withPointers, const void *Ptr) {
if (!Ptr) {
OF.emitInteger(0);
return;
}
if (pointerMap.find(Ptr) == pointerMap.end()) {
pointerMap[Ptr] = pointerCounter++;
}
OF.emitInteger(pointerMap[Ptr]);
}
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpPointer(const void *Ptr) {
writePointer(OF, Options.withPointers, Ptr);
}
//@atd type source_file = string
//@atd type source_location = {
//@atd ?file <ocaml mutable> : source_file option;
//@atd ?line <ocaml mutable> : int option;
//@atd ?column <ocaml mutable> : int option;
//@atd } <ocaml field_prefix="sl_" validator="Clang_ast_visit.visit_source_loc">
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpSourceLocation(SourceLocation Loc) {
const SourceManager &SM = Context.getSourceManager();
SourceLocation ExpLoc =
Options.useMacroExpansionLocation ? SM.getExpansionLoc(Loc) : Loc;
SourceLocation SpellingLoc = SM.getSpellingLoc(ExpLoc);
// The general format we print out is filename:line:col, but we drop pieces
// that haven't changed since the last loc printed.
PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc);
if (PLoc.isInvalid()) {
ObjectScope Scope(OF, 0);
return;
}
if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
ObjectScope Scope(OF, 3);
OF.emitTag("file");
// Normalizing filenames matters because the current directory may change
// during the compilation of large projects.
OF.emitString(Options.normalizeSourcePath(PLoc.getFilename()));
OF.emitTag("line");
OF.emitInteger(PLoc.getLine());
OF.emitTag("column");
OF.emitInteger(PLoc.getColumn());
} else if (PLoc.getLine() != LastLocLine) {
ObjectScope Scope(OF, 2);
OF.emitTag("line");
OF.emitInteger(PLoc.getLine());
OF.emitTag("column");
OF.emitInteger(PLoc.getColumn());
} else {
ObjectScope Scope(OF, 1);
OF.emitTag("column");
OF.emitInteger(PLoc.getColumn());
}
LastLocFilename = PLoc.getFilename();
LastLocLine = PLoc.getLine();
// TODO: lastLocColumn
}
//@atd type source_range = (source_location * source_location)
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpSourceRange(SourceRange R) {
TupleScope Scope(OF, 2);
dumpSourceLocation(R.getBegin());
dumpSourceLocation(R.getEnd());
}
//@atd type qual_type = {
//@atd type_ptr : type_ptr;
//@atd ~is_const : bool;
//@atd ~is_restrict : bool;
//@atd ~is_volatile : bool;
//@atd } <ocaml field_prefix="qt_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpQualType(const QualType &qt) {
clang::Qualifiers Quals =
qt.isNull() ? clang::Qualifiers() : qt.getQualifiers();
bool isConst = Quals.hasConst();
bool isRestrict = Quals.hasRestrict();
bool isVolatile = Quals.hasVolatile();
ObjectScope oScope(OF, 1 + isConst + isVolatile + isRestrict);
OF.emitTag("type_ptr");
dumpQualTypeNoQuals(qt);
OF.emitFlag("is_const", isConst);
OF.emitFlag("is_restrict", isRestrict);
OF.emitFlag("is_volatile", isVolatile);
}
//@atd type named_decl_info = {
//@atd name : string;
//@atd qual_name : string list;
//@atd } <ocaml field_prefix="ni_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpName(const NamedDecl &Decl) {
// dump name
ObjectScope oScope(OF, 2);
OF.emitTag("name");
std::string name = Decl.getNameAsString();
if (name.length() == 0) {
const FieldDecl *FD = dyn_cast<FieldDecl>(&Decl);
if (FD) {
name = "__anon_field_" + std::to_string(FD->getFieldIndex());
}
}
OF.emitString(name);
OF.emitTag("qual_name");
NamePrint.printDeclName(Decl);
}
//@atd type decl_ref = {
//@atd kind : decl_kind;
//@atd decl_pointer : pointer;
//@atd ?name : named_decl_info option;
//@atd ~is_hidden : bool;
//@atd ?qual_type : qual_type option
//@atd } <ocaml field_prefix="dr_">
//@atd type decl_kind = [
#define DECL(DERIVED, BASE) //@atd | DERIVED
#define ABSTRACT_DECL(DECL) DECL
#include <clang/AST/DeclNodes.inc>
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpDeclRef(const Decl &D) {
const NamedDecl *ND = dyn_cast<NamedDecl>(&D);
const ValueDecl *VD = dyn_cast<ValueDecl>(&D);
bool IsHidden = ND && !ND->isUnconditionallyVisible();
ObjectScope Scope(OF, 2 + (bool)ND + (bool)VD + IsHidden);
OF.emitTag("kind");
OF.emitSimpleVariant(D.getDeclKindName());
OF.emitTag("decl_pointer");
dumpPointer(&D);
if (ND) {
OF.emitTag("name");
dumpName(*ND);
OF.emitFlag("is_hidden", IsHidden);
}
if (VD) {
OF.emitTag("qual_type");
dumpQualType(VD->getType());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::DeclContextTupleSize() {
return 2;
}
//@atd #define decl_context_tuple decl list * decl_context_info
//@atd type decl_context_info = {
//@atd ~has_external_lexical_storage : bool;
//@atd ~has_external_visible_storage : bool
//@atd } <ocaml field_prefix="dci_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitDeclContext(const DeclContext *DC) {
if (!DC) {
{
ArrayScope Scope(OF, 0);
}
{ ObjectScope Scope(OF, 0); }
return;
}
{
std::vector<Decl *> declsToDump;
for (auto I : DC->decls()) {
declsToDump.push_back(I);
}
/* Some typedefs are not part of AST. 'instancetype' is one of them.
Export it nevertheless as part of TranslationUnitDecl context. */
// getObjCInstanceType() should return null type when 'instancetype' is not
// known yet - it doesn't work this way due to bug in clang, but keep
// the check for when the bug is fixed.
if (isa<TranslationUnitDecl>(DC) &&
Context.getObjCInstanceType().getTypePtrOrNull()) {
declsToDump.push_back(Context.getObjCInstanceTypeDecl());
}
ArrayScope Scope(OF, declsToDump.size());
for (auto I : declsToDump) {
dumpDecl(I);
}
}
{
bool HasExternalLexicalStorage = DC->hasExternalLexicalStorage();
bool HasExternalVisibleStorage = DC->hasExternalVisibleStorage();
ObjectScope Scope(OF,
0 + HasExternalLexicalStorage +
HasExternalVisibleStorage); // not covered by tests
OF.emitFlag("has_external_lexical_storage", HasExternalLexicalStorage);
OF.emitFlag("has_external_visible_storage", HasExternalVisibleStorage);
}
}
//@atd type lookups = {
//@atd decl_ref : decl_ref;
//@atd ?primary_context_pointer : pointer option;
//@atd lookups : lookup list;
//@atd ~has_undeserialized_decls : bool;
//@atd } <ocaml field_prefix="lups_">
//@atd type lookup = {
//@atd decl_name : string;
//@atd decl_refs : decl_ref list;
//@atd } <ocaml field_prefix="lup_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpLookups(const DeclContext &DC) {
ObjectScope Scope(OF, 4); // not covered by tests
OF.emitTag("decl_ref");
dumpDeclRef(cast<Decl>(DC));
const DeclContext *Primary = DC.getPrimaryContext();
if (Primary != &DC) {
OF.emitTag("primary_context_pointer");
dumpPointer(cast<Decl>(Primary));
}
OF.emitTag("lookups");
{
ArrayScope Scope(OF);
DeclContext::all_lookups_iterator I = Primary->noload_lookups_begin(),
E = Primary->noload_lookups_end();
while (I != E) {
DeclarationName Name = I.getLookupName();
DeclContextLookupResult R = *I++;
ObjectScope Scope(OF, 2); // not covered by tests
OF.emitTag("decl_name");
OF.emitString(Name.getAsString());
OF.emitTag("decl_refs");
{
ArrayScope Scope(OF);
for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end();
RI != RE;
++RI) {
dumpDeclRef(**RI);
}
}
}
}
bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage();
OF.emitFlag("has_undeserialized_decls", HasUndeserializedLookups);
}
//===----------------------------------------------------------------------===//
// C++ Utilities
//===----------------------------------------------------------------------===//
//@atd type access_specifier = [ None | Public | Protected | Private ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpAccessSpecifier(AccessSpecifier AS) {
switch (AS) {
case AS_public:
OF.emitSimpleVariant("Public");
break;
case AS_protected:
OF.emitSimpleVariant("Protected");
break;
case AS_private:
OF.emitSimpleVariant("Private");
break;
case AS_none:
OF.emitSimpleVariant("None");
break;
}
}
//@atd type cxx_ctor_initializer = {
//@atd subject : cxx_ctor_initializer_subject;
//@atd source_range : source_range;
//@atd ?init_expr : stmt option;
//@atd } <ocaml field_prefix="xci_">
//@atd type cxx_ctor_initializer_subject = [
//@atd Member of decl_ref
//@atd | Delegating of type_ptr
//@atd | BaseClass of (type_ptr * bool)
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpCXXCtorInitializer(
const CXXCtorInitializer &Init) {
const Expr *E = Init.getInit();
ObjectScope Scope(OF, 2 + (bool)E);
OF.emitTag("subject");
const FieldDecl *FD = Init.getAnyMember();
if (FD) {
VariantScope Scope(OF, "Member");
dumpDeclRef(*FD);
} else if (Init.isDelegatingInitializer()) {
VariantScope Scope(OF, "Delegating");
dumpQualTypeNoQuals(Init.getTypeSourceInfo()->getType());
} else {
VariantScope Scope(OF, "BaseClass");
{
TupleScope Scope(OF, 2);
dumpQualTypeNoQuals(Init.getTypeSourceInfo()->getType());
OF.emitBoolean(Init.isBaseVirtual());
}
}
OF.emitTag("source_range");
dumpSourceRange(Init.getSourceRange());
if (E) {
OF.emitTag("init_expr");
dumpStmt(E);
}
}
//@atd type declaration_name = {
//@atd kind : declaration_name_kind;
//@atd name : string;
//@atd } <ocaml field_prefix="dn_">
//@atd type declaration_name_kind = [
//@atd Identifier
//@atd | ObjCZeroArgSelector
//@atd | ObjCOneArgSelector
//@atd | ObjCMultiArgSelector
//@atd | CXXConstructorName
//@atd | CXXDestructorName
//@atd | CXXConversionFunctionName
//@atd | CXXOperatorName
//@atd | CXXLiteralOperatorName
//@atd | CXXUsingDirective
//@atd | CXXDeductionGuideName
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpDeclarationName(const DeclarationName &Name) {
ObjectScope Scope(OF, 2); // not covered by tests
OF.emitTag("kind");
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
OF.emitSimpleVariant("Identifier");
break;
case DeclarationName::ObjCZeroArgSelector:
OF.emitSimpleVariant("ObjCZeroArgSelector");
break;
case DeclarationName::ObjCOneArgSelector:
OF.emitSimpleVariant("ObjCOneArgSelector");
break;
case DeclarationName::ObjCMultiArgSelector:
OF.emitSimpleVariant("ObjCMultiArgSelector");
break;
case DeclarationName::CXXConstructorName:
OF.emitSimpleVariant("CXXConstructorName");
break;
case DeclarationName::CXXDestructorName:
OF.emitSimpleVariant("CXXDestructorName");
break;
case DeclarationName::CXXConversionFunctionName:
OF.emitSimpleVariant("CXXConversionFunctionName");
break;
case DeclarationName::CXXOperatorName:
OF.emitSimpleVariant("CXXOperatorName");
break;
case DeclarationName::CXXLiteralOperatorName:
OF.emitSimpleVariant("CXXLiteralOperatorName");
break;
case DeclarationName::CXXUsingDirective:
OF.emitSimpleVariant("CXXUsingDirective");
break;
case DeclarationName::CXXDeductionGuideName:
OF.emitSimpleVariant("CXXDeductionGuideName");
break;
}
OF.emitTag("name");
OF.emitString(Name.getAsString());
}
//@atd type nested_name_specifier_loc = {
//@atd kind : specifier_kind;
//@atd ?ref : decl_ref option;
//@atd } <ocaml field_prefix="nnsl_">
//@atd type specifier_kind = [
//@atd Identifier
//@atd | Namespace
//@atd | NamespaceAlias
//@atd | TypeSpec
//@atd | TypeSpecWithTemplate
//@atd | Global
//@atd | Super
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpNestedNameSpecifierLoc(
NestedNameSpecifierLoc NNS) {
SmallVector<NestedNameSpecifierLoc, 8> NestedNames;
while (NNS) {
NestedNames.push_back(NNS);
NNS = NNS.getPrefix();
}
ArrayScope Scope(OF, NestedNames.size());
while (!NestedNames.empty()) {
NNS = NestedNames.pop_back_val();
NestedNameSpecifier::SpecifierKind Kind =
NNS.getNestedNameSpecifier()->getKind();
ObjectScope Scope(OF, 2);
OF.emitTag("kind");
switch (Kind) {
case NestedNameSpecifier::Identifier:
OF.emitSimpleVariant("Identifier");
break;
case NestedNameSpecifier::Namespace:
OF.emitSimpleVariant("Namespace");
OF.emitTag("ref");
dumpDeclRef(*NNS.getNestedNameSpecifier()->getAsNamespace());
break;
case NestedNameSpecifier::NamespaceAlias:
OF.emitSimpleVariant("NamespaceAlias");
OF.emitTag("ref");
dumpDeclRef(*NNS.getNestedNameSpecifier()->getAsNamespaceAlias());
break;
case NestedNameSpecifier::TypeSpec:
OF.emitSimpleVariant("TypeSpec");
break;
case NestedNameSpecifier::TypeSpecWithTemplate:
OF.emitSimpleVariant("TypeSpecWithTemplate");
break;
case NestedNameSpecifier::Global:
OF.emitSimpleVariant("Global");
break;
case NestedNameSpecifier::Super:
OF.emitSimpleVariant("Super");
break;
}
}
}
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::dumpTemplateParameters(const
// TemplateParameterList *TPL) {
// if (!TPL)
// return;
//
// for (TemplateParameterList::const_iterator I = TPL->begin(), E = TPL->end();
// I != E; ++I)
// dumpDecl(*I);
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::dumpTemplateArgumentListInfo(
// const TemplateArgumentListInfo &TALI) {
// for (unsigned i = 0, e = TALI.size(); i < e; ++i) {
// dumpTemplateArgumentLoc(TALI[i]);
// }
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::dumpTemplateArgumentLoc(const
// TemplateArgumentLoc &A) {
// dumpTemplateArgument(A.getArgument(), A.getSourceRange());
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::dumpTemplateArgumentList(const
// TemplateArgumentList &TAL) {
// for (unsigned i = 0, e = TAL.size(); i < e; ++i)
// dumpTemplateArgument(TAL[i]);
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::dumpTemplateArgument(const TemplateArgument &A,
// SourceRange R) {
// ObjectScope Scope(OF);
// OS << "TemplateArgument";
// if (R.isValid())
// dumpSourceRange(R);
//
// switch (A.getKind()) {
// case TemplateArgument::Null:
// OS << " null";
// break;
// case TemplateArgument::Type:
// OS << " type";
// dumpQualType(A.getAsType());
// break;
// case TemplateArgument::Declaration:
// OS << " decl";
// dumpDeclRef(A.getAsDecl());
// break;
// case TemplateArgument::NullPtr:
// OS << " nullptr";
// break;
// case TemplateArgument::Integral:
// OS << " integral " << A.getAsIntegral();
// break;
// case TemplateArgument::Template:
// OS << " template ";
// // FIXME: do not use the local dump method
// A.getAsTemplate().dump(OS);
// break;
// case TemplateArgument::TemplateExpansion:
// OS << " template expansion";
// // FIXME: do not use the local dump method
// A.getAsTemplateOrTemplatePattern().dump(OS);
// break;
// case TemplateArgument::Expression:
// OS << " expr";
// dumpStmt(A.getAsExpr());
// break;
// case TemplateArgument::Pack:
// OS << " pack";
// for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end();
// I != E; ++I) {
// dumpTemplateArgument(*I);
// }
// break;
// }
//}
template <class ATDWriter>
bool ASTExporter<ATDWriter>::alwaysEmitParent(const Decl *D) {
if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D) || isa<FieldDecl>(D) ||
isa<ObjCIvarDecl>(D) || isa<BlockDecl>(D) ||
isa<ObjCInterfaceDecl>(D) || isa<ObjCImplementationDecl>(D) ||
isa<ObjCCategoryDecl>(D) || isa<ObjCCategoryImplDecl>(D) ||
isa<ObjCPropertyDecl>(D) || isa<RecordDecl>(D)
|| isa<ObjCProtocolDecl>(D) ) {
return true;
}
return false;
}
//===----------------------------------------------------------------------===//
// Decl dumping methods.
//===----------------------------------------------------------------------===//
#define DECL(DERIVED, BASE) //@atd #define @DERIVED@_decl_tuple @BASE@_tuple
#define ABSTRACT_DECL(DECL) DECL
#include <clang/AST/DeclNodes.inc>
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpDecl(const Decl *D) {
if (!D) {
// We use a fixed EmptyDecl node to represent null pointers
D = NullPtrDecl;
}
VariantScope Scope(OF, std::string(D->getDeclKindName()) + "Decl");
{
TupleScope Scope(OF, ASTExporter::tupleSizeOfDeclKind(D->getKind()));
ConstDeclVisitor<ASTExporter<ATDWriter>>::Visit(D);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::DeclTupleSize() {
return 1;
}
//@atd #define decl_tuple decl_info
//@atd type decl_info = {
//@atd pointer : pointer;
//@atd ?parent_pointer : pointer option;
//@atd source_range : source_range;
//@atd ?owning_module : string option;
//@atd ~is_hidden : bool;
//@atd ~is_implicit : bool;
//@atd ~is_used : bool;
//@atd ~is_this_declaration_referenced : bool;
//@atd ~is_invalid_decl : bool;
//@atd ~attributes : attribute list;
//@atd ?full_comment : comment option;
//@atd ~access <ocaml default="`None"> : access_specifier
//@atd } <ocaml field_prefix="di_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitDecl(const Decl *D) {
{
bool ShouldEmitParentPointer =
alwaysEmitParent(D) ||
D->getLexicalDeclContext() != D->getDeclContext();
Module *M = D->getImportedOwningModule();
if (!M) {
M = D->getLocalOwningModule();
}
const NamedDecl *ND = dyn_cast<NamedDecl>(D);
bool IsNDHidden = ND && !ND->isUnconditionallyVisible();
bool IsDImplicit = D->isImplicit();
bool IsDUsed = D->isUsed();
bool IsDReferenced = D->isThisDeclarationReferenced();
bool IsDInvalid = D->isInvalidDecl();
bool HasAttributes = D->hasAttrs();
const FullComment *Comment =
Options.dumpComments
? D->getASTContext().getLocalCommentForDeclUncached(D)
: nullptr;
AccessSpecifier Access = D->getAccess();
bool HasAccess = Access != AccessSpecifier::AS_none;
int size = 2 + ShouldEmitParentPointer + (bool)M + IsNDHidden +
IsDImplicit + IsDUsed + IsDReferenced + IsDInvalid +
HasAttributes + (bool)Comment + HasAccess;
ObjectScope Scope(OF, size);
OF.emitTag("pointer");
dumpPointer(D);
if (ShouldEmitParentPointer) {
OF.emitTag("parent_pointer");
dumpPointer(cast<Decl>(D->getDeclContext()));
}
OF.emitTag("source_range");
dumpSourceRange(D->getSourceRange());
if (M) {
OF.emitTag("owning_module");
OF.emitString(M->getFullModuleName());
}
OF.emitFlag("is_hidden", IsNDHidden);
OF.emitFlag("is_implicit", IsDImplicit);
OF.emitFlag("is_used", IsDUsed);
OF.emitFlag("is_this_declaration_referenced", IsDReferenced);
OF.emitFlag("is_invalid_decl", IsDInvalid);
if (HasAttributes) {
OF.emitTag("attributes");
ArrayScope ArrayAttr(OF, D->getAttrs().size());
for (auto I : D->getAttrs()) {
dumpAttr(I);
}
}
if (Comment) {
OF.emitTag("full_comment");
dumpFullComment(Comment);
}
if (HasAccess) {
OF.emitTag("access");
dumpAccessSpecifier(Access);
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CapturedDeclTupleSize() {
return DeclTupleSize() + DeclContextTupleSize();
}
//@atd #define captured_decl_tuple decl_tuple * decl_context_tuple
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCapturedDecl(const CapturedDecl *D) {
VisitDecl(D);
VisitDeclContext(D);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::LinkageSpecDeclTupleSize() {
return DeclTupleSize() + DeclContextTupleSize();
}
//@atd #define linkage_spec_decl_tuple decl_tuple * decl_context_tuple
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
VisitDecl(D);
VisitDeclContext(D);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::NamespaceDeclTupleSize() {
return NamedDeclTupleSize() + DeclContextTupleSize() + 1;
}
//@atd #define namespace_decl_tuple named_decl_tuple * decl_context_tuple * namespace_decl_info
//@atd type namespace_decl_info = {
//@atd ~is_inline : bool;
//@atd ?original_namespace : decl_ref option;
//@atd } <ocaml field_prefix="ndi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitNamespaceDecl(const NamespaceDecl *D) {
VisitNamedDecl(D);
VisitDeclContext(D);
bool IsInline = D->isInline();
bool IsOriginalNamespace = D->isOriginalNamespace();
ObjectScope Scope(OF, 0 + IsInline + !IsOriginalNamespace);
OF.emitFlag("is_inline", IsInline);
if (!IsOriginalNamespace) {
OF.emitTag("original_namespace");
dumpDeclRef(*D->getOriginalNamespace());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCContainerDeclTupleSize() {
return NamedDeclTupleSize() + DeclContextTupleSize();
}
//@atd #define obj_c_container_decl_tuple named_decl_tuple * decl_context_tuple
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCContainerDecl(
const ObjCContainerDecl *D) {
VisitNamedDecl(D);
VisitDeclContext(D);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::TagDeclTupleSize() {
return TypeDeclTupleSize() + DeclContextTupleSize() + 1;
}
//@atd type tag_kind = [
//@atd TTK_Struct
//@atd | TTK_Interface
//@atd | TTK_Union
//@atd | TTK_Class
//@atd | TTK_Enum
//@atd ]
//@atd #define tag_decl_tuple type_decl_tuple * decl_context_tuple * tag_kind
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitTagDecl(const TagDecl *D) {
VisitTypeDecl(D);
VisitDeclContext(D);
switch (D->getTagKind()) {
case TagTypeKind::TTK_Struct:
OF.emitSimpleVariant("TTK_Struct");
break;
case TagTypeKind::TTK_Interface:
OF.emitSimpleVariant("TTK_Interface");
break;
case TagTypeKind::TTK_Union:
OF.emitSimpleVariant("TTK_Union");
break;
case TagTypeKind::TTK_Class:
OF.emitSimpleVariant("TTK_Class");
break;
case TagTypeKind::TTK_Enum:
OF.emitSimpleVariant("TTK_Enum");
break;
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::TypeDeclTupleSize() {
return NamedDeclTupleSize() + 1;
}
//@atd #define type_decl_tuple named_decl_tuple * type_ptr
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitTypeDecl(const TypeDecl *D) {
VisitNamedDecl(D);
const Type *T = D->getTypeForDecl();
dumpPointerToType(T);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ValueDeclTupleSize() {
return NamedDeclTupleSize() + 1;
}
//@atd #define value_decl_tuple named_decl_tuple * qual_type
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitValueDecl(const ValueDecl *D) {
VisitNamedDecl(D);
dumpQualType(D->getType());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::TranslationUnitDeclTupleSize() {
return DeclTupleSize() + DeclContextTupleSize() + 1;
}
//@atd type input_kind = [
//@atd IK_None
//@atd | IK_Asm
//@atd | IK_C
//@atd | IK_CXX
//@atd | IK_ObjC
//@atd | IK_ObjCXX
//@atd | IK_OpenCL
//@atd | IK_CUDA
//@atd | IK_HIP
//@atd | IK_RenderScript
//@atd | IK_LLVM_IR
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpInputKind(InputKind kind) {
// Despite here we deal only with the language field of InputKind, there are
// new info in InputKind that can still be used, e.g. whether the source is
// preprocessed (PP), or precompiled.
switch (kind.getLanguage()) {
case Language::Unknown:
OF.emitSimpleVariant("IK_None");
break;
case Language::Asm:
OF.emitSimpleVariant("IK_Asm");
break;
case Language::C:
OF.emitSimpleVariant("IK_C");
break;
case Language::CXX:
OF.emitSimpleVariant("IK_CXX");
break;
case Language::ObjC:
OF.emitSimpleVariant("IK_ObjC");
break;
case Language::ObjCXX:
OF.emitSimpleVariant("IK_ObjCXX");
break;
case Language::OpenCL:
OF.emitSimpleVariant("IK_OpenCL");
break;
case Language::CUDA:
OF.emitSimpleVariant("IK_CUDA");
break;
case Language::RenderScript:
OF.emitSimpleVariant("IK_RenderScript");
break;
case Language::LLVM_IR:
OF.emitSimpleVariant("IK_LLVM_IR");
break;
case Language::HIP:
OF.emitSimpleVariant("IK_HIP");
break;
}
}
//@atd type integer_type_widths = {
//@atd char_type : int;
//@atd short_type : int;
//@atd int_type : int;
//@atd long_type : int;
//@atd longlong_type : int;
//@atd } <ocaml field_prefix="itw_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpIntegerTypeWidths(const TargetInfo &info) {
ObjectScope Scope(OF, 5);
OF.emitTag("char_type");
OF.emitInteger(info.getCharWidth());
OF.emitTag("short_type");
OF.emitInteger(info.getShortWidth());
OF.emitTag("int_type");
OF.emitInteger(info.getIntWidth());
OF.emitTag("long_type");
OF.emitInteger(info.getLongWidth());
OF.emitTag("longlong_type");
OF.emitInteger(info.getLongLongWidth());
}
//@atd #define translation_unit_decl_tuple decl_tuple * decl_context_tuple * translation_unit_decl_info
//@atd type translation_unit_decl_info = {
//@atd input_path : source_file;
//@atd input_kind : input_kind;
//@atd integer_type_widths : integer_type_widths;
//@atd ~is_objc_arc_on : bool;
//@atd types : c_type list;
//@atd } <ocaml field_prefix="tudi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitTranslationUnitDecl(
const TranslationUnitDecl *D) {
VisitDecl(D);
VisitDeclContext(D);
bool IsObjCArcOn = D->getASTContext().getLangOpts().ObjCAutoRefCount;
ObjectScope Scope(OF, 4 + IsObjCArcOn);
OF.emitTag("input_path");
OF.emitString(
Options.normalizeSourcePath(Options.inputFile.getFile().str().c_str()));
OF.emitTag("input_kind");
dumpInputKind(Options.inputFile.getKind());
OF.emitTag("integer_type_widths");
dumpIntegerTypeWidths(Context.getTargetInfo());
OF.emitFlag("is_objc_arc_on", IsObjCArcOn);
OF.emitTag("types");
const auto &types = Context.getTypes();
ArrayScope aScope(OF, types.size() + 1); // + 1 for nullptr
for (const Type *type : types) {
dumpType(type);
}
// Just in case, add NoneType to dumped types
dumpType(nullptr);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::NamedDeclTupleSize() {
return DeclTupleSize() + 1;
}
//@atd #define named_decl_tuple decl_tuple * named_decl_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitNamedDecl(const NamedDecl *D) {
VisitDecl(D);
dumpName(*D);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::TypedefDeclTupleSize() {
return ASTExporter::TypedefNameDeclTupleSize() + 1;
}
//@atd #define typedef_decl_tuple typedef_name_decl_tuple * typedef_decl_info
//@atd type typedef_decl_info = {
//@atd ~is_module_private : bool
//@atd } <ocaml field_prefix="tdi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitTypedefDecl(const TypedefDecl *D) {
ASTExporter<ATDWriter>::VisitTypedefNameDecl(D);
bool IsModulePrivate = D->isModulePrivate();
ObjectScope Scope(OF, 0 + IsModulePrivate);
OF.emitFlag("is_module_private", IsModulePrivate);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::EnumDeclTupleSize() {
return TagDeclTupleSize() + 1;
}
//@atd #define enum_decl_tuple tag_decl_tuple * enum_decl_info
//@atd type enum_decl_info = {
//@atd ?scope : enum_decl_scope option;
//@atd ~is_module_private : bool
//@atd } <ocaml field_prefix="edi_">
//@atd type enum_decl_scope = [Class | Struct]
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitEnumDecl(const EnumDecl *D) {
VisitTagDecl(D);
bool IsScoped = D->isScoped();
bool IsModulePrivate = D->isModulePrivate();
ObjectScope Scope(OF, 0 + IsScoped + IsModulePrivate); // not covered by tests
if (IsScoped) {
OF.emitTag("scope");
if (D->isScopedUsingClassTag())
OF.emitSimpleVariant("Class");
else
OF.emitSimpleVariant("Struct");
}
OF.emitFlag("is_module_private", IsModulePrivate);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::RecordDeclTupleSize() {
return TagDeclTupleSize() + 1;
}
//@atd #define record_decl_tuple tag_decl_tuple * record_decl_info
//@atd type record_decl_info = {
//@atd definition_ptr : pointer;
//@atd ~is_module_private : bool;
//@atd ~is_complete_definition : bool;
//@atd ~is_dependent_type : bool;
//@atd } <ocaml field_prefix="rdi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitRecordDecl(const RecordDecl *D) {
VisitTagDecl(D);
bool IsModulePrivate = D->isModulePrivate();
bool IsCompleteDefinition = D->isCompleteDefinition();
bool IsDependentType = D->isDependentType();
ObjectScope Scope(
OF, 1 + IsModulePrivate + IsCompleteDefinition + IsDependentType);
OF.emitTag("definition_ptr");
dumpPointer(D->getDefinition());
OF.emitFlag("is_module_private", IsModulePrivate);
OF.emitFlag("is_complete_definition", IsCompleteDefinition);
OF.emitFlag("is_dependent_type", IsDependentType);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::EnumConstantDeclTupleSize() {
return ValueDeclTupleSize() + 1;
}
//@atd #define enum_constant_decl_tuple value_decl_tuple * enum_constant_decl_info
//@atd type enum_constant_decl_info = {
//@atd ?init_expr : stmt option
//@atd } <ocaml field_prefix="ecdi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitEnumConstantDecl(const EnumConstantDecl *D) {
VisitValueDecl(D);
const Expr *Init = D->getInitExpr();
ObjectScope Scope(OF, 0 + (bool)Init); // not covered by tests
if (Init) {
OF.emitTag("init_expr");
dumpStmt(Init);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::IndirectFieldDeclTupleSize() {
return ValueDeclTupleSize() + 1;
}
//@atd #define indirect_field_decl_tuple value_decl_tuple * decl_ref list
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitIndirectFieldDecl(
const IndirectFieldDecl *D) {
VisitValueDecl(D);
ArrayScope Scope(
OF,
std::distance(D->chain_begin(), D->chain_end())); // not covered by tests
for (auto I : D->chain()) {
dumpDeclRef(*I);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::FunctionDeclTupleSize() {
return ASTExporter::DeclaratorDeclTupleSize() + 1;
}
//@atd #define function_decl_tuple declarator_decl_tuple * function_decl_info
//@atd type function_decl_info = {
//@atd ?mangled_name : string option;
//@atd ~is_cpp : bool;
//@atd ~is_inline : bool;
//@atd ~is_module_private : bool;
//@atd ~is_pure : bool;
//@atd ~is_delete_as_written : bool;
//@atd ~is_no_return : bool;
//@atd ~is_variadic : bool;
//@atd ~is_static : bool;
//@atd ~parameters : decl list;
//@atd ?decl_ptr_with_body : pointer option;
//@atd ?body : stmt option;
//@atd ?template_specialization : template_specialization_info option
//@atd } <ocaml field_prefix="fdi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitFunctionDecl(const FunctionDecl *D) {
ASTExporter<ATDWriter>::VisitDeclaratorDecl(D);
// We purposedly do not call VisitDeclContext(D).
auto DNkind = D->getDeclName().getNameKind();
bool ShouldMangleName = Mangler->shouldMangleDeclName(D) &&
DNkind != DeclarationName::CXXDeductionGuideName &&
DNkind != DeclarationName::CXXUsingDirective;
bool IsInlineSpecified = D->isInlineSpecified();
bool IsModulePrivate = D->isModulePrivate();
bool IsPure = D->isPure();
bool IsDeletedAsWritten = D->isDeletedAsWritten();
bool IsCpp = Mangler->getASTContext().getLangOpts().CPlusPlus;
bool IsVariadic = D->isVariadic();
bool IsStatic = false; // static functions
if (D->getStorageClass() == SC_Static) {
IsStatic = true;
}
auto IsNoReturn = D->isNoReturn();
bool HasParameters = !D->param_empty();
const FunctionDecl *DeclWithBody = D;
// FunctionDecl::hasBody() will set DeclWithBody pointer to decl that
// has body. If there is no body in all decls of that function,
// then we need to set DeclWithBody to nullptr manually
if (!D->hasBody(DeclWithBody)) {
DeclWithBody = nullptr;
}
bool HasDeclarationBody = D->doesThisDeclarationHaveABody();
FunctionTemplateDecl *TemplateDecl = D->getPrimaryTemplate();
int size = ShouldMangleName + IsCpp + IsInlineSpecified + IsModulePrivate +
IsPure + IsDeletedAsWritten + IsNoReturn + IsVariadic +
IsStatic + HasParameters + (bool)DeclWithBody +
HasDeclarationBody + (bool)TemplateDecl;
ObjectScope Scope(OF, size);
if (ShouldMangleName) {
OF.emitTag("mangled_name");
SmallString<64> Buf;
llvm::raw_svector_ostream StrOS(Buf);
GlobalDecl GD;
if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
GD = GlobalDecl(CD, Ctor_Base);
} else if (const auto *DD = dyn_cast<CXXDestructorDecl>(D)) {
GD = GlobalDecl(DD, Dtor_Base);
} else {
GD = GlobalDecl(D);
}
Mangler->mangleName(GD, StrOS);
// mangled names can get ridiculously long, so hash them to a fixed size
OF.emitString(std::to_string(fnv64Hash(StrOS)));
}
OF.emitFlag("is_cpp", IsCpp);
OF.emitFlag("is_inline", IsInlineSpecified);
OF.emitFlag("is_module_private", IsModulePrivate);
OF.emitFlag("is_pure", IsPure);
OF.emitFlag("is_delete_as_written", IsDeletedAsWritten);
OF.emitFlag("is_no_return", IsNoReturn);
OF.emitFlag("is_variadic", IsVariadic);
OF.emitFlag("is_static", IsStatic);
// if (const FunctionProtoType *FPT =
// D->getType()->getAs<FunctionProtoType>()) {
// FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
// switch (EPI.ExceptionSpec.Type) {
// default: break;
// case EST_Unevaluated:
// OS << " noexcept-unevaluated " << EPI.ExceptionSpec.SourceDecl;
// break;
// case EST_Uninstantiated:
// OS << " noexcept-uninstantiated " << EPI.ExceptionSpec.SourceTemplate;
// break;
// }
// }
//
// const FunctionTemplateSpecializationInfo *FTSI =
// D->getTemplateSpecializationInfo();
// bool HasTemplateSpecialization = FTSI;
//
//
// if (HasTemplateSpecialization) {
// dumpTemplateArgumentList(*FTSI->TemplateArguments);
// }
if (HasParameters) {
FunctionDecl::param_const_iterator I = D->param_begin(), E = D->param_end();
if (I != E) {
OF.emitTag("parameters");
ArrayScope Scope(OF, std::distance(I, E));
for (; I != E; ++I) {
dumpDecl(*I);
}
}
}
if (DeclWithBody) {
OF.emitTag("decl_ptr_with_body");
dumpPointer(DeclWithBody);
}
if (HasDeclarationBody) {
const Stmt *Body = D->getBody();
if (Body) {
OF.emitTag("body");
dumpStmt(Body);
}
}
if (TemplateDecl) {
OF.emitTag("template_specialization");
dumpTemplateSpecialization(TemplateDecl,
*D->getTemplateSpecializationArgs());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::FieldDeclTupleSize() {
return ASTExporter::DeclaratorDeclTupleSize() + 1;
}
//@atd #define field_decl_tuple declarator_decl_tuple * field_decl_info
//@atd type field_decl_info = {
//@atd ~is_mutable : bool;
//@atd ~is_module_private : bool;
//@atd ?init_expr : stmt option;
//@atd ?bit_width_expr : stmt option
//@atd } <ocaml field_prefix="fldi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitFieldDecl(const FieldDecl *D) {
ASTExporter<ATDWriter>::VisitDeclaratorDecl(D);
bool IsMutable = D->isMutable();
bool IsModulePrivate = D->isModulePrivate();
bool HasBitWidth = D->isBitField() && D->getBitWidth();
Expr *Init = D->getInClassInitializer();
ObjectScope Scope(OF,
0 + IsMutable + IsModulePrivate + HasBitWidth +
(bool)Init); // not covered by tests
OF.emitFlag("is_mutable", IsMutable);
OF.emitFlag("is_module_private", IsModulePrivate);
if (HasBitWidth) {
OF.emitTag("bit_width_expr");
dumpStmt(D->getBitWidth());
}
if (Init) {
OF.emitTag("init_expr");
dumpStmt(Init);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::VarDeclTupleSize() {
return ASTExporter::DeclaratorDeclTupleSize() + 1;
}
//@atd #define var_decl_tuple declarator_decl_tuple * var_decl_info
//@atd type var_decl_info = {
//@atd ~is_global : bool;
//@atd ~is_extern : bool;
//@atd ~is_static : bool;
//@atd ~is_static_local : bool;
//@atd ~is_static_data_member : bool;
//@atd ~is_const_expr : bool;
//@atd ~is_init_ice : bool;
//@atd ?init_expr : stmt option;
//@atd ~is_init_expr_cxx11_constant: bool;
//@atd ?parm_index_in_function : int option;
//@atd } <ocaml field_prefix="vdi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitVarDecl(const VarDecl *D) {
ASTExporter<ATDWriter>::VisitDeclaratorDecl(D);
bool IsGlobal = D->hasGlobalStorage(); // including static function variables
bool IsExtern = D->hasExternalStorage();
bool IsStatic = false; // static variables
if (D->getStorageClass() == SC_Static) {
IsStatic = true;
}
bool IsStaticLocal = D->isStaticLocal(); // static function variables
bool IsStaticDataMember = D->isStaticDataMember();
bool IsConstExpr = D->isConstexpr();
bool IsInitICE = D->isInitKnownICE() && D->isInitICE();
bool HasInit = D->hasInit();
const ParmVarDecl *ParmDecl = dyn_cast<ParmVarDecl>(D);
bool HasParmIndex = (bool)ParmDecl;
bool isInitExprCXX11ConstantExpr = false;
ObjectScope Scope(OF,
IsGlobal + IsExtern + IsStatic + IsStaticLocal +
IsStaticDataMember + IsConstExpr + IsInitICE + HasInit +
HasParmIndex + isInitExprCXX11ConstantExpr);
OF.emitFlag("is_global", IsGlobal);
OF.emitFlag("is_extern", IsExtern);
OF.emitFlag("is_static", IsStatic);
OF.emitFlag("is_static_local", IsStaticLocal);
OF.emitFlag("is_static_data_member", IsStaticDataMember);
OF.emitFlag("is_const_expr", IsConstExpr);
OF.emitFlag("is_init_ice", IsInitICE);
if (HasInit) {
OF.emitTag("init_expr");
dumpStmt(D->getInit());
OF.emitFlag("is_init_expr_cxx11_constant", isInitExprCXX11ConstantExpr);
}
if (HasParmIndex) {
OF.emitTag("parm_index_in_function");
OF.emitInteger(ParmDecl->getFunctionScopeIndex());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ImportDeclTupleSize() {
return DeclTupleSize() + 1;
}
//@atd #define import_decl_tuple decl_tuple * string
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitImportDecl(const ImportDecl *D) {
VisitDecl(D);
OF.emitString(D->getImportedModule()->getFullModuleName());
}
//===----------------------------------------------------------------------===//
// C++ Declarations
//===----------------------------------------------------------------------===//
template <class ATDWriter>
int ASTExporter<ATDWriter>::UsingDirectiveDeclTupleSize() {
return NamedDeclTupleSize() + 1;
}
//@atd #define using_directive_decl_tuple named_decl_tuple * using_directive_decl_info
//@atd type using_directive_decl_info = {
//@atd using_location : source_location;
//@atd namespace_key_location : source_location;
//@atd nested_name_specifier_locs : nested_name_specifier_loc list;
//@atd ?nominated_namespace : decl_ref option;
//@atd } <ocaml field_prefix="uddi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitUsingDirectiveDecl(
const UsingDirectiveDecl *D) {
VisitNamedDecl(D);
bool HasNominatedNamespace = D->getNominatedNamespace();
ObjectScope Scope(OF, 3 + HasNominatedNamespace);
OF.emitTag("using_location");
dumpSourceLocation(D->getUsingLoc());
OF.emitTag("namespace_key_location");
dumpSourceLocation(D->getNamespaceKeyLocation());
OF.emitTag("nested_name_specifier_locs");
dumpNestedNameSpecifierLoc(D->getQualifierLoc());
if (HasNominatedNamespace) {
OF.emitTag("nominated_namespace");
dumpDeclRef(*D->getNominatedNamespace());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::NamespaceAliasDeclTupleSize() {
return NamedDeclTupleSize() + 1;
}
//@atd #define namespace_alias_decl_tuple named_decl_tuple * namespace_alias_decl_info
//@atd type namespace_alias_decl_info = {
//@atd namespace_loc : source_location;
//@atd target_name_loc : source_location;
//@atd nested_name_specifier_locs : nested_name_specifier_loc list;
//@atd namespace : decl_ref;
//@atd } <ocaml field_prefix="nadi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitNamespaceAliasDecl(
const NamespaceAliasDecl *D) {
VisitNamedDecl(D);
ObjectScope Scope(OF, 4);
OF.emitTag("namespace_loc");
dumpSourceLocation(D->getNamespaceLoc());
OF.emitTag("target_name_loc");
dumpSourceLocation(D->getTargetNameLoc());
OF.emitTag("nested_name_specifier_locs");
dumpNestedNameSpecifierLoc(D->getQualifierLoc());
OF.emitTag("namespace");
dumpDeclRef(*D->getNamespace());
}
//@atd type lambda_capture_info = {
//@atd capture_kind : lambda_capture_kind;
//@atd ~capture_this : bool;
//@atd ~capture_variable : bool;
//@atd ~capture_VLAtype : bool;
//@atd ?init_captured_vardecl : decl option;
//@atd ?captured_var : decl_ref option;
//@atd ~is_implicit : bool;
//@atd location : source_range;
//@atd ~is_pack_expansion: bool;
//@atd } <ocaml field_prefix="lci_">
//@atd type lambda_capture_kind = [
//@atd | LCK_This
//@atd | LCK_ByCopy
//@atd | LCK_ByRef
//@atd | LCK_VLAType
//@atd | LCK_StarThis]
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpClassLambdaCapture(const LambdaCapture *C) {
LambdaCaptureKind CK = C->getCaptureKind();
bool CapturesThis = C->capturesThis();
bool CapturesVariable = C->capturesVariable();
bool CapturesVLAType = C->capturesVLAType();
VarDecl *decl = C->capturesVariable() ? C->getCapturedVar() : nullptr;
bool IsInitCapture = decl && decl->isInitCapture();
bool IsImplicit = C->isImplicit();
SourceRange source_range = C->getLocation();
bool IsPackExpansion = C->isPackExpansion();
ObjectScope Scope(OF,
2 + CapturesThis + CapturesVariable + CapturesVLAType +
IsInitCapture + (bool)decl + IsImplicit +
IsPackExpansion);
OF.emitTag("capture_kind");
switch (CK) {
case LCK_This:
OF.emitSimpleVariant("LCK_This");
break;
case LCK_ByCopy:
OF.emitSimpleVariant("LCK_ByCopy");
break;
case LCK_ByRef:
OF.emitSimpleVariant("LCK_ByRef");
break;
case LCK_VLAType:
OF.emitSimpleVariant("LCK_VLAType");
break;
case LCK_StarThis:
OF.emitSimpleVariant("LCK_StarThis");
break;
};
OF.emitFlag("capture_this", CapturesThis);
OF.emitFlag("capture_variable", CapturesVariable);
OF.emitFlag("capture_VLAtype", CapturesVLAType);
if (decl) {
if (IsInitCapture) {
OF.emitTag("init_captured_vardecl");
dumpDecl(decl);
}
OF.emitTag("captured_var");
dumpDeclRef(*decl);
}
OF.emitFlag("is_implicit", IsImplicit);
OF.emitTag("location");
dumpSourceRange(source_range);
OF.emitFlag("is_pack_expansion", IsPackExpansion);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CXXRecordDeclTupleSize() {
return RecordDeclTupleSize() + 1;
}
//@atd #define cxx_record_decl_tuple record_decl_tuple * cxx_record_decl_info
//@atd type cxx_record_decl_info = {
//@atd ~bases : type_ptr list;
//@atd ~vbases : type_ptr list;
//@atd ~transitive_vbases : type_ptr list;
//@atd ~is_pod : bool;
//@atd ?destructor : decl_ref option;
//@atd ?lambda_call_operator : decl_ref option;
//@atd ~lambda_captures : lambda_capture_info list;
//@atd } <ocaml field_prefix="xrdi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCXXRecordDecl(const CXXRecordDecl *D) {
VisitRecordDecl(D);
if (!D->isCompleteDefinition()) {
// We need to return early here. Otherwise plugin will crash.
// It looks like CXXRecordDecl may be initialized with garbage.
// Not sure what to do when we'll have some non-optional data to generate??
ObjectScope Scope(OF, 0);
return;
}
// getNumBases and getNumVBases are not reliable, extract this info
// directly from what is going to be dumped
SmallVector<CXXBaseSpecifier, 2> nonVBases;
SmallVector<CXXBaseSpecifier, 2> vBases;
for (const auto base : D->bases()) {
if (base.isVirtual()) {
vBases.push_back(base);
} else {
nonVBases.push_back(base);
}
}
bool HasVBases = vBases.size() > 0;
bool HasNonVBases = nonVBases.size() > 0;
unsigned numTransitiveVBases = D->getNumVBases();
bool HasTransitiveVBases = numTransitiveVBases > 0;
bool IsPOD = D->isPOD();
const CXXDestructorDecl *DestructorDecl = D->getDestructor();
const CXXMethodDecl *LambdaCallOperator = D->getLambdaCallOperator();
auto I = D->captures_begin(), E = D->captures_end();
ObjectScope Scope(OF,
0 + HasNonVBases + HasVBases + HasTransitiveVBases + IsPOD +
(bool)DestructorDecl + (bool)LambdaCallOperator +
(I != E));
if (HasNonVBases) {
OF.emitTag("bases");
ArrayScope aScope(OF, nonVBases.size());
for (const auto base : nonVBases) {
dumpQualTypeNoQuals(base.getType());
}
}
if (HasVBases) {
OF.emitTag("vbases");
ArrayScope aScope(OF, vBases.size());
for (const auto base : vBases) {
dumpQualTypeNoQuals(base.getType());
}
}
if (HasTransitiveVBases) {
OF.emitTag("transitive_vbases");
ArrayScope aScope(OF, numTransitiveVBases);
for (const auto base : D->vbases()) {
dumpQualTypeNoQuals(base.getType());
}
}
OF.emitFlag("is_pod", IsPOD);
if (DestructorDecl) {
OF.emitTag("destructor");
dumpDeclRef(*DestructorDecl);
}
if (LambdaCallOperator) {
OF.emitTag("lambda_call_operator");
dumpDeclRef(*LambdaCallOperator);
}
if (I != E) {
OF.emitTag("lambda_captures");
ArrayScope Scope(OF, std::distance(I, E));
for (; I != E; ++I) {
dumpClassLambdaCapture(I);
}
}
}
//@atd type template_instantiation_arg_info = [
//@atd | Null
//@atd | Type of qual_type
//@atd | Declaration of pointer
//@atd | NullPtr
//@atd | Integral of string
//@atd | Template
//@atd | TemplateExpansion
//@atd | Expression
//@atd | Pack of template_instantiation_arg_info list
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpTemplateArgument(const TemplateArgument &Arg) {
switch (Arg.getKind()) {
case TemplateArgument::Null:
OF.emitSimpleVariant("Null");
break;
case TemplateArgument::Type: {
VariantScope Scope(OF, "Type");
dumpQualType(Arg.getAsType());
break;
}
case TemplateArgument::Declaration: {
VariantScope Scope(OF, "Declaration");
dumpPointer(Arg.getAsDecl());
break;
}
case TemplateArgument::NullPtr:
OF.emitSimpleVariant("NullPtr");
break;
case TemplateArgument::Integral: {
VariantScope Scope(OF, "Integral");
OF.emitString(Arg.getAsIntegral().toString(10));
break;
}
case TemplateArgument::Template: {
OF.emitSimpleVariant("Template");
break;
}
case TemplateArgument::TemplateExpansion: {
OF.emitSimpleVariant("TemplateExpansion");
break;
}
case TemplateArgument::Expression: {
OF.emitSimpleVariant("Expression");
break;
}
case TemplateArgument::Pack: {
VariantScope Scope(OF, "Pack");
ArrayScope aScope(OF, Arg.pack_size());
for (TemplateArgument::pack_iterator I = Arg.pack_begin(),
E = Arg.pack_end();
I != E;
++I) {
dumpTemplateArgument(*I);
}
break;
}
}
}
//@atd type template_specialization_info = {
//@atd template_decl : pointer;
//@atd ~specialization_args : template_instantiation_arg_info list;
//@atd } <ocaml field_prefix="tsi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpTemplateSpecialization(
const TemplateDecl *D, const TemplateArgumentList &Args) {
bool HasTemplateArgs = Args.size() > 0;
ObjectScope oScope(OF, 1 + HasTemplateArgs);
OF.emitTag("template_decl");
dumpPointer(D);
if (HasTemplateArgs) {
OF.emitTag("specialization_args");
ArrayScope aScope(OF, Args.size());
for (size_t i = 0; i < Args.size(); i++) {
dumpTemplateArgument(Args[i]);
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ClassTemplateSpecializationDeclTupleSize() {
return CXXRecordDeclTupleSize() + 2;
}
//@atd #define class_template_specialization_decl_tuple cxx_record_decl_tuple * string * template_specialization_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitClassTemplateSpecializationDecl(
const ClassTemplateSpecializationDecl *D) {
VisitCXXRecordDecl(D);
bool ShouldMangleName = Mangler->shouldMangleDeclName(D) &&
(isa<FunctionDecl>(D) || isa<VarDecl>(D));
if (ShouldMangleName) {
SmallString<64> Buf;
llvm::raw_svector_ostream StrOS(Buf);
Mangler->mangleName(D, StrOS);
// mangled names can get ridiculously long, so hash them to a fixed size
OF.emitString(std::to_string(fnv64Hash(StrOS)));
} else {
OF.emitString("");
}
dumpTemplateSpecialization(D->getSpecializedTemplate(), D->getTemplateArgs());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CXXMethodDeclTupleSize() {
return FunctionDeclTupleSize() + 1;
}
//@atd #define cxx_method_decl_tuple function_decl_tuple * cxx_method_decl_info
//@atd type cxx_method_decl_info = {
//@atd ~is_virtual : bool;
//@atd ~is_static : bool;
//@atd ~is_constexpr : bool;
//@atd ~cxx_ctor_initializers : cxx_ctor_initializer list;
//@atd ~overriden_methods : decl_ref list;
//@atd } <ocaml field_prefix="xmdi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCXXMethodDecl(const CXXMethodDecl *D) {
VisitFunctionDecl(D);
bool IsVirtual = D->isVirtual();
bool IsStatic = D->isStatic();
const CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(D);
bool HasCtorInitializers = C && C->init_begin() != C->init_end();
bool IsConstexpr = D->isConstexpr();
auto OB = D->begin_overridden_methods();
auto OE = D->end_overridden_methods();
ObjectScope Scope(
OF,
IsVirtual + IsStatic + IsConstexpr + HasCtorInitializers + (OB != OE));
OF.emitFlag("is_virtual", IsVirtual);
OF.emitFlag("is_static", IsStatic);
OF.emitFlag("is_constexpr", IsConstexpr);
if (HasCtorInitializers) {
OF.emitTag("cxx_ctor_initializers");
ArrayScope Scope(OF, std::distance(C->init_begin(), C->init_end()));
for (auto I : C->inits()) {
dumpCXXCtorInitializer(*I);
}
}
if (OB != OE) {
OF.emitTag("overriden_methods");
ArrayScope Scope(OF, std::distance(OB, OE));
for (; OB != OE; ++OB) {
dumpDeclRef(**OB);
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ClassTemplateDeclTupleSize() {
return ASTExporter<ATDWriter>::RedeclarableTemplateDeclTupleSize() + 1;
}
//@atd #define class_template_decl_tuple redeclarable_template_decl_tuple * template_decl_info
//@atd type template_decl_info = {
//@atd ~specializations : decl list;
//@atd } <ocaml field_prefix="tdi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitClassTemplateDecl(
const ClassTemplateDecl *D) {
ASTExporter<ATDWriter>::VisitRedeclarableTemplateDecl(D);
std::vector<const ClassTemplateSpecializationDecl *> DeclsToDump;
if (D == D->getCanonicalDecl()) {
// dump specializations once
for (const auto *spec : D->specializations()) {
switch (spec->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
DeclsToDump.push_back(spec);
break;
case TSK_ExplicitSpecialization:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
// these specializations will be dumped elsewhere
break;
}
}
}
bool ShouldDumpSpecializations = !DeclsToDump.empty();
ObjectScope Scope(OF, 0 + ShouldDumpSpecializations);
if (ShouldDumpSpecializations) {
OF.emitTag("specializations");
ArrayScope aScope(OF, DeclsToDump.size());
for (const auto *spec : DeclsToDump) {
dumpDecl(spec);
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::FunctionTemplateDeclTupleSize() {
return ASTExporter<ATDWriter>::RedeclarableTemplateDeclTupleSize() + 1;
}
//@atd #define function_template_decl_tuple redeclarable_template_decl_tuple * template_decl_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitFunctionTemplateDecl(
const FunctionTemplateDecl *D) {
ASTExporter<ATDWriter>::VisitRedeclarableTemplateDecl(D);
std::vector<const FunctionDecl *> DeclsToDump;
if (D == D->getCanonicalDecl()) {
// dump specializations once
for (const auto *spec : D->specializations()) {
switch (spec->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
case TSK_ExplicitInstantiationDefinition:
case TSK_ExplicitInstantiationDeclaration:
DeclsToDump.push_back(spec);
break;
case TSK_ExplicitSpecialization:
// these specializations will be dumped when they are defined
break;
}
}
}
bool ShouldDumpSpecializations = !DeclsToDump.empty();
ObjectScope Scope(OF, 0 + ShouldDumpSpecializations);
if (ShouldDumpSpecializations) {
OF.emitTag("specializations");
ArrayScope aScope(OF, DeclsToDump.size());
for (const auto *spec : DeclsToDump) {
dumpDecl(spec);
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::FriendDeclTupleSize() {
return DeclTupleSize() + 1;
}
//@atd #define friend_decl_tuple decl_tuple * friend_info
//@atd type friend_info = [ Type of type_ptr | Decl of decl ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitFriendDecl(const FriendDecl *D) {
VisitDecl(D);
if (TypeSourceInfo *T = D->getFriendType()) {
VariantScope Scope(OF, "Type");
dumpQualTypeNoQuals(T->getType());
} else {
VariantScope Scope(OF, "Decl");
dumpDecl(D->getFriendDecl());
}
}
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitTypeAliasDecl(const TypeAliasDecl *D) {
// dumpName(D);
// dumpQualType(D->getUnderlyingType());
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitTypeAliasTemplateDecl(const
// TypeAliasTemplateDecl *D) {
// dumpName(D);
// dumpTemplateParameters(D->getTemplateParameters());
// dumpDecl(D->getTemplatedDecl());
//}
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitStaticAssertDecl(const StaticAssertDecl *D)
// {
// dumpStmt(D->getAssertExpr());
// dumpStmt(D->getMessage());
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitFunctionTemplateDecl(const
// FunctionTemplateDecl *D) {
// dumpName(D);
// dumpTemplateParameters(D->getTemplateParameters());
// dumpDecl(D->getTemplatedDecl());
// for (FunctionTemplateDecl::spec_iterator I = D->spec_begin(),
// E = D->spec_end();
// I != E; ++I) {
// FunctionTemplateDecl::spec_iterator Next = I;
// ++Next;
// switch (I->getTemplateSpecializationKind()) {
// case TSK_Undeclared:
// case TSK_ImplicitInstantiation:
// case TSK_ExplicitInstantiationDeclaration:
// case TSK_ExplicitInstantiationDefinition:
// if (D == D->getCanonicalDecl())
// dumpDecl(*I);
// else
// dumpDeclRef(*I);
// break;
// case TSK_ExplicitSpecialization:
// dumpDeclRef(*I);
// break;
// }
// }
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitClassTemplateDecl(const ClassTemplateDecl
// *D) {
// dumpName(D);
// dumpTemplateParameters(D->getTemplateParameters());
//
// ClassTemplateDecl::spec_iterator I = D->spec_begin();
// ClassTemplateDecl::spec_iterator E = D->spec_end();
// dumpDecl(D->getTemplatedDecl());
// for (; I != E; ++I) {
// ClassTemplateDecl::spec_iterator Next = I;
// ++Next;
// switch (I->getTemplateSpecializationKind()) {
// case TSK_Undeclared:
// case TSK_ImplicitInstantiation:
// if (D == D->getCanonicalDecl())
// dumpDecl(*I);
// else
// dumpDeclRef(*I);
// break;
// case TSK_ExplicitSpecialization:
// case TSK_ExplicitInstantiationDeclaration:
// case TSK_ExplicitInstantiationDefinition:
// dumpDeclRef(*I);
// break;
// }
// }
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitClassTemplateSpecializationDecl(
// const ClassTemplateSpecializationDecl *D) {
// VisitCXXRecordDecl(D);
// dumpTemplateArgumentList(D->getTemplateArgs());
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitClassTemplatePartialSpecializationDecl(
// const ClassTemplatePartialSpecializationDecl *D) {
// VisitClassTemplateSpecializationDecl(D);
// dumpTemplateParameters(D->getTemplateParameters());
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitClassScopeFunctionSpecializationDecl(
// const ClassScopeFunctionSpecializationDecl *D) {
// dumpDeclRef(D->getSpecialization());
// if (D->hasExplicitTemplateArgs())
// dumpTemplateArgumentListInfo(D->templateArgs());
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitVarTemplateDecl(const VarTemplateDecl *D) {
// dumpName(D);
// dumpTemplateParameters(D->getTemplateParameters());
//
// VarTemplateDecl::spec_iterator I = D->spec_begin();
// VarTemplateDecl::spec_iterator E = D->spec_end();
// dumpDecl(D->getTemplatedDecl());
// for (; I != E; ++I) {
// VarTemplateDecl::spec_iterator Next = I;
// ++Next;
// switch (I->getTemplateSpecializationKind()) {
// case TSK_Undeclared:
// case TSK_ImplicitInstantiation:
// if (D == D->getCanonicalDecl())
// dumpDecl(*I);
// else
// dumpDeclRef(*I);
// break;
// case TSK_ExplicitSpecialization:
// case TSK_ExplicitInstantiationDeclaration:
// case TSK_ExplicitInstantiationDefinition:
// dumpDeclRef(*I);
// break;
// }
// }
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitVarTemplateSpecializationDecl(
// const VarTemplateSpecializationDecl *D) {
// dumpTemplateArgumentList(D->getTemplateArgs());
// VisitVarDecl(D);
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitVarTemplatePartialSpecializationDecl(
// const VarTemplatePartialSpecializationDecl *D) {
// dumpTemplateParameters(D->getTemplateParameters());
// VisitVarTemplateSpecializationDecl(D);
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitTemplateTypeParmDecl(const
// TemplateTypeParmDecl *D) {
// if (D->wasDeclaredWithTypename())
// OS << " typename";
// else
// OS << " class";
// if (D->isParameterPack())
// OS << " ...";
// dumpName(D);
// if (D->hasDefaultArgument())
// dumpQualType(D->getDefaultArgument());
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitNonTypeTemplateParmDecl(const
// NonTypeTemplateParmDecl *D) {
// dumpQualType(D->getType());
// if (D->isParameterPack())
// OS << " ...";
// dumpName(D);
// if (D->hasDefaultArgument())
// dumpStmt(D->getDefaultArgument());
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitTemplateTemplateParmDecl(
// const TemplateTemplateParmDecl *D) {
// if (D->isParameterPack())
// OS << " ...";
// dumpName(D);
// dumpTemplateParameters(D->getTemplateParameters());
// if (D->hasDefaultArgument())
// dumpTemplateArgumentLoc(D->getDefaultArgument());
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitUsingDecl(const UsingDecl *D) {
// OS << ' ';
// D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
// OS << D->getNameAsString();
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitUnresolvedUsingTypenameDecl(
// const UnresolvedUsingTypenameDecl *D) {
// OS << ' ';
// D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
// OS << D->getNameAsString();
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitUnresolvedUsingValueDecl(const
// UnresolvedUsingValueDecl *D) {
// OS << ' ';
// D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
// OS << D->getNameAsString();
// dumpQualType(D->getType());
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitUsingShadowDecl(const UsingShadowDecl *D) {
// OS << ' ';
// dumpDeclRef(D->getTargetDecl());
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
// switch (D->getLanguage()) {
// case LinkageSpecDecl::lang_c: OS << " C"; break;
// case LinkageSpecDecl::lang_cxx: OS << " C++"; break;
// }
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::VisitAccessSpecDecl(const AccessSpecDecl *D) {
// OS << ' ';
// dumpAccessSpecifier(D->getAccess());
//}
//
//
////===----------------------------------------------------------------------===//
//// Obj-C Declarations
////===----------------------------------------------------------------------===//
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCIvarDeclTupleSize() {
return FieldDeclTupleSize() + 1;
}
//@atd #define obj_c_ivar_decl_tuple field_decl_tuple * obj_c_ivar_decl_info
//@atd type obj_c_ivar_decl_info = {
//@atd ~is_synthesize : bool;
//@atd ~access_control <ocaml default="`None"> : obj_c_access_control;
//@atd } <ocaml field_prefix="ovdi_">
//@atd type obj_c_access_control = [ None | Private | Protected | Public | Package
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
VisitFieldDecl(D);
bool IsSynthesize = D->getSynthesize();
ObjCIvarDecl::AccessControl AC = D->getAccessControl();
bool ShouldEmitAC = AC != ObjCIvarDecl::None;
ObjectScope Scope(OF, IsSynthesize + ShouldEmitAC); // not covered by tests
OF.emitFlag("is_synthesize", IsSynthesize);
if (ShouldEmitAC) {
OF.emitTag("access_control");
switch (AC) {
case ObjCIvarDecl::Private:
OF.emitSimpleVariant("Private");
break;
case ObjCIvarDecl::Protected:
OF.emitSimpleVariant("Protected");
break;
case ObjCIvarDecl::Public:
OF.emitSimpleVariant("Public");
break;
case ObjCIvarDecl::Package:
OF.emitSimpleVariant("Package");
break;
case ObjCIvarDecl::None:
llvm_unreachable("unreachable");
break;
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCMethodDeclTupleSize() {
return NamedDeclTupleSize() + 1;
}
//@atd #define obj_c_method_decl_tuple named_decl_tuple * obj_c_method_decl_info
//@atd type obj_c_method_decl_info = {
//@atd ~is_instance_method : bool;
//@atd result_type : qual_type;
//@atd ~is_property_accessor : bool;
//@atd ?property_decl : decl_ref option;
//@atd ~parameters : decl list;
//@atd ~implicit_parameters : decl list;
//@atd ~is_variadic : bool;
//@atd ~is_overriding : bool;
//@atd ~is_optional : bool;
//@atd ?body : stmt option;
//@atd ~mangled_name : string;
//@atd } <ocaml field_prefix="omdi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
VisitNamedDecl(D);
// We purposedly do not call VisitDeclContext(D).
bool IsInstanceMethod = D->isInstanceMethod();
bool IsPropertyAccessor = D->isPropertyAccessor();
const ObjCPropertyDecl *PropertyDecl = nullptr;
std::string selectorName = D->getSelector().getAsString();
// work around bug in clang
if (selectorName != ".cxx_construct" && selectorName != ".cxx_destruct") {
PropertyDecl = D->findPropertyDecl();
}
ObjCMethodDecl::param_const_iterator I = D->param_begin(), E = D->param_end();
bool HasParameters = I != E;
std::vector<ImplicitParamDecl *> ImplicitParams;
if (D->getSelfDecl()) {
ImplicitParams.push_back(D->getSelfDecl());
}
if (D->getCmdDecl()) {
ImplicitParams.push_back(D->getCmdDecl());
}
bool HasImplicitParameters = !ImplicitParams.empty();
bool IsVariadic = D->isVariadic();
bool IsOverriding = D->isOverriding();
bool IsOptional = D->isOptional();
const Stmt *Body = D->getBody();
SmallString<64> Buf;
llvm::raw_svector_ostream StrOS(Buf);
Mangler->mangleObjCMethodNameWithoutSize(D, StrOS);
std::string MangledName = StrOS.str().str();
ObjectScope Scope(OF,
1 + IsInstanceMethod + IsPropertyAccessor +
(bool)PropertyDecl + HasParameters +
HasImplicitParameters + IsVariadic + IsOverriding +
IsOptional + (bool)Body + 1 /*MangledName */);
OF.emitFlag("is_instance_method", IsInstanceMethod);
OF.emitTag("result_type");
dumpQualType(D->getReturnType());
OF.emitFlag("is_property_accessor", IsPropertyAccessor);
if (PropertyDecl) {
OF.emitTag("property_decl");
dumpDeclRef(*PropertyDecl);
}
if (HasParameters) {
OF.emitTag("parameters");
ArrayScope Scope(OF, std::distance(I, E));
for (; I != E; ++I) {
dumpDecl(*I);
}
}
if (HasImplicitParameters) {
OF.emitTag("implicit_parameters");
ArrayScope Scope(OF, ImplicitParams.size());
for (const ImplicitParamDecl *P : ImplicitParams) {
dumpDecl(P);
}
}
OF.emitFlag("is_variadic", IsVariadic);
OF.emitFlag("is_overriding", IsOverriding);
OF.emitFlag("is_optional", IsOptional);
if (Body) {
OF.emitTag("body");
dumpStmt(Body);
}
OF.emitTag("mangled_name");
OF.emitString(MangledName);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCCategoryDeclTupleSize() {
return ObjCContainerDeclTupleSize() + 1;
}
//@atd #define obj_c_category_decl_tuple obj_c_container_decl_tuple * obj_c_category_decl_info
//@atd type obj_c_category_decl_info = {
//@atd ?class_interface : decl_ref option;
//@atd ?implementation : decl_ref option;
//@atd ~protocols : decl_ref list;
//@atd } <ocaml field_prefix="odi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
VisitObjCContainerDecl(D);
const ObjCInterfaceDecl *CI = D->getClassInterface();
const ObjCCategoryImplDecl *Impl = D->getImplementation();
ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
E = D->protocol_end();
bool HasProtocols = I != E;
ObjectScope Scope(
OF, 0 + (bool)CI + (bool)Impl + HasProtocols); // not covered by tests
if (CI) {
OF.emitTag("class_interface");
dumpDeclRef(*CI);
}
if (Impl) {
OF.emitTag("implementation");
dumpDeclRef(*Impl);
}
if (HasProtocols) {
OF.emitTag("protocols");
ArrayScope Scope(OF, std::distance(I, E)); // not covered by tests
for (; I != E; ++I) {
assert(*I);
dumpDeclRef(**I);
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCCategoryImplDeclTupleSize() {
return ASTExporter::ObjCImplDeclTupleSize() + 1;
}
//@atd #define obj_c_category_impl_decl_tuple obj_c_impl_decl_tuple * obj_c_category_impl_decl_info
//@atd type obj_c_category_impl_decl_info = {
//@atd ?class_interface : decl_ref option;
//@atd ?category_decl : decl_ref option;
//@atd } <ocaml field_prefix="ocidi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCCategoryImplDecl(
const ObjCCategoryImplDecl *D) {
ASTExporter<ATDWriter>::VisitObjCImplDecl(D);
const ObjCInterfaceDecl *CI = D->getClassInterface();
const ObjCCategoryDecl *CD = D->getCategoryDecl();
ObjectScope Scope(OF, 0 + (bool)CI + (bool)CD); // not covered by tests
if (CI) {
OF.emitTag("class_interface");
dumpDeclRef(*CI);
}
if (CD) {
OF.emitTag("category_decl");
dumpDeclRef(*CD);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCProtocolDeclTupleSize() {
return ObjCContainerDeclTupleSize() + 1;
}
//@atd #define obj_c_protocol_decl_tuple obj_c_container_decl_tuple * obj_c_protocol_decl_info
//@atd type obj_c_protocol_decl_info = {
//@atd ~protocols : decl_ref list;
//@atd } <ocaml field_prefix="opcdi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
ASTExporter<ATDWriter>::VisitObjCContainerDecl(D);
ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
E = D->protocol_end();
bool HasProtocols = I != E;
ObjectScope Scope(OF, 0 + HasProtocols); // not covered by tests
if (HasProtocols) {
OF.emitTag("protocols");
ArrayScope Scope(OF, std::distance(I, E)); // not covered by tests
for (; I != E; ++I) {
assert(*I);
dumpDeclRef(**I);
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCInterfaceDeclTupleSize() {
return ObjCContainerDeclTupleSize() + 1;
}
//@atd #define obj_c_interface_decl_tuple obj_c_container_decl_tuple * obj_c_interface_decl_info
//@atd type obj_c_interface_decl_info = {
//@atd ?super : decl_ref option;
//@atd ?implementation : decl_ref option;
//@atd ~protocols : decl_ref list;
//@atd ~known_categories : decl_ref list;
//@atd } <ocaml field_prefix="otdi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCInterfaceDecl(
const ObjCInterfaceDecl *D) {
VisitObjCContainerDecl(D);
const ObjCInterfaceDecl *SC = D->getSuperClass();
const ObjCImplementationDecl *Impl = D->getImplementation();
ObjCInterfaceDecl::protocol_iterator IP = D->protocol_begin(),
EP = D->protocol_end();
bool HasProtocols = IP != EP;
ObjCInterfaceDecl::known_categories_iterator IC = D->known_categories_begin(),
EC = D->known_categories_end();
bool HasKnownCategories = IC != EC;
ObjectScope Scope(
OF, 0 + (bool)SC + (bool)Impl + HasProtocols + HasKnownCategories);
if (SC) {
OF.emitTag("super");
dumpDeclRef(*SC);
}
if (Impl) {
OF.emitTag("implementation");
dumpDeclRef(*Impl);
}
if (HasProtocols) {
OF.emitTag("protocols");
ArrayScope Scope(OF, std::distance(IP, EP));
for (; IP != EP; ++IP) {
assert(*IP);
dumpDeclRef(**IP);
}
}
if (HasKnownCategories) {
OF.emitTag("known_categories");
ArrayScope Scope(OF, std::distance(IC, EC));
for (; IC != EC; ++IC) {
assert(*IC);
dumpDeclRef(**IC);
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCImplementationDeclTupleSize() {
return ASTExporter::ObjCImplDeclTupleSize() + 1;
}
//@atd #define obj_c_implementation_decl_tuple obj_c_impl_decl_tuple * obj_c_implementation_decl_info
//@atd type obj_c_implementation_decl_info = {
//@atd ?super : decl_ref option;
//@atd ?class_interface : decl_ref option;
//@atd ~ivar_initializers : cxx_ctor_initializer list;
//@atd } <ocaml field_prefix="oidi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCImplementationDecl(
const ObjCImplementationDecl *D) {
ASTExporter<ATDWriter>::VisitObjCImplDecl(D);
const ObjCInterfaceDecl *SC = D->getSuperClass();
const ObjCInterfaceDecl *CI = D->getClassInterface();
ObjCImplementationDecl::init_const_iterator I = D->init_begin(),
E = D->init_end();
bool HasInitializers = I != E;
ObjectScope Scope(OF, 0 + (bool)SC + (bool)CI + HasInitializers);
if (SC) {
OF.emitTag("super");
dumpDeclRef(*SC);
}
if (CI) {
OF.emitTag("class_interface");
dumpDeclRef(*CI);
}
if (HasInitializers) {
OF.emitTag("ivar_initializers");
ArrayScope Scope(OF, std::distance(I, E)); // not covered by tests
for (; I != E; ++I) {
assert(*I);
dumpCXXCtorInitializer(**I);
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCCompatibleAliasDeclTupleSize() {
return NamedDeclTupleSize() + 1;
}
//@atd #define obj_c_compatible_alias_decl_tuple named_decl_tuple * obj_c_compatible_alias_decl_info
//@atd type obj_c_compatible_alias_decl_info = {
//@atd ?class_interface : decl_ref option;
//@atd } <ocaml field_prefix="ocadi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCCompatibleAliasDecl(
const ObjCCompatibleAliasDecl *D) {
VisitNamedDecl(D);
const ObjCInterfaceDecl *CI = D->getClassInterface();
ObjectScope Scope(OF, 0 + (bool)CI); // not covered by tests
if (CI) {
OF.emitTag("class_interface");
dumpDeclRef(*CI);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCPropertyDeclTupleSize() {
return NamedDeclTupleSize() + 1;
}
//@atd #define obj_c_property_decl_tuple named_decl_tuple * obj_c_property_decl_info
//@atd type obj_c_property_decl_info = {
//@atd qual_type : qual_type;
//@atd ?getter_method : decl_ref option;
//@atd ?setter_method : decl_ref option;
//@atd ?ivar_decl : decl_ref option;
//@atd ~property_control <ocaml default="`None"> : obj_c_property_control;
//@atd ~property_attributes : property_attribute list
//@atd } <ocaml field_prefix="opdi_">
//@atd type obj_c_property_control = [ None | Required | Optional ]
//@atd type property_attribute = [
//@atd Readonly
//@atd | Assign
//@atd | Readwrite
//@atd | Retain
//@atd | Copy
//@atd | Nonatomic
//@atd | Atomic
//@atd | Weak
//@atd | Strong
//@atd | Unsafe_unretained
//@atd | ExplicitGetter
//@atd | ExplicitSetter
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
VisitNamedDecl(D);
ObjCPropertyDecl::PropertyControl PC = D->getPropertyImplementation();
bool HasPropertyControl = PC != ObjCPropertyDecl::None;
ObjCPropertyAttribute::Kind Attrs = D->getPropertyAttributes();
bool HasPropertyAttributes = Attrs != ObjCPropertyAttribute::kind_noattr;
ObjCMethodDecl *Getter = D->getGetterMethodDecl();
ObjCMethodDecl *Setter = D->getSetterMethodDecl();
ObjCIvarDecl *Ivar = D->getPropertyIvarDecl();
ObjectScope Scope(OF,
1 + (bool)Getter + (bool)Setter + (bool)Ivar +
HasPropertyControl +
HasPropertyAttributes); // not covered by tests
OF.emitTag("qual_type");
dumpQualType(D->getType());
if (Getter) {
OF.emitTag("getter_method");
dumpDeclRef(*Getter);
}
if (Setter) {
OF.emitTag("setter_method");
dumpDeclRef(*Setter);
}
if (Ivar) {
OF.emitTag("ivar_decl");
dumpDeclRef(*Ivar);
}
if (HasPropertyControl) {
OF.emitTag("property_control");
switch (PC) {
case ObjCPropertyDecl::Required:
OF.emitSimpleVariant("Required");
break;
case ObjCPropertyDecl::Optional:
OF.emitSimpleVariant("Optional");
break;
default:
OF.emitSimpleVariant("None");
break;
}
}
if (HasPropertyAttributes) {
OF.emitTag("property_attributes");
bool readonly = Attrs & ObjCPropertyAttribute::kind_readonly;
bool assign = Attrs & ObjCPropertyAttribute::kind_assign;
bool readwrite = Attrs & ObjCPropertyAttribute::kind_readwrite;
bool retain = Attrs & ObjCPropertyAttribute::kind_retain;
bool copy = Attrs & ObjCPropertyAttribute::kind_copy;
bool nonatomic = Attrs & ObjCPropertyAttribute::kind_nonatomic;
bool atomic = Attrs & ObjCPropertyAttribute::kind_atomic;
bool weak = Attrs & ObjCPropertyAttribute::kind_weak;
bool strong = Attrs & ObjCPropertyAttribute::kind_strong;
bool unsafeUnretained =
Attrs & ObjCPropertyAttribute::kind_unsafe_unretained;
bool getter = Attrs & ObjCPropertyAttribute::kind_getter;
bool setter = Attrs & ObjCPropertyAttribute::kind_setter;
int toEmit = readonly + assign + readwrite + retain + copy + nonatomic +
atomic + weak + strong + unsafeUnretained + getter + setter;
ArrayScope Scope(OF, toEmit);
if (readonly)
OF.emitSimpleVariant("Readonly");
if (assign)
OF.emitSimpleVariant("Assign");
if (readwrite)
OF.emitSimpleVariant("Readwrite");
if (retain)
OF.emitSimpleVariant("Retain");
if (copy)
OF.emitSimpleVariant("Copy");
if (nonatomic)
OF.emitSimpleVariant("Nonatomic");
if (atomic)
OF.emitSimpleVariant("Atomic");
if (weak)
OF.emitSimpleVariant("Weak");
if (strong)
OF.emitSimpleVariant("Strong");
if (unsafeUnretained)
OF.emitSimpleVariant("Unsafe_unretained");
if (getter) {
OF.emitSimpleVariant("ExplicitGetter");
}
if (setter) {
OF.emitSimpleVariant("ExplicitSetter");
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCPropertyImplDeclTupleSize() {
return DeclTupleSize() + 1;
}
//@atd #define obj_c_property_impl_decl_tuple decl_tuple * obj_c_property_impl_decl_info
//@atd type obj_c_property_impl_decl_info = {
//@atd implementation : property_implementation;
//@atd ?property_decl : decl_ref option;
//@atd ?ivar_decl : decl_ref option;
//@atd } <ocaml field_prefix="opidi_">
//@atd type property_implementation = [ Synthesize | Dynamic ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCPropertyImplDecl(
const ObjCPropertyImplDecl *D) {
VisitDecl(D);
const ObjCPropertyDecl *PD = D->getPropertyDecl();
const ObjCIvarDecl *ID = D->getPropertyIvarDecl();
ObjectScope Scope(OF, 1 + (bool)PD + (bool)ID); // not covered by tests
OF.emitTag("implementation");
switch (D->getPropertyImplementation()) {
case ObjCPropertyImplDecl::Synthesize:
OF.emitSimpleVariant("Synthesize");
break;
case ObjCPropertyImplDecl::Dynamic:
OF.emitSimpleVariant("Dynamic");
break;
}
if (PD) {
OF.emitTag("property_decl");
dumpDeclRef(*PD);
}
if (ID) {
OF.emitTag("ivar_decl");
dumpDeclRef(*ID);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::BlockDeclTupleSize() {
return DeclTupleSize() + 1;
}
//@atd #define block_decl_tuple decl_tuple * block_decl_info
//@atd type block_decl_info = {
//@atd ~parameters : decl list;
//@atd ~is_variadic : bool;
//@atd ~captures_cxx_this : bool;
//@atd ~captured_variables : block_captured_variable list;
//@atd ?body : stmt option;
//@atd ~mangled_name : string;
//@atd } <ocaml field_prefix="bdi_">
//@atd type block_captured_variable = {
//@atd ~is_by_ref : bool;
//@atd ~is_nested : bool;
//@atd ?variable : decl_ref option;
//@atd ?copy_expr : stmt option
//@atd } <ocaml field_prefix="bcv_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitBlockDecl(const BlockDecl *D) {
VisitDecl(D);
// We purposedly do not call VisitDeclContext(D).
ObjCMethodDecl::param_const_iterator PCII = D->param_begin(),
PCIE = D->param_end();
bool HasParameters = PCII != PCIE;
bool IsVariadic = D->isVariadic();
bool CapturesCXXThis = D->capturesCXXThis();
BlockDecl::capture_const_iterator CII = D->capture_begin(),
CIE = D->capture_end();
bool HasCapturedVariables = CII != CIE;
const Stmt *Body = D->getBody();
std::string MangledName;
const DeclContext *DC = D->getDeclContext();
if (auto ND = dyn_cast<NamedDecl>(DC)) {
if (!isa<FunctionDecl>(ND) && !isa<VarDecl>(ND) && ND->getIdentifier()) {
MangledName = ND->getIdentifier()->getName().str();
} else if (!isa<CXXConstructorDecl>(DC) && !isa<CXXDestructorDecl>(DC)) {
SmallString<64> Buf;
llvm::raw_svector_ostream StrOS(Buf);
Mangler->mangleBlock(DC, D, StrOS);
MangledName = StrOS.str().str();
}
}
int size = 0 + HasParameters + IsVariadic + CapturesCXXThis +
HasCapturedVariables + (bool)Body;
if (!MangledName.empty())
++size;
ObjectScope Scope(OF, size); // not covered by tests
if (HasParameters) {
OF.emitTag("parameters");
ArrayScope Scope(OF, std::distance(PCII, PCIE));
for (; PCII != PCIE; ++PCII) {
dumpDecl(*PCII);
}
}
OF.emitFlag("is_variadic", IsVariadic);
OF.emitFlag("captures_cxx_this", CapturesCXXThis);
if (HasCapturedVariables) {
OF.emitTag("captured_variables");
ArrayScope Scope(OF, std::distance(CII, CIE));
for (; CII != CIE; ++CII) {
bool IsByRef = CII->isByRef();
bool IsNested = CII->isNested();
bool HasVariable = CII->getVariable();
bool HasCopyExpr = CII->hasCopyExpr();
ObjectScope Scope(OF,
0 + IsByRef + IsNested + HasVariable +
HasCopyExpr); // not covered by tests
OF.emitFlag("is_by_ref", IsByRef);
OF.emitFlag("is_nested", IsNested);
if (HasVariable) {
OF.emitTag("variable");
dumpDeclRef(*CII->getVariable());
}
if (HasCopyExpr) {
OF.emitTag("copy_expr");
dumpStmt(CII->getCopyExpr());
}
}
}
if (Body) {
OF.emitTag("body");
dumpStmt(Body);
}
if (!MangledName.empty()) {
OF.emitTag("mangled_name");
OF.emitString(MangledName);
}
}
// main variant for declarations
//@atd type decl = [
#define DECL(DERIVED, BASE) //@atd | DERIVED@@Decl of (@DERIVED@_decl_tuple)
#define ABSTRACT_DECL(DECL)
#include <clang/AST/DeclNodes.inc>
//@atd ] <ocaml repr="classic" validator="Clang_ast_visit.visit_decl">
//===----------------------------------------------------------------------===//
// Stmt dumping methods.
//===----------------------------------------------------------------------===//
// Default aliases for generating variant components
// The main variant is defined at the end of section.
#define STMT(CLASS, PARENT) //@atd #define @CLASS@_tuple @PARENT@_tuple
#define ABSTRACT_STMT(STMT) STMT
#include <clang/AST/StmtNodes.inc>
//
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpStmt(const Stmt *S) {
if (!S) {
// We use a fixed NullStmt node to represent null pointers
S = NullPtrStmt;
}
VariantScope Scope(OF, S->getStmtClassName());
{
TupleScope Scope(OF, ASTExporter::tupleSizeOfStmtClass(S->getStmtClass()));
ConstStmtVisitor<ASTExporter<ATDWriter>>::Visit(S);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::StmtTupleSize() {
return 2;
}
//@atd #define stmt_tuple stmt_info * stmt list
//@atd type stmt_info = {
//@atd pointer : pointer;
//@atd source_range : source_range;
//@atd } <ocaml field_prefix="si_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitStmt(const Stmt *S) {
{
ObjectScope Scope(OF, 2);
OF.emitTag("pointer");
dumpPointer(S);
OF.emitTag("source_range");
dumpSourceRange(S->getSourceRange());
}
{
ArrayScope Scope(OF, std::distance(S->child_begin(), S->child_end()));
for (const Stmt *CI : S->children()) {
dumpStmt(CI);
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::DeclStmtTupleSize() {
return StmtTupleSize() + 1;
}
//@atd #define decl_stmt_tuple stmt_tuple * decl list
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitDeclStmt(const DeclStmt *Node) {
VisitStmt(Node);
ArrayScope Scope(OF, std::distance(Node->decl_begin(), Node->decl_end()));
for (auto I : Node->decls()) {
dumpDecl(I);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::IfStmtTupleSize() {
return StmtTupleSize() + 1;
}
//@atd #define if_stmt_tuple stmt_tuple * if_stmt_info
//@atd type if_stmt_info = {
//@atd ?init : pointer option;
//@atd ?cond_var : stmt option;
//@atd cond : pointer;
//@atd then : pointer;
//@atd ?else : (pointer * source_location) option;
//@atd } <ocaml field_prefix="isi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitIfStmt(const IfStmt *Node) {
VisitStmt(Node);
const Stmt *Init = Node->getInit();
const DeclStmt *CondVar = Node->getConditionVariableDeclStmt();
bool hasElseStorage = Node->hasElseStorage();
ObjectScope Scope(OF, 2 + (bool)Init + (bool)CondVar + hasElseStorage);
if (Init) {
OF.emitTag("init");
dumpPointer(Init);
}
if (CondVar) {
OF.emitTag("cond_var");
dumpStmt(CondVar);
}
OF.emitTag("cond");
dumpPointer(Node->getCond());
OF.emitTag("then");
dumpPointer(Node->getThen());
if (hasElseStorage) {
OF.emitTag("else");
TupleScope Scope(OF, 2);
dumpPointer(Node->getElse());
dumpSourceLocation(Node->getElseLoc());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::SwitchStmtTupleSize() {
return StmtTupleSize() + 1;
}
//@atd #define switch_stmt_tuple stmt_tuple * switch_stmt_info
//@atd type switch_stmt_info = {
//@atd ?init : pointer option;
//@atd ?cond_var : stmt option;
//@atd cond : pointer;
//@atd body : pointer;
//@atd } <ocaml field_prefix="ssi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitSwitchStmt(const SwitchStmt *Node) {
VisitStmt(Node);
const Stmt *Init = Node->getInit();
const DeclStmt *CondVar = Node->getConditionVariableDeclStmt();
ObjectScope Scope(OF, 2 + (bool)Init + (bool)CondVar);
if (Init) {
OF.emitTag("init");
dumpPointer(Init);
}
if (CondVar) {
OF.emitTag("cond_var");
dumpStmt(CondVar);
}
OF.emitTag("cond");
dumpPointer(Node->getCond());
OF.emitTag("body");
dumpPointer(Node->getBody());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::AttributedStmtTupleSize() {
return StmtTupleSize() + 1;
}
//@atd #define attributed_stmt_tuple stmt_tuple * attribute list
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitAttributedStmt(const AttributedStmt *Node) {
VisitStmt(Node);
ArrayScope Scope(OF, Node->getAttrs().size()); // not covered by tests
for (auto A : Node->getAttrs()) {
dumpAttr(A);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::LabelStmtTupleSize() {
return StmtTupleSize() + 1;
}
//@atd #define label_stmt_tuple stmt_tuple * string
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitLabelStmt(const LabelStmt *Node) {
VisitStmt(Node);
OF.emitString(Node->getName());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::GotoStmtTupleSize() {
return StmtTupleSize() + 1;
}
//@atd #define goto_stmt_tuple stmt_tuple * goto_stmt_info
//@atd type goto_stmt_info = {
//@atd label : string;
//@atd pointer : pointer
//@atd } <ocaml field_prefix="gsi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitGotoStmt(const GotoStmt *Node) {
VisitStmt(Node);
ObjectScope Scope(OF, 2); // not covered by tests
OF.emitTag("label");
OF.emitString(Node->getLabel()->getName().str());
OF.emitTag("pointer");
dumpPointer(Node->getLabel());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CXXCatchStmtTupleSize() {
return StmtTupleSize() + 1;
}
//@atd #define cxx_catch_stmt_tuple stmt_tuple * cxx_catch_stmt_info
//@atd type cxx_catch_stmt_info = {
//@atd ?variable : decl option
//@atd } <ocaml field_prefix="xcsi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCXXCatchStmt(const CXXCatchStmt *Node) {
VisitStmt(Node);
const VarDecl *decl = Node->getExceptionDecl();
ObjectScope Scope(OF, 0 + (bool)decl); // not covered by tests
if (decl) {
OF.emitTag("variable");
dumpDecl(decl);
}
}
////===----------------------------------------------------------------------===//
//// Expr dumping methods.
////===----------------------------------------------------------------------===//
//
template <class ATDWriter>
int ASTExporter<ATDWriter>::ExprTupleSize() {
return StmtTupleSize() + 1;
}
//@atd #define expr_tuple stmt_tuple * expr_info
//@atd type expr_info = {
//@atd qual_type : qual_type;
//@atd ~value_kind <ocaml default="`RValue"> : value_kind;
//@atd ~object_kind <ocaml default="`Ordinary"> : object_kind;
//@atd } <ocaml field_prefix="ei_">
//@atd type value_kind = [ RValue | LValue | XValue ]
//@atd type object_kind = [ Ordinary | BitField | ObjCProperty | ObjCSubscript |
//@atd VectorComponent ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitExpr(const Expr *Node) {
VisitStmt(Node);
ExprValueKind VK = Node->getValueKind();
bool HasNonDefaultValueKind = VK != VK_RValue;
ExprObjectKind OK = Node->getObjectKind();
bool HasNonDefaultObjectKind = OK != OK_Ordinary;
ObjectScope Scope(OF, 1 + HasNonDefaultValueKind + HasNonDefaultObjectKind);
OF.emitTag("qual_type");
dumpQualType(Node->getType());
if (HasNonDefaultValueKind) {
OF.emitTag("value_kind");
switch (VK) {
case VK_LValue:
OF.emitSimpleVariant("LValue");
break;
case VK_XValue:
OF.emitSimpleVariant("XValue");
break;
case VK_RValue:
llvm_unreachable("unreachable");
break;
}
}
if (HasNonDefaultObjectKind) {
OF.emitTag("object_kind");
switch (Node->getObjectKind()) {
case OK_BitField:
OF.emitSimpleVariant("BitField");
break;
case OK_ObjCProperty:
OF.emitSimpleVariant("ObjCProperty");
break;
case OK_ObjCSubscript:
OF.emitSimpleVariant("ObjCSubscript");
break;
case OK_VectorComponent:
OF.emitSimpleVariant("VectorComponent");
break;
case OK_MatrixComponent:
OF.emitSimpleVariant("MatrixComponent");
break;
case OK_Ordinary:
llvm_unreachable("unreachable");
break;
}
}
}
//@atd type cxx_base_specifier = {
//@atd name : string;
//@atd ~virtual : bool;
//@atd } <ocaml field_prefix="xbs_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpCXXBaseSpecifier(
const CXXBaseSpecifier &Base) {
bool IsVirtual = Base.isVirtual();
ObjectScope Scope(OF, 1 + IsVirtual);
OF.emitTag("name");
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
OF.emitString(RD->getName().str());
OF.emitFlag("virtual", IsVirtual);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CastExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd type cast_kind = [
#define CAST_OPERATION(NAME) //@atd | NAME
#include <clang/AST/OperationKinds.def>
//@atd ]
//@atd #define cast_expr_tuple expr_tuple * cast_expr_info
//@atd type cast_expr_info = {
//@atd cast_kind : cast_kind;
//@atd base_path : cxx_base_specifier list;
//@atd } <ocaml field_prefix="cei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCastExpr(const CastExpr *Node) {
VisitExpr(Node);
ObjectScope Scope(OF, 2);
OF.emitTag("cast_kind");
OF.emitSimpleVariant(Node->getCastKindName());
OF.emitTag("base_path");
{
auto I = Node->path_begin(), E = Node->path_end();
ArrayScope Scope(OF, std::distance(I, E));
for (; I != E; ++I) {
dumpCXXBaseSpecifier(**I);
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ExplicitCastExprTupleSize() {
return CastExprTupleSize() + 1;
}
//@atd #define explicit_cast_expr_tuple cast_expr_tuple * qual_type
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitExplicitCastExpr(
const ExplicitCastExpr *Node) {
VisitCastExpr(Node);
dumpQualType(Node->getTypeAsWritten());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCBridgedCastExprTupleSize() {
return ExplicitCastExprTupleSize() + 1;
}
//@atd type obj_c_bridge_cast_kind = [
//@atd OBC_BridgeRetained
//@atd | OBC_Bridge
//@atd | OBC_BridgeTransfer
//@atd ]
//@atd #define obj_c_bridged_cast_expr_tuple explicit_cast_expr_tuple * obj_c_bridged_cast_expr_info
//@atd type obj_c_bridged_cast_expr_info = {
//@atd cast_kind : obj_c_bridge_cast_kind;
//@atd } <ocaml field_prefix="obcei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCBridgedCastExpr(
const ObjCBridgedCastExpr *Node) {
VisitExplicitCastExpr(Node);
ObjectScope Scope(OF, 1);
OF.emitTag("cast_kind");
switch (Node->getBridgeKind()) {
case OBC_BridgeRetained:
OF.emitSimpleVariant("OBC_BridgeRetained");
break;
case OBC_Bridge:
OF.emitSimpleVariant("OBC_Bridge");
break;
case OBC_BridgeTransfer:
OF.emitSimpleVariant("OBC_BridgeTransfer");
break;
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::DeclRefExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define decl_ref_expr_tuple expr_tuple * decl_ref_expr_info
//@atd type decl_ref_expr_info = {
//@atd ?decl_ref : decl_ref option;
//@atd ?found_decl_ref : decl_ref option
//@atd } <ocaml field_prefix="drti_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitDeclRefExpr(const DeclRefExpr *Node) {
VisitExpr(Node);
const ValueDecl *D = Node->getDecl();
const NamedDecl *FD = Node->getFoundDecl();
bool HasFoundDeclRef = FD && D != FD;
ObjectScope Scope(OF, 0 + (bool)D + HasFoundDeclRef);
if (D) {
OF.emitTag("decl_ref");
dumpDeclRef(*D);
}
if (HasFoundDeclRef) {
OF.emitTag("found_decl_ref");
dumpDeclRef(*FD);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::OverloadExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define overload_expr_tuple expr_tuple * overload_expr_info
//@atd type overload_expr_info = {
//@atd ~decls : decl_ref list;
//@atd name : declaration_name;
//@atd } <ocaml field_prefix="oei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitOverloadExpr(const OverloadExpr *Node) {
VisitExpr(Node);
bool HasDecls = Node->getNumDecls() > 0;
ObjectScope Scope(OF, 1 + HasDecls); // not covered by tests
if (HasDecls) {
OF.emitTag("decls");
ArrayScope Scope( // not covered by tests
OF,
std::distance(Node->decls_begin(), Node->decls_end()));
for (auto I : Node->decls()) {
dumpDeclRef(*I);
}
}
OF.emitTag("name");
dumpDeclarationName(Node->getName());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::UnresolvedLookupExprTupleSize() {
return OverloadExprTupleSize() + 1;
}
//@atd #define unresolved_lookup_expr_tuple overload_expr_tuple * unresolved_lookup_expr_info
//@atd type unresolved_lookup_expr_info = {
//@atd ~requires_ADL : bool;
//@atd ~is_overloaded : bool;
//@atd ?naming_class : decl_ref option;
//@atd } <ocaml field_prefix="ulei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitUnresolvedLookupExpr(
const UnresolvedLookupExpr *Node) {
VisitOverloadExpr(Node);
bool RequiresADL = Node->requiresADL();
bool IsOverloaded = Node->isOverloaded();
bool HasNamingClass = Node->getNamingClass();
ObjectScope Scope(
OF,
0 + RequiresADL + IsOverloaded + HasNamingClass); // not covered by tests
OF.emitFlag("requires_ADL", RequiresADL);
OF.emitFlag("is_overloaded", IsOverloaded);
if (HasNamingClass) {
OF.emitTag("naming_class");
dumpDeclRef(*Node->getNamingClass());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCIvarRefExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define obj_c_ivar_ref_expr_tuple expr_tuple * obj_c_ivar_ref_expr_info
//@atd type obj_c_ivar_ref_expr_info = {
//@atd decl_ref : decl_ref;
//@atd pointer : pointer;
//@atd ~is_free_ivar : bool
//@atd } <ocaml field_prefix="ovrei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node) {
VisitExpr(Node);
bool IsFreeIvar = Node->isFreeIvar();
ObjectScope Scope(OF, 2 + IsFreeIvar); // not covered by tests
OF.emitTag("decl_ref");
dumpDeclRef(*Node->getDecl());
OF.emitTag("pointer");
dumpPointer(Node->getDecl());
OF.emitFlag("is_free_ivar", IsFreeIvar);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::PredefinedExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define predefined_expr_tuple expr_tuple * predefined_expr_type
//@atd type predefined_expr_type = [
//@atd | Func
//@atd | Function
//@atd | LFunction
//@atd | FuncDName
//@atd | FuncSig
//@atd | LFuncSig
//@atd | PrettyFunction
//@atd | PrettyFunctionNoVirtual
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitPredefinedExpr(const PredefinedExpr *Node) {
VisitExpr(Node);
switch (Node->getIdentKind()) {
case PredefinedExpr::Func:
OF.emitSimpleVariant("Func");
break;
case PredefinedExpr::Function:
OF.emitSimpleVariant("Function");
break;
case PredefinedExpr::LFunction:
OF.emitSimpleVariant("LFunction");
break;
case PredefinedExpr::LFuncSig:
OF.emitSimpleVariant("LFuncSig");
break;
case PredefinedExpr::FuncDName:
OF.emitSimpleVariant("FuncDName");
break;
case PredefinedExpr::FuncSig:
OF.emitSimpleVariant("FuncSig");
break;
case PredefinedExpr::PrettyFunction:
OF.emitSimpleVariant("PrettyFunction");
break;
case PredefinedExpr::PrettyFunctionNoVirtual:
OF.emitSimpleVariant("PrettyFunctionNoVirtual");
break;
case PredefinedExpr::UniqueStableNameType:
OF.emitSimpleVariant("UniqueStableNameType");
break;
case PredefinedExpr::UniqueStableNameExpr:
OF.emitSimpleVariant("UniqueStableNameExpr");
break;
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CharacterLiteralTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define character_literal_tuple expr_tuple * int
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCharacterLiteral(
const CharacterLiteral *Node) {
VisitExpr(Node);
OF.emitInteger(Node->getValue());
}
template <class ATDWriter>
void ASTExporter<ATDWriter>::emitAPInt(bool isSigned,
const llvm::APInt &value) {
ObjectScope Scope(OF, 2 + isSigned);
OF.emitFlag("is_signed", isSigned);
OF.emitTag("bitwidth");
OF.emitInteger(value.getBitWidth());
OF.emitTag("value");
OF.emitString(value.toString(10, isSigned));
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::IntegerLiteralTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define integer_literal_tuple expr_tuple * integer_literal_info
//@atd type integer_literal_info = {
//@atd ~is_signed : bool;
//@atd bitwidth : int;
//@atd value : string;
//@atd } <ocaml field_prefix="ili_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitIntegerLiteral(const IntegerLiteral *Node) {
VisitExpr(Node);
const auto value = Node->getValue();
this->emitAPInt(Node->getType()->isSignedIntegerType(), value);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::FixedPointLiteralTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define fixed_point_literal_tuple expr_tuple * string
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitFixedPointLiteral(
const FixedPointLiteral *Node) {
VisitExpr(Node);
int radix = 10;
OF.emitString(Node->getValueAsString(radix));
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::FloatingLiteralTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define floating_literal_tuple expr_tuple * string
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitFloatingLiteral(const FloatingLiteral *Node) {
VisitExpr(Node);
llvm::SmallString<20> buf;
Node->getValue().toString(buf);
OF.emitString(buf.str().str());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::StringLiteralTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define string_literal_tuple expr_tuple * string list
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitStringLiteral(const StringLiteral *Str) {
VisitExpr(Str);
size_t n_chunks;
if (Str->getByteLength() == 0) {
n_chunks = 1;
} else {
n_chunks = 1 + ((Str->getByteLength() - 1) / Options.maxStringSize);
}
ArrayScope Scope(OF, n_chunks);
for (size_t i = 0; i < n_chunks; ++i) {
OF.emitString(Str->getBytes()
.substr(i * Options.maxStringSize, Options.maxStringSize)
.str());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::OffsetOfExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define offset_of_expr_tuple expr_tuple * offset_of_expr_info
//@atd type offset_of_expr_info = {
//@atd ?literal : integer_literal_info option;
//@atd } <ocaml field_prefix="ooe_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
VisitExpr(OOE);
Expr::EvalResult result;
bool isLiteral = OOE->EvaluateAsInt(result, this->Context);
ObjectScope Scope(OF, 0 + isLiteral);
if (isLiteral) {
OF.emitTag("literal");
llvm::APSInt IV = result.Val.getInt();
this->emitAPInt(IV.isSigned(), IV);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::UnaryOperatorTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define unary_operator_tuple expr_tuple * unary_operator_info
//@atd type unary_operator_info = {
//@atd kind : unary_operator_kind;
//@atd ~is_postfix : bool;
//@atd } <ocaml field_prefix="uoi_">
//@atd type unary_operator_kind = [
#define UNARY_OPERATION(NAME, SPELLING) //@atd | NAME
#include <clang/AST/OperationKinds.def>
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitUnaryOperator(const UnaryOperator *Node) {
VisitExpr(Node);
bool IsPostfix = Node->isPostfix();
ObjectScope Scope(OF, 1 + IsPostfix);
OF.emitTag("kind");
switch (Node->getOpcode()) {
#define UNARY_OPERATION(NAME, SPELLING) \
case UO_##NAME: \
OF.emitSimpleVariant(#NAME); \
break;
#include <clang/AST/OperationKinds.def>
}
OF.emitFlag("is_postfix", IsPostfix);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::UnaryExprOrTypeTraitExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define unary_expr_or_type_trait_expr_tuple expr_tuple * unary_expr_or_type_trait_expr_info
//@atd type unary_expr_or_type_trait_expr_info = {
//@atd kind : unary_expr_or_type_trait_kind;
//@atd qual_type : qual_type
//@atd } <ocaml field_prefix="uttei_">
//@atd type unary_expr_or_type_trait_kind = [
//@atd | AlignOf
//@atd | OpenMPRequiredSimdAlign
//@atd | PreferredAlignOf
//@atd | SizeOf
//@atd | SizeOfWithSize of int
//@atd | VecStep
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitUnaryExprOrTypeTraitExpr(
const UnaryExprOrTypeTraitExpr *Node) {
VisitExpr(Node);
ObjectScope Scope(OF, 2); // not covered by tests
OF.emitTag("kind");
switch (Node->getKind()) {
case UETT_AlignOf:
OF.emitSimpleVariant("AlignOf");
break;
case UETT_OpenMPRequiredSimdAlign:
OF.emitSimpleVariant("OpenMPRequiredSimdAlign");
break;
case UETT_PreferredAlignOf:
OF.emitSimpleVariant("PreferredAlignOf");
break;
case UETT_SizeOf: {
const Type *ArgType = Node->getTypeOfArgument().getTypePtr();
if (hasMeaningfulTypeInfo(ArgType)) {
VariantScope Scope(OF, "SizeOfWithSize");
OF.emitInteger(Context.getTypeInfo(ArgType).Width / 8);
} else {
OF.emitSimpleVariant("SizeOf");
}
break;
}
case UETT_VecStep:
OF.emitSimpleVariant("VecStep");
break;
}
OF.emitTag("qual_type");
dumpQualType(Node->getTypeOfArgument());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::MemberExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define member_expr_tuple expr_tuple * member_expr_info
//@atd type member_expr_info = {
//@atd ~is_arrow : bool;
//@atd ~performs_virtual_dispatch : bool;
//@atd name : named_decl_info;
//@atd decl_ref : decl_ref
//@atd } <ocaml field_prefix="mei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitMemberExpr(const MemberExpr *Node) {
VisitExpr(Node);
bool IsArrow = Node->isArrow();
LangOptions LO;
// ignore real lang options - it will get it wrong when compiling
// with -fapple-kext flag
bool PerformsVirtualDispatch = Node->performsVirtualDispatch(LO);
ObjectScope Scope(OF, 2 + IsArrow + PerformsVirtualDispatch);
OF.emitFlag("is_arrow", IsArrow);
OF.emitFlag("performs_virtual_dispatch", PerformsVirtualDispatch);
OF.emitTag("name");
ValueDecl *memberDecl = Node->getMemberDecl();
dumpName(*memberDecl);
OF.emitTag("decl_ref");
dumpDeclRef(*memberDecl);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ExtVectorElementExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define ext_vector_element_tuple expr_tuple * string
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitExtVectorElementExpr(
const ExtVectorElementExpr *Node) {
VisitExpr(Node);
OF.emitString(Node->getAccessor().getNameStart());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::BinaryOperatorTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define binary_operator_tuple expr_tuple * binary_operator_info
//@atd type binary_operator_info = {
//@atd kind : binary_operator_kind
//@atd } <ocaml field_prefix="boi_">
//@atd type binary_operator_kind = [
#define BINARY_OPERATION(NAME, SPELLING) //@atd | NAME
#include <clang/AST/OperationKinds.def>
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitBinaryOperator(const BinaryOperator *Node) {
VisitExpr(Node);
ObjectScope Scope(OF, 1);
OF.emitTag("kind");
switch (Node->getOpcode()) {
#define BINARY_OPERATION(NAME, SPELLING) \
case BO_##NAME: \
OF.emitSimpleVariant(#NAME); \
break;
#include <clang/AST/OperationKinds.def>
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CompoundAssignOperatorTupleSize() {
return BinaryOperatorTupleSize() + 1;
}
//@atd #define compound_assign_operator_tuple binary_operator_tuple * compound_assign_operator_info
//@atd type compound_assign_operator_info = {
//@atd lhs_type : qual_type;
//@atd result_type : qual_type;
//@atd } <ocaml field_prefix="caoi_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCompoundAssignOperator(
const CompoundAssignOperator *Node) {
VisitBinaryOperator(Node);
ObjectScope Scope(OF, 2); // not covered by tests
OF.emitTag("lhs_type");
dumpQualType(Node->getComputationLHSType());
OF.emitTag("result_type");
dumpQualType(Node->getComputationResultType());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::BlockExprTupleSize() {
return ExprTupleSize() + DeclTupleSize();
}
//@atd #define block_expr_tuple expr_tuple * decl
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitBlockExpr(const BlockExpr *Node) {
VisitExpr(Node);
dumpDecl(Node->getBlockDecl());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::OpaqueValueExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define opaque_value_expr_tuple expr_tuple * opaque_value_expr_info
//@atd type opaque_value_expr_info = {
//@atd ?source_expr : stmt option;
//@atd } <ocaml field_prefix="ovei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) {
VisitExpr(Node);
const Expr *Source = Node->getSourceExpr();
ObjectScope Scope(OF, 0 + (bool)Source); // not covered by tests
if (Source) {
OF.emitTag("source_expr");
dumpStmt(Source);
}
}
// GNU extensions.
template <class ATDWriter>
int ASTExporter<ATDWriter>::AddrLabelExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define addr_label_expr_tuple expr_tuple * addr_label_expr_info
//@atd type addr_label_expr_info = {
//@atd label : string;
//@atd pointer : pointer;
//@atd } <ocaml field_prefix="alei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitAddrLabelExpr(const AddrLabelExpr *Node) {
VisitExpr(Node);
ObjectScope Scope(OF, 2); // not covered by tests
OF.emitTag("label");
OF.emitString(Node->getLabel()->getName().str());
OF.emitTag("pointer");
dumpPointer(Node->getLabel());
}
////===----------------------------------------------------------------------===//
//// C++ Expressions
////===----------------------------------------------------------------------===//
template <class ATDWriter>
int ASTExporter<ATDWriter>::CXXNamedCastExprTupleSize() {
return ExplicitCastExprTupleSize() + 1;
}
//@atd #define cxx_named_cast_expr_tuple explicit_cast_expr_tuple * string
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCXXNamedCastExpr(
const CXXNamedCastExpr *Node) {
VisitExplicitCastExpr(Node);
OF.emitString(Node->getCastName());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CXXBoolLiteralExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define cxx_bool_literal_expr_tuple expr_tuple * int
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCXXBoolLiteralExpr(
const CXXBoolLiteralExpr *Node) {
VisitExpr(Node);
OF.emitInteger(Node->getValue());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CXXConstructExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define cxx_construct_expr_tuple expr_tuple * cxx_construct_expr_info
//@atd type cxx_construct_expr_info = {
//@atd decl_ref : decl_ref;
//@atd ~is_elidable : bool;
//@atd ~requires_zero_initialization : bool;
//@atd ~is_copy_constructor : bool;
//@atd } <ocaml field_prefix="xcei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCXXConstructExpr(
const CXXConstructExpr *Node) {
VisitExpr(Node);
CXXConstructorDecl *Ctor = Node->getConstructor();
bool IsCopyConstructor = Ctor->isCopyConstructor();
bool IsElidable = Node->isElidable();
bool RequiresZeroInitialization = Node->requiresZeroInitialization();
ObjectScope Scope(
OF, 1 + IsElidable + RequiresZeroInitialization + IsCopyConstructor);
OF.emitTag("decl_ref");
dumpDeclRef(*Ctor);
OF.emitFlag("is_elidable", IsElidable);
OF.emitFlag("requires_zero_initialization", RequiresZeroInitialization);
OF.emitFlag("is_copy_constructor", IsCopyConstructor);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CXXInheritedCtorInitExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define cxx_inherited_ctor_init_expr_tuple expr_tuple * cxx_construct_expr_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCXXInheritedCtorInitExpr(
const CXXInheritedCtorInitExpr *Node) {
VisitExpr(Node);
CXXConstructorDecl *Ctor = Node->getConstructor();
ObjectScope Scope(OF, 1);
OF.emitTag("decl_ref");
dumpDeclRef(*Ctor);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CXXBindTemporaryExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define cxx_bind_temporary_expr_tuple expr_tuple * cxx_bind_temporary_expr_info
//@atd type cxx_bind_temporary_expr_info = {
//@atd cxx_temporary : cxx_temporary;
//@atd } <ocaml field_prefix="xbtei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCXXBindTemporaryExpr(
const CXXBindTemporaryExpr *Node) {
VisitExpr(Node);
ObjectScope Scope(OF, 1);
OF.emitTag("cxx_temporary");
dumpCXXTemporary(Node->getTemporary());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::MaterializeTemporaryExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define materialize_temporary_expr_tuple expr_tuple * materialize_temporary_expr_info
//@atd type materialize_temporary_expr_info = {
//@atd ?decl_ref : decl_ref option;
//@atd } <ocaml field_prefix="mtei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *Node) {
VisitExpr(Node);
const ValueDecl *VD = Node->getExtendingDecl();
ObjectScope Scope(OF, 0 + (bool)VD);
if (VD) {
OF.emitTag("decl_ref");
dumpDeclRef(*VD);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ExprWithCleanupsTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define expr_with_cleanups_tuple expr_tuple * expr_with_cleanups_info
//@atd type expr_with_cleanups_info = {
//@atd ~decl_refs : decl_ref list;
//@atd } <ocaml field_prefix="ewci_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitExprWithCleanups(
const ExprWithCleanups *Node) {
VisitExpr(Node);
bool HasDeclRefs = Node->getNumObjects() > 0;
ObjectScope Scope(OF, 0 + HasDeclRefs);
if (HasDeclRefs) {
OF.emitTag("decl_refs");
unsigned int ctr = 0;
for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)
if (Node->getObject(i).is<clang::BlockDecl *>())
++ctr;
ArrayScope Scope(OF, ctr);
for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) {
auto p = Node->getObject(i);
if (p.is<clang::BlockDecl *>()) {
dumpDeclRef(**p.getAddrOfPtr1());
}
}
}
}
//@atd type cxx_temporary = pointer
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpCXXTemporary(const CXXTemporary *Temporary) {
dumpPointer(Temporary);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::LambdaExprTupleSize() {
return ExprTupleSize() + DeclTupleSize();
}
//@atd #define lambda_expr_tuple expr_tuple * lambda_expr_info
//@atd type lambda_expr_info = {
//@atd lambda_decl: decl;
//@atd } <ocaml field_prefix="lei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitLambdaExpr(const LambdaExpr *Node) {
VisitExpr(Node);
ObjectScope Scope(OF, 1);
OF.emitTag("lambda_decl");
dumpDecl(Node->getLambdaClass());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CXXNewExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define cxx_new_expr_tuple expr_tuple * cxx_new_expr_info
//@atd type cxx_new_expr_info = {
//@atd ~is_array : bool;
//@atd ?array_size_expr : pointer option;
//@atd ?initializer_expr : pointer option;
//@atd ~placement_args : pointer list;
//@atd } <ocaml field_prefix="xnei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCXXNewExpr(const CXXNewExpr *Node) {
VisitExpr(Node);
bool IsArray = Node->isArray();
bool HasArraySize = Node->getArraySize().hasValue();
bool HasInitializer = Node->hasInitializer();
unsigned PlacementArgs = Node->getNumPlacementArgs();
bool HasPlacementArgs = PlacementArgs > 0;
ObjectScope Scope(
OF, 0 + IsArray + HasArraySize + HasInitializer + HasPlacementArgs);
// ?should_null_check : bool;
// OF.emitFlag("should_null_check", Node->shouldNullCheckAllocation());
OF.emitFlag("is_array", IsArray);
if (HasArraySize) {
OF.emitTag("array_size_expr");
dumpPointer(Node->getArraySize().getValue());
}
if (HasInitializer) {
OF.emitTag("initializer_expr");
dumpPointer(Node->getInitializer());
}
if (HasPlacementArgs) {
OF.emitTag("placement_args");
ArrayScope aScope(OF, PlacementArgs);
for (auto arg : Node->placement_arguments()) {
dumpPointer(arg);
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CXXDeleteExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define cxx_delete_expr_tuple expr_tuple * cxx_delete_expr_info
//@atd type cxx_delete_expr_info = {
//@atd ~is_array : bool;
//@atd destroyed_type : qual_type;
//@atd } <ocaml field_prefix="xdei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCXXDeleteExpr(const CXXDeleteExpr *Node) {
VisitExpr(Node);
bool IsArray = Node->isArrayForm();
ObjectScope Scope(OF, 1 + IsArray);
OF.emitFlag("is_array", IsArray);
OF.emitTag("destroyed_type");
dumpQualType(Node->getDestroyedType());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CXXDefaultArgExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define cxx_default_arg_expr_tuple expr_tuple * cxx_default_expr_info
//@atd type cxx_default_expr_info = {
//@atd ?init_expr : stmt option;
//@atd } <ocaml field_prefix="xdaei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCXXDefaultArgExpr(
const CXXDefaultArgExpr *Node) {
VisitExpr(Node);
const Expr *InitExpr = Node->getExpr();
ObjectScope Scope(OF, 0 + (bool)InitExpr);
if (InitExpr) {
OF.emitTag("init_expr");
dumpStmt(InitExpr);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CXXDefaultInitExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define cxx_default_init_expr_tuple expr_tuple * cxx_default_expr_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCXXDefaultInitExpr(
const CXXDefaultInitExpr *Node) {
VisitExpr(Node);
const Expr *InitExpr = Node->getExpr();
ObjectScope Scope(OF, 0 + (bool)InitExpr);
if (InitExpr) {
OF.emitTag("init_expr");
dumpStmt(InitExpr);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::TypeTraitExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define type_trait_expr_tuple expr_tuple * type_trait_info
//@atd type type_trait_info = {
//@atd ~value : bool;
//@atd } <ocaml field_prefix="xtti_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitTypeTraitExpr(const TypeTraitExpr *Node) {
VisitExpr(Node);
// FIXME: don't dump false when value is dependent
bool value = Node->isValueDependent() ? false : Node->getValue();
ObjectScope Scope(OF, 0 + value);
OF.emitFlag("value", value);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::GenericSelectionExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define generic_selection_expr_tuple expr_tuple * generic_selection_info
//@atd type generic_selection_info = {
//@atd ?value : stmt option;
//@atd } <ocaml field_prefix="gse_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitGenericSelectionExpr(
const GenericSelectionExpr *Node) {
VisitExpr(Node);
const Expr *ResultExpr = Node->getResultExpr();
ObjectScope Scope(OF, 0 + (bool)ResultExpr);
if (ResultExpr) {
OF.emitTag("value");
dumpStmt(ResultExpr);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CXXNoexceptExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define cxx_noexcept_expr_tuple expr_tuple * cxx_noexcept_expr_info
//@atd type cxx_noexcept_expr_info = {
//@atd ~value : bool;
//@atd } <ocaml field_prefix="xnee_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitCXXNoexceptExpr(const CXXNoexceptExpr *Node) {
VisitExpr(Node);
bool value = Node->getValue();
ObjectScope Scope(OF, 0 + value);
OF.emitFlag("value", value);
}
////===----------------------------------------------------------------------===//
//// Obj-C Expressions
////===----------------------------------------------------------------------===//
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCMessageExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define obj_c_message_expr_tuple expr_tuple * obj_c_message_expr_info
//@atd type obj_c_message_expr_info = {
//@atd selector : string;
//@atd ~is_definition_found : bool;
//@atd ?decl_pointer : pointer option;
//@atd ~receiver_kind <ocaml default="`Instance"> : receiver_kind
//@atd } <ocaml field_prefix="omei_">
//@atd type receiver_kind = [ Instance | Class of qual_type | SuperInstance |
//@atd SuperClass ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCMessageExpr(const ObjCMessageExpr *Node) {
VisitExpr(Node);
bool IsDefinitionFound = false;
// Do not rely on Node->getMethodDecl() - it might be wrong if
// selector doesn't type check (ie. method of subclass is called)
const ObjCInterfaceDecl *receiver = Node->getReceiverInterface();
const Selector selector = Node->getSelector();
const ObjCMethodDecl *m_decl = NULL;
if (receiver) {
bool IsInst = Node->isInstanceMessage();
m_decl = receiver->lookupPrivateMethod(selector, IsInst);
// Look for definition first. It's possible that class redefines it without
// redeclaring. It needs to be defined in same translation unit to work.
if (m_decl) {
IsDefinitionFound = true;
} else {
// As a fallback look through method declarations in the interface.
// It's not very reliable (subclass might have redefined it)
// but it's better than nothing
IsDefinitionFound = false;
m_decl = receiver->lookupMethod(selector, IsInst);
}
}
// Fall back to the default method lookup method
if (!m_decl) {
m_decl = Node->getMethodDecl();
}
ObjCMessageExpr::ReceiverKind RK = Node->getReceiverKind();
bool HasNonDefaultReceiverKind = RK != ObjCMessageExpr::Instance;
ObjectScope Scope(
OF, 1 + IsDefinitionFound + (bool)m_decl + HasNonDefaultReceiverKind);
OF.emitTag("selector");
OF.emitString(selector.getAsString());
if (m_decl) {
OF.emitFlag("is_definition_found", IsDefinitionFound);
OF.emitTag("decl_pointer");
dumpPointer(m_decl);
}
if (HasNonDefaultReceiverKind) {
OF.emitTag("receiver_kind");
switch (RK) {
case ObjCMessageExpr::Class: {
VariantScope Scope(OF, "Class");
dumpQualType(Node->getClassReceiver());
} break;
case ObjCMessageExpr::SuperInstance:
OF.emitSimpleVariant("SuperInstance");
break;
case ObjCMessageExpr::SuperClass:
OF.emitSimpleVariant("SuperClass");
break;
case ObjCMessageExpr::Instance:
llvm_unreachable("unreachable");
break;
}
}
}
//@atd type selector = string
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpSelector(const Selector sel) {
OF.emitString(sel.getAsString());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCBoxedExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define obj_c_boxed_expr_tuple expr_tuple * objc_boxed_expr_info
//@atd type objc_boxed_expr_info = {
//@atd ?boxing_method : selector option;
//@atd } <ocaml field_prefix="obei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCBoxedExpr(const ObjCBoxedExpr *Node) {
VisitExpr(Node);
ObjCMethodDecl *boxingMethod = Node->getBoxingMethod();
ObjectScope Scope(OF, 0 + (bool)boxingMethod);
if (boxingMethod) {
OF.emitTag("boxing_method");
dumpSelector(boxingMethod->getSelector());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCAtCatchStmtTupleSize() {
return StmtTupleSize() + 1;
}
//@atd #define obj_c_at_catch_stmt_tuple stmt_tuple * obj_c_message_expr_kind
//@atd type obj_c_message_expr_kind = [
//@atd | CatchParam of decl
//@atd | CatchAll
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) {
VisitStmt(Node);
if (const VarDecl *CatchParam = Node->getCatchParamDecl()) {
VariantScope Scope(OF, "CatchParam");
dumpDecl(CatchParam);
} else {
OF.emitSimpleVariant("CatchAll");
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCEncodeExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define obj_c_encode_expr_tuple expr_tuple * objc_encode_expr_info
//@atd type objc_encode_expr_info = {
//@atd qual_type : qual_type;
//@atd raw : string;
//@atd } <ocaml field_prefix="oeei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCEncodeExpr(const ObjCEncodeExpr *Node) {
VisitExpr(Node);
ObjectScope Scope(OF, 2);
OF.emitTag("qual_type");
dumpQualType(Node->getEncodedType());
OF.emitTag("raw");
OF.emitString(Node->getEncodedType().getAsString());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCSelectorExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define obj_c_selector_expr_tuple expr_tuple * selector
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCSelectorExpr(
const ObjCSelectorExpr *Node) {
VisitExpr(Node);
dumpSelector(Node->getSelector());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCProtocolExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define obj_c_protocol_expr_tuple expr_tuple * decl_ref
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCProtocolExpr(
const ObjCProtocolExpr *Node) {
VisitExpr(Node);
dumpDeclRef(*Node->getProtocol());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCPropertyRefExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define obj_c_property_ref_expr_tuple expr_tuple * obj_c_property_ref_expr_info
//@atd type obj_c_property_ref_expr_info = {
//@atd kind : property_ref_kind;
//@atd ~is_super_receiver : bool;
//@atd ~is_messaging_getter : bool;
//@atd ~is_messaging_setter : bool;
//@atd } <ocaml field_prefix="oprei_">
//@atd type property_ref_kind = [
//@atd | MethodRef of obj_c_method_ref_info
//@atd | PropertyRef of decl_ref
//@atd ]
//@atd type obj_c_method_ref_info = {
//@atd ?getter : selector option;
//@atd ?setter : selector option
//@atd } <ocaml field_prefix="mri_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCPropertyRefExpr(
const ObjCPropertyRefExpr *Node) {
VisitExpr(Node);
bool IsSuperReceiver = Node->isSuperReceiver();
bool IsMessagingGetter = Node->isMessagingGetter();
bool IsMessagingSetter = Node->isMessagingSetter();
ObjectScope Scope(OF,
1 + IsSuperReceiver + IsMessagingGetter +
IsMessagingSetter); // not covered by tests
OF.emitTag("kind");
if (Node->isImplicitProperty()) {
VariantScope Scope(OF, "MethodRef");
{
bool HasImplicitPropertyGetter = Node->getImplicitPropertyGetter();
bool HasImplicitPropertySetter = Node->getImplicitPropertySetter();
ObjectScope Scope(
OF, 0 + HasImplicitPropertyGetter + HasImplicitPropertySetter);
if (HasImplicitPropertyGetter) {
OF.emitTag("getter");
dumpSelector(Node->getImplicitPropertyGetter()->getSelector());
}
if (HasImplicitPropertySetter) {
OF.emitTag("setter");
dumpSelector(Node->getImplicitPropertySetter()->getSelector());
}
}
} else {
VariantScope Scope(OF, "PropertyRef");
dumpDeclRef(*Node->getExplicitProperty());
}
OF.emitFlag("is_super_receiver", IsSuperReceiver);
OF.emitFlag("is_messaging_getter", IsMessagingGetter);
OF.emitFlag("is_messaging_setter", IsMessagingSetter);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCSubscriptRefExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define obj_c_subscript_ref_expr_tuple expr_tuple * obj_c_subscript_ref_expr_info
//@atd type obj_c_subscript_ref_expr_info = {
//@atd kind : obj_c_subscript_kind;
//@atd ?getter : selector option;
//@atd ?setter : selector option
//@atd } <ocaml field_prefix="osrei_">
//@atd type obj_c_subscript_kind = [ ArraySubscript | DictionarySubscript ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCSubscriptRefExpr(
const ObjCSubscriptRefExpr *Node) {
VisitExpr(Node);
bool HasGetter = Node->getAtIndexMethodDecl();
bool HasSetter = Node->setAtIndexMethodDecl();
ObjectScope Scope(OF, 1 + HasGetter + HasSetter); // not covered by tests
OF.emitTag("kind");
if (Node->isArraySubscriptRefExpr()) {
OF.emitSimpleVariant("ArraySubscript");
} else {
OF.emitSimpleVariant("DictionarySubscript");
}
if (HasGetter) {
OF.emitTag("getter");
dumpSelector(Node->getAtIndexMethodDecl()->getSelector());
}
if (HasSetter) {
OF.emitTag("setter");
dumpSelector(Node->setAtIndexMethodDecl()->getSelector());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCBoolLiteralExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define obj_c_bool_literal_expr_tuple expr_tuple * int
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCBoolLiteralExpr(
const ObjCBoolLiteralExpr *Node) {
VisitExpr(Node);
OF.emitInteger(Node->getValue());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCAvailabilityCheckExprTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define obj_c_availability_check_expr_tuple expr_tuple * obj_c_availability_check_expr_info
//@atd type obj_c_availability_check_expr_info = {
//@atd ?version : string option;
//@atd } <ocaml field_prefix="oacei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCAvailabilityCheckExpr(
const ObjCAvailabilityCheckExpr *Expr) {
VisitExpr(Expr);
bool HasVersion = Expr->hasVersion();
ObjectScope Scope(OF, HasVersion);
if (HasVersion) {
OF.emitTag("version");
// cast is safe, getVersion() should be marked const but isn't
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-qual"
ObjCAvailabilityCheckExpr *E = (ObjCAvailabilityCheckExpr *)Expr;
#pragma clang diagnostic pop
OF.emitString(E->getVersion().getAsString());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCArrayLiteralTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define obj_c_array_literal_tuple expr_tuple * obj_c_array_literal_expr_info
//@atd type obj_c_array_literal_expr_info = {
//@atd ?array_method : pointer option;
//@atd } <ocaml field_prefix="oalei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCArrayLiteral(
const ObjCArrayLiteral *Expr) {
VisitExpr(Expr);
ObjCMethodDecl *ArrayMethod = Expr->getArrayWithObjectsMethod();
ObjectScope Scope(OF, 1);
if (ArrayMethod) {
OF.emitTag("array_method");
dumpPointer(ArrayMethod);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCDictionaryLiteralTupleSize() {
return ExprTupleSize() + 1;
}
//@atd #define obj_c_dictionary_literal_tuple expr_tuple * obj_c_dictionary_literal_expr_info
//@atd type obj_c_dictionary_literal_expr_info = {
//@atd ?dict_method : pointer option;
//@atd } <ocaml field_prefix="odlei_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCDictionaryLiteral(
const ObjCDictionaryLiteral *Expr) {
VisitExpr(Expr);
ObjCMethodDecl *DictMethod = Expr->getDictWithObjectsMethod();
ObjectScope Scope(OF, 1);
if (DictMethod) {
OF.emitTag("dict_method");
dumpPointer(DictMethod);
}
}
// Main variant for statements
//@atd type stmt = [
#define STMT(CLASS, PARENT) //@atd | CLASS of (@CLASS@_tuple)
#define ABSTRACT_STMT(STMT)
#include <clang/AST/StmtNodes.inc>
//@atd ] <ocaml repr="classic" validator="Clang_ast_visit.visit_stmt">
//===----------------------------------------------------------------------===//
// Comments
//===----------------------------------------------------------------------===//
template <class ATDWriter>
const char *ASTExporter<ATDWriter>::getCommandName(unsigned CommandID) {
return Context.getCommentCommandTraits().getCommandInfo(CommandID)->Name;
}
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpFullComment(const FullComment *C) {
FC = C;
dumpComment(C);
FC = 0;
}
#define COMMENT(CLASS, PARENT) //@atd #define @CLASS@_tuple @PARENT@_tuple
#define ABSTRACT_COMMENT(COMMENT) COMMENT
#include <clang/AST/CommentNodes.inc>
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpComment(const Comment *C) {
if (!C) {
// We use a fixed NoComment node to represent null pointers
C = NullPtrComment;
}
VariantScope Scope(OF, std::string(C->getCommentKindName()));
{
TupleScope Scope(OF,
ASTExporter::tupleSizeOfCommentKind(C->getCommentKind()));
ConstCommentVisitor<ASTExporter<ATDWriter>>::visit(C);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::CommentTupleSize() {
return 2;
}
//@atd #define comment_tuple comment_info * comment list
//@atd type comment_info = {
//@atd parent_pointer : pointer;
//@atd source_range : source_range;
//@atd } <ocaml field_prefix="ci_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::visitComment(const Comment *C) {
{
ObjectScope ObjComment(OF, 2); // not covered by tests
OF.emitTag("parent_pointer");
dumpPointer(C);
OF.emitTag("source_range");
dumpSourceRange(C->getSourceRange());
}
{
Comment::child_iterator I = C->child_begin(), E = C->child_end();
ArrayScope Scope(OF, std::distance(I, E));
for (; I != E; ++I) {
dumpComment(*I);
}
}
}
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::visitInlineCommandComment(const
// InlineCommandComment *C) {
// OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
// switch (C->getRenderKind()) {
// case InlineCommandComment::RenderNormal:
// OS << " RenderNormal";
// break;
// case InlineCommandComment::RenderBold:
// OS << " RenderBold";
// break;
// case InlineCommandComment::RenderMonospaced:
// OS << " RenderMonospaced";
// break;
// case InlineCommandComment::RenderEmphasized:
// OS << " RenderEmphasized";
// break;
// }
//
// for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
// OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::visitHTMLStartTagComment(const
// HTMLStartTagComment *C) {
// OS << " Name=\"" << C->getTagName() << "\"";
// if (C->getNumAttrs() != 0) {
// OS << " Attrs: ";
// for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
// const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
// OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
// }
// }
// if (C->isSelfClosing())
// OS << " SelfClosing";
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::visitHTMLEndTagComment(const HTMLEndTagComment
// *C) {
// OS << " Name=\"" << C->getTagName() << "\"";
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::visitBlockCommandComment(const
// BlockCommandComment *C) {
// OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
// for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
// OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::visitParamCommandComment(const
// ParamCommandComment *C) {
// OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection());
//
// if (C->isDirectionExplicit())
// OS << " explicitly";
// else
// OS << " implicitly";
//
// if (C->hasParamName()) {
// if (C->isParamIndexValid())
// OS << " Param=\"" << C->getParamName(FC) << "\"";
// else
// OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
// }
//
// if (C->isParamIndexValid() && !C->isVarArgParam())
// OS << " ParamIndex=" << C->getParamIndex();
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::visitTParamCommandComment(const
// TParamCommandComment *C) {
// if (C->hasParamName()) {
// if (C->isPositionValid())
// OS << " Param=\"" << C->getParamName(FC) << "\"";
// else
// OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
// }
//
// if (C->isPositionValid()) {
// OS << " Position=<";
// for (unsigned i = 0, e = C->getDepth(); i != e; ++i) {
// OS << C->getIndex(i);
// if (i != e - 1)
// OS << ", ";
// }
// OS << ">";
// }
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::visitVerbatimBlockComment(const
// VerbatimBlockComment *C) {
// OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""
// " CloseName=\"" << C->getCloseName() << "\"";
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::visitVerbatimBlockLineComment(
// const VerbatimBlockLineComment *C) {
// OS << " Text=\"" << C->getText() << "\"";
//}
//
// template <class ATDWriter>
// void ASTExporter<ATDWriter>::visitVerbatimLineComment(const
// VerbatimLineComment *C) {
// OS << " Text=\"" << C->getText() << "\"";
//}
//@atd type comment = [
#define COMMENT(CLASS, PARENT) //@atd | CLASS of (@CLASS@_tuple)
#define ABSTRACT_COMMENT(COMMENT)
#include <clang/AST/CommentNodes.inc>
//@atd ] <ocaml repr="classic">
#define TYPE(DERIVED, BASE) //@atd #define @DERIVED@_type_tuple @BASE@_tuple
#define ABSTRACT_TYPE(DERIVED, BASE) TYPE(DERIVED, BASE)
TYPE(None, Type)
#include <clang/AST/TypeNodes.inc>
#undef TYPE
#undef ABSTRACT_TYPE
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpType(const Type *T) {
std::string typeClassName = T ? T->getTypeClassName() : "None";
VariantScope Scope(OF, typeClassName + "Type");
{
if (T) {
// TypeVisitor assumes T is non-null
TupleScope Scope(OF,
ASTExporter::tupleSizeOfTypeClass(T->getTypeClass()));
TypeVisitor<ASTExporter<ATDWriter>>::Visit(T);
} else {
TupleScope Scope(OF, 1);
VisitType(nullptr);
}
}
}
//@atd type type_ptr = int wrap <ocaml module="Clang_ast_types.TypePtr">
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpPointerToType(const Type *T) {
dumpPointer(T);
}
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpQualTypeNoQuals(const QualType &qt) {
const Type *T = qt.getTypePtrOrNull();
dumpPointerToType(T);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::TypeTupleSize() {
return 1;
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::TypeWithChildInfoTupleSize() {
return 2;
}
//@atd #define type_tuple type_info
//@atd type type_info = {
//@atd pointer : pointer;
//@atd ?desugared_type : type_ptr option;
//@atd } <ocaml field_prefix="ti_">
//@atd #define type_with_child_info type_info * qual_type
//@atd #define qual_type_with_child_info type_info * qual_type
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitType(const Type *T) {
// NOTE: T can (and will) be null here!!
bool HasDesugaredType = T && T->getUnqualifiedDesugaredType() != T;
ObjectScope Scope(OF, 1 + HasDesugaredType);
OF.emitTag("pointer");
dumpPointer(T);
if (HasDesugaredType) {
OF.emitTag("desugared_type");
dumpPointerToType(T->getUnqualifiedDesugaredType());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::AdjustedTypeTupleSize() {
return TypeWithChildInfoTupleSize();
}
//@atd #define adjusted_type_tuple type_with_child_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitAdjustedType(const AdjustedType *T) {
VisitType(T);
dumpQualType(T->getAdjustedType());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ArrayTypeTupleSize() {
return TypeTupleSize() + 1;
}
//@atd #define array_type_tuple type_tuple * array_type_info
//@atd type array_type_info = {
//@atd element_type : qual_type;
//@atd ?stride : int option;
//@atd } <ocaml field_prefix="arti_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitArrayType(const ArrayType *T) {
VisitType(T);
QualType EltT = T->getElementType();
bool HasStride = hasMeaningfulTypeInfo(EltT.getTypePtr());
ObjectScope Scope(OF, 1 + HasStride);
OF.emitTag("element_type");
dumpQualType(EltT);
if (HasStride) {
OF.emitTag("stride");
OF.emitInteger(Context.getTypeInfo(EltT).Width / 8);
};
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ConstantArrayTypeTupleSize() {
return ArrayTypeTupleSize() + 1;
}
//@atd #define constant_array_type_tuple array_type_tuple * int
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitConstantArrayType(
const ConstantArrayType *T) {
VisitArrayType(T);
OF.emitInteger(T->getSize().getLimitedValue());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::VariableArrayTypeTupleSize() {
return ArrayTypeTupleSize() + 1;
}
//@atd #define variable_array_type_tuple array_type_tuple * pointer
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitVariableArrayType(
const VariableArrayType *T) {
VisitArrayType(T);
dumpPointer(T->getSizeExpr());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::AtomicTypeTupleSize() {
return TypeWithChildInfoTupleSize();
}
//@atd #define atomic_type_tuple type_with_child_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitAtomicType(const AtomicType *T) {
VisitType(T);
dumpQualType(T->getValueType());
}
//@atd type attribute_kind = [
#define ATTR(NAME) //@atd | NAME@@AttrKind
#include <clang/Basic/AttrList.inc>
//@atd ] <ocaml repr="classic">
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpAttrKind(attr::Kind Kind) {
switch (Kind) {
#define ATTR(NAME) \
case AttributedType::Kind::NAME: \
OF.emitSimpleVariant(#NAME "AttrKind"); \
return;
#include <clang/Basic/AttrList.inc>
}
llvm_unreachable("Attribute kind that is not part of AttrList.inc!");
}
//@atd type objc_lifetime_attr = [
//@atd | OCL_None
//@atd | OCL_ExplicitNone
//@atd | OCL_Strong
//@atd | OCL_Weak
//@atd | OCL_Autoreleasing
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpObjCLifetimeQual(
Qualifiers::ObjCLifetime qual) {
switch (qual) {
case Qualifiers::ObjCLifetime::OCL_None:
OF.emitSimpleVariant("OCL_None");
break;
case Qualifiers::ObjCLifetime::OCL_ExplicitNone:
OF.emitSimpleVariant("OCL_ExplicitNone");
break;
case Qualifiers::ObjCLifetime::OCL_Strong:
OF.emitSimpleVariant("OCL_Strong");
break;
case Qualifiers::ObjCLifetime::OCL_Weak:
OF.emitSimpleVariant("OCL_Weak");
break;
case Qualifiers::ObjCLifetime::OCL_Autoreleasing:
OF.emitSimpleVariant("OCL_Autoreleasing");
break;
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::AttributedTypeTupleSize() {
return TypeTupleSize() + 1;
}
//@atd #define attributed_type_tuple type_tuple * attr_type_info
//@atd type attr_type_info = {
//@atd attr_kind : attribute_kind;
//@atd ~lifetime <ocaml default="`OCL_None"> : objc_lifetime_attr
//@atd } <ocaml field_prefix="ati_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitAttributedType(const AttributedType *T) {
VisitType(T);
Qualifiers quals = QualType(T, 0).getQualifiers();
bool hasLifetimeQual =
quals.hasObjCLifetime() &&
quals.getObjCLifetime() != Qualifiers::ObjCLifetime::OCL_None;
ObjectScope Scope(OF, 1 + hasLifetimeQual);
OF.emitTag("attr_kind");
dumpAttrKind(T->getAttrKind());
if (hasLifetimeQual) {
OF.emitTag("lifetime");
dumpObjCLifetimeQual(quals.getObjCLifetime());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::BlockPointerTypeTupleSize() {
return TypeWithChildInfoTupleSize();
}
//@atd #define block_pointer_type_tuple type_with_child_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitBlockPointerType(const BlockPointerType *T) {
VisitType(T);
dumpQualType(T->getPointeeType());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::BuiltinTypeTupleSize() {
return TypeTupleSize() + 1;
}
//@atd #define builtin_type_tuple type_tuple * builtin_type_kind
//@atd type builtin_type_kind = [
#define BUILTIN_TYPE(TYPE, ID) //@atd | TYPE
#include <clang/AST/BuiltinTypes.def>
#define SVE_PREDICATE_TYPE( \
Name, MangledName, Id, SingletonId, NumEls) //@atd | Id
#define SVE_VECTOR_TYPE(Name, \
MangledName, \
Id, \
SingletonId, \
NumEls, \
ElBits, \
IsSigned, \
IsFP, \
IsBF) //@atd | Id
#include <clang/Basic/AArch64SVEACLETypes.def>
//@atd ]
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitBuiltinType(const BuiltinType *T) {
VisitType(T);
std::string type_name;
switch (T->getKind()) {
#define BUILTIN_TYPE(TYPE, ID) \
case BuiltinType::TYPE: { \
type_name = #TYPE; \
break; \
}
#include <clang/AST/BuiltinTypes.def>
#define SVE_PREDICATE_TYPE(Name, MangeldName, Id, SingletonId, NumEls) \
case BuiltinType::Id: { \
type_name = #Id; \
break; \
}
#define SVE_VECTOR_TYPE( \
Name, MangledName, Id, SingletonId, NumEls, ElBits, IsSigned, IsFP, IsBF) \
case BuiltinType::Id: { \
type_name = #Id; \
break; \
}
#include <clang/Basic/AArch64SVEACLETypes.def>
#define IMAGE_TYPE(ImgType, ID, SingletonId, Access, Suffix) \
case BuiltinType::ID:
#include <clang/Basic/OpenCLImageTypes.def>
#define EXT_OPAQUE_TYPE(Name, Id, Ext) case BuiltinType::Id:
#include <clang/Basic/OpenCLExtensionTypes.def>
llvm_unreachable("OCL builtin types are unsupported");
break;
}
OF.emitSimpleVariant(type_name);
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::DecltypeTypeTupleSize() {
return TypeWithChildInfoTupleSize();
}
//@atd #define decltype_type_tuple type_with_child_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitDecltypeType(const DecltypeType *T) {
VisitType(T);
dumpQualType(T->getUnderlyingType());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::FunctionTypeTupleSize() {
return TypeTupleSize() + 1;
}
//@atd #define function_type_tuple type_tuple * function_type_info
//@atd type function_type_info = {
//@atd return_type : qual_type
//@atd } <ocaml field_prefix="fti_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitFunctionType(const FunctionType *T) {
VisitType(T);
ObjectScope Scope(OF, 1);
OF.emitTag("return_type");
dumpQualType(T->getReturnType());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::FunctionProtoTypeTupleSize() {
return FunctionTypeTupleSize() + 1;
}
//@atd #define function_proto_type_tuple function_type_tuple * params_type_info
//@atd type params_type_info = {
//@atd ~params_type : qual_type list
//@atd } <ocaml field_prefix="pti_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitFunctionProtoType(
const FunctionProtoType *T) {
VisitFunctionType(T);
bool HasParamsType = T->getNumParams() > 0;
ObjectScope Scope(OF, 0 + HasParamsType);
if (HasParamsType) {
OF.emitTag("params_type");
ArrayScope aScope(OF, T->getParamTypes().size());
for (const auto &paramType : T->getParamTypes()) {
dumpQualType(paramType);
}
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::MemberPointerTypeTupleSize() {
return TypeWithChildInfoTupleSize();
}
//@atd #define member_pointer_type_tuple type_with_child_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitMemberPointerType(
const MemberPointerType *T) {
VisitType(T);
dumpQualType(T->getPointeeType());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCObjectPointerTypeTupleSize() {
return TypeWithChildInfoTupleSize();
}
//@atd #define obj_c_object_pointer_type_tuple qual_type_with_child_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCObjectPointerType(
const ObjCObjectPointerType *T) {
VisitType(T);
dumpQualType(T->getPointeeType());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCObjectTypeTupleSize() {
return TypeTupleSize() + 1;
}
//@atd #define obj_c_object_type_tuple type_tuple * objc_object_type_info
//@atd type objc_object_type_info = {
//@atd base_type : type_ptr;
//@atd ~protocol_decls_ptr : pointer list;
//@atd ~type_args : qual_type list;
//@atd } <ocaml field_prefix="ooti_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCObjectType(const ObjCObjectType *T) {
VisitType(T);
int numProtocols = T->getNumProtocols();
bool HasProtocols = numProtocols > 0;
bool isSpecialized = T->isSpecialized();
ObjectScope Scope(OF, 1 + HasProtocols + isSpecialized);
OF.emitTag("base_type");
dumpQualTypeNoQuals(T->getBaseType());
if (HasProtocols) {
OF.emitTag("protocol_decls_ptr");
ArrayScope aScope(OF, numProtocols);
for (int i = 0; i < numProtocols; i++) {
dumpPointer(T->getProtocol(i));
}
}
if (isSpecialized) {
OF.emitTag("type_args");
ArrayScope aScope(OF, T->getTypeArgs().size());
for (auto &argType : T->getTypeArgs()) {
dumpQualType(argType);
};
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ObjCInterfaceTypeTupleSize() {
return TypeTupleSize() + 1;
}
//@atd #define obj_c_interface_type_tuple type_tuple * pointer
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitObjCInterfaceType(
const ObjCInterfaceType *T) {
// skip VisitObjCObjectType deliberately - ObjCInterfaceType can't have any
// protocols
VisitType(T);
dumpPointer(T->getDecl());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ParenTypeTupleSize() {
return TypeWithChildInfoTupleSize();
}
//@atd #define paren_type_tuple type_with_child_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitParenType(const ParenType *T) {
// this is just syntactic sugar
VisitType(T);
dumpQualType(T->getInnerType());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::PointerTypeTupleSize() {
return TypeWithChildInfoTupleSize();
}
//@atd #define pointer_type_tuple qual_type_with_child_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitPointerType(const PointerType *T) {
VisitType(T);
dumpQualType(T->getPointeeType());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::ReferenceTypeTupleSize() {
return TypeWithChildInfoTupleSize();
}
//@atd #define reference_type_tuple qual_type_with_child_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitReferenceType(const ReferenceType *T) {
VisitType(T);
dumpQualType(T->getPointeeType());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::TagTypeTupleSize() {
return TypeTupleSize() + 1;
}
//@atd #define tag_type_tuple type_tuple * pointer
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitTagType(const TagType *T) {
VisitType(T);
dumpPointer(T->getDecl());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::TypedefTypeTupleSize() {
return TypeTupleSize() + 1;
}
//@atd #define typedef_type_tuple type_tuple * typedef_type_info
//@atd type typedef_type_info = {
//@atd child_type : qual_type;
//@atd decl_ptr : pointer;
//@atd } <ocaml field_prefix="tti_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitTypedefType(const TypedefType *T) {
VisitType(T);
ObjectScope Scope(OF, 2);
OF.emitTag("child_type");
dumpQualType(T->desugar());
OF.emitTag("decl_ptr");
dumpPointer(T->getDecl());
}
//===----------------------------------------------------------------------===//
// Attr dumping methods.
//===----------------------------------------------------------------------===//
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpAttr(const Attr *A) {
std::string tag;
switch (A->getKind()) {
#define ATTR(NAME) \
case attr::Kind::NAME: \
tag = #NAME "Attr"; \
break;
#include <clang/Basic/AttrList.inc>
}
VariantScope Scope(OF, tag);
{
TupleScope Scope(OF, ASTExporter::tupleSizeOfAttrKind(A->getKind()));
ConstAttrVisitor<ASTExporter<ATDWriter>>::Visit(A);
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::AttrTupleSize() {
return 1;
}
//@atd type attribute_info = {
//@atd pointer : pointer;
//@atd source_range : source_range;
//@atd } <ocaml field_prefix="ai_">
//@atd type attr_tuple = attribute_info
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitAttr(const Attr *A) {
ObjectScope Scope(OF, 2);
OF.emitTag("pointer");
dumpPointer(A);
OF.emitTag("source_range");
dumpSourceRange(A->getRange());
}
// Default aliases for generating variant components
// The main variant is defined at the end of section.
#define ATTR(NAME) //@atd #define @NAME@_attr_tuple attribute_info
#include <clang/Basic/AttrList.inc>
//@atd type version_tuple = {
//@atd major: int;
//@atd ?minor: int option;
//@atd ?subminor: int option;
//@atd ?build: int option;
//@atd } <ocaml field_prefix="vt_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::dumpVersionTuple(const VersionTuple &VT) {
Optional<unsigned> minor = VT.getMinor();
Optional<unsigned> subminor = VT.getSubminor();
Optional<unsigned> build = VT.getBuild();
ObjectScope Scope(
OF, 1 + minor.hasValue() + subminor.hasValue() + build.hasValue());
OF.emitTag("major");
OF.emitInteger(VT.getMajor());
if (minor.hasValue()) {
OF.emitTag("minor");
OF.emitInteger(minor.getValue());
}
if (subminor.hasValue()) {
OF.emitTag("subminor");
OF.emitInteger(subminor.getValue());
}
if (build.hasValue()) {
OF.emitTag("build");
OF.emitInteger(build.getValue());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::AnnotateAttrTupleSize() {
return AttrTupleSize() + 1;
}
//@atd #define annotate_attr_tuple attr_tuple * string
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitAnnotateAttr(const AnnotateAttr *A) {
VisitAttr(A);
OF.emitString(A->getAnnotation().str());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::AvailabilityAttrTupleSize() {
return AttrTupleSize() + 1;
}
//@atd #define availability_attr_tuple attr_tuple * availability_attr_info
//@atd type availability_attr_info = {
//@atd ?platform: string option;
//@atd introduced: version_tuple;
//@atd } <ocaml field_prefix="aai_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitAvailabilityAttr(const AvailabilityAttr *A) {
VisitAttr(A);
{
IdentifierInfo *platform = A->getPlatform();
ObjectScope Scope(OF, 2 + (bool)platform);
if (platform != nullptr) {
OF.emitTag("platform");
OF.emitString(platform->getNameStart());
}
OF.emitTag("introduced");
dumpVersionTuple(A->getIntroduced());
}
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::SentinelAttrTupleSize() {
return AttrTupleSize() + 1;
}
//@atd #define sentinel_attr_tuple attr_tuple * sentinel_attr_info
//@atd type sentinel_attr_info = {
//@atd sentinel: int;
//@atd null_pos: int;
//@atd } <ocaml field_prefix="sai_">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitSentinelAttr(const SentinelAttr *A) {
VisitAttr(A);
ObjectScope Scope(OF, 2);
OF.emitTag("sentinel");
OF.emitInteger(A->getSentinel());
OF.emitTag("null_pos");
OF.emitInteger(A->getNullPos());
}
template <class ATDWriter>
int ASTExporter<ATDWriter>::VisibilityAttrTupleSize() {
return AttrTupleSize() + 1;
}
//@atd #define visibility_attr_tuple attr_tuple * visibility_attr
//@atd type visibility_attr = [
//@atd | DefaultVisibility
//@atd | HiddenVisibility
//@atd | ProtectedVisibility
//@atd ] <ocaml repr="classic">
template <class ATDWriter>
void ASTExporter<ATDWriter>::VisitVisibilityAttr(const VisibilityAttr *A) {
VisitAttr(A);
switch (A->getVisibility()) {
case VisibilityAttr::Default:
OF.emitSimpleVariant("DefaultVisibility");
break;
case VisibilityAttr::Hidden:
OF.emitSimpleVariant("HiddenVisibility");
break;
case VisibilityAttr::Protected:
OF.emitSimpleVariant("ProtectedVisibility");
break;
}
}
//@atd type attribute = [
#define ATTR(X) //@atd | X@@Attr of (@X@_attr_tuple)
#include <clang/Basic/AttrList.inc>
//@atd ]
//@atd type c_type = [
#define TYPE(CLASS, PARENT) //@atd | CLASS@@Type of (@CLASS@_type_tuple)
#define ABSTRACT_TYPE(CLASS, PARENT)
TYPE(None, Type)
#include <clang/AST/TypeNodes.inc>
//@atd ] <ocaml repr="classic" validator="Clang_ast_visit.visit_type">
template <class ATDWriter = JsonWriter, bool ForceYojson = false>
class ExporterASTConsumer : public ASTConsumer {
private:
std::shared_ptr<ASTExporterOptions> options;
std::unique_ptr<raw_ostream> OS;
public:
using ASTConsumerOptions = ASTLib::ASTExporterOptions;
using PreprocessorHandler = ASTPluginLib::EmptyPreprocessorHandler;
using PreprocessorHandlerData = ASTPluginLib::EmptyPreprocessorHandlerData;
ExporterASTConsumer(const CompilerInstance &CI,
std::shared_ptr<ASTConsumerOptions> options,
std::shared_ptr<PreprocessorHandlerData> sharedData,
std::unique_ptr<raw_ostream> &&OS)
: options(options), OS(std::move(OS)) {
if (ForceYojson) {
options->atdWriterOptions.useYojson = true;
}
}
virtual void HandleTranslationUnit(ASTContext &Context) {
TranslationUnitDecl *D = Context.getTranslationUnitDecl();
ASTExporter<ATDWriter> P(*OS, Context, *options);
P.dumpDecl(D);
}
};
typedef ASTPluginLib::SimplePluginASTAction<
ASTLib::ExporterASTConsumer<ASTLib::JsonWriter, false>>
JsonExporterASTAction;
typedef ASTPluginLib::SimplePluginASTAction<
ASTLib::ExporterASTConsumer<ASTLib::JsonWriter, true>>
YojsonExporterASTAction;
typedef ASTPluginLib::SimplePluginASTAction<
ASTLib::ExporterASTConsumer<ATDWriter::BiniouWriter<llvm::raw_ostream>,
true>>
BiniouExporterASTAction;
} // end of namespace ASTLib