
Structural equivalence check uses a cache to store already found non-equivalent values. This cache can be reused for calls (ASTImporter does this). Value of "IgnoreTemplateParmDepth" can have an effect on the structural equivalence therefore it is wrong to reuse the same cache for checks with different values of 'IgnoreTemplateParmDepth'. The current change adds the 'IgnoreTemplateParmDepth' to the cache key to fix the problem.
2741 lines
91 KiB
C++
2741 lines
91 KiB
C++
#include "clang/AST/ASTContext.h"
|
|
#include "clang/AST/ASTStructuralEquivalence.h"
|
|
#include "clang/AST/Decl.h"
|
|
#include "clang/AST/DeclTemplate.h"
|
|
#include "clang/ASTMatchers/ASTMatchers.h"
|
|
#include "clang/Frontend/ASTUnit.h"
|
|
#include "clang/Testing/CommandLineArgs.h"
|
|
#include "clang/Tooling/Tooling.h"
|
|
#include "llvm/TargetParser/Host.h"
|
|
|
|
#include "DeclMatcher.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace clang {
|
|
namespace ast_matchers {
|
|
|
|
using std::get;
|
|
|
|
struct StructuralEquivalenceTest : ::testing::Test {
|
|
std::unique_ptr<ASTUnit> AST0, AST1;
|
|
std::string Code0, Code1; // Buffers for SourceManager
|
|
|
|
// Parses the source code in the specified language and sets the ASTs of
|
|
// the current test instance to the parse result.
|
|
void makeASTUnits(const std::string &SrcCode0, const std::string &SrcCode1,
|
|
TestLanguage Lang) {
|
|
this->Code0 = SrcCode0;
|
|
this->Code1 = SrcCode1;
|
|
std::vector<std::string> Args = getCommandLineArgsForTesting(Lang);
|
|
|
|
const char *const InputFileName = "input.cc";
|
|
|
|
AST0 = tooling::buildASTFromCodeWithArgs(Code0, Args, InputFileName);
|
|
AST1 = tooling::buildASTFromCodeWithArgs(Code1, Args, InputFileName);
|
|
}
|
|
|
|
// Get a pair of node pointers into the synthesized AST from the given code
|
|
// snippets. To determine the returned node, a separate matcher is specified
|
|
// for both snippets. The first matching node is returned.
|
|
template <typename NodeType, typename MatcherType>
|
|
std::tuple<NodeType *, NodeType *>
|
|
makeDecls(const std::string &SrcCode0, const std::string &SrcCode1,
|
|
TestLanguage Lang, const MatcherType &Matcher0,
|
|
const MatcherType &Matcher1) {
|
|
makeASTUnits(SrcCode0, SrcCode1, Lang);
|
|
|
|
NodeType *D0 = FirstDeclMatcher<NodeType>().match(
|
|
AST0->getASTContext().getTranslationUnitDecl(), Matcher0);
|
|
NodeType *D1 = FirstDeclMatcher<NodeType>().match(
|
|
AST1->getASTContext().getTranslationUnitDecl(), Matcher1);
|
|
|
|
return std::make_tuple(D0, D1);
|
|
}
|
|
|
|
std::tuple<TranslationUnitDecl *, TranslationUnitDecl *>
|
|
makeTuDecls(const std::string &SrcCode0, const std::string &SrcCode1,
|
|
TestLanguage Lang) {
|
|
makeASTUnits(SrcCode0, SrcCode1, Lang);
|
|
|
|
return std::make_tuple(AST0->getASTContext().getTranslationUnitDecl(),
|
|
AST1->getASTContext().getTranslationUnitDecl());
|
|
}
|
|
|
|
// Get a pair of node pointers into the synthesized AST from the given code
|
|
// snippets. The same matcher is used for both snippets.
|
|
template <typename NodeType, typename MatcherType>
|
|
std::tuple<NodeType *, NodeType *>
|
|
makeDecls(const std::string &SrcCode0, const std::string &SrcCode1,
|
|
TestLanguage Lang, const MatcherType &AMatcher) {
|
|
return makeDecls<NodeType, MatcherType>(
|
|
SrcCode0, SrcCode1, Lang, AMatcher, AMatcher);
|
|
}
|
|
|
|
// Get a pair of Decl pointers to the synthesized declarations from the given
|
|
// code snippets. We search for the first NamedDecl with given name in both
|
|
// snippets.
|
|
std::tuple<NamedDecl *, NamedDecl *>
|
|
makeNamedDecls(const std::string &SrcCode0, const std::string &SrcCode1,
|
|
TestLanguage Lang, const char *const Identifier = "foo") {
|
|
auto Matcher = namedDecl(hasName(Identifier));
|
|
return makeDecls<NamedDecl>(SrcCode0, SrcCode1, Lang, Matcher);
|
|
}
|
|
|
|
// Wraps a Stmt and the ASTContext that contains it.
|
|
struct StmtWithASTContext {
|
|
Stmt *S;
|
|
ASTContext *Context;
|
|
explicit StmtWithASTContext(Stmt &S, ASTContext &Context)
|
|
: S(&S), Context(&Context) {}
|
|
explicit StmtWithASTContext(FunctionDecl *FD)
|
|
: S(FD->getBody()), Context(&FD->getASTContext()) {}
|
|
};
|
|
|
|
// Get a pair of node pointers into the synthesized AST from the given code
|
|
// snippets. To determine the returned node, a separate matcher is specified
|
|
// for both snippets. The first matching node is returned.
|
|
template <typename MatcherType>
|
|
std::tuple<StmtWithASTContext, StmtWithASTContext>
|
|
makeStmts(const std::string &SrcCode0, const std::string &SrcCode1,
|
|
TestLanguage Lang, const MatcherType &Matcher0,
|
|
const MatcherType &Matcher1) {
|
|
makeASTUnits(SrcCode0, SrcCode1, Lang);
|
|
|
|
Stmt *S0 = FirstDeclMatcher<Stmt>().match(
|
|
AST0->getASTContext().getTranslationUnitDecl(), Matcher0);
|
|
Stmt *S1 = FirstDeclMatcher<Stmt>().match(
|
|
AST1->getASTContext().getTranslationUnitDecl(), Matcher1);
|
|
|
|
return std::make_tuple(StmtWithASTContext(*S0, AST0->getASTContext()),
|
|
StmtWithASTContext(*S1, AST1->getASTContext()));
|
|
}
|
|
|
|
// Get a pair of node pointers into the synthesized AST from the given code
|
|
// snippets. The same matcher is used for both snippets.
|
|
template <typename MatcherType>
|
|
std::tuple<StmtWithASTContext, StmtWithASTContext>
|
|
makeStmts(const std::string &SrcCode0, const std::string &SrcCode1,
|
|
TestLanguage Lang, const MatcherType &AMatcher) {
|
|
return makeStmts(SrcCode0, SrcCode1, Lang, AMatcher, AMatcher);
|
|
}
|
|
|
|
// Convenience function for makeStmts that wraps the code inside a function
|
|
// body.
|
|
template <typename MatcherType>
|
|
std::tuple<StmtWithASTContext, StmtWithASTContext>
|
|
makeWrappedStmts(const std::string &SrcCode0, const std::string &SrcCode1,
|
|
TestLanguage Lang, const MatcherType &AMatcher) {
|
|
auto Wrap = [](const std::string &Src) {
|
|
return "void wrapped() {" + Src + ";}";
|
|
};
|
|
return makeStmts(Wrap(SrcCode0), Wrap(SrcCode1), Lang, AMatcher);
|
|
}
|
|
|
|
bool testStructuralMatch(Decl *D0, Decl *D1,
|
|
bool IgnoreTemplateParmDepth = false) {
|
|
StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls01;
|
|
StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls10;
|
|
StructuralEquivalenceContext Ctx01(
|
|
D0->getASTContext(), D1->getASTContext(), NonEquivalentDecls01,
|
|
StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false,
|
|
/*Complain=*/false, /*ErrorOnTagTypeMismatch=*/false,
|
|
IgnoreTemplateParmDepth);
|
|
StructuralEquivalenceContext Ctx10(
|
|
D1->getASTContext(), D0->getASTContext(), NonEquivalentDecls10,
|
|
StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false,
|
|
/*Complain=*/false, /*ErrorOnTagTypeMismatch=*/false,
|
|
IgnoreTemplateParmDepth);
|
|
bool Eq01 = Ctx01.IsEquivalent(D0, D1);
|
|
bool Eq10 = Ctx10.IsEquivalent(D1, D0);
|
|
EXPECT_EQ(Eq01, Eq10);
|
|
return Eq01;
|
|
}
|
|
|
|
bool testStructuralMatch(StmtWithASTContext S0, StmtWithASTContext S1) {
|
|
StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls01;
|
|
StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls10;
|
|
StructuralEquivalenceContext Ctx01(
|
|
*S0.Context, *S1.Context, NonEquivalentDecls01,
|
|
StructuralEquivalenceKind::Default, false, false);
|
|
StructuralEquivalenceContext Ctx10(
|
|
*S1.Context, *S0.Context, NonEquivalentDecls10,
|
|
StructuralEquivalenceKind::Default, false, false);
|
|
bool Eq01 = Ctx01.IsEquivalent(S0.S, S1.S);
|
|
bool Eq10 = Ctx10.IsEquivalent(S1.S, S0.S);
|
|
EXPECT_EQ(Eq01, Eq10);
|
|
return Eq01;
|
|
}
|
|
|
|
bool
|
|
testStructuralMatch(std::tuple<StmtWithASTContext, StmtWithASTContext> t) {
|
|
return testStructuralMatch(get<0>(t), get<1>(t));
|
|
}
|
|
|
|
bool testStructuralMatch(std::tuple<Decl *, Decl *> t,
|
|
bool IgnoreTemplateParmDepth = false) {
|
|
return testStructuralMatch(get<0>(t), get<1>(t), IgnoreTemplateParmDepth);
|
|
}
|
|
};
|
|
|
|
TEST_F(StructuralEquivalenceTest, Int) {
|
|
auto Decls = makeNamedDecls("int foo;", "int foo;", Lang_CXX03);
|
|
EXPECT_TRUE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, IntVsSignedInt) {
|
|
auto Decls = makeNamedDecls("int foo;", "signed int foo;", Lang_CXX03);
|
|
EXPECT_TRUE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, Char) {
|
|
auto Decls = makeNamedDecls("char foo;", "char foo;", Lang_CXX03);
|
|
EXPECT_TRUE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
// This test is disabled for now.
|
|
// FIXME Whether this is equivalent is dependent on the target.
|
|
TEST_F(StructuralEquivalenceTest, DISABLED_CharVsSignedChar) {
|
|
auto Decls = makeNamedDecls("char foo;", "signed char foo;", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, ForwardRecordDecl) {
|
|
auto Decls = makeNamedDecls("struct foo;", "struct foo;", Lang_CXX03);
|
|
EXPECT_TRUE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, IntVsSignedIntInStruct) {
|
|
auto Decls = makeNamedDecls("struct foo { int x; };",
|
|
"struct foo { signed int x; };", Lang_CXX03);
|
|
EXPECT_TRUE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, CharVsSignedCharInStruct) {
|
|
auto Decls = makeNamedDecls("struct foo { char x; };",
|
|
"struct foo { signed char x; };", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, IntVsSignedIntTemplateSpec) {
|
|
auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
|
|
R"(template <class T> struct foo; template<> struct foo<int>{};)",
|
|
R"(template <class T> struct foo; template<> struct foo<signed int>{};)",
|
|
Lang_CXX03, classTemplateSpecializationDecl());
|
|
auto Spec0 = get<0>(Decls);
|
|
auto Spec1 = get<1>(Decls);
|
|
EXPECT_TRUE(testStructuralMatch(Spec0, Spec1));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpec) {
|
|
auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
|
|
R"(template <class T> struct foo; template<> struct foo<char>{};)",
|
|
R"(template <class T> struct foo; template<> struct foo<signed char>{};)",
|
|
Lang_CXX03, classTemplateSpecializationDecl());
|
|
auto Spec0 = get<0>(Decls);
|
|
auto Spec1 = get<1>(Decls);
|
|
EXPECT_FALSE(testStructuralMatch(Spec0, Spec1));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpecWithInheritance) {
|
|
auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
|
|
R"(
|
|
struct true_type{};
|
|
template <class T> struct foo;
|
|
template<> struct foo<char> : true_type {};
|
|
)",
|
|
R"(
|
|
struct true_type{};
|
|
template <class T> struct foo;
|
|
template<> struct foo<signed char> : true_type {};
|
|
)",
|
|
Lang_CXX03, classTemplateSpecializationDecl());
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
// This test is disabled for now.
|
|
// FIXME Enable it, once the check is implemented.
|
|
TEST_F(StructuralEquivalenceTest, DISABLED_WrongOrderInNamespace) {
|
|
auto Code =
|
|
R"(
|
|
namespace NS {
|
|
template <class T> class Base {
|
|
int a;
|
|
};
|
|
class Derived : Base<Derived> {
|
|
};
|
|
}
|
|
void foo(NS::Derived &);
|
|
)";
|
|
auto Decls = makeNamedDecls(Code, Code, Lang_CXX03);
|
|
|
|
NamespaceDecl *NS =
|
|
LastDeclMatcher<NamespaceDecl>().match(get<1>(Decls), namespaceDecl());
|
|
ClassTemplateDecl *TD = LastDeclMatcher<ClassTemplateDecl>().match(
|
|
get<1>(Decls), classTemplateDecl(hasName("Base")));
|
|
|
|
// Reorder the decls, move the TD to the last place in the DC.
|
|
NS->removeDecl(TD);
|
|
NS->addDeclInternal(TD);
|
|
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, WrongOrderOfFieldsInClass) {
|
|
auto Code = "class X { int a; int b; };";
|
|
auto Decls = makeNamedDecls(Code, Code, Lang_CXX03, "X");
|
|
|
|
CXXRecordDecl *RD = FirstDeclMatcher<CXXRecordDecl>().match(
|
|
get<1>(Decls), cxxRecordDecl(hasName("X")));
|
|
FieldDecl *FD =
|
|
FirstDeclMatcher<FieldDecl>().match(get<1>(Decls), fieldDecl(hasName("a")));
|
|
|
|
// Reorder the FieldDecls
|
|
RD->removeDecl(FD);
|
|
RD->addDeclInternal(FD);
|
|
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
struct StructuralEquivalenceFunctionTest : StructuralEquivalenceTest {
|
|
};
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, TemplateVsNonTemplate) {
|
|
auto t = makeNamedDecls("void foo();", "template<class T> void foo();",
|
|
Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, DifferentOperators) {
|
|
auto t = makeDecls<FunctionDecl>(
|
|
"struct X{}; bool operator<(X, X);", "struct X{}; bool operator==(X, X);",
|
|
Lang_CXX03, functionDecl(hasOverloadedOperatorName("<")),
|
|
functionDecl(hasOverloadedOperatorName("==")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, SameOperators) {
|
|
auto t = makeDecls<FunctionDecl>(
|
|
"struct X{}; bool operator<(X, X);", "struct X{}; bool operator<(X, X);",
|
|
Lang_CXX03, functionDecl(hasOverloadedOperatorName("<")),
|
|
functionDecl(hasOverloadedOperatorName("<")));
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, CtorVsDtor) {
|
|
auto t = makeDecls<FunctionDecl>("struct X{ X(); };", "struct X{ ~X(); };",
|
|
Lang_CXX03, cxxConstructorDecl(),
|
|
cxxDestructorDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) {
|
|
auto t =
|
|
makeNamedDecls("void foo(int&);", "void foo(const int&);", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, ParamConstSimple) {
|
|
auto t = makeNamedDecls("void foo(int);", "void foo(const int);", Lang_CXX03);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
// consider this OK
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, Throw) {
|
|
auto t = makeNamedDecls("void foo();", "void foo() throw();", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, Noexcept) {
|
|
auto t = makeNamedDecls("void foo();",
|
|
"void foo() noexcept;", Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexcept) {
|
|
auto t = makeNamedDecls("void foo() throw();",
|
|
"void foo() noexcept;", Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptFalse) {
|
|
auto t = makeNamedDecls("void foo() throw();",
|
|
"void foo() noexcept(false);", Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptTrue) {
|
|
auto t = makeNamedDecls("void foo() throw();",
|
|
"void foo() noexcept(true);", Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, NoexceptNonMatch) {
|
|
auto t = makeNamedDecls("void foo() noexcept(false);",
|
|
"void foo() noexcept(true);", Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, NoexceptMatch) {
|
|
auto t = makeNamedDecls("void foo() noexcept(false);",
|
|
"void foo() noexcept(false);", Lang_CXX11);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptFalse) {
|
|
auto t = makeNamedDecls("void foo() noexcept;",
|
|
"void foo() noexcept(false);", Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptTrue) {
|
|
auto t = makeNamedDecls("void foo() noexcept;",
|
|
"void foo() noexcept(true);", Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, ReturnType) {
|
|
auto t = makeNamedDecls("char foo();", "int foo();", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, ReturnConst) {
|
|
auto t = makeNamedDecls("char foo();", "const char foo();", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, ReturnRef) {
|
|
auto t = makeNamedDecls("char &foo();",
|
|
"char &&foo();", Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, ParamCount) {
|
|
auto t = makeNamedDecls("void foo(int);", "void foo(int, int);", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, ParamType) {
|
|
auto t = makeNamedDecls("void foo(int);", "void foo(char);", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, ParamName) {
|
|
auto t = makeNamedDecls("void foo(int a);", "void foo(int b);", Lang_CXX03);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, Variadic) {
|
|
auto t =
|
|
makeNamedDecls("void foo(int x...);", "void foo(int x);", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, ParamPtr) {
|
|
auto t = makeNamedDecls("void foo(int *);", "void foo(int);", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, NameInParen) {
|
|
auto t = makeNamedDecls("void ((foo))();", "void foo();", Lang_CXX03);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithExceptionSpec) {
|
|
auto t = makeNamedDecls(
|
|
"void (foo)() throw(int);",
|
|
"void (foo)() noexcept;",
|
|
Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithConst) {
|
|
auto t = makeNamedDecls(
|
|
"struct A { void (foo)() const; };",
|
|
"struct A { void (foo)(); };",
|
|
Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, FunctionsWithDifferentNoreturnAttr) {
|
|
auto t = makeNamedDecls("__attribute__((noreturn)) void foo();",
|
|
" void foo();", Lang_C99);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest,
|
|
FunctionsWithDifferentCallingConventions) {
|
|
// These attributes may not be available on certain platforms.
|
|
if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getArch() !=
|
|
llvm::Triple::x86_64)
|
|
GTEST_SKIP();
|
|
auto t = makeNamedDecls("__attribute__((preserve_all)) void foo();",
|
|
"__attribute__((ms_abi)) void foo();", Lang_C99);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceFunctionTest, FunctionsWithDifferentSavedRegsAttr) {
|
|
if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getArch() !=
|
|
llvm::Triple::x86_64)
|
|
GTEST_SKIP();
|
|
auto t = makeNamedDecls(
|
|
"__attribute__((no_caller_saved_registers)) void foo();",
|
|
" void foo();", Lang_C99);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
struct StructuralEquivalenceCXXMethodTest : StructuralEquivalenceTest {
|
|
};
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, Virtual) {
|
|
auto t = makeDecls<CXXMethodDecl>("struct X { void foo(); };",
|
|
"struct X { virtual void foo(); };",
|
|
Lang_CXX03, cxxMethodDecl(hasName("foo")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, Pure) {
|
|
auto t = makeNamedDecls("struct X { virtual void foo(); };",
|
|
"struct X { virtual void foo() = 0; };", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, DISABLED_Final) {
|
|
// The final-ness is not checked yet.
|
|
auto t =
|
|
makeNamedDecls("struct X { virtual void foo(); };",
|
|
"struct X { virtual void foo() final; };", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, Const) {
|
|
auto t = makeNamedDecls("struct X { void foo(); };",
|
|
"struct X { void foo() const; };", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, Static) {
|
|
auto t = makeNamedDecls("struct X { void foo(); };",
|
|
"struct X { static void foo(); };", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, Ref1) {
|
|
auto t = makeNamedDecls("struct X { void foo(); };",
|
|
"struct X { void foo() &&; };", Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, Ref2) {
|
|
auto t = makeNamedDecls("struct X { void foo() &; };",
|
|
"struct X { void foo() &&; };", Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, AccessSpecifier) {
|
|
auto t = makeDecls<CXXMethodDecl>("struct X { public: void foo(); };",
|
|
"struct X { private: void foo(); };",
|
|
Lang_CXX03, cxxMethodDecl(hasName("foo")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, Delete) {
|
|
auto t = makeNamedDecls("struct X { void foo(); };",
|
|
"struct X { void foo() = delete; };", Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, Constructor) {
|
|
auto t = makeDecls<FunctionDecl>("void foo();", "struct foo { foo(); };",
|
|
Lang_CXX03, functionDecl(hasName("foo")),
|
|
cxxConstructorDecl(hasName("foo")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorParam) {
|
|
auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
|
|
"struct X { X(int); };", Lang_CXX03,
|
|
cxxConstructorDecl(hasName("X")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorExplicit) {
|
|
auto t = makeDecls<CXXConstructorDecl>("struct X { X(int); };",
|
|
"struct X { explicit X(int); };",
|
|
Lang_CXX11,
|
|
cxxConstructorDecl(hasName("X")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorDefault) {
|
|
auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
|
|
"struct X { X() = default; };",
|
|
Lang_CXX11,
|
|
cxxConstructorDecl(hasName("X")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, Conversion) {
|
|
auto t = makeDecls<CXXConversionDecl>("struct X { operator bool(); };",
|
|
"struct X { operator char(); };",
|
|
Lang_CXX11,
|
|
cxxConversionDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, Operator) {
|
|
auto t =
|
|
makeDecls<FunctionDecl>("struct X { int operator +(int); };",
|
|
"struct X { int operator -(int); };", Lang_CXX03,
|
|
functionDecl(hasOverloadedOperatorName("+")),
|
|
functionDecl(hasOverloadedOperatorName("-")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass1) {
|
|
auto t = makeDecls<FunctionDecl>(
|
|
"struct X { virtual void f(); }; void X::f() { }",
|
|
"struct X { virtual void f() { }; };", Lang_CXX03,
|
|
functionDecl(allOf(hasName("f"), isDefinition())));
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass2) {
|
|
auto t = makeDecls<FunctionDecl>(
|
|
"struct X { virtual void f(); }; void X::f() { }",
|
|
"struct X { void f(); }; void X::f() { }", Lang_CXX03,
|
|
functionDecl(allOf(hasName("f"), isDefinition())));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
struct StructuralEquivalenceRecordTest : StructuralEquivalenceTest {
|
|
// FIXME Use a common getRecordDecl with ASTImporterTest.cpp!
|
|
RecordDecl *getRecordDecl(FieldDecl *FD) {
|
|
auto *ET = cast<ElaboratedType>(FD->getType().getTypePtr());
|
|
return cast<RecordType>(ET->getNamedType().getTypePtr())->getDecl();
|
|
};
|
|
};
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, Name) {
|
|
auto t = makeDecls<CXXRecordDecl>("struct A{ };", "struct B{ };", Lang_CXX03,
|
|
cxxRecordDecl(hasName("A")),
|
|
cxxRecordDecl(hasName("B")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, Fields) {
|
|
auto t = makeNamedDecls("struct foo{ int x; };", "struct foo{ char x; };",
|
|
Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, DISABLED_Methods) {
|
|
// Currently, methods of a class are not checked at class equivalence.
|
|
auto t = makeNamedDecls("struct foo{ int x(); };", "struct foo{ char x(); };",
|
|
Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, Bases) {
|
|
auto t = makeNamedDecls("struct A{ }; struct foo: A { };",
|
|
"struct B{ }; struct foo: B { };", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, InheritanceVirtual) {
|
|
auto t =
|
|
makeNamedDecls("struct A{ }; struct foo: A { };",
|
|
"struct A{ }; struct foo: virtual A { };", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, DISABLED_InheritanceType) {
|
|
// Access specifier in inheritance is not checked yet.
|
|
auto t =
|
|
makeNamedDecls("struct A{ }; struct foo: public A { };",
|
|
"struct A{ }; struct foo: private A { };", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, Match) {
|
|
auto Code = R"(
|
|
struct A{ };
|
|
struct B{ };
|
|
struct foo: A, virtual B {
|
|
void x();
|
|
int a;
|
|
};
|
|
)";
|
|
auto t = makeNamedDecls(Code, Code, Lang_CXX03);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, UnnamedRecordsShouldBeInequivalent) {
|
|
auto t = makeTuDecls(
|
|
R"(
|
|
struct A {
|
|
struct {
|
|
struct A *next;
|
|
} entry0;
|
|
struct {
|
|
struct A *next;
|
|
} entry1;
|
|
};
|
|
)",
|
|
"", Lang_C99);
|
|
auto *TU = get<0>(t);
|
|
auto *Entry0 =
|
|
FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry0")));
|
|
auto *Entry1 =
|
|
FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry1")));
|
|
auto *R0 = getRecordDecl(Entry0);
|
|
auto *R1 = getRecordDecl(Entry1);
|
|
|
|
ASSERT_NE(R0, R1);
|
|
EXPECT_TRUE(testStructuralMatch(R0, R0));
|
|
EXPECT_TRUE(testStructuralMatch(R1, R1));
|
|
EXPECT_FALSE(testStructuralMatch(R0, R1));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, AnonymousRecordsShouldBeInequivalent) {
|
|
auto t = makeTuDecls(
|
|
R"(
|
|
struct X {
|
|
struct {
|
|
int a;
|
|
};
|
|
struct {
|
|
int b;
|
|
};
|
|
};
|
|
)",
|
|
"", Lang_C99);
|
|
auto *TU = get<0>(t);
|
|
auto *A = FirstDeclMatcher<IndirectFieldDecl>().match(
|
|
TU, indirectFieldDecl(hasName("a")));
|
|
auto *FA = cast<FieldDecl>(A->chain().front());
|
|
RecordDecl *RA = cast<RecordType>(FA->getType().getTypePtr())->getDecl();
|
|
auto *B = FirstDeclMatcher<IndirectFieldDecl>().match(
|
|
TU, indirectFieldDecl(hasName("b")));
|
|
auto *FB = cast<FieldDecl>(B->chain().front());
|
|
RecordDecl *RB = cast<RecordType>(FB->getType().getTypePtr())->getDecl();
|
|
|
|
ASSERT_NE(RA, RB);
|
|
EXPECT_TRUE(testStructuralMatch(RA, RA));
|
|
EXPECT_TRUE(testStructuralMatch(RB, RB));
|
|
EXPECT_FALSE(testStructuralMatch(RA, RB));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest,
|
|
RecordsAreInequivalentIfOrderOfAnonRecordsIsDifferent) {
|
|
auto t = makeTuDecls(
|
|
R"(
|
|
struct X {
|
|
struct { int a; };
|
|
struct { int b; };
|
|
};
|
|
)",
|
|
R"(
|
|
struct X { // The order is reversed.
|
|
struct { int b; };
|
|
struct { int a; };
|
|
};
|
|
)",
|
|
Lang_C99);
|
|
|
|
auto *TU = get<0>(t);
|
|
auto *A = FirstDeclMatcher<IndirectFieldDecl>().match(
|
|
TU, indirectFieldDecl(hasName("a")));
|
|
auto *FA = cast<FieldDecl>(A->chain().front());
|
|
RecordDecl *RA = cast<RecordType>(FA->getType().getTypePtr())->getDecl();
|
|
|
|
auto *TU1 = get<1>(t);
|
|
auto *A1 = FirstDeclMatcher<IndirectFieldDecl>().match(
|
|
TU1, indirectFieldDecl(hasName("a")));
|
|
auto *FA1 = cast<FieldDecl>(A1->chain().front());
|
|
RecordDecl *RA1 = cast<RecordType>(FA1->getType().getTypePtr())->getDecl();
|
|
|
|
RecordDecl *X =
|
|
FirstDeclMatcher<RecordDecl>().match(TU, recordDecl(hasName("X")));
|
|
RecordDecl *X1 =
|
|
FirstDeclMatcher<RecordDecl>().match(TU1, recordDecl(hasName("X")));
|
|
ASSERT_NE(X, X1);
|
|
EXPECT_FALSE(testStructuralMatch(X, X1));
|
|
|
|
ASSERT_NE(RA, RA1);
|
|
EXPECT_TRUE(testStructuralMatch(RA, RA));
|
|
EXPECT_TRUE(testStructuralMatch(RA1, RA1));
|
|
EXPECT_FALSE(testStructuralMatch(RA1, RA));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest,
|
|
UnnamedRecordsShouldBeInequivalentEvenIfTheSecondIsBeingDefined) {
|
|
auto Code =
|
|
R"(
|
|
struct A {
|
|
struct {
|
|
struct A *next;
|
|
} entry0;
|
|
struct {
|
|
struct A *next;
|
|
} entry1;
|
|
};
|
|
)";
|
|
auto t = makeTuDecls(Code, Code, Lang_C99);
|
|
|
|
auto *FromTU = get<0>(t);
|
|
auto *Entry1 =
|
|
FirstDeclMatcher<FieldDecl>().match(FromTU, fieldDecl(hasName("entry1")));
|
|
|
|
auto *ToTU = get<1>(t);
|
|
auto *Entry0 =
|
|
FirstDeclMatcher<FieldDecl>().match(ToTU, fieldDecl(hasName("entry0")));
|
|
auto *A =
|
|
FirstDeclMatcher<RecordDecl>().match(ToTU, recordDecl(hasName("A")));
|
|
A->startDefinition(); // Set isBeingDefined, getDefinition() will return a
|
|
// nullptr. This may be the case during ASTImport.
|
|
|
|
auto *R0 = getRecordDecl(Entry0);
|
|
auto *R1 = getRecordDecl(Entry1);
|
|
|
|
ASSERT_NE(R0, R1);
|
|
EXPECT_TRUE(testStructuralMatch(R0, R0));
|
|
EXPECT_TRUE(testStructuralMatch(R1, R1));
|
|
EXPECT_FALSE(testStructuralMatch(R0, R1));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, TemplateVsNonTemplate) {
|
|
auto t = makeDecls<CXXRecordDecl>("struct A { };",
|
|
"template<class T> struct A { };",
|
|
Lang_CXX03, cxxRecordDecl(hasName("A")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest,
|
|
FwdDeclRecordShouldBeEqualWithFwdDeclRecord) {
|
|
auto t = makeNamedDecls("class foo;", "class foo;", Lang_CXX11);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest,
|
|
FwdDeclRecordShouldBeEqualWithRecordWhichHasDefinition) {
|
|
auto t =
|
|
makeNamedDecls("class foo;", "class foo { int A; };", Lang_CXX11);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest,
|
|
RecordShouldBeEqualWithRecordWhichHasDefinition) {
|
|
auto t = makeNamedDecls("class foo { int A; };", "class foo { int A; };",
|
|
Lang_CXX11);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, RecordsWithDifferentBody) {
|
|
auto t = makeNamedDecls("class foo { int B; };", "class foo { int A; };",
|
|
Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, SameFriendMultipleTimes) {
|
|
auto t = makeNamedDecls("struct foo { friend class X; };",
|
|
"struct foo { friend class X; friend class X; };",
|
|
Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, SameFriendsDifferentOrder) {
|
|
auto t = makeNamedDecls("struct foo { friend class X; friend class Y; };",
|
|
"struct foo { friend class Y; friend class X; };",
|
|
Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordTest, SameFriendsSameOrder) {
|
|
auto t = makeNamedDecls("struct foo { friend class X; friend class Y; };",
|
|
"struct foo { friend class X; friend class Y; };",
|
|
Lang_CXX11);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
struct StructuralEquivalenceLambdaTest : StructuralEquivalenceTest {};
|
|
|
|
TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithDifferentMethods) {
|
|
// Get the LambdaExprs, unfortunately we can't match directly the underlying
|
|
// implicit CXXRecordDecl of the Lambda classes.
|
|
auto t = makeDecls<LambdaExpr>(
|
|
"void f() { auto L0 = [](int){}; }",
|
|
"void f() { auto L1 = [](){}; }",
|
|
Lang_CXX11,
|
|
lambdaExpr(),
|
|
lambdaExpr());
|
|
CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
|
|
CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
|
|
EXPECT_FALSE(testStructuralMatch(L0, L1));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithEqMethods) {
|
|
auto t = makeDecls<LambdaExpr>(
|
|
"void f() { auto L0 = [](int){}; }",
|
|
"void f() { auto L1 = [](int){}; }",
|
|
Lang_CXX11,
|
|
lambdaExpr(),
|
|
lambdaExpr());
|
|
CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
|
|
CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
|
|
EXPECT_TRUE(testStructuralMatch(L0, L1));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithDifferentFields) {
|
|
auto t = makeDecls<LambdaExpr>(
|
|
"void f() { char* X; auto L0 = [X](){}; }",
|
|
"void f() { float X; auto L1 = [X](){}; }",
|
|
Lang_CXX11,
|
|
lambdaExpr(),
|
|
lambdaExpr());
|
|
CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
|
|
CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
|
|
EXPECT_FALSE(testStructuralMatch(L0, L1));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithEqFields) {
|
|
auto t = makeDecls<LambdaExpr>(
|
|
"void f() { float X; auto L0 = [X](){}; }",
|
|
"void f() { float X; auto L1 = [X](){}; }",
|
|
Lang_CXX11,
|
|
lambdaExpr(),
|
|
lambdaExpr());
|
|
CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
|
|
CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
|
|
EXPECT_TRUE(testStructuralMatch(L0, L1));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
|
|
auto t = makeNamedDecls("struct A{ }; struct B{ }; void foo(A a, A b);",
|
|
"struct A{ }; struct B{ }; void foo(A a, B b);",
|
|
Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, ExplicitBoolDifferent) {
|
|
auto Decls = makeNamedDecls("struct foo {explicit(false) foo(int);};",
|
|
"struct foo {explicit(true) foo(int);};", Lang_CXX20);
|
|
CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
|
|
get<0>(Decls), cxxConstructorDecl(hasName("foo")));
|
|
CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
|
|
get<1>(Decls), cxxConstructorDecl(hasName("foo")));
|
|
EXPECT_FALSE(testStructuralMatch(First, Second));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, ExplicitBoolSame) {
|
|
auto Decls = makeNamedDecls("struct foo {explicit(true) foo(int);};",
|
|
"struct foo {explicit(true) foo(int);};", Lang_CXX20);
|
|
CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
|
|
get<0>(Decls), cxxConstructorDecl(hasName("foo")));
|
|
CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
|
|
get<1>(Decls), cxxConstructorDecl(hasName("foo")));
|
|
EXPECT_TRUE(testStructuralMatch(First, Second));
|
|
}
|
|
|
|
struct StructuralEquivalenceRecordContextTest : StructuralEquivalenceTest {};
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest, NamespaceNoVsNamed) {
|
|
auto Decls =
|
|
makeNamedDecls("class X;", "namespace N { class X; }", Lang_CXX03, "X");
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest, NamespaceNamedVsNamed) {
|
|
auto Decls = makeNamedDecls("namespace A { class X; }",
|
|
"namespace B { class X; }", Lang_CXX03, "X");
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest, NamespaceAnonVsNamed) {
|
|
auto Decls = makeNamedDecls("namespace { class X; }",
|
|
"namespace N { class X; }", Lang_CXX03, "X");
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest, NamespaceNoVsAnon) {
|
|
auto Decls =
|
|
makeNamedDecls("class X;", "namespace { class X; }", Lang_CXX03, "X");
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest, NamespaceAnonVsAnon) {
|
|
auto Decls = makeNamedDecls("namespace { class X; }",
|
|
"namespace { class X; }", Lang_CXX03, "X");
|
|
EXPECT_TRUE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest, NamespaceAnonVsAnonAnon) {
|
|
auto Decls =
|
|
makeNamedDecls("namespace { class X; }",
|
|
"namespace { namespace { class X; } }", Lang_CXX03, "X");
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest,
|
|
NamespaceNamedNamedVsNamedNamed) {
|
|
auto Decls = makeNamedDecls("namespace A { namespace N { class X; } }",
|
|
"namespace B { namespace N { class X; } }",
|
|
Lang_CXX03, "X");
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest, NamespaceNamedVsInline) {
|
|
auto Decls = makeNamedDecls("namespace A { namespace A { class X; } }",
|
|
"namespace A { inline namespace A { class X; } }",
|
|
Lang_CXX17, "X");
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest, NamespaceInlineVsInline) {
|
|
auto Decls = makeNamedDecls("namespace A { inline namespace A { class X; } }",
|
|
"namespace A { inline namespace B { class X; } }",
|
|
Lang_CXX17, "X");
|
|
EXPECT_TRUE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest, NamespaceInlineTopLevel) {
|
|
auto Decls =
|
|
makeNamedDecls("inline namespace A { class X; }",
|
|
"inline namespace B { class X; }", Lang_CXX17, "X");
|
|
EXPECT_TRUE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest, TransparentContext) {
|
|
auto Decls =
|
|
makeNamedDecls("extern \"C\" { class X; }", "class X;", Lang_CXX03, "X");
|
|
EXPECT_TRUE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest, TransparentContextNE) {
|
|
auto Decls = makeNamedDecls("extern \"C\" { class X; }",
|
|
"namespace { class X; }", Lang_CXX03, "X");
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest, TransparentContextInNamespace) {
|
|
auto Decls = makeNamedDecls("extern \"C\" { namespace N { class X; } }",
|
|
"namespace N { extern \"C\" { class X; } }",
|
|
Lang_CXX03, "X");
|
|
EXPECT_TRUE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest,
|
|
ClassTemplateSpecializationContext) {
|
|
std::string Code =
|
|
R"(
|
|
template <typename T> struct O {
|
|
struct M {};
|
|
};
|
|
)";
|
|
auto t = makeDecls<VarDecl>(Code + R"(
|
|
typedef O<int>::M MT1;
|
|
MT1 A;
|
|
)",
|
|
Code + R"(
|
|
namespace {
|
|
struct I {};
|
|
} // namespace
|
|
typedef O<I>::M MT2;
|
|
MT2 A;
|
|
)",
|
|
Lang_CXX11, varDecl(hasName("A")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, NamespaceOfRecordMember) {
|
|
auto Decls = makeNamedDecls(
|
|
R"(
|
|
class X;
|
|
class Y { X* x; };
|
|
)",
|
|
R"(
|
|
namespace N { class X; }
|
|
class Y { N::X* x; };
|
|
)",
|
|
Lang_CXX03, "Y");
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, StructDefinitionInPrototype) {
|
|
auto Decls =
|
|
makeNamedDecls("struct Param { int a; }; void foo(struct Param *p);",
|
|
"void foo(struct Param { int a; } *p);", Lang_C89);
|
|
EXPECT_TRUE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTest, StructDefinitionInPrototypeDifferentName) {
|
|
auto Decls =
|
|
makeNamedDecls("struct Param1 { int a; }; void foo(struct Param1 *p);",
|
|
"void foo(struct Param2 { int a; } *p);", Lang_C89);
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceRecordContextTest, RecordInsideFunction) {
|
|
auto Decls = makeNamedDecls("struct Param { int a; };",
|
|
"void f() { struct Param { int a; }; }", Lang_C89,
|
|
"Param");
|
|
EXPECT_TRUE(testStructuralMatch(Decls));
|
|
}
|
|
|
|
struct StructuralEquivalenceEnumTest : StructuralEquivalenceTest {};
|
|
|
|
TEST_F(StructuralEquivalenceEnumTest, FwdDeclEnumShouldBeEqualWithFwdDeclEnum) {
|
|
auto t = makeNamedDecls("enum class foo;", "enum class foo;", Lang_CXX11);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceEnumTest,
|
|
FwdDeclEnumShouldBeEqualWithEnumWhichHasDefinition) {
|
|
auto t =
|
|
makeNamedDecls("enum class foo;", "enum class foo { A };", Lang_CXX11);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceEnumTest,
|
|
EnumShouldBeEqualWithEnumWhichHasDefinition) {
|
|
auto t = makeNamedDecls("enum class foo { A };", "enum class foo { A };",
|
|
Lang_CXX11);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceEnumTest, EnumsWithDifferentBody) {
|
|
auto t = makeNamedDecls("enum class foo { B };", "enum class foo { A };",
|
|
Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceEnumTest, AnonymousEnumsWithSameConsts) {
|
|
// field x is required to trigger comparison of the anonymous enum
|
|
auto t = makeNamedDecls("struct foo { enum { A } x; };",
|
|
"struct foo { enum { A } x;};", Lang_CXX11);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceEnumTest, AnonymousEnumsWithDiffConsts) {
|
|
// field x is required to trigger comparison of the anonymous enum
|
|
auto t = makeNamedDecls("struct foo { enum { A } x; };",
|
|
"struct foo { enum { B } x;};", Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
struct StructuralEquivalenceEnumConstantTest : StructuralEquivalenceTest {};
|
|
|
|
TEST_F(StructuralEquivalenceEnumConstantTest, EnumConstantsWithSameValues) {
|
|
auto t = makeNamedDecls("enum foo { foo = 1 };", "enum foo { foo = 1 };",
|
|
Lang_C89);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceEnumConstantTest,
|
|
EnumConstantsWithDifferentValues) {
|
|
auto t =
|
|
makeNamedDecls("enum e { foo = 1 };", "enum e { foo = 2 };", Lang_C89);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceEnumConstantTest,
|
|
EnumConstantsWithDifferentExprsButSameValues) {
|
|
auto t = makeNamedDecls("enum e { foo = 1 + 1 };", "enum e { foo = 2 };",
|
|
Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceEnumConstantTest,
|
|
EnumConstantsWithDifferentSignedness) {
|
|
auto t = makeNamedDecls("enum e : unsigned { foo = 1 };",
|
|
"enum e : int { foo = 1 };", Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceEnumConstantTest, EnumConstantsWithDifferentWidth) {
|
|
auto t = makeNamedDecls("enum e : short { foo = 1 };",
|
|
"enum e : int { foo = 1 };", Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceEnumConstantTest, EnumConstantsWithDifferentName) {
|
|
auto t =
|
|
makeDecls<EnumConstantDecl>("enum e { foo = 1 };", "enum e { bar = 1 };",
|
|
Lang_CXX11, enumConstantDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
struct StructuralEquivalenceObjCCategoryTest : StructuralEquivalenceTest {};
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, MatchinCategoryNames) {
|
|
auto t = makeDecls<ObjCCategoryDecl>("@interface A @end @interface A(X) @end",
|
|
"@interface A @end @interface A(X) @end",
|
|
Lang_OBJC, objcCategoryDecl());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, CategoriesForDifferentClasses) {
|
|
auto t = makeDecls<ObjCCategoryDecl>("@interface A @end @interface A(X) @end",
|
|
"@interface B @end @interface B(X) @end",
|
|
Lang_OBJC, objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, CategoriesWithDifferentNames) {
|
|
auto t = makeDecls<ObjCCategoryDecl>("@interface A @end @interface A(X) @end",
|
|
"@interface A @end @interface A(Y) @end",
|
|
Lang_OBJC, objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, CategoriesWithoutInterfaces) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(" @interface A(X) @end",
|
|
"@interface A @end @interface A(X) @end",
|
|
Lang_OBJC, objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
|
|
auto t2 = makeDecls<ObjCCategoryDecl>("@interface A(X) @end",
|
|
"@interface A(X) @end",
|
|
Lang_OBJC, objcCategoryDecl());
|
|
EXPECT_TRUE(testStructuralMatch(t2));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, CategoryAndExtension) {
|
|
auto t = makeDecls<ObjCCategoryDecl>("@interface A @end @interface A(X) @end",
|
|
"@interface A @end @interface A() @end",
|
|
Lang_OBJC, objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, MatchingProtocols) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@protocol P @end @interface A @end @interface A(X)<P> @end",
|
|
"@protocol P @end @interface A @end @interface A(X)<P> @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentProtocols) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@protocol P @end @interface A @end @interface A(X)<P> @end",
|
|
"@protocol Q @end @interface A @end @interface A(X)<Q> @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentProtocolsOrder) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@protocol P @end @protocol Q @end @interface A @end @interface A(X)<P, "
|
|
"Q> @end",
|
|
"@protocol P @end @protocol Q @end @interface A @end @interface A(X)<Q, "
|
|
"P> @end",
|
|
Lang_OBJC, objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, MatchingIvars) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A() { int x; } @end",
|
|
"@interface A @end @interface A() { int x; } @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentIvarName) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A() { int x; } @end",
|
|
"@interface A @end @interface A() { int y; } @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentIvarType) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A() { int x; } @end",
|
|
"@interface A @end @interface A() { float x; } @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentIvarBitfieldWidth) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A() { int x: 1; } @end",
|
|
"@interface A @end @interface A() { int x: 2; } @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentIvarVisibility) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A() { @public int x; } @end",
|
|
"@interface A @end @interface A() { @protected int x; } @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentIvarNumber) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A() { int x; } @end",
|
|
"@interface A @end @interface A() {} @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentIvarOrder) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A() { int x; int y; } @end",
|
|
"@interface A @end @interface A() { int y; int x; } @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, MatchingMethods) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A(X) -(void)test; @end",
|
|
"@interface A @end @interface A(X) -(void)test; @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentMethodName) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A(X) -(void)test; @end",
|
|
"@interface A @end @interface A(X) -(void)wasd; @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
|
|
auto t2 = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A(X) -(void)test:(int)x more:(int)y; @end",
|
|
"@interface A @end @interface A(X) -(void)test:(int)x :(int)y; @end",
|
|
Lang_OBJC, objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t2));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentMethodClassInstance) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A(X) -(void)test; @end",
|
|
"@interface A @end @interface A(X) +(void)test; @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentMethodReturnType) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A(X) -(void)test; @end",
|
|
"@interface A @end @interface A(X) -(int)test; @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentMethodParameterType) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A(X) -(void)test:(int)x; @end",
|
|
"@interface A @end @interface A(X) -(void)test:(float)x; @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentMethodParameterName) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A(X) -(void)test:(int)x; @end",
|
|
"@interface A @end @interface A(X) -(void)test:(int)y; @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentMethodNumber) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A(X) -(void)test; @end",
|
|
"@interface A @end @interface A(X) @end", Lang_OBJC, objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceObjCCategoryTest, DifferentMethodOrder) {
|
|
auto t = makeDecls<ObjCCategoryDecl>(
|
|
"@interface A @end @interface A(X) -(void)u; -(void)v; @end",
|
|
"@interface A @end @interface A(X) -(void)v; -(void)u; @end", Lang_OBJC,
|
|
objcCategoryDecl());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
struct StructuralEquivalenceTemplateTest : StructuralEquivalenceTest {};
|
|
|
|
TEST_F(StructuralEquivalenceTemplateTest, ExactlySameTemplates) {
|
|
auto t = makeNamedDecls("template <class T> struct foo;",
|
|
"template <class T> struct foo;", Lang_CXX03);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgName) {
|
|
auto t = makeNamedDecls("template <class T> struct foo;",
|
|
"template <class U> struct foo;", Lang_CXX03);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgKind) {
|
|
auto t = makeNamedDecls("template <class T> struct foo;",
|
|
"template <int T> struct foo;", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTemplateTest, BitFieldDecl) {
|
|
const char *Code = "class foo { int a : 2; };";
|
|
auto t = makeNamedDecls(Code, Code, Lang_CXX03);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTemplateTest, BitFieldDeclDifferentWidth) {
|
|
auto t = makeNamedDecls("class foo { int a : 2; };",
|
|
"class foo { int a : 4; };", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTemplateTest, DependentBitFieldDecl) {
|
|
const char *Code = "template <class T> class foo { int a : sizeof(T); };";
|
|
auto t = makeNamedDecls(Code, Code, Lang_CXX03);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTemplateTest, DependentBitFieldDeclDifferentVal) {
|
|
auto t = makeNamedDecls(
|
|
"template <class A, class B> class foo { int a : sizeof(A); };",
|
|
"template <class A, class B> class foo { int a : sizeof(B); };",
|
|
Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTemplateTest, DependentBitFieldDeclDifferentVal2) {
|
|
auto t = makeNamedDecls(
|
|
"template <class A> class foo { int a : sizeof(A); };",
|
|
"template <class A> class foo { int a : sizeof(A) + 1; };", Lang_CXX03);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolSame) {
|
|
auto Decls = makeNamedDecls(
|
|
"template <bool b> struct foo {explicit(b) foo(int);};",
|
|
"template <bool b> struct foo {explicit(b) foo(int);};", Lang_CXX20);
|
|
CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
|
|
get<0>(Decls), cxxConstructorDecl(hasName("foo<b>")));
|
|
CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
|
|
get<1>(Decls), cxxConstructorDecl(hasName("foo<b>")));
|
|
EXPECT_TRUE(testStructuralMatch(First, Second));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolDifference) {
|
|
auto Decls = makeNamedDecls(
|
|
"template <bool b> struct foo {explicit(b) foo(int);};",
|
|
"template <bool b> struct foo {explicit(!b) foo(int);};", Lang_CXX20);
|
|
CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
|
|
get<0>(Decls), cxxConstructorDecl(hasName("foo<b>")));
|
|
CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
|
|
get<1>(Decls), cxxConstructorDecl(hasName("foo<b>")));
|
|
EXPECT_FALSE(testStructuralMatch(First, Second));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTemplateTest,
|
|
TemplateVsSubstTemplateTemplateParmInArgEq) {
|
|
auto t = makeDecls<ClassTemplateSpecializationDecl>(
|
|
R"(
|
|
template <typename P1> class Arg { };
|
|
template <template <typename PP1> class P1> class Primary { };
|
|
|
|
void f() {
|
|
// Make specialization with simple template.
|
|
Primary <Arg> A;
|
|
}
|
|
)",
|
|
R"(
|
|
template <typename P1> class Arg { };
|
|
template <template <typename PP1> class P1> class Primary { };
|
|
|
|
template <template <typename PP1> class P1> class Templ {
|
|
void f() {
|
|
// Make specialization with substituted template template param.
|
|
Primary <P1> A;
|
|
};
|
|
};
|
|
|
|
// Instantiate with substitution Arg into P1.
|
|
template class Templ <Arg>;
|
|
)",
|
|
Lang_CXX03, classTemplateSpecializationDecl(hasName("Primary")));
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTemplateTest,
|
|
TemplateVsSubstTemplateTemplateParmInArgNotEq) {
|
|
auto t = makeDecls<ClassTemplateSpecializationDecl>(
|
|
R"(
|
|
template <typename P1> class Arg { };
|
|
template <template <typename PP1> class P1> class Primary { };
|
|
|
|
void f() {
|
|
// Make specialization with simple template.
|
|
Primary <Arg> A;
|
|
}
|
|
)",
|
|
R"(
|
|
// Arg is different from the other, this should cause non-equivalence.
|
|
template <typename P1> class Arg { int X; };
|
|
template <template <typename PP1> class P1> class Primary { };
|
|
|
|
template <template <typename PP1> class P1> class Templ {
|
|
void f() {
|
|
// Make specialization with substituted template template param.
|
|
Primary <P1> A;
|
|
};
|
|
};
|
|
|
|
// Instantiate with substitution Arg into P1.
|
|
template class Templ <Arg>;
|
|
)",
|
|
Lang_CXX03, classTemplateSpecializationDecl(hasName("Primary")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
struct StructuralEquivalenceDependentTemplateArgsTest
|
|
: StructuralEquivalenceTemplateTest {};
|
|
|
|
TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
|
|
SameStructsInDependentArgs) {
|
|
std::string Code =
|
|
R"(
|
|
template <typename>
|
|
struct S1;
|
|
|
|
template <typename>
|
|
struct enable_if;
|
|
|
|
struct S
|
|
{
|
|
template <typename T, typename enable_if<S1<T>>::type>
|
|
void f();
|
|
};
|
|
)";
|
|
auto t = makeDecls<FunctionTemplateDecl>(Code, Code, Lang_CXX11,
|
|
functionTemplateDecl(hasName("f")));
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
|
|
DifferentStructsInDependentArgs) {
|
|
std::string Code =
|
|
R"(
|
|
template <typename>
|
|
struct S1;
|
|
|
|
template <typename>
|
|
struct S2;
|
|
|
|
template <typename>
|
|
struct enable_if;
|
|
)";
|
|
auto t = makeDecls<FunctionTemplateDecl>(Code + R"(
|
|
struct S
|
|
{
|
|
template <typename T, typename enable_if<S1<T>>::type>
|
|
void f();
|
|
};
|
|
)",
|
|
Code + R"(
|
|
struct S
|
|
{
|
|
template <typename T, typename enable_if<S2<T>>::type>
|
|
void f();
|
|
};
|
|
)",
|
|
Lang_CXX11,
|
|
functionTemplateDecl(hasName("f")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
|
|
SameStructsInDependentScopeDeclRefExpr) {
|
|
std::string Code =
|
|
R"(
|
|
template <typename>
|
|
struct S1;
|
|
|
|
template <bool>
|
|
struct enable_if;
|
|
|
|
struct S
|
|
{
|
|
template <typename T, typename enable_if<S1<T>::value>::type>
|
|
void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^
|
|
};
|
|
)";
|
|
auto t = makeDecls<FunctionTemplateDecl>(Code, Code, Lang_CXX11,
|
|
functionTemplateDecl(hasName("f")));
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
|
|
DifferentStructsInDependentScopeDeclRefExpr) {
|
|
std::string Code =
|
|
R"(
|
|
template <typename>
|
|
struct S1;
|
|
|
|
template <typename>
|
|
struct S2;
|
|
|
|
template <bool>
|
|
struct enable_if;
|
|
)";
|
|
auto t = makeDecls<FunctionTemplateDecl>(Code + R"(
|
|
struct S
|
|
{
|
|
template <typename T, typename enable_if<S1<T>::value>::type>
|
|
void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^
|
|
};
|
|
)",
|
|
Code + R"(
|
|
struct S
|
|
{
|
|
template <typename T, typename enable_if<S2<T>::value>::type>
|
|
void f();
|
|
};
|
|
)",
|
|
Lang_CXX03,
|
|
functionTemplateDecl(hasName("f")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
|
|
DifferentValueInDependentScopeDeclRefExpr) {
|
|
std::string Code =
|
|
R"(
|
|
template <typename>
|
|
struct S1;
|
|
|
|
template <bool>
|
|
struct enable_if;
|
|
)";
|
|
auto t = makeDecls<FunctionTemplateDecl>(Code + R"(
|
|
struct S
|
|
{
|
|
template <typename T, typename enable_if<S1<T>::value1>::type>
|
|
void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^
|
|
};
|
|
)",
|
|
Code + R"(
|
|
struct S
|
|
{
|
|
template <typename T, typename enable_if<S1<T>::value2>::type>
|
|
void f();
|
|
};
|
|
)",
|
|
Lang_CXX03,
|
|
functionTemplateDecl(hasName("f")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(
|
|
StructuralEquivalenceTemplateTest,
|
|
ClassTemplSpecWithQualifiedAndNonQualifiedTypeArgsShouldBeEqual) {
|
|
auto t = makeDecls<ClassTemplateSpecializationDecl>(
|
|
R"(
|
|
template <class T> struct Primary {};
|
|
namespace N {
|
|
struct Arg;
|
|
}
|
|
// Explicit instantiation with qualified name.
|
|
template struct Primary<N::Arg>;
|
|
)",
|
|
R"(
|
|
template <class T> struct Primary {};
|
|
namespace N {
|
|
struct Arg;
|
|
}
|
|
using namespace N;
|
|
// Explicit instantiation with UNqualified name.
|
|
template struct Primary<Arg>;
|
|
)",
|
|
Lang_CXX03, classTemplateSpecializationDecl(hasName("Primary")));
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(
|
|
StructuralEquivalenceTemplateTest,
|
|
ClassTemplSpecWithInequivalentQualifiedAndNonQualifiedTypeArgs) {
|
|
auto t = makeDecls<ClassTemplateSpecializationDecl>(
|
|
R"(
|
|
template <class T> struct Primary {};
|
|
namespace N {
|
|
struct Arg { int a; };
|
|
}
|
|
// Explicit instantiation with qualified name.
|
|
template struct Primary<N::Arg>;
|
|
)",
|
|
R"(
|
|
template <class T> struct Primary {};
|
|
namespace N {
|
|
// This struct is not equivalent with the other in the prev TU.
|
|
struct Arg { double b; }; // -- Field mismatch.
|
|
}
|
|
using namespace N;
|
|
// Explicit instantiation with UNqualified name.
|
|
template struct Primary<Arg>;
|
|
)",
|
|
Lang_CXX03, classTemplateSpecializationDecl(hasName("Primary")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(
|
|
StructuralEquivalenceTemplateTest,
|
|
ClassTemplSpecWithQualifiedAndNonQualifiedTemplArgsShouldBeEqual) {
|
|
auto t = makeDecls<ClassTemplateSpecializationDecl>(
|
|
R"(
|
|
template <template <class> class T> struct Primary {};
|
|
namespace N {
|
|
template <class T> struct Arg;
|
|
}
|
|
// Explicit instantiation with qualified name.
|
|
template struct Primary<N::Arg>;
|
|
)",
|
|
R"(
|
|
template <template <class> class T> struct Primary {};
|
|
namespace N {
|
|
template <class T> struct Arg;
|
|
}
|
|
using namespace N;
|
|
// Explicit instantiation with UNqualified name.
|
|
template struct Primary<Arg>;
|
|
)",
|
|
Lang_CXX03, classTemplateSpecializationDecl(hasName("Primary")));
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(
|
|
StructuralEquivalenceTemplateTest,
|
|
ClassTemplSpecWithInequivalentQualifiedAndNonQualifiedTemplArgs) {
|
|
auto t = makeDecls<ClassTemplateSpecializationDecl>(
|
|
R"(
|
|
template <template <class> class T> struct Primary {};
|
|
namespace N {
|
|
template <class T> struct Arg { int a; };
|
|
}
|
|
// Explicit instantiation with qualified name.
|
|
template struct Primary<N::Arg>;
|
|
)",
|
|
R"(
|
|
template <template <class> class T> struct Primary {};
|
|
namespace N {
|
|
// This template is not equivalent with the other in the prev TU.
|
|
template <class T> struct Arg { double b; }; // -- Field mismatch.
|
|
}
|
|
using namespace N;
|
|
// Explicit instantiation with UNqualified name.
|
|
template struct Primary<Arg>;
|
|
)",
|
|
Lang_CXX03, classTemplateSpecializationDecl(hasName("Primary")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTemplateTest,
|
|
IgnoreTemplateParmDepthAtTemplateTypeParmDecl) {
|
|
auto Decls = makeDecls<ClassTemplateDecl>(
|
|
R"(
|
|
template<class> struct A;
|
|
)",
|
|
R"(
|
|
template<class> struct S {
|
|
template<class> friend struct A;
|
|
};
|
|
)",
|
|
Lang_CXX03, classTemplateDecl(hasName("A")),
|
|
classTemplateDecl(hasName("A")));
|
|
EXPECT_TRUE(testStructuralMatch(Decls));
|
|
EXPECT_TRUE(testStructuralMatch(Decls, true));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceTemplateTest,
|
|
IgnoreTemplateParmDepthAtNonTypeTemplateParmDecl) {
|
|
auto Decls = makeDecls<ClassTemplateDecl>(
|
|
R"(
|
|
template<class T, T U> struct A;
|
|
)",
|
|
R"(
|
|
template<class T> struct S {
|
|
template<class P, P Q> friend struct A;
|
|
};
|
|
)",
|
|
Lang_CXX03, classTemplateDecl(hasName("A")),
|
|
classTemplateDecl(hasName("A")));
|
|
EXPECT_FALSE(testStructuralMatch(Decls));
|
|
EXPECT_TRUE(testStructuralMatch(Decls, /*IgnoreTemplateParmDepth=*/true));
|
|
}
|
|
|
|
TEST_F(
|
|
StructuralEquivalenceTemplateTest,
|
|
ClassTemplSpecWithInequivalentShadowedTemplArg) {
|
|
auto t = makeDecls<ClassTemplateSpecializationDecl>(
|
|
R"(
|
|
template <template <class> class T> struct Primary {};
|
|
template <class T> struct Arg { int a; };
|
|
// Explicit instantiation with ::Arg
|
|
template struct Primary<Arg>;
|
|
)",
|
|
R"(
|
|
template <template <class> class T> struct Primary {};
|
|
template <class T> struct Arg { int a; };
|
|
namespace N {
|
|
// This template is not equivalent with the other in the global scope.
|
|
template <class T> struct Arg { double b; }; // -- Field mismatch.
|
|
// Explicit instantiation with N::Arg which shadows ::Arg
|
|
template struct Primary<Arg>;
|
|
}
|
|
)",
|
|
Lang_CXX03, classTemplateSpecializationDecl(hasName("Primary")));
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
struct StructuralEquivalenceCacheTest : public StructuralEquivalenceTest {
|
|
StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls;
|
|
|
|
template <typename NodeType, typename MatcherType>
|
|
std::pair<NodeType *, NodeType *>
|
|
findDeclPair(std::tuple<TranslationUnitDecl *, TranslationUnitDecl *> TU,
|
|
MatcherType M) {
|
|
NodeType *D0 = FirstDeclMatcher<NodeType>().match(get<0>(TU), M);
|
|
NodeType *D1 = FirstDeclMatcher<NodeType>().match(get<1>(TU), M);
|
|
return {D0, D1};
|
|
}
|
|
|
|
template <typename NodeType>
|
|
bool isInNonEqCache(std::pair<NodeType *, NodeType *> D,
|
|
bool IgnoreTemplateParmDepth = false) {
|
|
return NonEquivalentDecls.count(
|
|
std::make_tuple(D.first, D.second, IgnoreTemplateParmDepth)) > 0;
|
|
}
|
|
};
|
|
|
|
TEST_F(StructuralEquivalenceCacheTest, SimpleNonEq) {
|
|
auto TU = makeTuDecls(
|
|
R"(
|
|
class A {};
|
|
class B {};
|
|
void x(A, A);
|
|
)",
|
|
R"(
|
|
class A {};
|
|
class B {};
|
|
void x(A, B);
|
|
)",
|
|
Lang_CXX03);
|
|
|
|
StructuralEquivalenceContext Ctx(
|
|
get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(),
|
|
NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false);
|
|
|
|
auto X = findDeclPair<FunctionDecl>(TU, functionDecl(hasName("x")));
|
|
EXPECT_FALSE(Ctx.IsEquivalent(X.first, X.second));
|
|
|
|
EXPECT_FALSE(isInNonEqCache(findDeclPair<CXXRecordDecl>(
|
|
TU, cxxRecordDecl(hasName("A"), unless(isImplicit())))));
|
|
EXPECT_FALSE(isInNonEqCache(findDeclPair<CXXRecordDecl>(
|
|
TU, cxxRecordDecl(hasName("B"), unless(isImplicit())))));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCacheTest, ReturnStmtNonEq) {
|
|
auto TU = makeTuDecls(
|
|
R"(
|
|
bool x() { return true; }
|
|
)",
|
|
R"(
|
|
bool x() { return false; }
|
|
)",
|
|
Lang_CXX03);
|
|
|
|
StructuralEquivalenceContext Ctx(
|
|
get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(),
|
|
NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false);
|
|
|
|
auto X = findDeclPair<FunctionDecl>(TU, functionDecl(hasName("x")));
|
|
EXPECT_FALSE(Ctx.IsEquivalent(X.first->getBody(), X.second->getBody()));
|
|
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCacheTest, VarDeclNoEq) {
|
|
auto TU = makeTuDecls(
|
|
R"(
|
|
int p;
|
|
)",
|
|
R"(
|
|
int q;
|
|
)",
|
|
Lang_CXX03);
|
|
|
|
StructuralEquivalenceContext Ctx(
|
|
get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(),
|
|
NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false);
|
|
|
|
auto Var = findDeclPair<VarDecl>(TU, varDecl());
|
|
EXPECT_FALSE(Ctx.IsEquivalent(Var.first, Var.second));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCacheTest, VarDeclWithDifferentStorageClassNoEq) {
|
|
auto TU = makeTuDecls(
|
|
R"(
|
|
int p;
|
|
)",
|
|
R"(
|
|
static int p;
|
|
)",
|
|
Lang_CXX03);
|
|
|
|
StructuralEquivalenceContext Ctx(
|
|
get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(),
|
|
NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false);
|
|
|
|
auto Var = findDeclPair<VarDecl>(TU, varDecl());
|
|
EXPECT_FALSE(Ctx.IsEquivalent(Var.first, Var.second));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCacheTest,
|
|
NonTypeTemplateParmWithDifferentPositionNoEq) {
|
|
auto TU = makeTuDecls(
|
|
R"(
|
|
template<int T>
|
|
struct A {
|
|
template<int U>
|
|
void foo() {}
|
|
};
|
|
)",
|
|
R"(
|
|
template<int U>
|
|
struct A {
|
|
template<int V, int T>
|
|
void foo() {}
|
|
};
|
|
)",
|
|
Lang_CXX03);
|
|
|
|
StructuralEquivalenceContext Ctx(
|
|
get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(),
|
|
NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false);
|
|
|
|
auto NTTP = findDeclPair<NonTypeTemplateParmDecl>(
|
|
TU, nonTypeTemplateParmDecl(hasName("T")));
|
|
EXPECT_FALSE(Ctx.IsEquivalent(NTTP.first, NTTP.second));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCacheTest, VarDeclWithInitNoEq) {
|
|
auto TU = makeTuDecls(
|
|
R"(
|
|
int p = 1;
|
|
)",
|
|
R"(
|
|
int p = 2;
|
|
)",
|
|
Lang_CXX03);
|
|
|
|
StructuralEquivalenceContext Ctx(
|
|
get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(),
|
|
NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false);
|
|
|
|
auto Var = findDeclPair<VarDecl>(TU, varDecl());
|
|
EXPECT_FALSE(Ctx.IsEquivalent(Var.first, Var.second));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCacheTest, SpecialNonEq) {
|
|
auto TU = makeTuDecls(
|
|
R"(
|
|
class A {};
|
|
class B { int i; };
|
|
void x(A *);
|
|
void y(A *);
|
|
class C {
|
|
friend void x(A *);
|
|
friend void y(A *);
|
|
};
|
|
)",
|
|
R"(
|
|
class A {};
|
|
class B { int i; };
|
|
void x(A *);
|
|
void y(B *);
|
|
class C {
|
|
friend void x(A *);
|
|
friend void y(B *);
|
|
};
|
|
)",
|
|
Lang_CXX03);
|
|
|
|
StructuralEquivalenceContext Ctx(
|
|
get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(),
|
|
NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false);
|
|
|
|
auto C = findDeclPair<CXXRecordDecl>(
|
|
TU, cxxRecordDecl(hasName("C"), unless(isImplicit())));
|
|
EXPECT_FALSE(Ctx.IsEquivalent(C.first, C.second));
|
|
|
|
EXPECT_FALSE(isInNonEqCache(C));
|
|
EXPECT_FALSE(isInNonEqCache(findDeclPair<CXXRecordDecl>(
|
|
TU, cxxRecordDecl(hasName("A"), unless(isImplicit())))));
|
|
EXPECT_FALSE(isInNonEqCache(findDeclPair<CXXRecordDecl>(
|
|
TU, cxxRecordDecl(hasName("B"), unless(isImplicit())))));
|
|
EXPECT_FALSE(isInNonEqCache(
|
|
findDeclPair<FunctionDecl>(TU, functionDecl(hasName("x")))));
|
|
EXPECT_FALSE(isInNonEqCache(
|
|
findDeclPair<FunctionDecl>(TU, functionDecl(hasName("y")))));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCacheTest, Cycle) {
|
|
auto TU = makeTuDecls(
|
|
R"(
|
|
class C;
|
|
class A { C *c; };
|
|
void x(A *);
|
|
class C {
|
|
friend void x(A *);
|
|
};
|
|
)",
|
|
R"(
|
|
class C;
|
|
class A { C *c; };
|
|
void x(A *);
|
|
class C {
|
|
friend void x(A *);
|
|
};
|
|
)",
|
|
Lang_CXX03);
|
|
|
|
StructuralEquivalenceContext Ctx(
|
|
get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(),
|
|
NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false);
|
|
|
|
auto C = findDeclPair<CXXRecordDecl>(
|
|
TU, cxxRecordDecl(hasName("C"), unless(isImplicit())));
|
|
EXPECT_TRUE(Ctx.IsEquivalent(C.first, C.second));
|
|
|
|
EXPECT_FALSE(isInNonEqCache(C));
|
|
EXPECT_FALSE(isInNonEqCache(findDeclPair<CXXRecordDecl>(
|
|
TU, cxxRecordDecl(hasName("A"), unless(isImplicit())))));
|
|
EXPECT_FALSE(isInNonEqCache(
|
|
findDeclPair<FunctionDecl>(TU, functionDecl(hasName("x")))));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCacheTest, TemplateParmDepth) {
|
|
// In 'friend struct Y' ClassTemplateDecl has the TU as parent context.
|
|
// This declaration has template depth 1 (it is already inside a template).
|
|
// It has not a previous declaration and is an "undeclared" friend.
|
|
//
|
|
// Second TU has a specialization of 'struct X'.
|
|
// In this case 'friend struct Y' has the ClassTemplateSpecializationDecl as
|
|
// parent. It has template depth 0 (it is in the specialization). It has the
|
|
// first 'struct Y' declaration as previous declaration and canonical
|
|
// declaration.
|
|
//
|
|
// When these two 'friend struct Y' are compared, only the template depth is
|
|
// different.
|
|
// FIXME: Structural equivalence checks the depth only in types, not in
|
|
// TemplateParmDecl. For this reason the second 'A1' argument is needed (as a
|
|
// type) in the template to make the check fail.
|
|
auto TU = makeTuDecls(
|
|
R"(
|
|
template <class A1, A1>
|
|
struct Y;
|
|
|
|
template <class A>
|
|
struct X {
|
|
template <class A1, A1>
|
|
friend struct Y;
|
|
};
|
|
)",
|
|
R"(
|
|
template <class A1, A1>
|
|
struct Y;
|
|
|
|
template <class A>
|
|
struct X {
|
|
template <class A1, A1>
|
|
friend struct Y;
|
|
};
|
|
|
|
X<int> x;
|
|
)",
|
|
Lang_CXX03);
|
|
|
|
auto *D0 = LastDeclMatcher<ClassTemplateDecl>().match(
|
|
get<0>(TU), classTemplateDecl(hasName("Y"), unless(isImplicit())));
|
|
auto *D1 = LastDeclMatcher<ClassTemplateDecl>().match(
|
|
get<1>(TU), classTemplateDecl(hasName("Y"), unless(isImplicit())));
|
|
ASSERT_EQ(D0->getTemplateDepth(), 1u);
|
|
ASSERT_EQ(D1->getTemplateDepth(), 0u);
|
|
|
|
StructuralEquivalenceContext Ctx_NoIgnoreTemplateParmDepth(
|
|
get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(),
|
|
NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false,
|
|
false, false);
|
|
|
|
EXPECT_FALSE(Ctx_NoIgnoreTemplateParmDepth.IsEquivalent(D0, D1));
|
|
|
|
Decl *NonEqDecl0 =
|
|
D0->getCanonicalDecl()->getTemplateParameters()->getParam(1);
|
|
Decl *NonEqDecl1 =
|
|
D1->getCanonicalDecl()->getTemplateParameters()->getParam(1);
|
|
EXPECT_TRUE(isInNonEqCache(std::make_pair(NonEqDecl0, NonEqDecl1), false));
|
|
EXPECT_FALSE(isInNonEqCache(std::make_pair(NonEqDecl0, NonEqDecl1), true));
|
|
|
|
StructuralEquivalenceContext Ctx_IgnoreTemplateParmDepth(
|
|
get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(),
|
|
NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false,
|
|
false, true);
|
|
|
|
EXPECT_TRUE(Ctx_IgnoreTemplateParmDepth.IsEquivalent(D0, D1));
|
|
|
|
EXPECT_FALSE(isInNonEqCache(std::make_pair(NonEqDecl0, NonEqDecl1), true));
|
|
}
|
|
|
|
struct StructuralEquivalenceStmtTest : StructuralEquivalenceTest {};
|
|
|
|
/// Fallback matcher to be used only when there is no specific matcher for a
|
|
/// Expr subclass. Remove this once all Expr subclasses have their own matcher.
|
|
static auto &fallbackExprMatcher = expr;
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, AddrLabelExpr) {
|
|
auto t = makeWrappedStmts("lbl: &&lbl;", "lbl: &&lbl;", Lang_CXX03,
|
|
addrLabelExpr());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, AddrLabelExprDifferentLabel) {
|
|
auto t = makeWrappedStmts("lbl1: lbl2: &&lbl1;", "lbl1: lbl2: &&lbl2;",
|
|
Lang_CXX03, addrLabelExpr());
|
|
// FIXME: Should be false. LabelDecl are incorrectly matched.
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
static const std::string MemoryOrderSrc = R"(
|
|
enum memory_order {
|
|
memory_order_relaxed,
|
|
memory_order_consume,
|
|
memory_order_acquire,
|
|
memory_order_release,
|
|
memory_order_acq_rel,
|
|
memory_order_seq_cst
|
|
};
|
|
)";
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, AtomicExpr) {
|
|
std::string Prefix = "char a, b; " + MemoryOrderSrc;
|
|
auto t = makeStmts(
|
|
Prefix +
|
|
"void wrapped() { __atomic_load(&a, &b, memory_order_seq_cst); }",
|
|
Prefix +
|
|
"void wrapped() { __atomic_load(&a, &b, memory_order_seq_cst); }",
|
|
Lang_CXX03, atomicExpr());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, AtomicExprDifferentOp) {
|
|
std::string Prefix = "char a, b; " + MemoryOrderSrc;
|
|
auto t = makeStmts(
|
|
Prefix +
|
|
"void wrapped() { __atomic_load(&a, &b, memory_order_seq_cst); }",
|
|
Prefix +
|
|
"void wrapped() { __atomic_store(&a, &b, memory_order_seq_cst); }",
|
|
Lang_CXX03, atomicExpr());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, BinaryOperator) {
|
|
auto t = makeWrappedStmts("1 + 1", "1 + 1", Lang_CXX03, binaryOperator());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, BinaryOperatorDifferentOps) {
|
|
auto t = makeWrappedStmts("1 + 1", "1 - 1", Lang_CXX03, binaryOperator());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, CallExpr) {
|
|
std::string Src = "int call(); int wrapped() { call(); }";
|
|
auto t = makeStmts(Src, Src, Lang_CXX03, callExpr());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, CallExprDifferentCallee) {
|
|
std::string FunctionSrc = "int func1(); int func2();\n";
|
|
auto t = makeStmts(FunctionSrc + "void wrapper() { func1(); }",
|
|
FunctionSrc + "void wrapper() { func2(); }", Lang_CXX03,
|
|
callExpr());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, CharacterLiteral) {
|
|
auto t = makeWrappedStmts("'a'", "'a'", Lang_CXX03, characterLiteral());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, CharacterLiteralDifferentValues) {
|
|
auto t = makeWrappedStmts("'a'", "'b'", Lang_CXX03, characterLiteral());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, ExpressionTraitExpr) {
|
|
auto t = makeWrappedStmts("__is_lvalue_expr(1)", "__is_lvalue_expr(1)",
|
|
Lang_CXX03, fallbackExprMatcher());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, ExpressionTraitExprDifferentKind) {
|
|
auto t = makeWrappedStmts("__is_lvalue_expr(1)", "__is_rvalue_expr(1)",
|
|
Lang_CXX03, fallbackExprMatcher());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, FloatingLiteral) {
|
|
auto t = makeWrappedStmts("1.0", "1.0", Lang_CXX03, fallbackExprMatcher());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, FloatingLiteralDifferentSpelling) {
|
|
auto t = makeWrappedStmts("0x10.1p0", "16.0625", Lang_CXX17,
|
|
fallbackExprMatcher());
|
|
// Same value but with different spelling is equivalent.
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, FloatingLiteralDifferentType) {
|
|
auto t = makeWrappedStmts("1.0", "1.0f", Lang_CXX03, fallbackExprMatcher());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, FloatingLiteralDifferentValue) {
|
|
auto t = makeWrappedStmts("1.01", "1.0", Lang_CXX03, fallbackExprMatcher());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, GenericSelectionExprSame) {
|
|
auto t = makeWrappedStmts("_Generic(0u, unsigned int: 0, float: 1)",
|
|
"_Generic(0u, unsigned int: 0, float: 1)", Lang_C99,
|
|
genericSelectionExpr());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, GenericSelectionExprSignsDiffer) {
|
|
auto t = makeWrappedStmts("_Generic(0u, unsigned int: 0, float: 1)",
|
|
"_Generic(0, int: 0, float: 1)", Lang_C99,
|
|
genericSelectionExpr());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, GenericSelectionExprOrderDiffers) {
|
|
auto t = makeWrappedStmts("_Generic(0u, unsigned int: 0, float: 1)",
|
|
"_Generic(0u, float: 1, unsigned int: 0)", Lang_C99,
|
|
genericSelectionExpr());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, GenericSelectionExprDependentResultSame) {
|
|
auto t = makeStmts(
|
|
R"(
|
|
template <typename T>
|
|
void f() {
|
|
T x;
|
|
(void)_Generic(x, int: 0, float: 1);
|
|
}
|
|
void g() { f<int>(); }
|
|
)",
|
|
R"(
|
|
template <typename T>
|
|
void f() {
|
|
T x;
|
|
(void)_Generic(x, int: 0, float: 1);
|
|
}
|
|
void g() { f<int>(); }
|
|
)",
|
|
Lang_CXX03, genericSelectionExpr());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest,
|
|
GenericSelectionExprDependentResultOrderDiffers) {
|
|
auto t = makeStmts(
|
|
R"(
|
|
template <typename T>
|
|
void f() {
|
|
T x;
|
|
(void)_Generic(x, float: 1, int: 0);
|
|
}
|
|
void g() { f<int>(); }
|
|
)",
|
|
R"(
|
|
template <typename T>
|
|
void f() {
|
|
T x;
|
|
(void)_Generic(x, int: 0, float: 1);
|
|
}
|
|
void g() { f<int>(); }
|
|
)",
|
|
Lang_CXX03, genericSelectionExpr());
|
|
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
TEST_F(StructuralEquivalenceStmtTest, IntegerLiteral) {
|
|
auto t = makeWrappedStmts("1", "1", Lang_CXX03, integerLiteral());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, IntegerLiteralDifferentSpelling) {
|
|
auto t = makeWrappedStmts("1", "0x1", Lang_CXX03, integerLiteral());
|
|
// Same value but with different spelling is equivalent.
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, IntegerLiteralDifferentValue) {
|
|
auto t = makeWrappedStmts("1", "2", Lang_CXX03, integerLiteral());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, IntegerLiteralDifferentTypes) {
|
|
auto t = makeWrappedStmts("1", "1L", Lang_CXX03, integerLiteral());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, MemberExpr) {
|
|
std::string ClassSrc = "struct C { int a; int b; };";
|
|
auto t = makeStmts(ClassSrc + "int wrapper() { C c; return c.a; }",
|
|
ClassSrc + "int wrapper() { C c; return c.a; }",
|
|
Lang_CXX03, memberExpr());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, MemberExprDifferentMember) {
|
|
std::string ClassSrc = "struct C { int a; int b; };";
|
|
auto t = makeStmts(ClassSrc + "int wrapper() { C c; return c.a; }",
|
|
ClassSrc + "int wrapper() { C c; return c.b; }",
|
|
Lang_CXX03, memberExpr());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, ObjCStringLiteral) {
|
|
auto t =
|
|
makeWrappedStmts("@\"a\"", "@\"a\"", Lang_OBJCXX, fallbackExprMatcher());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, ObjCStringLiteralDifferentContent) {
|
|
auto t =
|
|
makeWrappedStmts("@\"a\"", "@\"b\"", Lang_OBJCXX, fallbackExprMatcher());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, StringLiteral) {
|
|
auto t = makeWrappedStmts("\"a\"", "\"a\"", Lang_CXX03, stringLiteral());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, StringLiteralDifferentContent) {
|
|
auto t = makeWrappedStmts("\"a\"", "\"b\"", Lang_CXX03, stringLiteral());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, StringLiteralDifferentLength) {
|
|
auto t = makeWrappedStmts("\"a\"", "\"aa\"", Lang_CXX03, stringLiteral());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, TypeTraitExpr) {
|
|
auto t = makeWrappedStmts("__is_pod(int)", "__is_pod(int)", Lang_CXX03,
|
|
fallbackExprMatcher());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, TypeTraitExprDifferentType) {
|
|
auto t = makeWrappedStmts("__is_pod(int)", "__is_pod(long)", Lang_CXX03,
|
|
fallbackExprMatcher());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, TypeTraitExprDifferentTrait) {
|
|
auto t = makeWrappedStmts(
|
|
"__is_pod(int)", "__is_trivially_constructible(int)", Lang_CXX03, expr());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, TypeTraitExprDifferentTraits) {
|
|
auto t = makeWrappedStmts("__is_constructible(int)",
|
|
"__is_constructible(int, int)", Lang_CXX03, expr());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, UnaryExprOrTypeTraitExpr) {
|
|
auto t = makeWrappedStmts("sizeof(int)", "sizeof(int)", Lang_CXX03,
|
|
unaryExprOrTypeTraitExpr());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, UnaryExprOrTypeTraitExprDifferentKind) {
|
|
auto t = makeWrappedStmts("sizeof(int)", "alignof(long)", Lang_CXX11,
|
|
unaryExprOrTypeTraitExpr());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, UnaryExprOrTypeTraitExprDifferentType) {
|
|
auto t = makeWrappedStmts("sizeof(int)", "sizeof(long)", Lang_CXX03,
|
|
unaryExprOrTypeTraitExpr());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, UnaryOperator) {
|
|
auto t = makeWrappedStmts("+1", "+1", Lang_CXX03, unaryOperator());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, UnaryOperatorDifferentOps) {
|
|
auto t = makeWrappedStmts("+1", "-1", Lang_CXX03, unaryOperator());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest,
|
|
CXXOperatorCallExprVsUnaryBinaryOperator) {
|
|
auto t = makeNamedDecls(
|
|
R"(
|
|
template <typename T, T x>
|
|
class A;
|
|
template <typename T, T x, T y>
|
|
void foo(
|
|
A<T, x + y>,
|
|
A<T, x - y>,
|
|
A<T, -x>,
|
|
A<T, x * y>,
|
|
A<T, *x>,
|
|
A<T, x / y>,
|
|
A<T, x % y>,
|
|
A<T, x ^ y>,
|
|
A<T, x & y>,
|
|
A<T, &x>,
|
|
A<T, x | y>,
|
|
A<T, ~x>,
|
|
A<T, !x>,
|
|
A<T, x < y>,
|
|
A<T, (x > y)>,
|
|
A<T, x << y>,
|
|
A<T, (x >> y)>,
|
|
A<T, x == y>,
|
|
A<T, x != y>,
|
|
A<T, x <= y>,
|
|
A<T, x >= y>,
|
|
A<T, x <=> y>,
|
|
A<T, x && y>,
|
|
A<T, x || y>,
|
|
A<T, ++x>,
|
|
A<T, --x>,
|
|
A<T, (x , y)>,
|
|
A<T, x ->* y>,
|
|
A<T, x -> y>
|
|
);
|
|
)",
|
|
R"(
|
|
struct Bar {
|
|
Bar& operator=(Bar&);
|
|
Bar& operator->();
|
|
};
|
|
|
|
Bar& operator+(Bar&, Bar&);
|
|
Bar& operator+(Bar&);
|
|
Bar& operator-(Bar&, Bar&);
|
|
Bar& operator-(Bar&);
|
|
Bar& operator*(Bar&, Bar&);
|
|
Bar& operator*(Bar&);
|
|
Bar& operator/(Bar&, Bar&);
|
|
Bar& operator%(Bar&, Bar&);
|
|
Bar& operator^(Bar&, Bar&);
|
|
Bar& operator&(Bar&, Bar&);
|
|
Bar& operator&(Bar&);
|
|
Bar& operator|(Bar&, Bar&);
|
|
Bar& operator~(Bar&);
|
|
Bar& operator!(Bar&);
|
|
Bar& operator<(Bar&, Bar&);
|
|
Bar& operator>(Bar&, Bar&);
|
|
Bar& operator+=(Bar&, Bar&);
|
|
Bar& operator-=(Bar&, Bar&);
|
|
Bar& operator*=(Bar&, Bar&);
|
|
Bar& operator/=(Bar&, Bar&);
|
|
Bar& operator%=(Bar&, Bar&);
|
|
Bar& operator^=(Bar&, Bar&);
|
|
Bar& operator&=(Bar&, Bar&);
|
|
Bar& operator|=(Bar&, Bar&);
|
|
Bar& operator<<(Bar&, Bar&);
|
|
Bar& operator>>(Bar&, Bar&);
|
|
Bar& operator<<=(Bar&, Bar&);
|
|
Bar& operator>>=(Bar&, Bar&);
|
|
Bar& operator==(Bar&, Bar&);
|
|
Bar& operator!=(Bar&, Bar&);
|
|
Bar& operator<=(Bar&, Bar&);
|
|
Bar& operator>=(Bar&, Bar&);
|
|
Bar& operator<=>(Bar&, Bar&);
|
|
Bar& operator&&(Bar&, Bar&);
|
|
Bar& operator||(Bar&, Bar&);
|
|
Bar& operator++(Bar&);
|
|
Bar& operator--(Bar&);
|
|
Bar& operator,(Bar&, Bar&);
|
|
Bar& operator->*(Bar&, Bar&);
|
|
|
|
template <typename T, T x>
|
|
class A;
|
|
template <typename T, T x, T y>
|
|
void foo(
|
|
A<T, x + y>,
|
|
A<T, x - y>,
|
|
A<T, -x>,
|
|
A<T, x * y>,
|
|
A<T, *x>,
|
|
A<T, x / y>,
|
|
A<T, x % y>,
|
|
A<T, x ^ y>,
|
|
A<T, x & y>,
|
|
A<T, &x>,
|
|
A<T, x | y>,
|
|
A<T, ~x>,
|
|
A<T, !x>,
|
|
A<T, x < y>,
|
|
A<T, (x > y)>,
|
|
A<T, x << y>,
|
|
A<T, (x >> y)>,
|
|
A<T, x == y>,
|
|
A<T, x != y>,
|
|
A<T, x <= y>,
|
|
A<T, x >= y>,
|
|
A<T, x <=> y>,
|
|
A<T, x && y>,
|
|
A<T, x || y>,
|
|
A<T, ++x>,
|
|
A<T, --x>,
|
|
A<T, (x , y)>,
|
|
A<T, x ->* y>,
|
|
A<T, x -> y>
|
|
);
|
|
)",
|
|
Lang_CXX20);
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest,
|
|
CXXOperatorCallExprVsUnaryBinaryOperatorNe) {
|
|
auto t = makeNamedDecls(
|
|
R"(
|
|
template <typename T, T x>
|
|
class A;
|
|
template <typename T, T x, T y>
|
|
void foo(
|
|
A<T, x + y>
|
|
);
|
|
)",
|
|
R"(
|
|
struct Bar;
|
|
|
|
Bar& operator-(Bar&, Bar&);
|
|
|
|
template <typename T, T x>
|
|
class A;
|
|
template <typename T, T x, T y>
|
|
void foo(
|
|
A<T, x - y>
|
|
);
|
|
)",
|
|
Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, NonTypeTemplateParm) {
|
|
auto t = makeNamedDecls(
|
|
R"(
|
|
template <typename T, T x>
|
|
class A;
|
|
template <typename T, T x, T y>
|
|
void foo(A<T, x>);
|
|
)",
|
|
R"(
|
|
template <typename T, T x>
|
|
class A;
|
|
template <typename T, T x, T y>
|
|
void foo(A<T, y>);
|
|
)",
|
|
Lang_CXX11);
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, UnresolvedLookupDifferentName) {
|
|
auto t = makeStmts(
|
|
R"(
|
|
void f1(int);
|
|
template <typename T>
|
|
void f(T t) {
|
|
f1(t);
|
|
}
|
|
void g() { f<int>(1); }
|
|
)",
|
|
R"(
|
|
void f2(int);
|
|
template <typename T>
|
|
void f(T t) {
|
|
f2(t);
|
|
}
|
|
void g() { f<int>(1); }
|
|
)",
|
|
Lang_CXX03, unresolvedLookupExpr());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, UnresolvedLookupDifferentQualifier) {
|
|
auto t = makeStmts(
|
|
R"(
|
|
struct X {
|
|
static void g(int);
|
|
static void g(char);
|
|
};
|
|
|
|
template <typename T>
|
|
void f(T t) {
|
|
X::g(t);
|
|
}
|
|
|
|
void g() { f<int>(1); }
|
|
)",
|
|
R"(
|
|
struct Y {
|
|
static void g(int);
|
|
static void g(char);
|
|
};
|
|
|
|
template <typename T>
|
|
void f(T t) {
|
|
Y::g(t);
|
|
}
|
|
|
|
void g() { f<int>(1); }
|
|
)",
|
|
Lang_CXX03, unresolvedLookupExpr());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest,
|
|
UnresolvedLookupDifferentTemplateArgument) {
|
|
auto t = makeStmts(
|
|
R"(
|
|
struct A {};
|
|
template<typename T1, typename T2>
|
|
void g() {}
|
|
|
|
template <typename T>
|
|
void f() {
|
|
g<A, T>();
|
|
}
|
|
|
|
void h() { f<int>(); }
|
|
)",
|
|
R"(
|
|
struct B {};
|
|
template<typename T1, typename T2>
|
|
void g() {}
|
|
|
|
template <typename T>
|
|
void f() {
|
|
g<B, T>();
|
|
}
|
|
|
|
void h() { f<int>(); }
|
|
)",
|
|
Lang_CXX03, unresolvedLookupExpr());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, UnresolvedLookup) {
|
|
auto t = makeStmts(
|
|
R"(
|
|
struct A {};
|
|
struct B {
|
|
template<typename T1, typename T2>
|
|
static void g(int) {};
|
|
template<typename T1, typename T2>
|
|
static void g(char) {};
|
|
};
|
|
|
|
template <typename T1, typename T2>
|
|
void f(T2 x) {
|
|
B::g<A, T1>(x);
|
|
}
|
|
|
|
void g() { f<char, int>(1); }
|
|
)",
|
|
R"(
|
|
struct A {};
|
|
struct B {
|
|
template<typename T1, typename T2>
|
|
static void g(int) {};
|
|
template<typename T1, typename T2>
|
|
static void g(char) {};
|
|
};
|
|
|
|
template <typename T1, typename T2>
|
|
void f(T2 x) {
|
|
B::g<A, T1>(x);
|
|
}
|
|
|
|
void g() { f<char, int>(1); }
|
|
)",
|
|
Lang_CXX03, unresolvedLookupExpr());
|
|
EXPECT_TRUE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCacheTest, GotoStmtNoEq) {
|
|
auto S = makeStmts(
|
|
R"(
|
|
void foo() {
|
|
goto L1;
|
|
L1: foo();
|
|
}
|
|
)",
|
|
R"(
|
|
void foo() {
|
|
goto L2;
|
|
L2: foo();
|
|
}
|
|
)",
|
|
Lang_CXX03, gotoStmt());
|
|
EXPECT_FALSE(testStructuralMatch(S));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceStmtTest, DeclRefExpr) {
|
|
std::string Prefix = "enum Test { AAA, BBB };";
|
|
auto t = makeStmts(
|
|
Prefix + "void foo(int i) {if (i > 0) {i = AAA;} else {i = BBB;}}",
|
|
Prefix + "void foo(int i) {if (i > 0) {i = BBB;} else {i = AAA;}}",
|
|
Lang_CXX03, ifStmt());
|
|
EXPECT_FALSE(testStructuralMatch(t));
|
|
}
|
|
|
|
TEST_F(StructuralEquivalenceCacheTest, CXXDependentScopeMemberExprNoEq) {
|
|
auto S = makeStmts(
|
|
R"(
|
|
template <class T>
|
|
void foo() {
|
|
(void)T().x;
|
|
}
|
|
struct A { int x; };
|
|
void bar() {
|
|
foo<A>();
|
|
}
|
|
)",
|
|
R"(
|
|
template <class T>
|
|
void foo() {
|
|
(void)T().y;
|
|
}
|
|
struct A { int y; };
|
|
void bar() {
|
|
foo<A>();
|
|
}
|
|
)",
|
|
Lang_CXX11, cxxDependentScopeMemberExpr());
|
|
EXPECT_FALSE(testStructuralMatch(S));
|
|
}
|
|
|
|
} // end namespace ast_matchers
|
|
} // end namespace clang
|