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.
5398 lines
168 KiB
5398 lines
168 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/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.def>
|
|
|
|
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.def>
|
|
}
|
|
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->isHidden();
|
|
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->isHidden();
|
|
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 InputKind::Unknown:
|
|
OF.emitSimpleVariant("IK_None");
|
|
break;
|
|
case InputKind::Asm:
|
|
OF.emitSimpleVariant("IK_Asm");
|
|
break;
|
|
case InputKind::C:
|
|
OF.emitSimpleVariant("IK_C");
|
|
break;
|
|
case InputKind::CXX:
|
|
OF.emitSimpleVariant("IK_CXX");
|
|
break;
|
|
case InputKind::ObjC:
|
|
OF.emitSimpleVariant("IK_ObjC");
|
|
break;
|
|
case InputKind::ObjCXX:
|
|
OF.emitSimpleVariant("IK_ObjCXX");
|
|
break;
|
|
case InputKind::OpenCL:
|
|
OF.emitSimpleVariant("IK_OpenCL");
|
|
break;
|
|
case InputKind::CUDA:
|
|
OF.emitSimpleVariant("IK_CUDA");
|
|
break;
|
|
case InputKind::RenderScript:
|
|
OF.emitSimpleVariant("IK_RenderScript");
|
|
break;
|
|
case InputKind::LLVM_IR:
|
|
OF.emitSimpleVariant("IK_LLVM_IR");
|
|
break;
|
|
case InputKind::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 types : c_type list;
|
|
//@atd } <ocaml field_prefix="tudi_">
|
|
template <class ATDWriter>
|
|
void ASTExporter<ATDWriter>::VisitTranslationUnitDecl(
|
|
const TranslationUnitDecl *D) {
|
|
VisitDecl(D);
|
|
VisitDeclContext(D);
|
|
ObjectScope Scope(OF, 4);
|
|
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.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).
|
|
|
|
bool ShouldMangleName = Mangler->shouldMangleDeclName(D);
|
|
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);
|
|
if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
|
|
Mangler->mangleCXXCtor(CD, Ctor_Complete, StrOS);
|
|
} else if (const auto *DD = dyn_cast<CXXDestructorDecl>(D)) {
|
|
Mangler->mangleCXXDtor(DD, Dtor_Deleting, StrOS);
|
|
} else {
|
|
Mangler->mangleName(D, 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);
|
|
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();
|
|
|
|
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;
|
|
ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes();
|
|
bool HasPropertyAttributes = Attrs != ObjCPropertyDecl::OBJC_PR_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;
|
|
case ObjCPropertyDecl::None:
|
|
llvm_unreachable("unreachable");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (HasPropertyAttributes) {
|
|
OF.emitTag("property_attributes");
|
|
bool readonly = Attrs & ObjCPropertyDecl::OBJC_PR_readonly;
|
|
bool assign = Attrs & ObjCPropertyDecl::OBJC_PR_assign;
|
|
bool readwrite = Attrs & ObjCPropertyDecl::OBJC_PR_readwrite;
|
|
bool retain = Attrs & ObjCPropertyDecl::OBJC_PR_retain;
|
|
bool copy = Attrs & ObjCPropertyDecl::OBJC_PR_copy;
|
|
bool nonatomic = Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic;
|
|
bool atomic = Attrs & ObjCPropertyDecl::OBJC_PR_atomic;
|
|
bool weak = Attrs & ObjCPropertyDecl::OBJC_PR_weak;
|
|
bool strong = Attrs & ObjCPropertyDecl::OBJC_PR_strong;
|
|
bool unsafeUnretained = Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained;
|
|
bool getter = Attrs & ObjCPropertyDecl::OBJC_PR_getter;
|
|
bool setter = Attrs & ObjCPropertyDecl::OBJC_PR_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();
|
|
|
|
SmallString<64> Buf;
|
|
llvm::raw_svector_ostream StrOS(Buf);
|
|
Mangler->mangleBlock(D->getDeclContext(), D, StrOS);
|
|
std::string MangledName = StrOS.str();
|
|
|
|
int size = 0 + HasParameters + IsVariadic + CapturesCXXThis +
|
|
HasCapturedVariables + (bool)Body + 1 /* MangledName*/;
|
|
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);
|
|
}
|
|
|
|
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());
|
|
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_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());
|
|
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;
|
|
}
|
|
}
|
|
|
|
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());
|
|
}
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
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());
|
|
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");
|
|
ArrayScope Scope(OF, Node->getNumObjects());
|
|
for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)
|
|
dumpDeclRef(*Node->getObject(i));
|
|
}
|
|
}
|
|
|
|
//@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.def>
|
|
#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>
|
|
//@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 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 ¶mType : 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.def>
|
|
//@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
|