Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,82 @@
//===- unittest/AST/ASTContextParentMapTest.cpp - AST parent map 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 getParents(...) methods of ASTContext.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.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 {
TEST(GetParents, ReturnsParentForDecl) {
MatchVerifier<Decl> Verifier;
EXPECT_TRUE(
Verifier.match("class C { void f(); };",
cxxMethodDecl(hasParent(recordDecl(hasName("C"))))));
}
TEST(GetParents, ReturnsParentForStmt) {
MatchVerifier<Stmt> Verifier;
EXPECT_TRUE(Verifier.match("class C { void f() { if (true) {} } };",
ifStmt(hasParent(compoundStmt()))));
}
TEST(GetParents, ReturnsParentForTypeLoc) {
MatchVerifier<TypeLoc> Verifier;
EXPECT_TRUE(
Verifier.match("namespace a { class b {}; } void f(a::b) {}",
typeLoc(hasParent(typeLoc(hasParent(functionDecl()))))));
}
TEST(GetParents, ReturnsParentForNestedNameSpecifierLoc) {
MatchVerifier<NestedNameSpecifierLoc> Verifier;
EXPECT_TRUE(Verifier.match("namespace a { class b {}; } void f(a::b) {}",
nestedNameSpecifierLoc(hasParent(typeLoc()))));
}
TEST(GetParents, ReturnsParentInsideTemplateInstantiations) {
MatchVerifier<Decl> DeclVerifier;
EXPECT_TRUE(DeclVerifier.match(
"template<typename T> struct C { void f() {} };"
"void g() { C<int> c; c.f(); }",
cxxMethodDecl(hasName("f"),
hasParent(cxxRecordDecl(isTemplateInstantiation())))));
EXPECT_TRUE(DeclVerifier.match(
"template<typename T> struct C { void f() {} };"
"void g() { C<int> c; c.f(); }",
cxxMethodDecl(hasName("f"),
hasParent(cxxRecordDecl(unless(isTemplateInstantiation()))))));
EXPECT_FALSE(DeclVerifier.match(
"template<typename T> struct C { void f() {} };"
"void g() { C<int> c; c.f(); }",
cxxMethodDecl(
hasName("f"),
allOf(hasParent(cxxRecordDecl(unless(isTemplateInstantiation()))),
hasParent(cxxRecordDecl(isTemplateInstantiation()))))));
}
TEST(GetParents, ReturnsMultipleParentsInTemplateInstantiations) {
MatchVerifier<Stmt> TemplateVerifier;
EXPECT_TRUE(TemplateVerifier.match(
"template<typename T> struct C { void f() {} };"
"void g() { C<int> c; c.f(); }",
compoundStmt(allOf(
hasAncestor(cxxRecordDecl(isTemplateInstantiation())),
hasAncestor(cxxRecordDecl(unless(isTemplateInstantiation())))))));
}
} // end namespace ast_matchers
} // end namespace clang

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,184 @@
//===- unittest/AST/ASTTypeTraits.cpp - AST type traits unit tests ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===--------------------------------------------------------------------===//
#include "clang/AST/ASTTypeTraits.h"
#include "MatchVerifier.h"
#include "gtest/gtest.h"
using namespace clang::ast_matchers;
namespace clang {
namespace ast_type_traits {
TEST(ASTNodeKind, NoKind) {
EXPECT_FALSE(ASTNodeKind().isBaseOf(ASTNodeKind()));
EXPECT_FALSE(ASTNodeKind().isSame(ASTNodeKind()));
}
template <typename T> static ASTNodeKind DNT() {
return ASTNodeKind::getFromNodeKind<T>();
}
TEST(ASTNodeKind, IsNone) {
EXPECT_TRUE(ASTNodeKind().isNone());
EXPECT_FALSE(DNT<Decl>().isNone());
EXPECT_FALSE(DNT<VarDecl>().isNone());
}
TEST(ASTNodeKind, Bases) {
EXPECT_TRUE(DNT<Decl>().isBaseOf(DNT<VarDecl>()));
EXPECT_FALSE(DNT<Decl>().isSame(DNT<VarDecl>()));
EXPECT_FALSE(DNT<VarDecl>().isBaseOf(DNT<Decl>()));
EXPECT_TRUE(DNT<Decl>().isSame(DNT<Decl>()));
}
TEST(ASTNodeKind, BaseDistances) {
unsigned Distance = 1;
EXPECT_TRUE(DNT<Expr>().isBaseOf(DNT<Expr>(), &Distance));
EXPECT_EQ(0u, Distance);
EXPECT_TRUE(DNT<Stmt>().isBaseOf(DNT<IfStmt>(), &Distance));
EXPECT_EQ(1u, Distance);
Distance = 3;
EXPECT_TRUE(DNT<DeclaratorDecl>().isBaseOf(DNT<ParmVarDecl>(), &Distance));
EXPECT_EQ(2u, Distance);
}
TEST(ASTNodeKind, SameBase) {
EXPECT_TRUE(DNT<Expr>().isBaseOf(DNT<CallExpr>()));
EXPECT_TRUE(DNT<Expr>().isBaseOf(DNT<BinaryOperator>()));
EXPECT_FALSE(DNT<CallExpr>().isBaseOf(DNT<BinaryOperator>()));
EXPECT_FALSE(DNT<BinaryOperator>().isBaseOf(DNT<CallExpr>()));
}
TEST(ASTNodeKind, DiffBase) {
EXPECT_FALSE(DNT<Expr>().isBaseOf(DNT<ArrayType>()));
EXPECT_FALSE(DNT<QualType>().isBaseOf(DNT<FunctionDecl>()));
EXPECT_FALSE(DNT<Type>().isSame(DNT<QualType>()));
}
TEST(ASTNodeKind, MostDerivedType) {
EXPECT_TRUE(DNT<BinaryOperator>().isSame(
ASTNodeKind::getMostDerivedType(DNT<Expr>(), DNT<BinaryOperator>())));
EXPECT_TRUE(DNT<BinaryOperator>().isSame(
ASTNodeKind::getMostDerivedType(DNT<BinaryOperator>(), DNT<Expr>())));
EXPECT_TRUE(DNT<VarDecl>().isSame(
ASTNodeKind::getMostDerivedType(DNT<VarDecl>(), DNT<VarDecl>())));
// Not related. Returns nothing.
EXPECT_TRUE(
ASTNodeKind::getMostDerivedType(DNT<IfStmt>(), DNT<VarDecl>()).isNone());
EXPECT_TRUE(ASTNodeKind::getMostDerivedType(DNT<IfStmt>(),
DNT<BinaryOperator>()).isNone());
}
TEST(ASTNodeKind, MostDerivedCommonAncestor) {
EXPECT_TRUE(DNT<Expr>().isSame(ASTNodeKind::getMostDerivedCommonAncestor(
DNT<Expr>(), DNT<BinaryOperator>())));
EXPECT_TRUE(DNT<Expr>().isSame(ASTNodeKind::getMostDerivedCommonAncestor(
DNT<BinaryOperator>(), DNT<Expr>())));
EXPECT_TRUE(DNT<VarDecl>().isSame(ASTNodeKind::getMostDerivedCommonAncestor(
DNT<VarDecl>(), DNT<VarDecl>())));
// A little related. Returns the ancestor.
EXPECT_TRUE(
DNT<NamedDecl>().isSame(ASTNodeKind::getMostDerivedCommonAncestor(
DNT<CXXMethodDecl>(), DNT<RecordDecl>())));
// Not related. Returns nothing.
EXPECT_TRUE(ASTNodeKind::getMostDerivedCommonAncestor(
DNT<IfStmt>(), DNT<VarDecl>()).isNone());
}
struct Foo {};
TEST(ASTNodeKind, UnknownKind) {
// We can construct one, but it is nowhere in the hierarchy.
EXPECT_FALSE(DNT<Foo>().isSame(DNT<Foo>()));
}
TEST(ASTNodeKind, Name) {
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) {
RangeVerifier<DynTypedNode> Verifier;
Verifier.expectRange(1, 1, 1, 11);
EXPECT_TRUE(Verifier.match("void f() {}", decl()));
}
TEST(DynTypedNode, StmtSourceRange) {
RangeVerifier<DynTypedNode> Verifier;
Verifier.expectRange(1, 10, 1, 11);
EXPECT_TRUE(Verifier.match("void f() {}", stmt()));
}
TEST(DynTypedNode, TypeLocSourceRange) {
RangeVerifier<DynTypedNode> Verifier;
Verifier.expectRange(1, 1, 1, 8);
EXPECT_TRUE(Verifier.match("void f() {}", typeLoc(loc(functionType()))));
}
TEST(DynTypedNode, NNSLocSourceRange) {
RangeVerifier<DynTypedNode> Verifier;
Verifier.expectRange(1, 33, 1, 34);
EXPECT_TRUE(Verifier.match("namespace N { typedef void T; } N::T f() {}",
nestedNameSpecifierLoc()));
}
TEST(DynTypedNode, DeclDump) {
DumpVerifier Verifier;
Verifier.expectSubstring("FunctionDecl");
EXPECT_TRUE(Verifier.match("void f() {}", functionDecl()));
}
TEST(DynTypedNode, StmtDump) {
DumpVerifier Verifier;
Verifier.expectSubstring("CompoundStmt");
EXPECT_TRUE(Verifier.match("void f() {}", stmt()));
}
TEST(DynTypedNode, DeclPrint) {
PrintVerifier Verifier;
Verifier.expectString("void f() {\n}\n");
EXPECT_TRUE(Verifier.match("void f() {}", functionDecl()));
}
TEST(DynTypedNode, StmtPrint) {
PrintVerifier Verifier;
Verifier.expectString("{\n}\n");
EXPECT_TRUE(Verifier.match("void f() {}", stmt()));
}
TEST(DynTypedNode, QualType) {
QualType Q;
DynTypedNode Node = DynTypedNode::create(Q);
EXPECT_TRUE(Node == Node);
EXPECT_FALSE(Node < Node);
}
} // namespace ast_type_traits
} // namespace clang

