diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -6339,6 +6339,199 @@ new internal::TypeLocTypeMatcher(InnerMatcher)); } +/// Matches `QualifiedTypeLoc`s in the clang AST. +/// +/// Given +/// \code +/// const int x = 0; +/// \endcode +/// qualifiedTypeLoc() +/// matches `const int`. +extern const internal::VariadicDynCastAllOfMatcher + qualifiedTypeLoc; + +/// Matches `QualifiedTypeLoc`s that have an unqualified `TypeLoc` matching +/// `InnerMatcher`. +/// +/// Given +/// \code +/// int* x = 0; +/// \endcode +/// qualifiedTypeLoc(hasUnqualifiedLoc(typeLoc())) +/// matches `int*`. +AST_MATCHER_P(QualifiedTypeLoc, hasUnqualifiedLoc, TypeLocMatcher, + InnerMatcher) { + return InnerMatcher.matches(Node.getUnqualifiedLoc(), Finder, Builder); +} + +/// Matches a function declared with the specified return `TypeLoc`. +/// +/// Given +/// \code +/// int f() { return 5; } +/// void g() {} +/// \endcode +/// functionDecl(hasReturnTypeLoc(loc(asString("int")))) +/// matches the declaration of `f`, but not `g`. +AST_MATCHER_P(FunctionDecl, hasReturnTypeLoc, TypeLocMatcher, ReturnMatcher) { + auto Loc = Node.getFunctionTypeLoc(); + return Loc && ReturnMatcher.matches(Loc.getReturnLoc(), Finder, Builder); +} + +/// Matches pointer `TypeLoc`s. +/// +/// Given +/// \code +/// int* x; +/// \endcode +/// pointerTypeLoc() +/// matches `int*`. +extern const internal::VariadicDynCastAllOfMatcher + pointerTypeLoc; + +/// Matches pointer `TypeLoc`s that have a pointee `TypeLoc` matching +/// `PointeeMatcher`. +/// +/// Given +/// \code +/// int* x; +/// \endcode +/// pointerTypeLoc(hasPointeeLoc(loc(asString("int")))) +/// matches `int*`. +AST_MATCHER_P(PointerTypeLoc, hasPointeeLoc, TypeLocMatcher, PointeeMatcher) { + return PointeeMatcher.matches(Node.getPointeeLoc(), Finder, Builder); +} + +/// Matches reference `TypeLoc`s. +/// +/// Given +/// \code +/// int x = 3; +/// int& xx = x; +/// \endcode +/// referenceTypeLoc() +/// matches `int&`. +extern const internal::VariadicDynCastAllOfMatcher + referenceTypeLoc; + +/// Matches reference `TypeLoc`s that have a referent `TypeLoc` matching +/// `ReferentMatcher`. +/// +/// Given +/// \code +/// int x = 3; +/// int& xx = x; +/// \endcode +/// referenceTypeLoc(hasReferentLoc(loc(asString("int")))) +/// matches `int&`. +AST_MATCHER_P(ReferenceTypeLoc, hasReferentLoc, TypeLocMatcher, + ReferentMatcher) { + return ReferentMatcher.matches(Node.getPointeeLoc(), Finder, Builder); +} + +/// Matches template specialization `TypeLoc`s. +/// +/// Given +/// \code +/// template class C {}; +/// C var; +/// \endcode +/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(typeLoc()))) +/// matches `C var`. +extern const internal::VariadicDynCastAllOfMatcher< + TypeLoc, TemplateSpecializationTypeLoc> + templateSpecializationTypeLoc; + +/// Matches template specialization `TypeLoc`s that have at least one +/// `TemplateArgumentLoc` matching the given `InnerMatcher`. +/// +/// Given +/// \code +/// template class A {}; +/// A a; +/// \endcode +/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( +/// hasTypeLoc(loc(asString("int"))))))) +/// matches `A a`. +AST_MATCHER_P(TemplateSpecializationTypeLoc, hasAnyTemplateArgumentLoc, + internal::Matcher, InnerMatcher) { + for (unsigned Index = 0, N = Node.getNumArgs(); Index < N; ++Index) { + clang::ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder); + if (InnerMatcher.matches(Node.getArgLoc(Index), Finder, &Result)) { + *Builder = std::move(Result); + return true; + } + } + return false; +} + +inline const bool MatchTemplateArgLocAt( + const DeclRefExpr &Node, unsigned int Index, + std::function Matcher) { + llvm::ArrayRef ArgLocs = Node.template_arguments(); + return Index < ArgLocs.size() && Matcher(ArgLocs[Index]); +} + +inline const bool MatchTemplateArgLocAt( + const TemplateSpecializationTypeLoc &Node, unsigned int Index, + std::function Matcher) { + return !Node.isNull() && Index < Node.getNumArgs() && + Matcher(Node.getArgLoc(Index)); +} + +/// Matches template specialization `TypeLoc`s where the n'th +/// `TemplateArgumentLoc` matches the given `InnerMatcher`. +/// +/// Given +/// \code +/// template class A {}; +/// A b; +/// A c; +/// \endcode +/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, +/// hasTypeLoc(loc(asString("double"))))))) +/// matches `A b`, but not `A c`. +AST_POLYMORPHIC_MATCHER_P2( + hasTemplateArgumentLoc, + AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr, TemplateSpecializationTypeLoc), + unsigned int, Index, internal::Matcher, InnerMatcher) { + return MatchTemplateArgLocAt( + Node, Index, + [this, Finder, Builder](const clang::TemplateArgumentLoc &ArgLoc) { + return InnerMatcher.matches(ArgLoc, Finder, Builder); + }); +} + +/// Matches elaborated `TypeLoc`s. +/// +/// Given +/// \code +/// class C {}; +/// class C c; +/// \endcode +/// elaboratedTypeLoc() +/// matches `class C`. +extern const internal::VariadicDynCastAllOfMatcher + elaboratedTypeLoc; + +/// Matches elaborated `TypeLoc`s that have a named `TypeLoc` matching +/// `InnerMatcher`. +/// +/// Given +/// \code +/// template +/// class C {}; +/// class C c; +/// \endcode +/// varDecl(hasTypeLoc(elaboratedTypeLoc(hasNamedTypeLoc( +/// templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( +/// templateArgumentLoc())))))) +/// matches `class C c`. +AST_MATCHER_P(ElaboratedTypeLoc, hasNamedTypeLoc, TypeLocMatcher, + InnerMatcher) { + return InnerMatcher.matches(Node.getNamedTypeLoc(), Finder, Builder); +} + /// Matches type \c bool. /// /// Given diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -771,6 +771,19 @@ const internal::VariadicAllOfMatcher qualType; const internal::VariadicAllOfMatcher type; const internal::VariadicAllOfMatcher typeLoc; + +const internal::VariadicDynCastAllOfMatcher + qualifiedTypeLoc; +const internal::VariadicDynCastAllOfMatcher + pointerTypeLoc; +const internal::VariadicDynCastAllOfMatcher + referenceTypeLoc; +const internal::VariadicDynCastAllOfMatcher + templateSpecializationTypeLoc; +const internal::VariadicDynCastAllOfMatcher + elaboratedTypeLoc; + const internal::VariadicDynCastAllOfMatcher unaryExprOrTypeTraitExpr; const internal::VariadicDynCastAllOfMatcher valueDecl; diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -2078,6 +2078,168 @@ notMatches(Code, typeAliasTemplateDecl(hasName("typeAliasDecl")))); } +TEST_P(ASTMatchersTest, QualifiedTypeLocTest_BindsToConstIntVarDecl) { + EXPECT_TRUE(matches("const int x = 0;", + qualifiedTypeLoc(loc(asString("const int"))))); +} + +TEST_P(ASTMatchersTest, QualifiedTypeLocTest_BindsToConstIntFunctionDecl) { + EXPECT_TRUE(matches("const int f() { return 5; }", + qualifiedTypeLoc(loc(asString("const int"))))); +} + +TEST_P(ASTMatchersTest, QualifiedTypeLocTest_DoesNotBindToUnqualifiedVarDecl) { + EXPECT_TRUE(notMatches("int x = 0;", qualifiedTypeLoc(loc(asString("int"))))); +} + +TEST_P(ASTMatchersTest, QualifiedTypeLocTest_IntDoesNotBindToConstIntDecl) { + EXPECT_TRUE( + notMatches("const int x = 0;", qualifiedTypeLoc(loc(asString("int"))))); +} + +TEST_P(ASTMatchersTest, QualifiedTypeLocTest_IntDoesNotBindToConstFloatDecl) { + EXPECT_TRUE( + notMatches("const float x = 0;", qualifiedTypeLoc(loc(asString("int"))))); +} + +TEST_P(ASTMatchersTest, PointerTypeLocTest_BindsToAnyPointerTypeLoc) { + auto matcher = varDecl(hasName("x"), hasTypeLoc(pointerTypeLoc())); + EXPECT_TRUE(matches("int* x;", matcher)); + EXPECT_TRUE(matches("float* x;", matcher)); + EXPECT_TRUE(matches("char* x;", matcher)); + EXPECT_TRUE(matches("void* x;", matcher)); +} + +TEST_P(ASTMatchersTest, PointerTypeLocTest_DoesNotBindToNonPointerTypeLoc) { + auto matcher = varDecl(hasName("x"), hasTypeLoc(pointerTypeLoc())); + EXPECT_TRUE(notMatches("int x;", matcher)); + EXPECT_TRUE(notMatches("float x;", matcher)); + EXPECT_TRUE(notMatches("char x;", matcher)); +} + +TEST_P(ASTMatchersTest, ReferenceTypeLocTest_BindsToAnyReferenceTypeLoc) { + if (!GetParam().isCXX()) { + return; + } + auto matcher = varDecl(hasName("r"), hasTypeLoc(referenceTypeLoc())); + EXPECT_TRUE(matches("int rr = 3; int& r = rr;", matcher)); + EXPECT_TRUE(matches("int rr = 3; auto& r = rr;", matcher)); + EXPECT_TRUE(matches("int rr = 3; const int& r = rr;", matcher)); + EXPECT_TRUE(matches("float rr = 3.0; float& r = rr;", matcher)); + EXPECT_TRUE(matches("char rr = 'a'; char& r = rr;", matcher)); +} + +TEST_P(ASTMatchersTest, ReferenceTypeLocTest_DoesNotBindToNonReferenceTypeLoc) { + auto matcher = varDecl(hasName("r"), hasTypeLoc(referenceTypeLoc())); + EXPECT_TRUE(notMatches("int r;", matcher)); + EXPECT_TRUE(notMatches("int r = 3;", matcher)); + EXPECT_TRUE(notMatches("const int r = 3;", matcher)); + EXPECT_TRUE(notMatches("int* r;", matcher)); + EXPECT_TRUE(notMatches("float r;", matcher)); + EXPECT_TRUE(notMatches("char r;", matcher)); +} + +TEST_P(ASTMatchersTest, ReferenceTypeLocTest_BindsToAnyRvalueReferenceTypeLoc) { + if (!GetParam().isCXX()) { + return; + } + auto matcher = varDecl(hasName("r"), hasTypeLoc(referenceTypeLoc())); + EXPECT_TRUE(matches("int&& r = 3;", matcher)); + EXPECT_TRUE(matches("auto&& r = 3;", matcher)); + EXPECT_TRUE(matches("float&& r = 3.0;", matcher)); +} + +TEST_P( + ASTMatchersTest, + TemplateSpecializationTypeLocTest_BindsToTemplateSpecializationExplicitInstantiation) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE( + matches("template class C {}; template class C;", + classTemplateSpecializationDecl( + hasName("C"), hasTypeLoc(templateSpecializationTypeLoc())))); +} + +TEST_P(ASTMatchersTest, + TemplateSpecializationTypeLocTest_BindsToVarDeclTemplateSpecialization) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(matches( + "template class C {}; C var;", + varDecl(hasName("var"), hasTypeLoc(templateSpecializationTypeLoc())))); +} + +TEST_P( + ASTMatchersTest, + TemplateSpecializationTypeLocTest_DoesNotBindToNonTemplateSpecialization) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(notMatches( + "class C {}; C var;", + varDecl(hasName("var"), hasTypeLoc(templateSpecializationTypeLoc())))); +} + +TEST_P(ASTMatchersTest, + ElaboratedTypeLocTest_BindsToElaboratedObjectDeclaration) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(matches("class C {}; class C c;", + varDecl(hasName("c"), hasTypeLoc(elaboratedTypeLoc())))); +} + +TEST_P(ASTMatchersTest, + ElaboratedTypeLocTest_BindsToNamespaceElaboratedObjectDeclaration) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(matches("namespace N { class D {}; } N::D d;", + varDecl(hasName("d"), hasTypeLoc(elaboratedTypeLoc())))); +} + +TEST_P(ASTMatchersTest, + ElaboratedTypeLocTest_BindsToElaboratedStructDeclaration) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE(matches("struct s {}; struct s ss;", + varDecl(hasName("ss"), hasTypeLoc(elaboratedTypeLoc())))); +} + +TEST_P(ASTMatchersTest, + ElaboratedTypeLocTest_DoesNotBindToNonElaboratedObjectDeclaration) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE( + notMatches("class C {}; C c;", + varDecl(hasName("c"), hasTypeLoc(elaboratedTypeLoc())))); +} + +TEST_P( + ASTMatchersTest, + ElaboratedTypeLocTest_DoesNotBindToNamespaceNonElaboratedObjectDeclaration) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE( + notMatches("namespace N { class D {}; } using N::D; D d;", + varDecl(hasName("d"), hasTypeLoc(elaboratedTypeLoc())))); +} + +TEST_P(ASTMatchersTest, + ElaboratedTypeLocTest_DoesNotBindToNonElaboratedStructDeclaration) { + if (!GetParam().isCXX()) { + return; + } + EXPECT_TRUE( + notMatches("struct s {}; s ss;", + varDecl(hasName("ss"), hasTypeLoc(elaboratedTypeLoc())))); +} + TEST(ASTMatchersTestObjC, ObjCMessageExpr) { // Don't find ObjCMessageExpr where none are present. EXPECT_TRUE(notMatchesObjC("", objcMessageExpr(anything()))); diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -5764,5 +5764,425 @@ IsPlacementNew)); } +TEST(HasUnqualifiedLoc, BindsToConstIntVarDecl) { + EXPECT_TRUE(matches("const int x = 0;", qualifiedTypeLoc(hasUnqualifiedLoc( + loc(asString("int")))))); +} + +TEST(HasUnqualifiedLoc, BindsToVolatileIntVarDecl) { + EXPECT_TRUE(matches("volatile int x = 0;", qualifiedTypeLoc(hasUnqualifiedLoc( + loc(asString("int")))))); +} + +TEST(HasUnqualifiedLoc, BindsToConstVolatileIntPointerVarDecl) { + EXPECT_TRUE( + matches("const volatile int* x = 0;", + qualifiedTypeLoc(hasUnqualifiedLoc(loc(asString("int")))))); +} + +TEST(HasUnqualifiedLoc, BindsToConstIntFunctionDecl) { + EXPECT_TRUE( + matches("const int f() { return 5; }", + qualifiedTypeLoc(hasUnqualifiedLoc(loc(asString("int")))))); +} + +TEST(HasUnqualifiedLoc, FloatBindsToConstFloatVarDecl) { + EXPECT_TRUE(matches("const float x = 0;", qualifiedTypeLoc(hasUnqualifiedLoc( + loc(asString("float")))))); +} + +TEST(HasUnqualifiedLoc, FloatDoesNotBindToIntVarDecl) { + EXPECT_TRUE(notMatches("int x = 0;", qualifiedTypeLoc(hasUnqualifiedLoc( + loc(asString("float")))))); +} + +TEST(HasUnqualifiedLoc, FloatDoesNotBindToConstIntVarDecl) { + EXPECT_TRUE(notMatches("const int x = 0;", qualifiedTypeLoc(hasUnqualifiedLoc( + loc(asString("float")))))); +} + +TEST(HasReturnTypeLoc, BindsToIntReturnTypeLoc) { + EXPECT_TRUE(matches( + "int f() { return 5; }", + functionDecl(hasName("f"), hasReturnTypeLoc(loc(asString("int")))))); +} + +TEST(HasReturnTypeLoc, BindsToFloatReturnTypeLoc) { + EXPECT_TRUE(matches( + "float f() { return 5.0; }", + functionDecl(hasName("f"), hasReturnTypeLoc(loc(asString("float")))))); +} + +TEST(HasReturnTypeLoc, BindsToVoidReturnTypeLoc) { + EXPECT_TRUE(matches( + "void f() {}", + functionDecl(hasName("f"), hasReturnTypeLoc(loc(asString("void")))))); +} + +TEST(HasReturnTypeLoc, FloatDoesNotBindToIntReturnTypeLoc) { + EXPECT_TRUE(notMatches( + "int f() { return 5; }", + functionDecl(hasName("f"), hasReturnTypeLoc(loc(asString("float")))))); +} + +TEST(HasReturnTypeLoc, IntDoesNotBindToFloatReturnTypeLoc) { + EXPECT_TRUE(notMatches( + "float f() { return 5.0; }", + functionDecl(hasName("f"), hasReturnTypeLoc(loc(asString("int")))))); +} + +TEST(HasPointeeLoc, BindsToAnyPointeeTypeLoc) { + auto matcher = varDecl(hasName("x"), + hasTypeLoc(pointerTypeLoc(hasPointeeLoc(typeLoc())))); + EXPECT_TRUE(matches("int* x;", matcher)); + EXPECT_TRUE(matches("float* x;", matcher)); + EXPECT_TRUE(matches("char* x;", matcher)); + EXPECT_TRUE(matches("void* x;", matcher)); +} + +TEST(HasPointeeLoc, DoesNotBindToTypeLocWithoutPointee) { + auto matcher = varDecl(hasName("x"), + hasTypeLoc(pointerTypeLoc(hasPointeeLoc(typeLoc())))); + EXPECT_TRUE(notMatches("int x;", matcher)); + EXPECT_TRUE(notMatches("float x;", matcher)); + EXPECT_TRUE(notMatches("char x;", matcher)); +} + +TEST(HasPointeeLoc, BindsToTypeLocPointingToInt) { + EXPECT_TRUE( + matches("int* x;", pointerTypeLoc(hasPointeeLoc(loc(asString("int")))))); +} + +TEST(HasPointeeLoc, BindsToTypeLocPointingToIntPointer) { + EXPECT_TRUE(matches("int** x;", + pointerTypeLoc(hasPointeeLoc(loc(asString("int *")))))); +} + +TEST(HasPointeeLoc, BindsToTypeLocPointingToTypeLocPointingToInt) { + EXPECT_TRUE(matches("int** x;", pointerTypeLoc(hasPointeeLoc(pointerTypeLoc( + hasPointeeLoc(loc(asString("int")))))))); +} + +TEST(HasPointeeLoc, BindsToTypeLocPointingToFloat) { + EXPECT_TRUE(matches("float* x;", + pointerTypeLoc(hasPointeeLoc(loc(asString("float")))))); +} + +TEST(HasPointeeLoc, IntPointeeDoesNotBindToTypeLocPointingToFloat) { + EXPECT_TRUE(notMatches("float* x;", + pointerTypeLoc(hasPointeeLoc(loc(asString("int")))))); +} + +TEST(HasPointeeLoc, FloatPointeeDoesNotBindToTypeLocPointingToInt) { + EXPECT_TRUE(notMatches( + "int* x;", pointerTypeLoc(hasPointeeLoc(loc(asString("float")))))); +} + +TEST(HasReferentLoc, BindsToAnyReferentTypeLoc) { + auto matcher = varDecl( + hasName("r"), hasTypeLoc(referenceTypeLoc(hasReferentLoc(typeLoc())))); + EXPECT_TRUE(matches("int rr = 3; int& r = rr;", matcher)); + EXPECT_TRUE(matches("int rr = 3; auto& r = rr;", matcher)); + EXPECT_TRUE(matches("int rr = 3; const int& r = rr;", matcher)); + EXPECT_TRUE(matches("float rr = 3.0; float& r = rr;", matcher)); + EXPECT_TRUE(matches("char rr = 'a'; char& r = rr;", matcher)); +} + +TEST(HasReferentLoc, DoesNotBindToTypeLocWithoutReferent) { + auto matcher = varDecl( + hasName("r"), hasTypeLoc(referenceTypeLoc(hasReferentLoc(typeLoc())))); + EXPECT_TRUE(notMatches("int r;", matcher)); + EXPECT_TRUE(notMatches("int r = 3;", matcher)); + EXPECT_TRUE(notMatches("const int r = 3;", matcher)); + EXPECT_TRUE(notMatches("int* r;", matcher)); + EXPECT_TRUE(notMatches("float r;", matcher)); + EXPECT_TRUE(notMatches("char r;", matcher)); +} + +TEST(HasReferentLoc, BindsToAnyRvalueReference) { + auto matcher = varDecl( + hasName("r"), hasTypeLoc(referenceTypeLoc(hasReferentLoc(typeLoc())))); + EXPECT_TRUE(matches("int&& r = 3;", matcher)); + EXPECT_TRUE(matches("auto&& r = 3;", matcher)); + EXPECT_TRUE(matches("float&& r = 3.0;", matcher)); +} + +TEST(HasReferentLoc, BindsToIntReferenceTypeLoc) { + EXPECT_TRUE(matches("int rr = 3; int& r = rr;", + referenceTypeLoc(hasReferentLoc(loc(asString("int")))))); +} + +TEST(HasReferentLoc, BindsToIntRvalueReferenceTypeLoc) { + EXPECT_TRUE(matches("int&& r = 3;", + referenceTypeLoc(hasReferentLoc(loc(asString("int")))))); +} + +TEST(HasReferentLoc, BindsToFloatReferenceTypeLoc) { + EXPECT_TRUE( + matches("float rr = 3.0; float& r = rr;", + referenceTypeLoc(hasReferentLoc(loc(asString("float")))))); +} + +TEST(HasReferentLoc, BindsToParameterWithIntReferenceTypeLoc) { + EXPECT_TRUE(matches( + "int f(int& r) { return r; }", + parmVarDecl(hasName("r"), hasTypeLoc(referenceTypeLoc( + hasReferentLoc(loc(asString("int")))))))); +} + +TEST(HasReferentLoc, IntReferenceDoesNotBindToFloatReferenceTypeLoc) { + EXPECT_TRUE( + notMatches("float rr = 3.0; float& r = rr;", + referenceTypeLoc(hasReferentLoc(loc(asString("int")))))); +} + +TEST(HasReferentLoc, FloatReferenceDoesNotBindToIntReferenceTypeLoc) { + EXPECT_TRUE( + notMatches("int rr = 3; int& r = rr;", + referenceTypeLoc(hasReferentLoc(loc(asString("float")))))); +} + +TEST(HasReferentLoc, DoesNotBindToParameterWithoutIntReferenceTypeLoc) { + EXPECT_TRUE(notMatches( + "int f(int r) { return r; }", + parmVarDecl(hasName("r"), hasTypeLoc(referenceTypeLoc( + hasReferentLoc(loc(asString("int")))))))); +} + +TEST(HasAnyTemplateArgumentLoc, BindsToSpecializationWithIntArgument) { + EXPECT_TRUE( + matches("template class A {}; A a;", + varDecl(hasName("a"), hasTypeLoc(templateSpecializationTypeLoc( + hasAnyTemplateArgumentLoc(hasTypeLoc( + loc(asString("int"))))))))); +} + +TEST(HasAnyTemplateArgumentLoc, BindsToSpecializationWithDoubleArgument) { + EXPECT_TRUE( + matches("template class A {}; A a;", + varDecl(hasName("a"), hasTypeLoc(templateSpecializationTypeLoc( + hasAnyTemplateArgumentLoc(hasTypeLoc( + loc(asString("double"))))))))); +} + +TEST(HasAnyTemplateArgumentLoc, BindsToExplicitSpecializationWithIntArgument) { + EXPECT_TRUE(matches( + "template class A {}; template<> class A {};", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc( + hasAnyTemplateArgumentLoc(hasTypeLoc(loc(asString("int"))))))))); +} + +TEST(HasAnyTemplateArgumentLoc, + BindsToExplicitSpecializationWithDoubleArgument) { + EXPECT_TRUE(matches( + "template class A {}; template<> class A {};", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( + hasTypeLoc(loc(asString("double"))))))))); +} + +TEST(HasAnyTemplateArgumentLoc, BindsToSpecializationWithMultipleArguments) { + auto code = R"( + template class A {}; + template<> class A {}; + )"; + EXPECT_TRUE( + matches(code, classTemplateSpecializationDecl( + hasName("A"), hasTypeLoc(templateSpecializationTypeLoc( + hasAnyTemplateArgumentLoc(hasTypeLoc( + loc(asString("double"))))))))); + EXPECT_TRUE(matches( + code, + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc( + hasAnyTemplateArgumentLoc(hasTypeLoc(loc(asString("int"))))))))); +} + +TEST(HasAnyTemplateArgumentLoc, DoesNotBindToSpecializationWithIntArgument) { + EXPECT_TRUE(notMatches( + "template class A {}; A a;", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( + hasTypeLoc(loc(asString("double"))))))))); +} + +TEST(HasAnyTemplateArgumentLoc, + DoesNotBindToExplicitSpecializationWithIntArgument) { + EXPECT_TRUE(notMatches( + "template class A {}; template<> class A {};", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( + hasTypeLoc(loc(asString("double"))))))))); +} + +TEST(HasTemplateArgumentLoc, BindsToSpecializationWithIntArgument) { + EXPECT_TRUE(matches( + "template class A {}; A a;", + varDecl(hasName("a"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("int"))))))))); +} + +TEST(HasTemplateArgumentLoc, BindsToSpecializationWithDoubleArgument) { + EXPECT_TRUE(matches( + "template class A {}; A a;", + varDecl(hasName("a"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("double"))))))))); +} + +TEST(HasTemplateArgumentLoc, BindsToExplicitSpecializationWithIntArgument) { + EXPECT_TRUE(matches( + "template class A {}; template<> class A {};", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc( + hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("int"))))))))); +} + +TEST(HasTemplateArgumentLoc, BindsToExplicitSpecializationWithDoubleArgument) { + EXPECT_TRUE(matches( + "template class A {}; template<> class A {};", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("double"))))))))); +} + +TEST(HasTemplateArgumentLoc, BindsToSpecializationWithMultipleArguments) { + auto code = R"( + template class A {}; + template<> class A {}; + )"; + EXPECT_TRUE(matches( + code, classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("double"))))))))); + EXPECT_TRUE(matches( + code, classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 1, hasTypeLoc(loc(asString("int"))))))))); +} + +TEST(HasTemplateArgumentLoc, DoesNotBindToSpecializationWithIntArgument) { + EXPECT_TRUE(notMatches( + "template class A {}; A a;", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("double"))))))))); +} + +TEST(HasTemplateArgumentLoc, + DoesNotBindToExplicitSpecializationWithIntArgument) { + EXPECT_TRUE(notMatches( + "template class A {}; template<> class A {};", + classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("double"))))))))); +} + +TEST(HasTemplateArgumentLoc, + DoesNotBindToSpecializationWithMisplacedArguments) { + auto code = R"( + template class A {}; + template<> class A {}; + )"; + EXPECT_TRUE(notMatches( + code, classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 1, hasTypeLoc(loc(asString("double"))))))))); + EXPECT_TRUE(notMatches( + code, classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("int"))))))))); +} + +TEST(HasTemplateArgumentLoc, DoesNotBindWithBadIndex) { + auto code = R"( + template class A {}; + template<> class A {}; + )"; + EXPECT_TRUE(notMatches( + code, classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + -1, hasTypeLoc(loc(asString("double"))))))))); + EXPECT_TRUE(notMatches( + code, classTemplateSpecializationDecl( + hasName("A"), + hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc( + 100, hasTypeLoc(loc(asString("int"))))))))); +} + +TEST(HasTemplateArgumentLoc, BindsToDeclRefExprWithIntArgument) { + EXPECT_TRUE(matches(R"( + template T f(T t) { return t; } + int g() { int i = f(3); return i; } + )", + declRefExpr(to(functionDecl(hasName("f"))), + hasTemplateArgumentLoc( + 0, hasTypeLoc(loc(asString("int"))))))); +} + +TEST(HasTemplateArgumentLoc, BindsToDeclRefExprWithDoubleArgument) { + EXPECT_TRUE(matches( + R"( + template T f(T t) { return t; } + double g() { double i = f(3.0); return i; } + )", + declRefExpr( + to(functionDecl(hasName("f"))), + hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("double"))))))); +} + +TEST(HasTemplateArgumentLoc, DoesNotBindToDeclRefExprWithDoubleArgument) { + EXPECT_TRUE(notMatches( + R"( + template T f(T t) { return t; } + double g() { double i = f(3.0); return i; } + )", + declRefExpr( + to(functionDecl(hasName("f"))), + hasTemplateArgumentLoc(0, hasTypeLoc(loc(asString("int"))))))); +} + +TEST(HasNamedTypeLoc, BindsToElaboratedObjectDeclaration) { + EXPECT_TRUE(matches( + R"( + template + class C {}; + class C c; + )", + varDecl(hasName("c"), + hasTypeLoc(elaboratedTypeLoc( + hasNamedTypeLoc(templateSpecializationTypeLoc( + hasAnyTemplateArgumentLoc(templateArgumentLoc())))))))); +} + +TEST(HasNamedTypeLoc, DoesNotBindToNonElaboratedObjectDeclaration) { + EXPECT_TRUE(notMatches( + R"( + template + class C {}; + C c; + )", + varDecl(hasName("c"), + hasTypeLoc(elaboratedTypeLoc( + hasNamedTypeLoc(templateSpecializationTypeLoc( + hasAnyTemplateArgumentLoc(templateArgumentLoc())))))))); +} + } // namespace ast_matchers } // namespace clang