Peter Wu 0f215dd8ae [ASTMatchers] temporary disable tests with floating suffix
r305022 assumed that floatLiteral(equals(1.2)) would also match 1.2f and
1.2l, but apparently that is not the case. Until it is clear how to
match, temporary disable the test to fix CI.

llvm-svn: 305025
2017-06-08 22:58:12 +00:00

561 lines
21 KiB
C++

//===- unittest/ASTMatchers/Dynamic/RegistryTest.cpp - Registry 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/ASTMatchers/Dynamic/Registry.h"
#include "gtest/gtest.h"
#include <vector>
namespace clang {
namespace ast_matchers {
namespace dynamic {
namespace {
using ast_matchers::internal::Matcher;
class RegistryTest : public ::testing::Test {
public:
std::vector<ParserValue> Args() { return std::vector<ParserValue>(); }
std::vector<ParserValue> Args(const VariantValue &Arg1) {
std::vector<ParserValue> Out(1);
Out[0].Value = Arg1;
return Out;
}
std::vector<ParserValue> Args(const VariantValue &Arg1,
const VariantValue &Arg2) {
std::vector<ParserValue> Out(2);
Out[0].Value = Arg1;
Out[1].Value = Arg2;
return Out;
}
llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) {
return Registry::lookupMatcherCtor(MatcherName);
}
VariantMatcher constructMatcher(StringRef MatcherName,
Diagnostics *Error = nullptr) {
Diagnostics DummyError;
if (!Error) Error = &DummyError;
llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
VariantMatcher Out;
if (Ctor)
Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(), Error);
EXPECT_EQ("", DummyError.toStringFull());
return Out;
}
VariantMatcher constructMatcher(StringRef MatcherName,
const VariantValue &Arg1,
Diagnostics *Error = nullptr) {
Diagnostics DummyError;
if (!Error) Error = &DummyError;
llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
VariantMatcher Out;
if (Ctor)
Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1), Error);
EXPECT_EQ("", DummyError.toStringFull()) << MatcherName;
return Out;
}
VariantMatcher constructMatcher(StringRef MatcherName,
const VariantValue &Arg1,
const VariantValue &Arg2,
Diagnostics *Error = nullptr) {
Diagnostics DummyError;
if (!Error) Error = &DummyError;
llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
VariantMatcher Out;
if (Ctor)
Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1, Arg2),
Error);
EXPECT_EQ("", DummyError.toStringFull());
return Out;
}
typedef std::vector<MatcherCompletion> CompVector;
CompVector getCompletions() {
std::vector<std::pair<MatcherCtor, unsigned> > Context;
return Registry::getMatcherCompletions(
Registry::getAcceptedCompletionTypes(Context));
}
CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1) {
std::vector<std::pair<MatcherCtor, unsigned> > Context;
llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1);
if (!Ctor)
return CompVector();
Context.push_back(std::make_pair(*Ctor, ArgNo1));
return Registry::getMatcherCompletions(
Registry::getAcceptedCompletionTypes(Context));
}
CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1,
StringRef MatcherName2, unsigned ArgNo2) {
std::vector<std::pair<MatcherCtor, unsigned> > Context;
llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1);
if (!Ctor)
return CompVector();
Context.push_back(std::make_pair(*Ctor, ArgNo1));
Ctor = lookupMatcherCtor(MatcherName2);
if (!Ctor)
return CompVector();
Context.push_back(std::make_pair(*Ctor, ArgNo2));
return Registry::getMatcherCompletions(
Registry::getAcceptedCompletionTypes(Context));
}
bool hasCompletion(const CompVector &Comps, StringRef TypedText,
StringRef MatcherDecl = StringRef()) {
for (CompVector::const_iterator I = Comps.begin(), E = Comps.end(); I != E;
++I) {
if (I->TypedText == TypedText &&
(MatcherDecl.empty() || I->MatcherDecl == MatcherDecl)) {
return true;
}
}
return false;
}
};
TEST_F(RegistryTest, CanConstructNoArgs) {
Matcher<Stmt> IsArrowValue = constructMatcher(
"memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>();
Matcher<Stmt> BoolValue =
constructMatcher("cxxBoolLiteral").getTypedMatcher<Stmt>();
const std::string ClassSnippet = "struct Foo { int x; };\n"
"Foo *foo = new Foo;\n"
"int i = foo->x;\n";
const std::string BoolSnippet = "bool Foo = true;\n";
EXPECT_TRUE(matches(ClassSnippet, IsArrowValue));
EXPECT_TRUE(matches(BoolSnippet, BoolValue));
EXPECT_FALSE(matches(ClassSnippet, BoolValue));
EXPECT_FALSE(matches(BoolSnippet, IsArrowValue));
}
TEST_F(RegistryTest, ConstructWithSimpleArgs) {
Matcher<Decl> Value = constructMatcher(
"namedDecl", constructMatcher("hasName", StringRef("X")))
.getTypedMatcher<Decl>();
EXPECT_TRUE(matches("class X {};", Value));
EXPECT_FALSE(matches("int x;", Value));
Value = functionDecl(constructMatcher("parameterCountIs", 2)
.getTypedMatcher<FunctionDecl>());
EXPECT_TRUE(matches("void foo(int,int);", Value));
EXPECT_FALSE(matches("void foo(int);", Value));
}
TEST_F(RegistryTest, ConstructWithMatcherArgs) {
Matcher<Decl> HasInitializerSimple = constructMatcher(
"varDecl", constructMatcher("hasInitializer", constructMatcher("stmt")))
.getTypedMatcher<Decl>();
Matcher<Decl> HasInitializerComplex = constructMatcher(
"varDecl",
constructMatcher("hasInitializer", constructMatcher("callExpr")))
.getTypedMatcher<Decl>();
std::string code = "int i;";
EXPECT_FALSE(matches(code, HasInitializerSimple));
EXPECT_FALSE(matches(code, HasInitializerComplex));
code = "int i = 1;";
EXPECT_TRUE(matches(code, HasInitializerSimple));
EXPECT_FALSE(matches(code, HasInitializerComplex));
code = "int y(); int i = y();";
EXPECT_TRUE(matches(code, HasInitializerSimple));
EXPECT_TRUE(matches(code, HasInitializerComplex));
Matcher<Decl> HasParameter =
functionDecl(constructMatcher(
"hasParameter", 1, constructMatcher("hasName", StringRef("x")))
.getTypedMatcher<FunctionDecl>());
EXPECT_TRUE(matches("void f(int a, int x);", HasParameter));
EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
}
TEST_F(RegistryTest, OverloadedMatchers) {
Matcher<Stmt> CallExpr0 = constructMatcher(
"callExpr",
constructMatcher("callee", constructMatcher("memberExpr",
constructMatcher("isArrow"))))
.getTypedMatcher<Stmt>();
Matcher<Stmt> CallExpr1 = constructMatcher(
"callExpr",
constructMatcher(
"callee",
constructMatcher("cxxMethodDecl",
constructMatcher("hasName", StringRef("x")))))
.getTypedMatcher<Stmt>();
std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }";
EXPECT_FALSE(matches(Code, CallExpr0));
EXPECT_TRUE(matches(Code, CallExpr1));
Code = "class Z { public: void z() { this->z(); } };";
EXPECT_TRUE(matches(Code, CallExpr0));
EXPECT_FALSE(matches(Code, CallExpr1));
Matcher<Decl> DeclDecl = declaratorDecl(hasTypeLoc(
constructMatcher(
"loc", constructMatcher("asString", StringRef("const double *")))
.getTypedMatcher<TypeLoc>()));
Matcher<NestedNameSpecifierLoc> NNSL =
constructMatcher(
"loc", VariantMatcher::SingleMatcher(nestedNameSpecifier(
specifiesType(hasDeclaration(recordDecl(hasName("A")))))))
.getTypedMatcher<NestedNameSpecifierLoc>();
Code = "const double * x = 0;";
EXPECT_TRUE(matches(Code, DeclDecl));
EXPECT_FALSE(matches(Code, NNSL));
Code = "struct A { struct B {}; }; A::B a_b;";
EXPECT_FALSE(matches(Code, DeclDecl));
EXPECT_TRUE(matches(Code, NNSL));
}
TEST_F(RegistryTest, PolymorphicMatchers) {
const VariantMatcher IsDefinition = constructMatcher("isDefinition");
Matcher<Decl> Var =
constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>();
Matcher<Decl> Class =
constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>();
Matcher<Decl> Func =
constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>();
EXPECT_TRUE(matches("int a;", Var));
EXPECT_FALSE(matches("extern int a;", Var));
EXPECT_TRUE(matches("class A {};", Class));
EXPECT_FALSE(matches("class A;", Class));
EXPECT_TRUE(matches("void f(){};", Func));
EXPECT_FALSE(matches("void f();", Func));
Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>();
Matcher<Decl> RecordDecl = constructMatcher(
"recordDecl", constructMatcher("hasName", StringRef("Foo")),
VariantMatcher::SingleMatcher(Anything)).getTypedMatcher<Decl>();
EXPECT_TRUE(matches("int Foo;", Anything));
EXPECT_TRUE(matches("class Foo {};", Anything));
EXPECT_TRUE(matches("void Foo(){};", Anything));
EXPECT_FALSE(matches("int Foo;", RecordDecl));
EXPECT_TRUE(matches("class Foo {};", RecordDecl));
EXPECT_FALSE(matches("void Foo(){};", RecordDecl));
Matcher<Stmt> ConstructExpr = constructMatcher(
"cxxConstructExpr",
constructMatcher(
"hasDeclaration",
constructMatcher(
"cxxMethodDecl",
constructMatcher(
"ofClass", constructMatcher("hasName", StringRef("Foo"))))))
.getTypedMatcher<Stmt>();
EXPECT_FALSE(matches("class Foo { public: Foo(); };", ConstructExpr));
EXPECT_TRUE(
matches("class Foo { public: Foo(); }; Foo foo = Foo();", ConstructExpr));
}
TEST_F(RegistryTest, TemplateArgument) {
Matcher<Decl> HasTemplateArgument = constructMatcher(
"classTemplateSpecializationDecl",
constructMatcher(
"hasAnyTemplateArgument",
constructMatcher("refersToType",
constructMatcher("asString", StringRef("int")))))
.getTypedMatcher<Decl>();
EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;",
HasTemplateArgument));
EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;",
HasTemplateArgument));
}
TEST_F(RegistryTest, TypeTraversal) {
Matcher<Type> M = constructMatcher(
"pointerType",
constructMatcher("pointee", constructMatcher("isConstQualified"),
constructMatcher("isInteger"))).getTypedMatcher<Type>();
EXPECT_FALSE(matches("int *a;", M));
EXPECT_TRUE(matches("int const *b;", M));
M = constructMatcher(
"arrayType",
constructMatcher("hasElementType", constructMatcher("builtinType")))
.getTypedMatcher<Type>();
EXPECT_FALSE(matches("struct A{}; A a[7];;", M));
EXPECT_TRUE(matches("int b[7];", M));
}
TEST_F(RegistryTest, CXXCtorInitializer) {
Matcher<Decl> CtorDecl = constructMatcher(
"cxxConstructorDecl",
constructMatcher(
"hasAnyConstructorInitializer",
constructMatcher("forField",
constructMatcher("hasName", StringRef("foo")))))
.getTypedMatcher<Decl>();
EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl));
EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl));
EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl));
}
TEST_F(RegistryTest, Adaptative) {
Matcher<Decl> D = constructMatcher(
"recordDecl",
constructMatcher(
"has",
constructMatcher("recordDecl",
constructMatcher("hasName", StringRef("X")))))
.getTypedMatcher<Decl>();
EXPECT_TRUE(matches("class X {};", D));
EXPECT_TRUE(matches("class Y { class X {}; };", D));
EXPECT_FALSE(matches("class Y { class Z {}; };", D));
Matcher<Stmt> S = constructMatcher(
"forStmt",
constructMatcher(
"hasDescendant",
constructMatcher("varDecl",
constructMatcher("hasName", StringRef("X")))))
.getTypedMatcher<Stmt>();
EXPECT_TRUE(matches("void foo() { for(int X;;); }", S));
EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S));
EXPECT_FALSE(matches("void foo() { for(;;); }", S));
EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S));
S = constructMatcher(
"compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt")))
.getTypedMatcher<Stmt>();
EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S));
EXPECT_FALSE(matches("void foo() { if (true) return; }", S));
}
TEST_F(RegistryTest, VariadicOp) {
Matcher<Decl> D = constructMatcher(
"anyOf",
constructMatcher("recordDecl",
constructMatcher("hasName", StringRef("Foo"))),
constructMatcher("functionDecl",
constructMatcher("hasName", StringRef("foo"))))
.getTypedMatcher<Decl>();
EXPECT_TRUE(matches("void foo(){}", D));
EXPECT_TRUE(matches("struct Foo{};", D));
EXPECT_FALSE(matches("int i = 0;", D));
D = constructMatcher(
"allOf", constructMatcher("recordDecl"),
constructMatcher(
"namedDecl",
constructMatcher("anyOf",
constructMatcher("hasName", StringRef("Foo")),
constructMatcher("hasName", StringRef("Bar")))))
.getTypedMatcher<Decl>();
EXPECT_FALSE(matches("void foo(){}", D));
EXPECT_TRUE(matches("struct Foo{};", D));
EXPECT_FALSE(matches("int i = 0;", D));
EXPECT_TRUE(matches("class Bar{};", D));
EXPECT_FALSE(matches("class OtherBar{};", D));
D = recordDecl(
has(fieldDecl(hasName("Foo"))),
constructMatcher(
"unless",
constructMatcher("namedDecl",
constructMatcher("hasName", StringRef("Bar"))))
.getTypedMatcher<Decl>());
EXPECT_FALSE(matches("class Bar{ int Foo; };", D));
EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D));
D = constructMatcher(
"namedDecl", constructMatcher("hasName", StringRef("Foo")),
constructMatcher("unless", constructMatcher("recordDecl")))
.getTypedMatcher<Decl>();
EXPECT_TRUE(matches("void Foo(){}", D));
EXPECT_TRUE(notMatches("struct Foo {};", D));
}
TEST_F(RegistryTest, Errors) {
// Incorrect argument count.
std::unique_ptr<Diagnostics> Error(new Diagnostics());
EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull());
EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
Error->toString());
Error.reset(new Diagnostics());
EXPECT_TRUE(constructMatcher("isArrow", StringRef(), Error.get()).isNull());
EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
Error->toString());
Error.reset(new Diagnostics());
EXPECT_TRUE(constructMatcher("anyOf", Error.get()).isNull());
EXPECT_EQ("Incorrect argument count. (Expected = (2, )) != (Actual = 0)",
Error->toString());
Error.reset(new Diagnostics());
EXPECT_TRUE(constructMatcher("unless", StringRef(), StringRef(),
Error.get()).isNull());
EXPECT_EQ("Incorrect argument count. (Expected = (1, 1)) != (Actual = 2)",
Error->toString());
// Bad argument type
Error.reset(new Diagnostics());
EXPECT_TRUE(constructMatcher("ofClass", StringRef(), Error.get()).isNull());
EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
"(Actual = String)",
Error->toString());
Error.reset(new Diagnostics());
EXPECT_TRUE(
constructMatcher("cxxRecordDecl", constructMatcher("cxxRecordDecl"),
constructMatcher("parameterCountIs", 3), Error.get())
.isNull());
EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
"(Actual = Matcher<FunctionDecl|FunctionProtoType>)",
Error->toString());
// Bad argument type with variadic.
Error.reset(new Diagnostics());
EXPECT_TRUE(constructMatcher("anyOf", StringRef(), StringRef(),
Error.get()).isNull());
EXPECT_EQ(
"Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)",
Error->toString());
Error.reset(new Diagnostics());
EXPECT_TRUE(constructMatcher(
"cxxRecordDecl",
constructMatcher("allOf",
constructMatcher("isDerivedFrom", StringRef("FOO")),
constructMatcher("isArrow")),
Error.get()).isNull());
EXPECT_EQ("Incorrect type for arg 1. "
"(Expected = Matcher<CXXRecordDecl>) != "
"(Actual = Matcher<CXXRecordDecl>&Matcher<MemberExpr>)",
Error->toString());
}
TEST_F(RegistryTest, Completion) {
CompVector Comps = getCompletions();
// Overloaded
EXPECT_TRUE(hasCompletion(
Comps, "hasParent(",
"Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...> "
"hasParent(Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...>)"));
// Variadic.
EXPECT_TRUE(hasCompletion(Comps, "whileStmt(",
"Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)"));
// Polymorphic.
EXPECT_TRUE(hasCompletion(
Comps, "hasDescendant(",
"Matcher<NestedNameSpecifierLoc|QualType|TypeLoc|...> "
"hasDescendant(Matcher<NestedNameSpecifierLoc|QualType|TypeLoc|...>)"));
CompVector WhileComps = getCompletions("whileStmt", 0);
EXPECT_TRUE(hasCompletion(WhileComps, "hasBody(",
"Matcher<WhileStmt> hasBody(Matcher<Stmt>)"));
EXPECT_TRUE(hasCompletion(
WhileComps, "hasParent(",
"Matcher<Stmt> "
"hasParent(Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...>)"));
EXPECT_TRUE(
hasCompletion(WhileComps, "allOf(", "Matcher<T> allOf(Matcher<T>...)"));
EXPECT_FALSE(hasCompletion(WhileComps, "whileStmt("));
EXPECT_FALSE(hasCompletion(WhileComps, "ifStmt("));
CompVector AllOfWhileComps =
getCompletions("allOf", 0, "whileStmt", 0);
ASSERT_EQ(AllOfWhileComps.size(), WhileComps.size());
EXPECT_TRUE(std::equal(WhileComps.begin(), WhileComps.end(),
AllOfWhileComps.begin()));
CompVector DeclWhileComps =
getCompletions("decl", 0, "whileStmt", 0);
EXPECT_EQ(0u, DeclWhileComps.size());
CompVector NamedDeclComps = getCompletions("namedDecl", 0);
EXPECT_TRUE(
hasCompletion(NamedDeclComps, "isPublic()", "Matcher<Decl> isPublic()"));
EXPECT_TRUE(hasCompletion(NamedDeclComps, "hasName(\"",
"Matcher<NamedDecl> hasName(string)"));
// Heterogeneous overloads.
Comps = getCompletions("classTemplateSpecializationDecl", 0);
EXPECT_TRUE(hasCompletion(
Comps, "isSameOrDerivedFrom(",
"Matcher<CXXRecordDecl> isSameOrDerivedFrom(string|Matcher<NamedDecl>)"));
}
TEST_F(RegistryTest, HasArgs) {
Matcher<Decl> Value = constructMatcher(
"decl", constructMatcher("hasAttr", StringRef("attr::WarnUnused")))
.getTypedMatcher<Decl>();
EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};", Value));
EXPECT_FALSE(matches("struct X {};", Value));
}
TEST_F(RegistryTest, ParenExpr) {
Matcher<Stmt> Value = constructMatcher("parenExpr").getTypedMatcher<Stmt>();
EXPECT_TRUE(matches("int i = (1);", Value));
EXPECT_FALSE(matches("int i = 1;", Value));
}
TEST_F(RegistryTest, EqualsMatcher) {
Matcher<Stmt> BooleanStmt = constructMatcher(
"cxxBoolLiteral", constructMatcher("equals", VariantValue(true)))
.getTypedMatcher<Stmt>();
EXPECT_TRUE(matches("bool x = true;", BooleanStmt));
EXPECT_FALSE(matches("bool x = false;", BooleanStmt));
EXPECT_FALSE(matches("bool x = 0;", BooleanStmt));
BooleanStmt = constructMatcher(
"cxxBoolLiteral", constructMatcher("equals", VariantValue(0)))
.getTypedMatcher<Stmt>();
EXPECT_TRUE(matches("bool x = false;", BooleanStmt));
EXPECT_FALSE(matches("bool x = true;", BooleanStmt));
EXPECT_FALSE(matches("bool x = 0;", BooleanStmt));
Matcher<Stmt> DoubleStmt = constructMatcher(
"floatLiteral", constructMatcher("equals", VariantValue(1.2)))
.getTypedMatcher<Stmt>();
EXPECT_TRUE(matches("double x = 1.2;", DoubleStmt));
#if 0
// FIXME floatLiteral matching should work regardless of suffix.
EXPECT_TRUE(matches("double x = 1.2f;", DoubleStmt));
EXPECT_TRUE(matches("double x = 1.2l;", DoubleStmt));
#endif
EXPECT_TRUE(matches("double x = 12e-1;", DoubleStmt));
EXPECT_FALSE(matches("double x = 1.23;", DoubleStmt));
Matcher<Stmt> IntegerStmt = constructMatcher(
"integerLiteral", constructMatcher("equals", VariantValue(42)))
.getTypedMatcher<Stmt>();
EXPECT_TRUE(matches("int x = 42;", IntegerStmt));
EXPECT_FALSE(matches("int x = 1;", IntegerStmt));
Matcher<Stmt> CharStmt = constructMatcher(
"characterLiteral", constructMatcher("equals", VariantValue('x')))
.getTypedMatcher<Stmt>();
EXPECT_TRUE(matches("int x = 'x';", CharStmt));
EXPECT_TRUE(matches("int x = L'x';", CharStmt));
EXPECT_TRUE(matches("int x = u'x';", CharStmt));
EXPECT_TRUE(matches("int x = U'x';", CharStmt));
EXPECT_FALSE(matches("int x = 120;", CharStmt));
}
} // end anonymous namespace
} // end namespace dynamic
} // end namespace ast_matchers
} // end namespace clang