View File

@@ -0,0 +1,91 @@
//===- unittests/AST/DeclTest.cpp --- Declaration tests -------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Unit tests for the ASTVector container.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTVector.h"
#include "clang/Basic/Builtins.h"
#include "gtest/gtest.h"
using namespace clang;
namespace clang {
namespace ast {
namespace {
class ASTVectorTest : public ::testing::Test {
protected:
ASTVectorTest()
: FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
SourceMgr(Diags, FileMgr), Idents(LangOpts, nullptr),
Ctxt(LangOpts, SourceMgr, Idents, Sels, Builtins) {}
FileSystemOptions FileMgrOpts;
FileManager FileMgr;
IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
DiagnosticsEngine Diags;
SourceManager SourceMgr;
LangOptions LangOpts;
IdentifierTable Idents;
SelectorTable Sels;
Builtin::Context Builtins;
ASTContext Ctxt;
};
} // unnamed namespace
TEST_F(ASTVectorTest, Compile) {
ASTVector<int> V;
V.insert(Ctxt, V.begin(), 0);
}
TEST_F(ASTVectorTest, InsertFill) {
ASTVector<double> V;
// Ensure returned iterator points to first of inserted elements
auto I = V.insert(Ctxt, V.begin(), 5, 1.0);
ASSERT_EQ(V.begin(), I);
// Check non-empty case as well
I = V.insert(Ctxt, V.begin() + 1, 5, 1.0);
ASSERT_EQ(V.begin() + 1, I);
// And insert-at-end
I = V.insert(Ctxt, V.end(), 5, 1.0);
ASSERT_EQ(V.end() - 5, I);
}
TEST_F(ASTVectorTest, InsertEmpty) {
ASTVector<double> V;
// Ensure no pointer overflow when inserting empty range
int Values[] = { 0, 1, 2, 3 };
ArrayRef<int> IntVec(Values);
auto I = V.insert(Ctxt, V.begin(), IntVec.begin(), IntVec.begin());
ASSERT_EQ(V.begin(), I);
ASSERT_TRUE(V.empty());
// Non-empty range
I = V.insert(Ctxt, V.begin(), IntVec.begin(), IntVec.end());
ASSERT_EQ(V.begin(), I);
// Non-Empty Vector, empty range
I = V.insert(Ctxt, V.end(), IntVec.begin(), IntVec.begin());
ASSERT_EQ(V.begin() + IntVec.size(), I);
// Non-Empty Vector, non-empty range
I = V.insert(Ctxt, V.end(), IntVec.begin(), IntVec.end());
ASSERT_EQ(V.begin() + IntVec.size(), I);
}
} // end namespace ast
} // end namespace clang

View File

