[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:
Artem Dergachev 2016-04-14 11:51:27 +00:00
parent 909d080d98
commit 4e7c6fdeeb
4 changed files with 997 additions and 61 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_unittest(ASTTests
ASTContextParentMapTest.cpp
ASTImporterTest.cpp
ASTTypeTraitsTest.cpp
ASTVectorTest.cpp
CommentLexer.cpp