[ASTImporter] Implement some expression-related AST node import.
Introduce ASTImporter unit test framework. Fix a memory leak introduced in cf8ccff5: an array is allocated in ImportArray and never freed. Support new node kinds: - GCCAsmStmt - AddrLabelExpr - AtomicExpr - CompoundLiteralExpr - CXXBoolLiteralExpr - CXXNullPtrLiteralExpr - CXXThisExpr - DesignatedInitExpr - GNUNullExpr - ImplicitValueInitExpr - InitListExpr - OpaqueValueExpr - PredefinedExpr - ParenListExpr - StmtExpr - VAArgExpr - BinaryConditionalOperator - ConditionalOperator - FloatingLiteral - StringLiteral - InjectedClassNameType - TemplateTypeParmType - LabelDecl Patch by Aleksei Sidorin! Differential Revision: http://reviews.llvm.org/D14286 llvm-svn: 266292
This commit is contained in:
parent
909d080d98
commit
4e7c6fdeeb
|
@ -4278,6 +4278,8 @@ class InjectedClassNameType : public Type {
|
|||
friend class ASTReader; // FIXME: ASTContext::getInjectedClassNameType is not
|
||||
// currently suitable for AST reading, too much
|
||||
// interdependencies.
|
||||
friend class ASTNodeImporter;
|
||||
|
||||
InjectedClassNameType(CXXRecordDecl *D, QualType TST)
|
||||
: Type(InjectedClassName, QualType(), /*Dependent=*/true,
|
||||
/*InstantiationDependent=*/true,
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace clang {
|
|||
public DeclVisitor<ASTNodeImporter, Decl *>,
|
||||
public StmtVisitor<ASTNodeImporter, Stmt *> {
|
||||
ASTImporter &Importer;
|
||||
|
||||
|
||||
public:
|
||||
explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) { }
|
||||
|
||||
|
@ -64,11 +64,12 @@ namespace clang {
|
|||
QualType VisitDecltypeType(const DecltypeType *T);
|
||||
QualType VisitUnaryTransformType(const UnaryTransformType *T);
|
||||
QualType VisitAutoType(const AutoType *T);
|
||||
QualType VisitInjectedClassNameType(const InjectedClassNameType *T);
|
||||
// FIXME: DependentDecltypeType
|
||||
QualType VisitRecordType(const RecordType *T);
|
||||
QualType VisitEnumType(const EnumType *T);
|
||||
QualType VisitAttributedType(const AttributedType *T);
|
||||
// FIXME: TemplateTypeParmType
|
||||
QualType VisitTemplateTypeParmType(const TemplateTypeParmType *T);
|
||||
// FIXME: SubstTemplateTypeParmType
|
||||
QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T);
|
||||
QualType VisitElaboratedType(const ElaboratedType *T);
|
||||
|
@ -86,6 +87,10 @@ namespace clang {
|
|||
void ImportDeclarationNameLoc(const DeclarationNameInfo &From,
|
||||
DeclarationNameInfo& To);
|
||||
void ImportDeclContext(DeclContext *FromDC, bool ForceImport = false);
|
||||
|
||||
typedef DesignatedInitExpr::Designator Designator;
|
||||
Designator ImportDesignator(const Designator &D);
|
||||
|
||||
|
||||
/// \brief What we should import from the definition.
|
||||
enum ImportDefinitionKind {
|
||||
|
@ -136,6 +141,7 @@ namespace clang {
|
|||
Decl *VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias);
|
||||
Decl *VisitTypedefDecl(TypedefDecl *D);
|
||||
Decl *VisitTypeAliasDecl(TypeAliasDecl *D);
|
||||
Decl *VisitLabelDecl(LabelDecl *D);
|
||||
Decl *VisitEnumDecl(EnumDecl *D);
|
||||
Decl *VisitRecordDecl(RecordDecl *D);
|
||||
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
|
||||
|
@ -175,6 +181,7 @@ namespace clang {
|
|||
DeclGroupRef ImportDeclGroup(DeclGroupRef DG);
|
||||
|
||||
Stmt *VisitStmt(Stmt *S);
|
||||
Stmt *VisitGCCAsmStmt(GCCAsmStmt *S);
|
||||
Stmt *VisitDeclStmt(DeclStmt *S);
|
||||
Stmt *VisitNullStmt(NullStmt *S);
|
||||
Stmt *VisitCompoundStmt(CompoundStmt *S);
|
||||
|
@ -192,7 +199,6 @@ namespace clang {
|
|||
Stmt *VisitContinueStmt(ContinueStmt *S);
|
||||
Stmt *VisitBreakStmt(BreakStmt *S);
|
||||
Stmt *VisitReturnStmt(ReturnStmt *S);
|
||||
// FIXME: GCCAsmStmt
|
||||
// FIXME: MSAsmStmt
|
||||
// FIXME: SEHExceptStmt
|
||||
// FIXME: SEHFinallyStmt
|
||||
|
@ -213,13 +219,29 @@ namespace clang {
|
|||
|
||||
// Importing expressions
|
||||
Expr *VisitExpr(Expr *E);
|
||||
Expr *VisitVAArgExpr(VAArgExpr *E);
|
||||
Expr *VisitGNUNullExpr(GNUNullExpr *E);
|
||||
Expr *VisitPredefinedExpr(PredefinedExpr *E);
|
||||
Expr *VisitDeclRefExpr(DeclRefExpr *E);
|
||||
Expr *VisitImplicitValueInitExpr(ImplicitValueInitExpr *ILE);
|
||||
Expr *VisitDesignatedInitExpr(DesignatedInitExpr *E);
|
||||
Expr *VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E);
|
||||
Expr *VisitIntegerLiteral(IntegerLiteral *E);
|
||||
Expr *VisitFloatingLiteral(FloatingLiteral *E);
|
||||
Expr *VisitCharacterLiteral(CharacterLiteral *E);
|
||||
Expr *VisitStringLiteral(StringLiteral *E);
|
||||
Expr *VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
|
||||
Expr *VisitAtomicExpr(AtomicExpr *E);
|
||||
Expr *VisitAddrLabelExpr(AddrLabelExpr *E);
|
||||
Expr *VisitParenExpr(ParenExpr *E);
|
||||
Expr *VisitParenListExpr(ParenListExpr *E);
|
||||
Expr *VisitStmtExpr(StmtExpr *E);
|
||||
Expr *VisitUnaryOperator(UnaryOperator *E);
|
||||
Expr *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
|
||||
Expr *VisitBinaryOperator(BinaryOperator *E);
|
||||
Expr *VisitConditionalOperator(ConditionalOperator *E);
|
||||
Expr *VisitBinaryConditionalOperator(BinaryConditionalOperator *E);
|
||||
Expr *VisitOpaqueValueExpr(OpaqueValueExpr *E);
|
||||
Expr *VisitCompoundAssignOperator(CompoundAssignOperator *E);
|
||||
Expr *VisitImplicitCastExpr(ImplicitCastExpr *E);
|
||||
Expr *VisitCStyleCastExpr(CStyleCastExpr *E);
|
||||
|
@ -230,32 +252,34 @@ namespace clang {
|
|||
Expr *VisitMemberExpr(MemberExpr *E);
|
||||
Expr *VisitCallExpr(CallExpr *E);
|
||||
Expr *VisitInitListExpr(InitListExpr *E);
|
||||
|
||||
template <typename T, typename Iter> bool ImportArray(Iter B, Iter E, llvm::ArrayRef<T*> &ToArray) {
|
||||
size_t NumElements = E - B;
|
||||
SmallVector<T *, 1> ImportedElements(NumElements);
|
||||
ASTImporter &_Importer = Importer;
|
||||
|
||||
bool Failed = false;
|
||||
std::transform(B, E, ImportedElements.begin(),
|
||||
[&_Importer, &Failed](T *Element) -> T* {
|
||||
T *ToElement = _Importer.Import(Element);
|
||||
if (Element && !ToElement)
|
||||
Failed = true;
|
||||
return ToElement;
|
||||
|
||||
template<typename IIter, typename OIter>
|
||||
void ImportArray(IIter Ibegin, IIter Iend, OIter Obegin) {
|
||||
typedef typename std::remove_reference<decltype(*Obegin)>::type ItemT;
|
||||
ASTImporter &ImporterRef = Importer;
|
||||
std::transform(Ibegin, Iend, Obegin,
|
||||
[&ImporterRef](ItemT From) -> ItemT {
|
||||
return ImporterRef.Import(From);
|
||||
});
|
||||
|
||||
if (Failed)
|
||||
return false;
|
||||
|
||||
T **CopiedElements = new (Importer.getToContext()) T*[NumElements];
|
||||
std::copy(ImportedElements.begin(), ImportedElements.end(), &CopiedElements[0]);
|
||||
ToArray = llvm::ArrayRef<T*>(CopiedElements, NumElements);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename IIter, typename OIter>
|
||||
bool ImportArrayChecked(IIter Ibegin, IIter Iend, OIter Obegin) {
|
||||
typedef typename std::remove_reference<decltype(**Obegin)>::type ItemT;
|
||||
ASTImporter &ImporterRef = Importer;
|
||||
bool Failed = false;
|
||||
std::transform(Ibegin, Iend, Obegin,
|
||||
[&ImporterRef, &Failed](ItemT *From) -> ItemT * {
|
||||
ItemT *To = ImporterRef.Import(From);
|
||||
if (!To && From)
|
||||
Failed = true;
|
||||
return To;
|
||||
});
|
||||
return Failed;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -1791,6 +1815,28 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
|
|||
/*IsDependent*/false);
|
||||
}
|
||||
|
||||
QualType ASTNodeImporter::VisitInjectedClassNameType(
|
||||
const InjectedClassNameType *T) {
|
||||
CXXRecordDecl *D = cast_or_null<CXXRecordDecl>(Importer.Import(T->getDecl()));
|
||||
if (!D)
|
||||
return QualType();
|
||||
|
||||
QualType InjType = Importer.Import(T->getInjectedSpecializationType());
|
||||
if (InjType.isNull())
|
||||
return QualType();
|
||||
|
||||
// FIXME: ASTContext::getInjectedClassNameType is not suitable for AST reading
|
||||
// See comments in InjectedClassNameType definition for details
|
||||
// return Importer.getToContext().getInjectedClassNameType(D, InjType);
|
||||
enum {
|
||||
TypeAlignmentInBits = 4,
|
||||
TypeAlignment = 1 << TypeAlignmentInBits
|
||||
};
|
||||
|
||||
return QualType(new (Importer.getToContext(), TypeAlignment)
|
||||
InjectedClassNameType(D, InjType), 0);
|
||||
}
|
||||
|
||||
QualType ASTNodeImporter::VisitRecordType(const RecordType *T) {
|
||||
RecordDecl *ToDecl
|
||||
= dyn_cast_or_null<RecordDecl>(Importer.Import(T->getDecl()));
|
||||
|
@ -1830,6 +1876,18 @@ QualType ASTNodeImporter::VisitAttributedType(const AttributedType *T) {
|
|||
ToModifiedType, ToEquivalentType);
|
||||
}
|
||||
|
||||
|
||||
QualType ASTNodeImporter::VisitTemplateTypeParmType(
|
||||
const TemplateTypeParmType *T) {
|
||||
TemplateTypeParmDecl *ParmDecl =
|
||||
cast_or_null<TemplateTypeParmDecl>(Importer.Import(T->getDecl()));
|
||||
if (!ParmDecl && T->getDecl())
|
||||
return QualType();
|
||||
|
||||
return Importer.getToContext().getTemplateTypeParmType(
|
||||
T->getDepth(), T->getIndex(), T->isParameterPack(), ParmDecl);
|
||||
}
|
||||
|
||||
QualType ASTNodeImporter::VisitTemplateSpecializationType(
|
||||
const TemplateSpecializationType *T) {
|
||||
TemplateName ToTemplate = Importer.Import(T->getTemplateName());
|
||||
|
@ -2525,6 +2583,39 @@ Decl *ASTNodeImporter::VisitTypeAliasDecl(TypeAliasDecl *D) {
|
|||
return VisitTypedefNameDecl(D, /*IsAlias=*/true);
|
||||
}
|
||||
|
||||
Decl *ASTNodeImporter::VisitLabelDecl(LabelDecl *D) {
|
||||
// Import the major distinguishing characteristics of this label.
|
||||
DeclContext *DC, *LexicalDC;
|
||||
DeclarationName Name;
|
||||
SourceLocation Loc;
|
||||
NamedDecl *ToD;
|
||||
if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc))
|
||||
return nullptr;
|
||||
if (ToD)
|
||||
return ToD;
|
||||
|
||||
assert(LexicalDC->isFunctionOrMethod());
|
||||
|
||||
LabelDecl *ToLabel = D->isGnuLocal()
|
||||
? LabelDecl::Create(Importer.getToContext(),
|
||||
DC, Importer.Import(D->getLocation()),
|
||||
Name.getAsIdentifierInfo(),
|
||||
Importer.Import(D->getLocStart()))
|
||||
: LabelDecl::Create(Importer.getToContext(),
|
||||
DC, Importer.Import(D->getLocation()),
|
||||
Name.getAsIdentifierInfo());
|
||||
Importer.Imported(D, ToLabel);
|
||||
|
||||
LabelStmt *Label = cast_or_null<LabelStmt>(Importer.Import(D->getStmt()));
|
||||
if (!Label)
|
||||
return nullptr;
|
||||
|
||||
ToLabel->setStmt(Label);
|
||||
ToLabel->setLexicalDeclContext(LexicalDC);
|
||||
LexicalDC->addDeclInternal(ToLabel);
|
||||
return ToLabel;
|
||||
}
|
||||
|
||||
Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
|
||||
// Import the major distinguishing characteristics of this enum.
|
||||
DeclContext *DC, *LexicalDC;
|
||||
|
@ -4328,16 +4419,16 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
|||
CXXRecordDecl *DTemplated = D->getTemplatedDecl();
|
||||
|
||||
// Create the declaration that is being templated.
|
||||
SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart());
|
||||
SourceLocation IdLoc = Importer.Import(DTemplated->getLocation());
|
||||
CXXRecordDecl *D2Templated = CXXRecordDecl::Create(Importer.getToContext(),
|
||||
DTemplated->getTagKind(),
|
||||
DC, StartLoc, IdLoc,
|
||||
Name.getAsIdentifierInfo());
|
||||
D2Templated->setAccess(DTemplated->getAccess());
|
||||
D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc()));
|
||||
D2Templated->setLexicalDeclContext(LexicalDC);
|
||||
|
||||
// Create the declaration that is being templated.
|
||||
CXXRecordDecl *D2Templated = cast_or_null<CXXRecordDecl>(
|
||||
Importer.Import(DTemplated));
|
||||
if (!D2Templated)
|
||||
return nullptr;
|
||||
|
||||
// Resolve possible cyclic import.
|
||||
if (Decl *AlreadyImported = Importer.GetAlreadyImportedOrNull(D))
|
||||
return AlreadyImported;
|
||||
|
||||
// Create the class template declaration itself.
|
||||
TemplateParameterList *TemplateParams
|
||||
= ImportTemplateParameterList(D->getTemplateParameters());
|
||||
|
@ -4681,7 +4772,78 @@ DeclGroupRef ASTNodeImporter::ImportDeclGroup(DeclGroupRef DG) {
|
|||
<< S->getStmtClassName();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Stmt *ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) {
|
||||
SmallVector<IdentifierInfo *, 4> Names;
|
||||
for (unsigned I = 0, E = S->getNumOutputs(); I != E; I++) {
|
||||
IdentifierInfo *ToII = Importer.Import(S->getOutputIdentifier(I));
|
||||
if (!ToII)
|
||||
return nullptr;
|
||||
Names.push_back(ToII);
|
||||
}
|
||||
for (unsigned I = 0, E = S->getNumInputs(); I != E; I++) {
|
||||
IdentifierInfo *ToII = Importer.Import(S->getInputIdentifier(I));
|
||||
if (!ToII)
|
||||
return nullptr;
|
||||
Names.push_back(ToII);
|
||||
}
|
||||
|
||||
SmallVector<StringLiteral *, 4> Clobbers;
|
||||
for (unsigned I = 0, E = S->getNumClobbers(); I != E; I++) {
|
||||
StringLiteral *Clobber = cast_or_null<StringLiteral>(
|
||||
Importer.Import(S->getClobberStringLiteral(I)));
|
||||
if (!Clobber)
|
||||
return nullptr;
|
||||
Clobbers.push_back(Clobber);
|
||||
}
|
||||
|
||||
SmallVector<StringLiteral *, 4> Constraints;
|
||||
for (unsigned I = 0, E = S->getNumOutputs(); I != E; I++) {
|
||||
StringLiteral *Output = cast_or_null<StringLiteral>(
|
||||
Importer.Import(S->getOutputConstraintLiteral(I)));
|
||||
if (!Output)
|
||||
return nullptr;
|
||||
Constraints.push_back(Output);
|
||||
}
|
||||
|
||||
for (unsigned I = 0, E = S->getNumInputs(); I != E; I++) {
|
||||
StringLiteral *Input = cast_or_null<StringLiteral>(
|
||||
Importer.Import(S->getInputConstraintLiteral(I)));
|
||||
if (!Input)
|
||||
return nullptr;
|
||||
Constraints.push_back(Input);
|
||||
}
|
||||
|
||||
SmallVector<Expr *, 4> Exprs(S->getNumOutputs() + S->getNumInputs());
|
||||
if (ImportArrayChecked(S->begin_outputs(), S->end_outputs(), Exprs.begin()))
|
||||
return nullptr;
|
||||
|
||||
if (ImportArrayChecked(S->begin_inputs(), S->end_inputs(),
|
||||
Exprs.begin() + S->getNumOutputs()))
|
||||
return nullptr;
|
||||
|
||||
StringLiteral *AsmStr = cast_or_null<StringLiteral>(
|
||||
Importer.Import(S->getAsmString()));
|
||||
if (!AsmStr)
|
||||
return nullptr;
|
||||
|
||||
return new (Importer.getToContext()) GCCAsmStmt(
|
||||
Importer.getToContext(),
|
||||
Importer.Import(S->getAsmLoc()),
|
||||
S->isSimple(),
|
||||
S->isVolatile(),
|
||||
S->getNumOutputs(),
|
||||
S->getNumInputs(),
|
||||
Names.data(),
|
||||
Constraints.data(),
|
||||
Exprs.data(),
|
||||
AsmStr,
|
||||
S->getNumClobbers(),
|
||||
Clobbers.data(),
|
||||
Importer.Import(S->getRParenLoc()));
|
||||
}
|
||||
|
||||
Stmt *ASTNodeImporter::VisitDeclStmt(DeclStmt *S) {
|
||||
DeclGroupRef ToDG = ImportDeclGroup(S->getDeclGroup());
|
||||
for (Decl *ToD : ToDG) {
|
||||
|
@ -4700,9 +4862,9 @@ Stmt *ASTNodeImporter::VisitNullStmt(NullStmt *S) {
|
|||
}
|
||||
|
||||
Stmt *ASTNodeImporter::VisitCompoundStmt(CompoundStmt *S) {
|
||||
llvm::ArrayRef<Stmt *> ToStmts;
|
||||
llvm::SmallVector<Stmt *, 8> ToStmts(S->size());
|
||||
|
||||
if (!ImportArray(S->body_begin(), S->body_end(), ToStmts))
|
||||
if (ImportArrayChecked(S->body_begin(), S->body_end(), ToStmts.begin()))
|
||||
return nullptr;
|
||||
|
||||
SourceLocation ToLBraceLoc = Importer.Import(S->getLBracLoc());
|
||||
|
@ -5123,6 +5285,48 @@ Expr *ASTNodeImporter::VisitExpr(Expr *E) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitVAArgExpr(VAArgExpr *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
|
||||
Expr *SubExpr = Importer.Import(E->getSubExpr());
|
||||
if (!SubExpr && E->getSubExpr())
|
||||
return nullptr;
|
||||
|
||||
TypeSourceInfo *TInfo = Importer.Import(E->getWrittenTypeInfo());
|
||||
if (!TInfo)
|
||||
return nullptr;
|
||||
|
||||
return new (Importer.getToContext()) VAArgExpr(
|
||||
Importer.Import(E->getBuiltinLoc()), SubExpr, TInfo,
|
||||
Importer.Import(E->getRParenLoc()), T, E->isMicrosoftABI());
|
||||
}
|
||||
|
||||
|
||||
Expr *ASTNodeImporter::VisitGNUNullExpr(GNUNullExpr *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
|
||||
return new (Importer.getToContext()) GNUNullExpr(
|
||||
T, Importer.Import(E->getExprLoc()));
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitPredefinedExpr(PredefinedExpr *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
|
||||
StringLiteral *SL = cast_or_null<StringLiteral>(
|
||||
Importer.Import(E->getFunctionName()));
|
||||
if (!SL && E->getFunctionName())
|
||||
return nullptr;
|
||||
|
||||
return new (Importer.getToContext()) PredefinedExpr(
|
||||
Importer.Import(E->getExprLoc()), T, E->getIdentType(), SL);
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
|
||||
ValueDecl *ToD = cast_or_null<ValueDecl>(Importer.Import(E->getDecl()));
|
||||
if (!ToD)
|
||||
|
@ -5153,6 +5357,76 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
|
|||
return DRE;
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
return NULL;
|
||||
|
||||
return new (Importer.getToContext()) ImplicitValueInitExpr(T);
|
||||
}
|
||||
|
||||
ASTNodeImporter::Designator
|
||||
ASTNodeImporter::ImportDesignator(const Designator &D) {
|
||||
if (D.isFieldDesignator()) {
|
||||
IdentifierInfo *ToFieldName = Importer.Import(D.getFieldName());
|
||||
// Caller checks for import error
|
||||
return Designator(ToFieldName, Importer.Import(D.getDotLoc()),
|
||||
Importer.Import(D.getFieldLoc()));
|
||||
}
|
||||
if (D.isArrayDesignator())
|
||||
return Designator(D.getFirstExprIndex(),
|
||||
Importer.Import(D.getLBracketLoc()),
|
||||
Importer.Import(D.getRBracketLoc()));
|
||||
|
||||
assert(D.isArrayRangeDesignator());
|
||||
return Designator(D.getFirstExprIndex(),
|
||||
Importer.Import(D.getLBracketLoc()),
|
||||
Importer.Import(D.getEllipsisLoc()),
|
||||
Importer.Import(D.getRBracketLoc()));
|
||||
}
|
||||
|
||||
|
||||
Expr *ASTNodeImporter::VisitDesignatedInitExpr(DesignatedInitExpr *DIE) {
|
||||
Expr *Init = cast_or_null<Expr>(Importer.Import(DIE->getInit()));
|
||||
if (!Init)
|
||||
return nullptr;
|
||||
|
||||
SmallVector<Expr *, 4> IndexExprs(DIE->getNumSubExprs() - 1);
|
||||
// List elements from the second, the first is Init itself
|
||||
for (unsigned I = 1, E = DIE->getNumSubExprs(); I < E; I++) {
|
||||
if (Expr *Arg = cast_or_null<Expr>(Importer.Import(DIE->getSubExpr(I))))
|
||||
IndexExprs[I - 1] = Arg;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SmallVector<Designator, 4> Designators(DIE->size());
|
||||
std::transform(DIE->designators_begin(), DIE->designators_end(),
|
||||
Designators.begin(),
|
||||
[this](const Designator &D) -> Designator {
|
||||
return ImportDesignator(D);
|
||||
});
|
||||
|
||||
for (auto I = DIE->designators_begin(), E = DIE->designators_end(); I != E;
|
||||
++I)
|
||||
if (I->isFieldDesignator() && !I->getFieldName())
|
||||
return nullptr;
|
||||
|
||||
return DesignatedInitExpr::Create(
|
||||
Importer.getToContext(), Designators.data(), Designators.size(),
|
||||
IndexExprs, Importer.Import(DIE->getEqualOrColonLoc()),
|
||||
DIE->usesGNUSyntax(), Init);
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
|
||||
return new (Importer.getToContext())
|
||||
CXXNullPtrLiteralExpr(T, Importer.Import(E->getLocation()));
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
|
@ -5163,6 +5437,16 @@ Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) {
|
|||
Importer.Import(E->getLocation()));
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitFloatingLiteral(FloatingLiteral *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
|
||||
return FloatingLiteral::Create(Importer.getToContext(),
|
||||
E->getValue(), E->isExact(), T,
|
||||
Importer.Import(E->getLocation()));
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitCharacterLiteral(CharacterLiteral *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
|
@ -5173,6 +5457,67 @@ Expr *ASTNodeImporter::VisitCharacterLiteral(CharacterLiteral *E) {
|
|||
Importer.Import(E->getLocation()));
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitStringLiteral(StringLiteral *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
|
||||
SmallVector<SourceLocation, 4> Locations(E->getNumConcatenated());
|
||||
ImportArray(E->tokloc_begin(), E->tokloc_end(), Locations.begin());
|
||||
|
||||
return StringLiteral::Create(Importer.getToContext(), E->getBytes(),
|
||||
E->getKind(), E->isPascal(), T,
|
||||
Locations.data(), Locations.size());
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
|
||||
TypeSourceInfo *TInfo = Importer.Import(E->getTypeSourceInfo());
|
||||
if (!TInfo)
|
||||
return nullptr;
|
||||
|
||||
Expr *Init = Importer.Import(E->getInitializer());
|
||||
if (!Init)
|
||||
return nullptr;
|
||||
|
||||
return new (Importer.getToContext()) CompoundLiteralExpr(
|
||||
Importer.Import(E->getLParenLoc()), TInfo, T, E->getValueKind(),
|
||||
Init, E->isFileScope());
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitAtomicExpr(AtomicExpr *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
|
||||
SmallVector<Expr *, 6> Exprs(E->getNumSubExprs());
|
||||
if (ImportArrayChecked(
|
||||
E->getSubExprs(), E->getSubExprs() + E->getNumSubExprs(),
|
||||
Exprs.begin()))
|
||||
return nullptr;
|
||||
|
||||
return new (Importer.getToContext()) AtomicExpr(
|
||||
Importer.Import(E->getBuiltinLoc()), Exprs, T, E->getOp(),
|
||||
Importer.Import(E->getRParenLoc()));
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitAddrLabelExpr(AddrLabelExpr *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
|
||||
LabelDecl *ToLabel = cast_or_null<LabelDecl>(Importer.Import(E->getLabel()));
|
||||
if (!ToLabel)
|
||||
return nullptr;
|
||||
|
||||
return new (Importer.getToContext()) AddrLabelExpr(
|
||||
Importer.Import(E->getAmpAmpLoc()), Importer.Import(E->getLabelLoc()),
|
||||
ToLabel, T);
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitParenExpr(ParenExpr *E) {
|
||||
Expr *SubExpr = Importer.Import(E->getSubExpr());
|
||||
if (!SubExpr)
|
||||
|
@ -5184,6 +5529,31 @@ Expr *ASTNodeImporter::VisitParenExpr(ParenExpr *E) {
|
|||
SubExpr);
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitParenListExpr(ParenListExpr *E) {
|
||||
SmallVector<Expr *, 4> Exprs(E->getNumExprs());
|
||||
if (ImportArrayChecked(
|
||||
E->getExprs(), E->getExprs() + E->getNumExprs(), Exprs.begin()))
|
||||
return nullptr;
|
||||
|
||||
return new (Importer.getToContext()) ParenListExpr(
|
||||
Importer.getToContext(), Importer.Import(E->getLParenLoc()),
|
||||
Exprs, Importer.Import(E->getLParenLoc()));
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitStmtExpr(StmtExpr *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
|
||||
CompoundStmt *ToSubStmt = cast_or_null<CompoundStmt>(
|
||||
Importer.Import(E->getSubStmt()));
|
||||
if (!ToSubStmt && E->getSubStmt())
|
||||
return nullptr;
|
||||
|
||||
return new (Importer.getToContext()) StmtExpr(ToSubStmt, T,
|
||||
Importer.Import(E->getLParenLoc()), Importer.Import(E->getRParenLoc()));
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
|
@ -5244,6 +5614,76 @@ Expr *ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) {
|
|||
E->isFPContractable());
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitConditionalOperator(ConditionalOperator *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
|
||||
Expr *ToLHS = Importer.Import(E->getLHS());
|
||||
if (!ToLHS)
|
||||
return nullptr;
|
||||
|
||||
Expr *ToRHS = Importer.Import(E->getRHS());
|
||||
if (!ToRHS)
|
||||
return nullptr;
|
||||
|
||||
Expr *ToCond = Importer.Import(E->getCond());
|
||||
if (!ToCond)
|
||||
return nullptr;
|
||||
|
||||
return new (Importer.getToContext()) ConditionalOperator(
|
||||
ToCond, Importer.Import(E->getQuestionLoc()),
|
||||
ToLHS, Importer.Import(E->getColonLoc()),
|
||||
ToRHS, T, E->getValueKind(), E->getObjectKind());
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitBinaryConditionalOperator(
|
||||
BinaryConditionalOperator *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
|
||||
Expr *Common = Importer.Import(E->getCommon());
|
||||
if (!Common)
|
||||
return nullptr;
|
||||
|
||||
Expr *Cond = Importer.Import(E->getCond());
|
||||
if (!Cond)
|
||||
return nullptr;
|
||||
|
||||
OpaqueValueExpr *OpaqueValue = cast_or_null<OpaqueValueExpr>(
|
||||
Importer.Import(E->getOpaqueValue()));
|
||||
if (!OpaqueValue)
|
||||
return nullptr;
|
||||
|
||||
Expr *TrueExpr = Importer.Import(E->getTrueExpr());
|
||||
if (!TrueExpr)
|
||||
return nullptr;
|
||||
|
||||
Expr *FalseExpr = Importer.Import(E->getFalseExpr());
|
||||
if (!FalseExpr)
|
||||
return nullptr;
|
||||
|
||||
return new (Importer.getToContext()) BinaryConditionalOperator(
|
||||
Common, OpaqueValue, Cond, TrueExpr, FalseExpr,
|
||||
Importer.Import(E->getQuestionLoc()), Importer.Import(E->getColonLoc()),
|
||||
T, E->getValueKind(), E->getObjectKind());
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
|
||||
Expr *SourceExpr = Importer.Import(E->getSourceExpr());
|
||||
if (!SourceExpr && E->getSourceExpr())
|
||||
return nullptr;
|
||||
|
||||
return new (Importer.getToContext()) OpaqueValueExpr(
|
||||
Importer.Import(E->getExprLoc()), T, E->getValueKind(),
|
||||
E->getObjectKind(), SourceExpr);
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
if (T.isNull())
|
||||
|
@ -5332,9 +5772,9 @@ Expr *ASTNodeImporter::VisitCXXConstructExpr(CXXConstructExpr *E) {
|
|||
if (!ToCCD && E->getConstructor())
|
||||
return nullptr;
|
||||
|
||||
ArrayRef<Expr *> ToArgs;
|
||||
|
||||
if (!ImportArray(E->arg_begin(), E->arg_end(), ToArgs))
|
||||
SmallVector<Expr *, 6> ToArgs(E->getNumArgs());
|
||||
if (ImportArrayChecked(E->getArgs(), E->getArgs() + E->getNumArgs(),
|
||||
ToArgs.begin()))
|
||||
return nullptr;
|
||||
|
||||
return CXXConstructExpr::Create(Importer.getToContext(), T,
|
||||
|
@ -5357,14 +5797,14 @@ Expr *ASTNodeImporter::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
|
|||
if (!ToFn)
|
||||
return nullptr;
|
||||
|
||||
ArrayRef<Expr *> ToArgs;
|
||||
SmallVector<Expr *, 4> ToArgs(E->getNumArgs());
|
||||
|
||||
if (!ImportArray(E->arg_begin(), E->arg_end(), ToArgs))
|
||||
if (ImportArrayChecked(E->arg_begin(), E->arg_end(), ToArgs.begin()))
|
||||
return nullptr;
|
||||
|
||||
return new (Importer.getToContext()) CXXMemberCallExpr(Importer.getToContext(), ToFn,
|
||||
ToArgs, T, E->getValueKind(),
|
||||
Importer.Import(E->getRParenLoc()));
|
||||
return new (Importer.getToContext()) CXXMemberCallExpr(
|
||||
Importer.getToContext(), ToFn, ToArgs, T, E->getValueKind(),
|
||||
Importer.Import(E->getRParenLoc()));
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitCXXThisExpr(CXXThisExpr *E) {
|
||||
|
@ -5454,26 +5894,49 @@ Expr *ASTNodeImporter::VisitCallExpr(CallExpr *E) {
|
|||
Importer.Import(E->getRParenLoc()));
|
||||
}
|
||||
|
||||
Expr *ASTNodeImporter::VisitInitListExpr(InitListExpr *E) {
|
||||
QualType T = Importer.Import(E->getType());
|
||||
Expr *ASTNodeImporter::VisitInitListExpr(InitListExpr *ILE) {
|
||||
QualType T = Importer.Import(ILE->getType());
|
||||
if (T.isNull())
|
||||
return nullptr;
|
||||
|
||||
ArrayRef<Expr *> ToInits;
|
||||
|
||||
if (!ImportArray(E->inits().begin(), E->inits().end(), ToInits))
|
||||
llvm::SmallVector<Expr *, 4> Exprs(ILE->getNumInits());
|
||||
if (ImportArrayChecked(
|
||||
ILE->getInits(), ILE->getInits() + ILE->getNumInits(), Exprs.begin()))
|
||||
return nullptr;
|
||||
|
||||
InitListExpr *ToE = new (Importer.getToContext())
|
||||
InitListExpr(Importer.getToContext(),
|
||||
Importer.Import(E->getLBraceLoc()),
|
||||
ToInits,
|
||||
Importer.Import(E->getRBraceLoc()));
|
||||
|
||||
if (ToE)
|
||||
ToE->setType(T);
|
||||
|
||||
return ToE;
|
||||
ASTContext &ToCtx = Importer.getToContext();
|
||||
InitListExpr *To = new (ToCtx) InitListExpr(
|
||||
ToCtx, Importer.Import(ILE->getLBraceLoc()),
|
||||
Exprs, Importer.Import(ILE->getLBraceLoc()));
|
||||
To->setType(T);
|
||||
|
||||
if (ILE->hasArrayFiller()) {
|
||||
Expr *Filler = Importer.Import(ILE->getArrayFiller());
|
||||
if (!Filler)
|
||||
return nullptr;
|
||||
To->setArrayFiller(Filler);
|
||||
}
|
||||
|
||||
if (FieldDecl *FromFD = ILE->getInitializedFieldInUnion()) {
|
||||
FieldDecl *ToFD = cast_or_null<FieldDecl>(Importer.Import(FromFD));
|
||||
if (!ToFD)
|
||||
return nullptr;
|
||||
To->setInitializedFieldInUnion(ToFD);
|
||||
}
|
||||
|
||||
if (InitListExpr *SyntForm = ILE->getSyntacticForm()) {
|
||||
InitListExpr *ToSyntForm = cast_or_null<InitListExpr>(
|
||||
Importer.Import(SyntForm));
|
||||
if (!ToSyntForm)
|
||||
return nullptr;
|
||||
To->setSyntacticForm(ToSyntForm);
|
||||
}
|
||||
|
||||
To->sawArrayRangeDesignator(ILE->hadArrayRangeDesignator());
|
||||
To->setValueDependent(ILE->isValueDependent());
|
||||
To->setInstantiationDependent(ILE->isInstantiationDependent());
|
||||
|
||||
return To;
|
||||
}
|
||||
|
||||
ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
|
||||
|
|
|
@ -0,0 +1,470 @@
|
|||
//===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Tests for the correct import of AST nodes from one AST context to another.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/ASTImporter.h"
|
||||
#include "MatchVerifier.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace clang {
|
||||
namespace ast_matchers {
|
||||
|
||||
using clang::tooling::newFrontendActionFactory;
|
||||
using clang::tooling::runToolOnCodeWithArgs;
|
||||
using clang::tooling::FrontendActionFactory;
|
||||
|
||||
typedef std::vector<std::string> StringVector;
|
||||
|
||||
void getLangArgs(Language Lang, StringVector &Args) {
|
||||
switch (Lang) {
|
||||
case Lang_C:
|
||||
Args.insert(Args.end(), { "-x", "c", "-std=c99" });
|
||||
break;
|
||||
case Lang_C89:
|
||||
Args.insert(Args.end(), { "-x", "c", "-std=c89" });
|
||||
break;
|
||||
case Lang_CXX:
|
||||
Args.push_back("-std=c++98");
|
||||
break;
|
||||
case Lang_CXX11:
|
||||
Args.push_back("-std=c++11");
|
||||
break;
|
||||
case Lang_OpenCL:
|
||||
case Lang_OBJCXX:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename NodeType, typename MatcherType>
|
||||
testing::AssertionResult
|
||||
testImport(const std::string &FromCode, Language FromLang,
|
||||
const std::string &ToCode, Language ToLang,
|
||||
MatchVerifier<NodeType> &Verifier,
|
||||
const MatcherType &AMatcher) {
|
||||
StringVector FromArgs, ToArgs;
|
||||
getLangArgs(FromLang, FromArgs);
|
||||
getLangArgs(ToLang, ToArgs);
|
||||
|
||||
const char *const InputFileName = "input.cc";
|
||||
const char *const OutputFileName = "output.cc";
|
||||
|
||||
std::unique_ptr<ASTUnit>
|
||||
FromAST = tooling::buildASTFromCodeWithArgs(
|
||||
FromCode, FromArgs, InputFileName),
|
||||
ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, OutputFileName);
|
||||
|
||||
ASTContext &FromCtx = FromAST->getASTContext(),
|
||||
&ToCtx = ToAST->getASTContext();
|
||||
|
||||
// Add input.cc to virtual file system so importer can 'find' it
|
||||
// while importing SourceLocations.
|
||||
vfs::OverlayFileSystem *OFS = static_cast<vfs::OverlayFileSystem *>(
|
||||
ToCtx.getSourceManager().getFileManager().getVirtualFileSystem().get());
|
||||
vfs::InMemoryFileSystem *MFS = static_cast<vfs::InMemoryFileSystem *>(
|
||||
OFS->overlays_begin()->get());
|
||||
MFS->addFile(InputFileName, 0,
|
||||
llvm::MemoryBuffer::getMemBuffer(FromCode.c_str()));
|
||||
|
||||
ASTImporter Importer(ToCtx, ToAST->getFileManager(),
|
||||
FromCtx, FromAST->getFileManager(), false);
|
||||
|
||||
IdentifierInfo *ImportedII = &FromCtx.Idents.get("declToImport");
|
||||
assert(ImportedII && "Declaration with 'declToImport' name"
|
||||
"should be specified in test!");
|
||||
DeclarationName ImportDeclName(ImportedII);
|
||||
SmallVector<NamedDecl *, 4> FoundDecls;
|
||||
FromCtx.getTranslationUnitDecl()->localUncachedLookup(
|
||||
ImportDeclName, FoundDecls);
|
||||
|
||||
if (FoundDecls.size() != 1)
|
||||
return testing::AssertionFailure() << "Multiple declarations were found!";
|
||||
|
||||
auto Imported = Importer.Import(*FoundDecls.begin());
|
||||
if (!Imported)
|
||||
return testing::AssertionFailure() << "Import failed, nullptr returned!";
|
||||
|
||||
// This should dump source locations and assert if some source locations
|
||||
// were not imported
|
||||
SmallString<1024> ImportChecker;
|
||||
llvm::raw_svector_ostream ToNothing(ImportChecker);
|
||||
ToCtx.getTranslationUnitDecl()->print(ToNothing);
|
||||
|
||||
return Verifier.match(Imported, AMatcher);
|
||||
}
|
||||
|
||||
TEST(ImportExpr, ImportStringLiteral) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
EXPECT_TRUE(testImport("void declToImport() { \"foo\"; }",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
stringLiteral(
|
||||
hasType(
|
||||
asString("const char [4]")))))))));
|
||||
EXPECT_TRUE(testImport("void declToImport() { L\"foo\"; }",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
stringLiteral(
|
||||
hasType(
|
||||
asString("const wchar_t [4]")))))))));
|
||||
EXPECT_TRUE(testImport("void declToImport() { \"foo\" \"bar\"; }",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
stringLiteral(
|
||||
hasType(
|
||||
asString("const char [7]")))))))));
|
||||
}
|
||||
|
||||
TEST(ImportExpr, ImportGNUNullExpr) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
EXPECT_TRUE(testImport("void declToImport() { __null; }",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
gnuNullExpr(
|
||||
hasType(isInteger()))))))));
|
||||
}
|
||||
|
||||
TEST(ImportExpr, ImportCXXNullPtrLiteralExpr) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
EXPECT_TRUE(testImport("void declToImport() { nullptr; }",
|
||||
Lang_CXX11, "", Lang_CXX11, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
cxxNullPtrLiteralExpr()))))));
|
||||
}
|
||||
|
||||
|
||||
TEST(ImportExpr, ImportFloatinglLiteralExpr) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
EXPECT_TRUE(testImport("void declToImport() { 1.0; }",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
floatLiteral(
|
||||
equals(1.0),
|
||||
hasType(asString("double")))))))));
|
||||
EXPECT_TRUE(testImport("void declToImport() { 1.0e-5f; }",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
floatLiteral(
|
||||
equals(1.0e-5f),
|
||||
hasType(asString("float")))))))));
|
||||
}
|
||||
|
||||
TEST(ImportExpr, ImportCompoundLiteralExpr) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
EXPECT_TRUE(
|
||||
testImport(
|
||||
"void declToImport() {"
|
||||
" struct s { int x; long y; unsigned z; }; "
|
||||
" (struct s){ 42, 0L, 1U }; }",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
compoundLiteralExpr(
|
||||
hasType(asString("struct s")),
|
||||
has(initListExpr(
|
||||
hasType(asString("struct s")),
|
||||
has(integerLiteral(
|
||||
equals(42), hasType(asString("int")))),
|
||||
has(integerLiteral(
|
||||
equals(0), hasType(asString("long")))),
|
||||
has(integerLiteral(
|
||||
equals(1),
|
||||
hasType(asString("unsigned int"))))
|
||||
)))))))));
|
||||
}
|
||||
|
||||
TEST(ImportExpr, ImportCXXThisExpr) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
EXPECT_TRUE(
|
||||
testImport("class declToImport { void f() { this; } };",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
cxxRecordDecl(
|
||||
hasMethod(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
cxxThisExpr(
|
||||
hasType(
|
||||
asString("class declToImport *"))))))))));
|
||||
}
|
||||
|
||||
TEST(ImportExpr, ImportAtomicExpr) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
EXPECT_TRUE(
|
||||
testImport(
|
||||
"void declToImport() { int *ptr; __atomic_load_n(ptr, 1); }",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
atomicExpr(
|
||||
has(declRefExpr(
|
||||
hasDeclaration(varDecl(hasName("ptr"))),
|
||||
hasType(asString("int *")))),
|
||||
has(integerLiteral(equals(1), hasType(asString("int"))))
|
||||
)))))));
|
||||
}
|
||||
|
||||
TEST(ImportExpr, ImportLabelDeclAndAddrLabelExpr) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
EXPECT_TRUE(
|
||||
testImport(
|
||||
"void declToImport() { loop: goto loop; &&loop; }",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(labelStmt(hasDeclaration(labelDecl(hasName("loop"))))),
|
||||
has(addrLabelExpr(hasDeclaration(labelDecl(hasName("loop")))))
|
||||
)))));
|
||||
}
|
||||
|
||||
AST_MATCHER_P(TemplateDecl, hasTemplateDecl,
|
||||
internal::Matcher<NamedDecl>, InnerMatcher) {
|
||||
const NamedDecl *Template = Node.getTemplatedDecl();
|
||||
return Template && InnerMatcher.matches(*Template, Finder, Builder);
|
||||
}
|
||||
|
||||
TEST(ImportExpr, ImportParenListExpr) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
EXPECT_TRUE(
|
||||
testImport(
|
||||
"template<typename T> class dummy { void f() { dummy X(*this); } };"
|
||||
"typedef dummy<int> declToImport;"
|
||||
"template class dummy<int>;",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
typedefDecl(
|
||||
hasType(
|
||||
templateSpecializationType(
|
||||
hasDeclaration(
|
||||
classTemplateDecl(
|
||||
hasTemplateDecl(
|
||||
cxxRecordDecl(
|
||||
hasMethod(
|
||||
allOf(
|
||||
hasName("f"),
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
declStmt(
|
||||
hasSingleDecl(
|
||||
varDecl(
|
||||
hasInitializer(
|
||||
parenListExpr(
|
||||
has(
|
||||
unaryOperator(
|
||||
hasOperatorName("*"),
|
||||
hasUnaryOperand(cxxThisExpr())
|
||||
)))))))))))))))))))));
|
||||
}
|
||||
|
||||
TEST(ImportExpr, ImportStmtExpr) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
// NOTE: has() ignores implicit casts, using hasDescendant() to match it
|
||||
EXPECT_TRUE(
|
||||
testImport(
|
||||
"void declToImport() { int b; int a = b ?: 1; int C = ({int X=4; X;}); }",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
declStmt(
|
||||
hasSingleDecl(
|
||||
varDecl(
|
||||
hasName("C"),
|
||||
hasType(asString("int")),
|
||||
hasInitializer(
|
||||
stmtExpr(
|
||||
hasAnySubstatement(
|
||||
declStmt(
|
||||
hasSingleDecl(
|
||||
varDecl(
|
||||
hasName("X"),
|
||||
hasType(asString("int")),
|
||||
hasInitializer(
|
||||
integerLiteral(equals(4))))))),
|
||||
hasDescendant(
|
||||
implicitCastExpr()
|
||||
))))))))))));
|
||||
}
|
||||
|
||||
TEST(ImportExpr, ImportConditionalOperator) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
EXPECT_TRUE(
|
||||
testImport(
|
||||
"void declToImport() { true ? 1 : -5; }",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
conditionalOperator(
|
||||
hasCondition(cxxBoolLiteral(equals(true))),
|
||||
hasTrueExpression(integerLiteral(equals(1))),
|
||||
hasFalseExpression(
|
||||
unaryOperator(hasUnaryOperand(integerLiteral(equals(5))))
|
||||
))))))));
|
||||
}
|
||||
|
||||
TEST(ImportExpr, ImportBinaryConditionalOperator) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
EXPECT_TRUE(
|
||||
testImport(
|
||||
"void declToImport() { 1 ?: -5; }",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
binaryConditionalOperator(
|
||||
hasCondition(
|
||||
implicitCastExpr(
|
||||
hasSourceExpression(
|
||||
opaqueValueExpr(
|
||||
hasSourceExpression(integerLiteral(equals(1))))),
|
||||
hasType(booleanType()))),
|
||||
hasTrueExpression(
|
||||
opaqueValueExpr(hasSourceExpression(
|
||||
integerLiteral(equals(1))))),
|
||||
hasFalseExpression(
|
||||
unaryOperator(hasOperatorName("-"),
|
||||
hasUnaryOperand(integerLiteral(equals(5)))))
|
||||
)))))));
|
||||
}
|
||||
|
||||
TEST(ImportExpr, ImportDesignatedInitExpr) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
EXPECT_TRUE(testImport("void declToImport() {"
|
||||
" struct point { double x; double y; };"
|
||||
" struct point ptarray[10] = "
|
||||
"{ [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; }",
|
||||
Lang_C, "", Lang_C, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
declStmt(
|
||||
hasSingleDecl(
|
||||
varDecl(
|
||||
hasInitializer(
|
||||
initListExpr(
|
||||
hasSyntacticForm(
|
||||
initListExpr(
|
||||
has(
|
||||
designatedInitExpr(
|
||||
designatorCountIs(2),
|
||||
has(floatLiteral(
|
||||
equals(1.0))),
|
||||
has(integerLiteral(
|
||||
equals(2))))),
|
||||
has(
|
||||
designatedInitExpr(
|
||||
designatorCountIs(2),
|
||||
has(floatLiteral(
|
||||
equals(2.0))),
|
||||
has(integerLiteral(
|
||||
equals(2))))),
|
||||
has(
|
||||
designatedInitExpr(
|
||||
designatorCountIs(2),
|
||||
has(floatLiteral(
|
||||
equals(1.0))),
|
||||
has(integerLiteral(
|
||||
equals(0)))))
|
||||
)))))))))))));
|
||||
}
|
||||
|
||||
|
||||
TEST(ImportExpr, ImportPredefinedExpr) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
// __func__ expands as StringLiteral("declToImport")
|
||||
EXPECT_TRUE(testImport("void declToImport() { __func__; }",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
predefinedExpr(
|
||||
hasType(
|
||||
asString("const char [13]")),
|
||||
has(
|
||||
stringLiteral(
|
||||
hasType(
|
||||
asString("const char [13]")))))))))));
|
||||
}
|
||||
|
||||
TEST(ImportExpr, ImportInitListExpr) {
|
||||
MatchVerifier<Decl> Verifier;
|
||||
EXPECT_TRUE(
|
||||
testImport(
|
||||
"void declToImport() {"
|
||||
" struct point { double x; double y; };"
|
||||
" point ptarray[10] = { [2].y = 1.0, [2].x = 2.0,"
|
||||
" [0].x = 1.0 }; }",
|
||||
Lang_CXX, "", Lang_CXX, Verifier,
|
||||
functionDecl(
|
||||
hasBody(
|
||||
compoundStmt(
|
||||
has(
|
||||
declStmt(
|
||||
hasSingleDecl(
|
||||
varDecl(
|
||||
hasInitializer(
|
||||
initListExpr(
|
||||
has(
|
||||
cxxConstructExpr(
|
||||
requiresZeroInitialization())),
|
||||
has(
|
||||
initListExpr(
|
||||
hasType(asString("struct point")),
|
||||
has(floatLiteral(equals(1.0))),
|
||||
has(implicitValueInitExpr(
|
||||
hasType(asString("double")))))),
|
||||
has(
|
||||
initListExpr(
|
||||
hasType(asString("struct point")),
|
||||
has(floatLiteral(equals(2.0))),
|
||||
has(floatLiteral(equals(1.0)))))
|
||||
)))))))))));
|
||||
}
|
||||
|
||||
|
||||
} // end namespace ast_matchers
|
||||
} // end namespace clang
|
|
@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
|
|||
|
||||
add_clang_unittest(ASTTests
|
||||
ASTContextParentMapTest.cpp
|
||||
ASTImporterTest.cpp
|
||||
ASTTypeTraitsTest.cpp
|
||||
ASTVectorTest.cpp
|
||||
CommentLexer.cpp
|
||||
|
|
Loading…
Reference in New Issue