@@ -0,0 +1,30 @@
set(LLVM_LINK_COMPONENTS
Support
)
add_clang_unittest(ASTTests
ASTContextParentMapTest.cpp
ASTImporterTest.cpp
ASTTypeTraitsTest.cpp
ASTVectorTest.cpp
CommentLexer.cpp
CommentParser.cpp
DataCollectionTest.cpp
DeclPrinterTest.cpp
DeclTest.cpp
EvaluateAsRValueTest.cpp
ExternalASTSourceTest.cpp
NamedDeclPrinterTest.cpp
PostOrderASTVisitor.cpp
SourceLocationTest.cpp
StmtPrinterTest.cpp
)
target_link_libraries(ASTTests
PRIVATE
clangAST
clangASTMatchers
clangBasic
clangFrontend
clangTooling
)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,173 @@
//===- unittests/AST/DataCollectionTest.cpp -------------------------------===//
//
// 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 DataCollection module.
//
// They work by hashing the collected data of two nodes and asserting that the
// hash values are equal iff the nodes are considered equal.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/DataCollection.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
using namespace clang;
using namespace tooling;
using namespace ast_matchers;
namespace {
class StmtDataCollector : public ConstStmtVisitor<StmtDataCollector> {
ASTContext &Context;
llvm::MD5 &DataConsumer;
template <class T> void addData(const T &Data) {
data_collection::addDataToConsumer(DataConsumer, Data);
}
public:
StmtDataCollector(const Stmt *S, ASTContext &Context, llvm::MD5 &DataConsumer)
: Context(Context), DataConsumer(DataConsumer) {
this->Visit(S);
}
#define DEF_ADD_DATA(CLASS, CODE) \
template <class Dummy = void> Dummy Visit##CLASS(const CLASS *S) { \
CODE; \
ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S); \
}
#include "clang/AST/StmtDataCollectors.inc"
};
} // end anonymous namespace
namespace {
struct StmtHashMatch : public MatchFinder::MatchCallback {
unsigned NumFound;
llvm::MD5::MD5Result &Hash;
StmtHashMatch(llvm::MD5::MD5Result &Hash) : NumFound(0), Hash(Hash) {}
void run(const MatchFinder::MatchResult &Result) override {
const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id");
if (!S)
return;
++NumFound;
if (NumFound > 1)
return;
llvm::MD5 MD5;
StmtDataCollector(S, *Result.Context, MD5);
MD5.final(Hash);
}
};
} // end anonymous namespace
static testing::AssertionResult hashStmt(llvm::MD5::MD5Result &Hash,
const StatementMatcher &StmtMatch,
StringRef Code) {
StmtHashMatch Hasher(Hash);
MatchFinder Finder;
Finder.addMatcher(StmtMatch, &Hasher);
std::unique_ptr<FrontendActionFactory> Factory(
newFrontendActionFactory(&Finder));
if (!runToolOnCode(Factory->create(), Code))
return testing::AssertionFailure()
<< "Parsing error in \"" << Code.str() << "\"";
if (Hasher.NumFound == 0)
return testing::AssertionFailure() << "Matcher didn't find any statements";
if (Hasher.NumFound > 1)
return testing::AssertionFailure()
<< "Matcher should match only one statement "
"(found "
<< Hasher.NumFound << ")";
return testing::AssertionSuccess();
}
static testing::AssertionResult
isStmtHashEqual(const StatementMatcher &StmtMatch, StringRef Code1,
StringRef Code2) {
llvm::MD5::MD5Result Hash1, Hash2;
testing::AssertionResult Result = hashStmt(Hash1, StmtMatch, Code1);
if (!Result)
return Result;
if (!(Result = hashStmt(Hash2, StmtMatch, Code2)))
return Result;
return testing::AssertionResult(Hash1 == Hash2);
}
TEST(StmtDataCollector, TestDeclRefExpr) {
ASSERT_TRUE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
"int x, r = x;"));
ASSERT_FALSE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
"int y, r = y;"));
ASSERT_FALSE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
"namespace n { int x, r = x; };"));
}
TEST(StmtDataCollector, TestMemberExpr) {
ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
"struct { int x; } X; int r = X.x;",
"struct { int x; } X; int r = (&X)->x;"));
ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
"struct { int x; } X; int r = X.x;",
"struct { int x; } Y; int r = Y.x;"));
ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
"struct { int x; } X; int r = X.x;",
"struct C { int x; } X; int r = X.C::x;"));
ASSERT_FALSE(isStmtHashEqual(memberExpr().bind("id"),
"struct { int x; } X; int r = X.x;",
"struct { int y; } X; int r = X.y;"));
}
TEST(StmtDataCollector, TestIntegerLiteral) {
ASSERT_TRUE(
isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x = 0;"));
ASSERT_TRUE(
isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x =00;"));
ASSERT_FALSE(
isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x = 1;"));
}
TEST(StmtDataCollector, TestFloatingLiteral) {
ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .0;",
"double x = .0;"));
ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .10;",
"double x = .1;"));
ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .1;",
"double x = 1e-1;"));
ASSERT_FALSE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .0;",
"double x = .1;"));
}
TEST(StmtDataCollector, TestStringLiteral) {
ASSERT_TRUE(isStmtHashEqual(stringLiteral().bind("id"), R"(char x[] = "0";)",
R"(char x[] = "0";)"));
ASSERT_FALSE(isStmtHashEqual(stringLiteral().bind("id"), R"(char x[] = "0";)",
R"(char x[] = "1";)"));
}
TEST(StmtDataCollector, TestCXXBoolLiteral) {
ASSERT_TRUE(isStmtHashEqual(cxxBoolLiteral().bind("id"), "bool x = false;",
"bool x = false;"));
ASSERT_FALSE(isStmtHashEqual(cxxBoolLiteral().bind("id"), "bool x = false;",
"bool x = true;"));
}
TEST(StmtDataCollector, TestCharacterLiteral) {
ASSERT_TRUE(isStmtHashEqual(characterLiteral().bind("id"), "char x = '0';",
"char x = '0';"));
ASSERT_TRUE(isStmtHashEqual(characterLiteral().bind("id"),
R"(char x = '\0';)",
R"(char x = '\x00';)"));
ASSERT_FALSE(isStmtHashEqual(characterLiteral().bind("id"), "char x = '0';",
"char x = '1';"));
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
//===- unittests/AST/DeclTest.cpp --- Declaration tests -------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Unit tests for Decl nodes in the AST.
//
//===----------------------------------------------------------------------===//
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
using namespace clang::ast_matchers;
using namespace clang::tooling;
TEST(Decl, CleansUpAPValues) {
MatchFinder Finder;
std::unique_ptr<FrontendActionFactory> Factory(
newFrontendActionFactory(&Finder));
// This is a regression test for a memory leak in APValues for structs that
// allocate memory. This test only fails if run under valgrind with full leak
// checking enabled.
std::vector<std::string> Args(1, "-std=c++11");
Args.push_back("-fno-ms-extensions");
ASSERT_TRUE(runToolOnCodeWithArgs(
Factory->create(),
"struct X { int a; }; constexpr X x = { 42 };"
"union Y { constexpr Y(int a) : a(a) {} int a; }; constexpr Y y = { 42 };"
"constexpr int z[2] = { 42, 43 };"
"constexpr int __attribute__((vector_size(16))) v1 = {};"
"\n#ifdef __SIZEOF_INT128__\n"
"constexpr __uint128_t large_int = 0xffffffffffffffff;"
"constexpr __uint128_t small_int = 1;"
"\n#endif\n"
"constexpr double d1 = 42.42;"
"constexpr long double d2 = 42.42;"
"constexpr _Complex long double c1 = 42.0i;"
"constexpr _Complex long double c2 = 42.0;"
"template<int N> struct A : A<N-1> {};"
"template<> struct A<0> { int n; }; A<50> a;"
"constexpr int &r = a.n;"
"constexpr int A<50>::*p = &A<50>::n;"
"void f() { foo: bar: constexpr int k = __builtin_constant_p(0) ?"
" (char*)&&foo - (char*)&&bar : 0; }",
Args));
// FIXME: Once this test starts breaking we can test APValue::needsCleanup
// for ComplexInt.
ASSERT_FALSE(runToolOnCodeWithArgs(
Factory->create(),
"constexpr _Complex __uint128_t c = 0xffffffffffffffff;",
Args));
}

View File

@@ -0,0 +1,111 @@
//===- unittests/AST/EvaluateAsRValueTest.cpp -----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// \file
// \brief Unit tests for evaluation of constant initializers.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
#include <map>
#include <string>
using namespace clang::tooling;
namespace {
// For each variable name encountered, whether its initializer was a
// constant.
typedef std::map<std::string, bool> VarInfoMap;
/// \brief Records information on variable initializers to a map.
class EvaluateConstantInitializersVisitor
: public clang::RecursiveASTVisitor<EvaluateConstantInitializersVisitor> {
public:
explicit EvaluateConstantInitializersVisitor(VarInfoMap &VarInfo)
: VarInfo(VarInfo) {}
/// \brief Checks that isConstantInitializer and EvaluateAsRValue agree
/// and don't crash.
///
/// For each VarDecl with an initializer this also records in VarInfo
/// whether the initializer could be evaluated as a constant.
bool VisitVarDecl(const clang::VarDecl *VD) {
if (const clang::Expr *Init = VD->getInit()) {
clang::Expr::EvalResult Result;
bool WasEvaluated = Init->EvaluateAsRValue(Result, VD->getASTContext());
VarInfo[VD->getNameAsString()] = WasEvaluated;
EXPECT_EQ(WasEvaluated, Init->isConstantInitializer(VD->getASTContext(),
false /*ForRef*/));
}
return true;
}
private:
VarInfoMap &VarInfo;
};
class EvaluateConstantInitializersAction : public clang::ASTFrontendAction {
public:
std::unique_ptr<clang::ASTConsumer>
CreateASTConsumer(clang::CompilerInstance &Compiler,
llvm::StringRef FilePath) override {
return llvm::make_unique<Consumer>();
}
private:
class Consumer : public clang::ASTConsumer {
public:
~Consumer() override {}
void HandleTranslationUnit(clang::ASTContext &Ctx) override {
VarInfoMap VarInfo;
EvaluateConstantInitializersVisitor Evaluator(VarInfo);
Evaluator.TraverseDecl(Ctx.getTranslationUnitDecl());
EXPECT_EQ(2u, VarInfo.size());
EXPECT_FALSE(VarInfo["Dependent"]);
EXPECT_TRUE(VarInfo["Constant"]);
EXPECT_EQ(2u, VarInfo.size());
}
};
};
}
TEST(EvaluateAsRValue, FailsGracefullyForUnknownTypes) {
// This is a regression test; the AST library used to trigger assertion
// failures because it assumed that the type of initializers was always
// known (which is true only after template instantiation).
std::string ModesToTest[] = {"-std=c++03", "-std=c++11", "-std=c++1y"};
for (std::string const &Mode : ModesToTest) {
std::vector<std::string> Args(1, Mode);
Args.push_back("-fno-delayed-template-parsing");
ASSERT_TRUE(runToolOnCodeWithArgs(
new EvaluateConstantInitializersAction(),
"template <typename T>"
"struct vector {"
" explicit vector(int size);"
"};"
"template <typename R>"
"struct S {"
" vector<R> intervals() const {"
" vector<R> Dependent(2);"
" return Dependent;"
" }"
"};"
"void doSomething() {"
" int Constant = 2 + 2;"
" (void) Constant;"
"}",
Args));
}
}

View File

@@ -0,0 +1,84 @@
//===- unittest/AST/ExternalASTSourceTest.cpp -----------------------------===//
//
// 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 Clang's ExternalASTSource.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "gtest/gtest.h"
using namespace clang;
using namespace llvm;
class TestFrontendAction : public ASTFrontendAction {
public:
TestFrontendAction(ExternalASTSource *Source) : Source(Source) {}
private:
void ExecuteAction() override {
getCompilerInstance().getASTContext().setExternalSource(Source);
getCompilerInstance().getASTContext().getTranslationUnitDecl()
->setHasExternalVisibleStorage();
return ASTFrontendAction::ExecuteAction();
}
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override {
return llvm::make_unique<ASTConsumer>();
}
IntrusiveRefCntPtr<ExternalASTSource> Source;
};
bool testExternalASTSource(ExternalASTSource *Source,
StringRef FileContents) {
CompilerInstance Compiler;
Compiler.createDiagnostics();
auto Invocation = std::make_shared<CompilerInvocation>();
Invocation->getPreprocessorOpts().addRemappedFile(
"test.cc", MemoryBuffer::getMemBuffer(FileContents).release());
const char *Args[] = { "test.cc" };
CompilerInvocation::CreateFromArgs(*Invocation, Args,
Args + array_lengthof(Args),
Compiler.getDiagnostics());
Compiler.setInvocation(std::move(Invocation));
TestFrontendAction Action(Source);
return Compiler.ExecuteAction(Action);
}
// Ensure that a failed name lookup into an external source only occurs once.
TEST(ExternalASTSourceTest, FailedLookupOccursOnce) {
struct TestSource : ExternalASTSource {
TestSource(unsigned &Calls) : Calls(Calls) {}
bool FindExternalVisibleDeclsByName(const DeclContext *,
DeclarationName Name) override {
if (Name.getAsString() == "j")
++Calls;
return false;
}
unsigned &Calls;
};
unsigned Calls = 0;
ASSERT_TRUE(testExternalASTSource(new TestSource(Calls), "int j, k = j;"));
EXPECT_EQ(1u, Calls);
}

View File

@@ -0,0 +1,316 @@
//===- unittest/AST/MatchVerifier.h - AST unit test support ---------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Provides MatchVerifier, a base class to implement gtest matchers that
// verify things that can be matched on the AST.
//
// Also implements matchers based on MatchVerifier:
// LocationVerifier and RangeVerifier to verify whether a matched node has
// the expected source location or source range.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_UNITTESTS_AST_MATCHVERIFIER_H
#define LLVM_CLANG_UNITTESTS_AST_MATCHVERIFIER_H
#include "clang/AST/ASTContext.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 {
enum Language {
Lang_C,
Lang_C89,
Lang_CXX,
Lang_CXX11,
Lang_OpenCL,
Lang_OBJCXX
};
/// \brief Base class for verifying some property of nodes found by a matcher.
template <typename NodeType>
class MatchVerifier : public MatchFinder::MatchCallback {
public:
template <typename MatcherType>
testing::AssertionResult match(const std::string &Code,
const MatcherType &AMatcher) {
std::vector<std::string> Args;
return match(Code, AMatcher, Args, Lang_CXX);
}
template <typename MatcherType>
testing::AssertionResult match(const std::string &Code,
const MatcherType &AMatcher,
Language L) {
std::vector<std::string> Args;
return match(Code, AMatcher, Args, L);
}
template <typename MatcherType>
testing::AssertionResult match(const std::string &Code,
const MatcherType &AMatcher,
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,
const NodeType &Node) {}
void setFailure(const Twine &Result) {
Verified = false;
VerifyResult = Result.str();
}
void setSuccess() {
Verified = true;
}
private:
bool Verified;
std::string VerifyResult;
};
/// \brief Runs a matcher over some code, and returns the result of the
/// verifier for the matched node.
template <typename NodeType> template <typename MatcherType>
testing::AssertionResult MatchVerifier<NodeType>::match(
const std::string &Code, const MatcherType &AMatcher,
std::vector<std::string>& Args, Language L) {
MatchFinder Finder;
Finder.addMatcher(AMatcher.bind(""), this);
std::unique_ptr<tooling::FrontendActionFactory> Factory(
tooling::newFrontendActionFactory(&Finder));
StringRef FileName;
switch (L) {
case Lang_C:
Args.push_back("-std=c99");
FileName = "input.c";
break;
case Lang_C89:
Args.push_back("-std=c89");
FileName = "input.c";
break;
case Lang_CXX:
Args.push_back("-std=c++98");
FileName = "input.cc";
break;
case Lang_CXX11:
Args.push_back("-std=c++11");
FileName = "input.cc";
break;
case Lang_OpenCL:
FileName = "input.cl";
break;
case Lang_OBJCXX:
FileName = "input.mm";
break;
}
// Default to failure in case callback is never called
setFailure("Could not find match");
if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
return testing::AssertionFailure() << "Parsing error";
if (!Verified)
return testing::AssertionFailure() << VerifyResult;
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>("");
if (!Node) {
setFailure("Matched node has wrong type");
} else {
// Callback has been called, default to success.
setSuccess();
verify(Result, *Node);
}
}
template <>
inline void MatchVerifier<ast_type_traits::DynTypedNode>::run(
const MatchFinder::MatchResult &Result) {
BoundNodes::IDToNodeMap M = Result.Nodes.getMap();
BoundNodes::IDToNodeMap::const_iterator I = M.find("");
if (I == M.end()) {
setFailure("Node was not bound");
} else {
// Callback has been called, default to success.
setSuccess();
verify(Result, I->second);
}
}
/// \brief Verify whether a node has the correct source location.
///
/// By default, Node.getSourceLocation() is checked. This can be changed
/// by overriding getLocation().
template <typename NodeType>
class LocationVerifier : public MatchVerifier<NodeType> {
public:
void expectLocation(unsigned Line, unsigned Column) {
ExpectLine = Line;
ExpectColumn = Column;
}
protected:
void verify(const MatchFinder::MatchResult &Result,
const NodeType &Node) override {
SourceLocation Loc = getLocation(Node);
unsigned Line = Result.SourceManager->getSpellingLineNumber(Loc);
unsigned Column = Result.SourceManager->getSpellingColumnNumber(Loc);
if (Line != ExpectLine || Column != ExpectColumn) {
std::string MsgStr;
llvm::raw_string_ostream Msg(MsgStr);
Msg << "Expected location <" << ExpectLine << ":" << ExpectColumn
<< ">, found <";
Loc.print(Msg, *Result.SourceManager);
Msg << '>';
this->setFailure(Msg.str());
}
}
virtual SourceLocation getLocation(const NodeType &Node) {
return Node.getLocation();
}
private:
unsigned ExpectLine, ExpectColumn;
};
/// \brief Verify whether a node has the correct source range.
///
/// By default, Node.getSourceRange() is checked. This can be changed
/// by overriding getRange().
template <typename NodeType>
class RangeVerifier : public MatchVerifier<NodeType> {
public:
void expectRange(unsigned BeginLine, unsigned BeginColumn,
unsigned EndLine, unsigned EndColumn) {
ExpectBeginLine = BeginLine;
ExpectBeginColumn = BeginColumn;
ExpectEndLine = EndLine;
ExpectEndColumn = EndColumn;
}
protected:
void verify(const MatchFinder::MatchResult &Result,
const NodeType &Node) override {
SourceRange R = getRange(Node);
SourceLocation Begin = R.getBegin();
SourceLocation End = R.getEnd();
unsigned BeginLine = Result.SourceManager->getSpellingLineNumber(Begin);
unsigned BeginColumn = Result.SourceManager->getSpellingColumnNumber(Begin);
unsigned EndLine = Result.SourceManager->getSpellingLineNumber(End);
unsigned EndColumn = Result.SourceManager->getSpellingColumnNumber(End);
if (BeginLine != ExpectBeginLine || BeginColumn != ExpectBeginColumn ||
EndLine != ExpectEndLine || EndColumn != ExpectEndColumn) {
std::string MsgStr;
llvm::raw_string_ostream Msg(MsgStr);
Msg << "Expected range <" << ExpectBeginLine << ":" << ExpectBeginColumn
<< '-' << ExpectEndLine << ":" << ExpectEndColumn << ">, found <";
Begin.print(Msg, *Result.SourceManager);
Msg << '-';
End.print(Msg, *Result.SourceManager);
Msg << '>';
this->setFailure(Msg.str());
}
}
virtual SourceRange getRange(const NodeType &Node) {
return Node.getSourceRange();
}
private:
unsigned ExpectBeginLine, ExpectBeginColumn, ExpectEndLine, ExpectEndColumn;
};
/// \brief Verify whether a node's dump contains a given substring.
class DumpVerifier : public MatchVerifier<ast_type_traits::DynTypedNode> {
public:
void expectSubstring(const std::string &Str) {
ExpectSubstring = Str;
}
protected:
void verify(const MatchFinder::MatchResult &Result,
const ast_type_traits::DynTypedNode &Node) override {
std::string DumpStr;
llvm::raw_string_ostream Dump(DumpStr);
Node.dump(Dump, *Result.SourceManager);
if (Dump.str().find(ExpectSubstring) == std::string::npos) {
std::string MsgStr;
llvm::raw_string_ostream Msg(MsgStr);
Msg << "Expected dump substring <" << ExpectSubstring << ">, found <"
<< Dump.str() << '>';
this->setFailure(Msg.str());
}
}
private:
std::string ExpectSubstring;
};
/// \brief Verify whether a node's pretty print matches a given string.
class PrintVerifier : public MatchVerifier<ast_type_traits::DynTypedNode> {
public:
void expectString(const std::string &Str) {
ExpectString = Str;
}
protected:
void verify(const MatchFinder::MatchResult &Result,
const ast_type_traits::DynTypedNode &Node) override {
std::string PrintStr;
llvm::raw_string_ostream Print(PrintStr);
Node.print(Print, Result.Context->getPrintingPolicy());
if (Print.str() != ExpectString) {
std::string MsgStr;
llvm::raw_string_ostream Msg(MsgStr);
Msg << "Expected pretty print <" << ExpectString << ">, found <"
<< Print.str() << '>';
this->setFailure(Msg.str());
}
}
private:
std::string ExpectString;
};
} // end namespace ast_matchers
} // end namespace clang
#endif

