diff options
Diffstat (limited to 'unittests/AST')
-rw-r--r-- | unittests/AST/ASTContextParentMapTest.cpp | 4 | ||||
-rw-r--r-- | unittests/AST/ASTImporterTest.cpp | 460 | ||||
-rw-r--r-- | unittests/AST/ASTTypeTraitsTest.cpp | 17 | ||||
-rw-r--r-- | unittests/AST/CMakeLists.txt | 2 | ||||
-rw-r--r-- | unittests/AST/Makefile | 19 | ||||
-rw-r--r-- | unittests/AST/MatchVerifier.h | 19 | ||||
-rw-r--r-- | unittests/AST/PostOrderASTVisitor.cpp | 123 |
7 files changed, 618 insertions, 26 deletions
diff --git a/unittests/AST/ASTContextParentMapTest.cpp b/unittests/AST/ASTContextParentMapTest.cpp index b1d7db4164ef..a39189620b69 100644 --- a/unittests/AST/ASTContextParentMapTest.cpp +++ b/unittests/AST/ASTContextParentMapTest.cpp @@ -21,10 +21,6 @@ namespace clang { namespace ast_matchers { -using clang::tooling::newFrontendActionFactory; -using clang::tooling::runToolOnCodeWithArgs; -using clang::tooling::FrontendActionFactory; - TEST(GetParents, ReturnsParentForDecl) { MatchVerifier<Decl> Verifier; EXPECT_TRUE( diff --git a/unittests/AST/ASTImporterTest.cpp b/unittests/AST/ASTImporterTest.cpp new file mode 100644 index 000000000000..3cc38fb55b2e --- /dev/null +++ b/unittests/AST/ASTImporterTest.cpp @@ -0,0 +1,460 @@ +//===- 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 { + +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(ignoringParenImpCasts( + 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 diff --git a/unittests/AST/ASTTypeTraitsTest.cpp b/unittests/AST/ASTTypeTraitsTest.cpp index b6356538a12a..436cd7751411 100644 --- a/unittests/AST/ASTTypeTraitsTest.cpp +++ b/unittests/AST/ASTTypeTraitsTest.cpp @@ -107,10 +107,21 @@ TEST(ASTNodeKind, UnknownKind) { } TEST(ASTNodeKind, Name) { - EXPECT_EQ("Decl", DNT<Decl>().asStringRef()); - EXPECT_EQ("CallExpr", DNT<CallExpr>().asStringRef()); - EXPECT_EQ("ConstantArrayType", DNT<ConstantArrayType>().asStringRef()); EXPECT_EQ("<None>", ASTNodeKind().asStringRef()); +#define VERIFY_NAME(Node) EXPECT_EQ(#Node, DNT<Node>().asStringRef()); + VERIFY_NAME(TemplateArgument); + VERIFY_NAME(NestedNameSpecifierLoc); + VERIFY_NAME(QualType); + VERIFY_NAME(TypeLoc); + VERIFY_NAME(CXXCtorInitializer); + VERIFY_NAME(NestedNameSpecifier); + VERIFY_NAME(Decl); + VERIFY_NAME(CXXRecordDecl); + VERIFY_NAME(Stmt); + VERIFY_NAME(CallExpr); + VERIFY_NAME(Type); + VERIFY_NAME(ConstantArrayType); +#undef VERIFY_NAME } TEST(DynTypedNode, DeclSourceRange) { diff --git a/unittests/AST/CMakeLists.txt b/unittests/AST/CMakeLists.txt index 2fa1078a5e1b..a7008f3e7e09 100644 --- a/unittests/AST/CMakeLists.txt +++ b/unittests/AST/CMakeLists.txt @@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS add_clang_unittest(ASTTests ASTContextParentMapTest.cpp + ASTImporterTest.cpp ASTTypeTraitsTest.cpp ASTVectorTest.cpp CommentLexer.cpp @@ -13,6 +14,7 @@ add_clang_unittest(ASTTests EvaluateAsRValueTest.cpp ExternalASTSourceTest.cpp NamedDeclPrinterTest.cpp + PostOrderASTVisitor.cpp SourceLocationTest.cpp StmtPrinterTest.cpp ) diff --git a/unittests/AST/Makefile b/unittests/AST/Makefile deleted file mode 100644 index e3b3d7dc33e8..000000000000 --- a/unittests/AST/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -##===- unittests/AST/Makefile ------------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL = ../.. -TESTNAME = AST -include $(CLANG_LEVEL)/../../Makefile.config -LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option -USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \ - clangRewrite.a clangRewriteFrontend.a \ - clangParse.a clangSema.a clangAnalysis.a \ - clangEdit.a clangAST.a clangASTMatchers.a clangLex.a clangBasic.a - -include $(CLANG_LEVEL)/unittests/Makefile diff --git a/unittests/AST/MatchVerifier.h b/unittests/AST/MatchVerifier.h index 31932479ef8d..74b9bdfbe7e6 100644 --- a/unittests/AST/MatchVerifier.h +++ b/unittests/AST/MatchVerifier.h @@ -62,6 +62,9 @@ public: std::vector<std::string>& Args, Language L); + template <typename MatcherType> + testing::AssertionResult match(const Decl *D, const MatcherType &AMatcher); + protected: void run(const MatchFinder::MatchResult &Result) override; virtual void verify(const MatchFinder::MatchResult &Result, @@ -127,6 +130,22 @@ testing::AssertionResult MatchVerifier<NodeType>::match( return testing::AssertionSuccess(); } +/// \brief Runs a matcher over some AST, and returns the result of the +/// verifier for the matched node. +template <typename NodeType> template <typename MatcherType> +testing::AssertionResult MatchVerifier<NodeType>::match( + const Decl *D, const MatcherType &AMatcher) { + MatchFinder Finder; + Finder.addMatcher(AMatcher.bind(""), this); + + setFailure("Could not find match"); + Finder.match(*D, D->getASTContext()); + + if (!Verified) + return testing::AssertionFailure() << VerifyResult; + return testing::AssertionSuccess(); +} + template <typename NodeType> void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) { const NodeType *Node = Result.Nodes.getNodeAs<NodeType>(""); diff --git a/unittests/AST/PostOrderASTVisitor.cpp b/unittests/AST/PostOrderASTVisitor.cpp new file mode 100644 index 000000000000..012f63a48ade --- /dev/null +++ b/unittests/AST/PostOrderASTVisitor.cpp @@ -0,0 +1,123 @@ +//===- unittests/AST/PostOrderASTVisitor.cpp - Declaration printer tests --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains tests for the post-order traversing functionality +// of RecursiveASTVisitor. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" + +using namespace clang; + +namespace { + + class RecordingVisitor + : public RecursiveASTVisitor<RecordingVisitor> { + + bool VisitPostOrder; + public: + explicit RecordingVisitor(bool VisitPostOrder) + : VisitPostOrder(VisitPostOrder) { + } + + // List of visited nodes during traversal. + std::vector<std::string> VisitedNodes; + + bool shouldTraversePostOrder() const { return VisitPostOrder; } + + bool VisitBinaryOperator(BinaryOperator *Op) { + VisitedNodes.push_back(Op->getOpcodeStr()); + return true; + } + + bool VisitIntegerLiteral(IntegerLiteral *Lit) { + VisitedNodes.push_back(Lit->getValue().toString(10, false)); + return true; + } + + bool VisitVarDecl(VarDecl* D) { + VisitedNodes.push_back(D->getNameAsString()); + return true; + } + + bool VisitCXXMethodDecl(CXXMethodDecl *D) { + VisitedNodes.push_back(D->getQualifiedNameAsString()); + return true; + } + + bool VisitReturnStmt(ReturnStmt *S) { + VisitedNodes.push_back("return"); + return true; + } + + bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) { + VisitedNodes.push_back(Declaration->getQualifiedNameAsString()); + return true; + } + + bool VisitTemplateTypeParmType(TemplateTypeParmType *T) { + VisitedNodes.push_back(T->getDecl()->getQualifiedNameAsString()); + return true; + } + }; + +} + +TEST(RecursiveASTVisitor, PostOrderTraversal) { + auto ASTUnit = tooling::buildASTFromCode( + "class A {" + " class B {" + " int foo() { while(4) { int i = 9; } return (1 + 3) + 2; }" + " };" + "};" + ); + auto TU = ASTUnit->getASTContext().getTranslationUnitDecl(); + // We traverse the translation unit and store all + // visited nodes. + RecordingVisitor Visitor(true); + Visitor.TraverseTranslationUnitDecl(TU); + + std::vector<std::string> expected = { + "4", "9", "i", "1", "3", "+", "2", "+", "return", "A::B::foo", "A::B", "A" + }; + // Compare the list of actually visited nodes + // with the expected list of visited nodes. + ASSERT_EQ(expected.size(), Visitor.VisitedNodes.size()); + for (std::size_t I = 0; I < expected.size(); I++) { + ASSERT_EQ(expected[I], Visitor.VisitedNodes[I]); + } +} + +TEST(RecursiveASTVisitor, NoPostOrderTraversal) { + auto ASTUnit = tooling::buildASTFromCode( + "class A {" + " class B {" + " int foo() { return 1 + 2; }" + " };" + "};" + ); + auto TU = ASTUnit->getASTContext().getTranslationUnitDecl(); + // We traverse the translation unit and store all + // visited nodes. + RecordingVisitor Visitor(false); + Visitor.TraverseTranslationUnitDecl(TU); + + std::vector<std::string> expected = { + "A", "A::B", "A::B::foo", "return", "+", "1", "2" + }; + // Compare the list of actually visited nodes + // with the expected list of visited nodes. + ASSERT_EQ(expected.size(), Visitor.VisitedNodes.size()); + for (std::size_t I = 0; I < expected.size(); I++) { + ASSERT_EQ(expected[I], Visitor.VisitedNodes[I]); + } +} |