View File

@@ -0,0 +1,175 @@
//===- unittests/AST/NamedDeclPrinterTest.cpp --- NamedDecl 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 NamedDecl::printQualifiedName().
//
// These tests have a coding convention:
// * declaration to be printed is named 'A' unless it should have some special
// name (e.g., 'operator+');
// * additional helper declarations are 'Z', 'Y', 'X' and so on.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallString.h"
#include "gtest/gtest.h"
using namespace clang;
using namespace ast_matchers;
using namespace tooling;
namespace {
class PrintMatch : public MatchFinder::MatchCallback {
SmallString<1024> Printed;
unsigned NumFoundDecls;
bool SuppressUnwrittenScope;
public:
explicit PrintMatch(bool suppressUnwrittenScope)
: NumFoundDecls(0), SuppressUnwrittenScope(suppressUnwrittenScope) {}
void run(const MatchFinder::MatchResult &Result) override {
const NamedDecl *ND = Result.Nodes.getNodeAs<NamedDecl>("id");
if (!ND)
return;
NumFoundDecls++;
if (NumFoundDecls > 1)
return;
llvm::raw_svector_ostream Out(Printed);
PrintingPolicy Policy = Result.Context->getPrintingPolicy();
Policy.SuppressUnwrittenScope = SuppressUnwrittenScope;
ND->printQualifiedName(Out, Policy);
}
StringRef getPrinted() const {
return Printed;
}
unsigned getNumFoundDecls() const {
return NumFoundDecls;
}
};
::testing::AssertionResult
PrintedNamedDeclMatches(StringRef Code, const std::vector<std::string> &Args,
bool SuppressUnwrittenScope,
const DeclarationMatcher &NodeMatch,
StringRef ExpectedPrinted, StringRef FileName) {
PrintMatch Printer(SuppressUnwrittenScope);
MatchFinder Finder;
Finder.addMatcher(NodeMatch, &Printer);
std::unique_ptr<FrontendActionFactory> Factory =
newFrontendActionFactory(&Finder);
if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
return testing::AssertionFailure()
<< "Parsing error in \"" << Code.str() << "\"";
if (Printer.getNumFoundDecls() == 0)
return testing::AssertionFailure()
<< "Matcher didn't find any named declarations";
if (Printer.getNumFoundDecls() > 1)
return testing::AssertionFailure()
<< "Matcher should match only one named declaration "
"(found " << Printer.getNumFoundDecls() << ")";
if (Printer.getPrinted() != ExpectedPrinted)
return ::testing::AssertionFailure()
<< "Expected \"" << ExpectedPrinted.str() << "\", "
"got \"" << Printer.getPrinted().str() << "\"";
return ::testing::AssertionSuccess();
}
::testing::AssertionResult
PrintedNamedDeclCXX98Matches(StringRef Code, StringRef DeclName,
StringRef ExpectedPrinted) {
std::vector<std::string> Args(1, "-std=c++98");
return PrintedNamedDeclMatches(Code,
Args,
/*SuppressUnwrittenScope*/ false,
namedDecl(hasName(DeclName)).bind("id"),
ExpectedPrinted,
"input.cc");
}
::testing::AssertionResult
PrintedWrittenNamedDeclCXX11Matches(StringRef Code, StringRef DeclName,
StringRef ExpectedPrinted) {
std::vector<std::string> Args(1, "-std=c++11");
return PrintedNamedDeclMatches(Code,
Args,
/*SuppressUnwrittenScope*/ true,
namedDecl(hasName(DeclName)).bind("id"),
ExpectedPrinted,
"input.cc");
}
} // unnamed namespace
TEST(NamedDeclPrinter, TestNamespace1) {
ASSERT_TRUE(PrintedNamedDeclCXX98Matches(
"namespace { int A; }",
"A",
"(anonymous namespace)::A"));
}
TEST(NamedDeclPrinter, TestNamespace2) {
ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
"inline namespace Z { namespace { int A; } }",
"A",
"A"));
}
TEST(NamedDeclPrinter, TestUnscopedUnnamedEnum) {
ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
"enum { A };",
"A",
"A"));
}
TEST(NamedDeclPrinter, TestNamedEnum) {
ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
"enum X { A };",
"A",
"A"));
}
TEST(NamedDeclPrinter, TestScopedNamedEnum) {
ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
"enum class X { A };",
"A",
"X::A"));
}
TEST(NamedDeclPrinter, TestClassWithUnscopedUnnamedEnum) {
ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
"class X { enum { A }; };",
"A",
"X::A"));
}
TEST(NamedDeclPrinter, TestClassWithUnscopedNamedEnum) {
ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
"class X { enum Y { A }; };",
"A",
"X::A"));
}
TEST(NamedDeclPrinter, TestClassWithScopedNamedEnum) {
ASSERT_TRUE(PrintedWrittenNamedDeclCXX11Matches(
"class X { enum class Y { A }; };",
"A",
"X::Y::A"));
}

View File

@@ -0,0 +1,128 @@
//===- 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 VisitUnaryOperator(UnaryOperator *Op) {
VisitedNodes.push_back(Op->getOpcodeStr(Op->getOpcode()));
return true;
}
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; int j = -5; } 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", "5", "-",
"j", "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]);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,276 @@
//===- unittests/AST/StmtPrinterTest.cpp --- Statement 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 Stmt::printPretty() and related methods.
//
// Search this file for WRONG to see test cases that are producing something
// completely wrong, invalid C++ or just misleading.
//
// These tests have a coding convention:
// * statements to be printed should be contained within a function named 'A'
// unless it should have some special name (e.g., 'operator+');
// * additional helper declarations are 'Z', 'Y', 'X' and so on.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallString.h"
#include "gtest/gtest.h"
using namespace clang;
using namespace ast_matchers;
using namespace tooling;
namespace {
using PolicyAdjusterType =
Optional<llvm::function_ref<void(PrintingPolicy &Policy)>>;
void PrintStmt(raw_ostream &Out, const ASTContext *Context, const Stmt *S,
PolicyAdjusterType PolicyAdjuster) {
assert(S != nullptr && "Expected non-null Stmt");
PrintingPolicy Policy = Context->getPrintingPolicy();
if (PolicyAdjuster)
(*PolicyAdjuster)(Policy);
S->printPretty(Out, /*Helper*/ nullptr, Policy);
}
class PrintMatch : public MatchFinder::MatchCallback {
SmallString<1024> Printed;
unsigned NumFoundStmts;
PolicyAdjusterType PolicyAdjuster;
public:
PrintMatch(PolicyAdjusterType PolicyAdjuster)
: NumFoundStmts(0), PolicyAdjuster(PolicyAdjuster) {}
void run(const MatchFinder::MatchResult &Result) override {
const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id");
if (!S)
return;
NumFoundStmts++;
if (NumFoundStmts > 1)
return;
llvm::raw_svector_ostream Out(Printed);
PrintStmt(Out, Result.Context, S, PolicyAdjuster);
}
StringRef getPrinted() const {
return Printed;
}
unsigned getNumFoundStmts() const {
return NumFoundStmts;
}
};
template <typename T>
::testing::AssertionResult
PrintedStmtMatches(StringRef Code, const std::vector<std::string> &Args,
const T &NodeMatch, StringRef ExpectedPrinted,
PolicyAdjusterType PolicyAdjuster = None) {
PrintMatch Printer(PolicyAdjuster);
MatchFinder Finder;
Finder.addMatcher(NodeMatch, &Printer);
std::unique_ptr<FrontendActionFactory> Factory(
newFrontendActionFactory(&Finder));
if (!runToolOnCodeWithArgs(Factory->create(), Code, Args))
return testing::AssertionFailure()
<< "Parsing error in \"" << Code.str() << "\"";
if (Printer.getNumFoundStmts() == 0)
return testing::AssertionFailure()
<< "Matcher didn't find any statements";
if (Printer.getNumFoundStmts() > 1)
return testing::AssertionFailure()
<< "Matcher should match only one statement "
"(found " << Printer.getNumFoundStmts() << ")";
if (Printer.getPrinted() != ExpectedPrinted)
return ::testing::AssertionFailure()
<< "Expected \"" << ExpectedPrinted.str() << "\", "
"got \"" << Printer.getPrinted().str() << "\"";
return ::testing::AssertionSuccess();
}
::testing::AssertionResult
PrintedStmtCXX98Matches(StringRef Code, const StatementMatcher &NodeMatch,
StringRef ExpectedPrinted) {
std::vector<std::string> Args;
Args.push_back("-std=c++98");
Args.push_back("-Wno-unused-value");
return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted);
}
::testing::AssertionResult PrintedStmtCXX98Matches(
StringRef Code,
StringRef ContainingFunction,
StringRef ExpectedPrinted) {
std::vector<std::string> Args;
Args.push_back("-std=c++98");
Args.push_back("-Wno-unused-value");
return PrintedStmtMatches(Code,
Args,
functionDecl(hasName(ContainingFunction),
has(compoundStmt(has(stmt().bind("id"))))),
ExpectedPrinted);
}
::testing::AssertionResult
PrintedStmtCXX11Matches(StringRef Code, const StatementMatcher &NodeMatch,
StringRef ExpectedPrinted,
PolicyAdjusterType PolicyAdjuster = None) {
std::vector<std::string> Args;
Args.push_back("-std=c++11");
Args.push_back("-Wno-unused-value");
return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
PolicyAdjuster);
}
::testing::AssertionResult PrintedStmtMSMatches(
StringRef Code,
StringRef ContainingFunction,
StringRef ExpectedPrinted) {
std::vector<std::string> Args;
Args.push_back("-target");
Args.push_back("i686-pc-win32");
Args.push_back("-std=c++98");
Args.push_back("-fms-extensions");
Args.push_back("-Wno-unused-value");
return PrintedStmtMatches(Code,
Args,
functionDecl(hasName(ContainingFunction),
has(compoundStmt(has(stmt().bind("id"))))),
ExpectedPrinted);
}
::testing::AssertionResult
PrintedStmtObjCMatches(StringRef Code, const StatementMatcher &NodeMatch,
StringRef ExpectedPrinted,
PolicyAdjusterType PolicyAdjuster = None) {
std::vector<std::string> Args;
Args.push_back("-ObjC");
Args.push_back("-fobjc-runtime=macosx-10.12.0");
return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
PolicyAdjuster);
}
} // unnamed namespace
TEST(StmtPrinter, TestIntegerLiteral) {
ASSERT_TRUE(PrintedStmtCXX98Matches(
"void A() {"
" 1, -1, 1U, 1u,"
" 1L, 1l, -1L, 1UL, 1ul,"
" 1LL, -1LL, 1ULL;"
"}",
"A",
"1 , -1 , 1U , 1U , "
"1L , 1L , -1L , 1UL , 1UL , "
"1LL , -1LL , 1ULL"));
// Should be: with semicolon
}
TEST(StmtPrinter, TestMSIntegerLiteral) {
ASSERT_TRUE(PrintedStmtMSMatches(
"void A() {"
" 1i8, -1i8, 1ui8, "
" 1i16, -1i16, 1ui16, "
" 1i32, -1i32, 1ui32, "
" 1i64, -1i64, 1ui64;"
"}",
"A",
"1i8 , -1i8 , 1Ui8 , "
"1i16 , -1i16 , 1Ui16 , "
"1 , -1 , 1U , "
"1LL , -1LL , 1ULL"));
// Should be: with semicolon
}
TEST(StmtPrinter, TestFloatingPointLiteral) {
ASSERT_TRUE(PrintedStmtCXX98Matches(
"void A() { 1.0f, -1.0f, 1.0, -1.0, 1.0l, -1.0l; }",
"A",
"1.F , -1.F , 1. , -1. , 1.L , -1.L"));
// Should be: with semicolon
}
TEST(StmtPrinter, TestCXXConversionDeclImplicit) {
ASSERT_TRUE(PrintedStmtCXX98Matches(
"struct A {"
"operator void *();"
"A operator&(A);"
"};"
"void bar(void *);"
"void foo(A a, A b) {"
" bar(a & b);"
"}",
cxxMemberCallExpr(anything()).bind("id"),
"a & b"));
}
TEST(StmtPrinter, TestCXXConversionDeclExplicit) {
ASSERT_TRUE(PrintedStmtCXX11Matches(
"struct A {"
"operator void *();"
"A operator&(A);"
"};"
"void bar(void *);"
"void foo(A a, A b) {"
" auto x = (a & b).operator void *();"
"}",
cxxMemberCallExpr(anything()).bind("id"),
"(a & b)"));
// WRONG; Should be: (a & b).operator void *()
}
TEST(StmtPrinter, TestNoImplicitBases) {
const char *CPPSource = R"(
class A {
int field;
int member() { return field; }
};
)";
// No implicit 'this'.
ASSERT_TRUE(PrintedStmtCXX11Matches(
CPPSource, memberExpr(anything()).bind("id"), "field",
PolicyAdjusterType(
[](PrintingPolicy &PP) { PP.SuppressImplicitBase = true; })));
// Print implicit 'this'.
ASSERT_TRUE(PrintedStmtCXX11Matches(
CPPSource, memberExpr(anything()).bind("id"), "this->field"));
const char *ObjCSource = R"(
@interface I {
int ivar;
}
@end
@implementation I
- (int) method {
return ivar;
}
@end
)";
// No implicit 'self'.
ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"),
"return ivar;\n",
PolicyAdjusterType([](PrintingPolicy &PP) {
PP.SuppressImplicitBase = true;
})));
// Print implicit 'self'.
ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"),
"return self->ivar;\n"));
}

View File

@@ -0,0 +1,240 @@
// unittests/ASTMatchers/ASTMatchersInternalTest.cpp - AST matcher unit tests //
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "ASTMatchersTest.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Host.h"
#include "gtest/gtest.h"
namespace clang {
namespace ast_matchers {
#if GTEST_HAS_DEATH_TEST
TEST(HasNameDeathTest, DiesOnEmptyName) {
ASSERT_DEBUG_DEATH({
DeclarationMatcher HasEmptyName = recordDecl(hasName(""));
EXPECT_TRUE(notMatches("class X {};", HasEmptyName));
}, "");
}
TEST(HasNameDeathTest, DiesOnEmptyPattern) {
ASSERT_DEBUG_DEATH({
DeclarationMatcher HasEmptyName = recordDecl(matchesName(""));
EXPECT_TRUE(notMatches("class X {};", HasEmptyName));
}, "");
}
TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) {
ASSERT_DEBUG_DEATH({
DeclarationMatcher IsDerivedFromEmpty = cxxRecordDecl(isDerivedFrom(""));
EXPECT_TRUE(notMatches("class X {};", IsDerivedFromEmpty));
}, "");
}
#endif
TEST(ConstructVariadic, MismatchedTypes_Regression) {
EXPECT_TRUE(
matches("const int a = 0;",
internal::DynTypedMatcher::constructVariadic(
internal::DynTypedMatcher::VO_AnyOf,
ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>(),
{isConstQualified(), arrayType()})
.convertTo<QualType>()));
}
// For testing AST_MATCHER_P().
AST_MATCHER_P(Decl, just, internal::Matcher<Decl>, AMatcher) {
// Make sure all special variables are used: node, match_finder,
// bound_nodes_builder, and the parameter named 'AMatcher'.
return AMatcher.matches(Node, Finder, Builder);
}
TEST(AstMatcherPMacro, Works) {
DeclarationMatcher HasClassB = just(has(recordDecl(hasName("B")).bind("b")));
EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
HasClassB, llvm::make_unique<VerifyIdIsBoundTo<Decl>>("b")));
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
HasClassB, llvm::make_unique<VerifyIdIsBoundTo<Decl>>("a")));
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
HasClassB, llvm::make_unique<VerifyIdIsBoundTo<Decl>>("b")));
}
AST_POLYMORPHIC_MATCHER_P(polymorphicHas,
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt),
internal::Matcher<Decl>, AMatcher) {
return Finder->matchesChildOf(
Node, AMatcher, Builder,
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
ASTMatchFinder::BK_First);
}
TEST(AstPolymorphicMatcherPMacro, Works) {
DeclarationMatcher HasClassB =
polymorphicHas(recordDecl(hasName("B")).bind("b"));
EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
HasClassB, llvm::make_unique<VerifyIdIsBoundTo<Decl>>("b")));
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
HasClassB, llvm::make_unique<VerifyIdIsBoundTo<Decl>>("a")));
EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
HasClassB, llvm::make_unique<VerifyIdIsBoundTo<Decl>>("b")));
StatementMatcher StatementHasClassB =
polymorphicHas(recordDecl(hasName("B")));
EXPECT_TRUE(matches("void x() { class B {}; }", StatementHasClassB));
}
TEST(MatchFinder, CheckProfiling) {
MatchFinder::MatchFinderOptions Options;
llvm::StringMap<llvm::TimeRecord> Records;
Options.CheckProfiling.emplace(Records);
MatchFinder Finder(std::move(Options));
struct NamedCallback : public MatchFinder::MatchCallback {
void run(const MatchFinder::MatchResult &Result) override {}
StringRef getID() const override { return "MyID"; }
} Callback;
Finder.addMatcher(decl(), &Callback);
std::unique_ptr<FrontendActionFactory> Factory(
newFrontendActionFactory(&Finder));
ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
EXPECT_EQ(1u, Records.size());
EXPECT_EQ("MyID", Records.begin()->getKey());
}
class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback {
public:
VerifyStartOfTranslationUnit() : Called(false) {}
void run(const MatchFinder::MatchResult &Result) override {
EXPECT_TRUE(Called);
}
void onStartOfTranslationUnit() override { Called = true; }
bool Called;
};
TEST(MatchFinder, InterceptsStartOfTranslationUnit) {
MatchFinder Finder;
VerifyStartOfTranslationUnit VerifyCallback;
Finder.addMatcher(decl(), &VerifyCallback);
std::unique_ptr<FrontendActionFactory> Factory(
newFrontendActionFactory(&Finder));
ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
EXPECT_TRUE(VerifyCallback.Called);
VerifyCallback.Called = false;
std::unique_ptr<ASTUnit> AST(tooling::buildASTFromCode("int x;"));
ASSERT_TRUE(AST.get());
Finder.matchAST(AST->getASTContext());
EXPECT_TRUE(VerifyCallback.Called);
}
class VerifyEndOfTranslationUnit : public MatchFinder::MatchCallback {
public:
VerifyEndOfTranslationUnit() : Called(false) {}
void run(const MatchFinder::MatchResult &Result) override {
EXPECT_FALSE(Called);
}
void onEndOfTranslationUnit() override { Called = true; }
bool Called;
};
TEST(MatchFinder, InterceptsEndOfTranslationUnit) {
MatchFinder Finder;
VerifyEndOfTranslationUnit VerifyCallback;
Finder.addMatcher(decl(), &VerifyCallback);
std::unique_ptr<FrontendActionFactory> Factory(
newFrontendActionFactory(&Finder));
ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
EXPECT_TRUE(VerifyCallback.Called);
VerifyCallback.Called = false;
std::unique_ptr<ASTUnit> AST(tooling::buildASTFromCode("int x;"));
ASSERT_TRUE(AST.get());
Finder.matchAST(AST->getASTContext());
EXPECT_TRUE(VerifyCallback.Called);
}
TEST(Matcher, matchOverEntireASTContext) {
std::unique_ptr<ASTUnit> AST =
clang::tooling::buildASTFromCode("struct { int *foo; };");
ASSERT_TRUE(AST.get());
auto PT = selectFirst<PointerType>(
"x", match(pointerType().bind("x"), AST->getASTContext()));
EXPECT_NE(nullptr, PT);
}
TEST(IsInlineMatcher, IsInline) {
EXPECT_TRUE(matches("void g(); inline void f();",
functionDecl(isInline(), hasName("f"))));
EXPECT_TRUE(matches("namespace n { inline namespace m {} }",
namespaceDecl(isInline(), hasName("m"))));
}
// FIXME: Figure out how to specify paths so the following tests pass on
// Windows.
#ifndef LLVM_ON_WIN32
TEST(Matcher, IsExpansionInMainFileMatcher) {
EXPECT_TRUE(matches("class X {};",
recordDecl(hasName("X"), isExpansionInMainFile())));
EXPECT_TRUE(notMatches("", recordDecl(isExpansionInMainFile())));
FileContentMappings M;
M.push_back(std::make_pair("/other", "class X {};"));
EXPECT_TRUE(matchesConditionally("#include <other>\n",
recordDecl(isExpansionInMainFile()), false,
"-isystem/", M));
}
TEST(Matcher, IsExpansionInSystemHeader) {
FileContentMappings M;
M.push_back(std::make_pair("/other", "class X {};"));
EXPECT_TRUE(matchesConditionally(
"#include \"other\"\n", recordDecl(isExpansionInSystemHeader()), true,
"-isystem/", M));
EXPECT_TRUE(matchesConditionally("#include \"other\"\n",
recordDecl(isExpansionInSystemHeader()),
false, "-I/", M));
EXPECT_TRUE(notMatches("class X {};",
recordDecl(isExpansionInSystemHeader())));
EXPECT_TRUE(notMatches("", recordDecl(isExpansionInSystemHeader())));
}
TEST(Matcher, IsExpansionInFileMatching) {
FileContentMappings M;
M.push_back(std::make_pair("/foo", "class A {};"));
M.push_back(std::make_pair("/bar", "class B {};"));
EXPECT_TRUE(matchesConditionally(
"#include <foo>\n"
"#include <bar>\n"
"class X {};",
recordDecl(isExpansionInFileMatching("b.*"), hasName("B")), true,
"-isystem/", M));
EXPECT_TRUE(matchesConditionally(
"#include <foo>\n"
"#include <bar>\n"
"class X {};",
recordDecl(isExpansionInFileMatching("f.*"), hasName("X")), false,
"-isystem/", M));
}
#endif // LLVM_ON_WIN32
} // end namespace ast_matchers
} // end namespace clang

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More