2016-05-18 03:22:57 +08:00
|
|
|
//== unittests/ASTMatchers/ASTMatchersNodeTest.cpp - AST matcher unit tests ==//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2016-05-18 03:22:57 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "ASTMatchersTest.h"
|
|
|
|
#include "clang/AST/PrettyPrinter.h"
|
|
|
|
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
|
|
|
#include "clang/ASTMatchers/ASTMatchers.h"
|
|
|
|
#include "clang/Tooling/Tooling.h"
|
|
|
|
#include "llvm/ADT/Triple.h"
|
|
|
|
#include "llvm/Support/Host.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace ast_matchers {
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, Decl_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
// FIXME: Add a test for `decl()` that does not depend on C++.
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("", decl(usingDecl())));
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("namespace x { class X {}; } using x::X;", decl(usingDecl())));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, NameableDeclaration_MatchesVariousDecls) {
|
2016-05-18 03:22:57 +08:00
|
|
|
DeclarationMatcher NamedX = namedDecl(hasName("X"));
|
|
|
|
EXPECT_TRUE(matches("typedef int X;", NamedX));
|
|
|
|
EXPECT_TRUE(matches("int X;", NamedX));
|
|
|
|
EXPECT_TRUE(matches("void foo() { int X; }", NamedX));
|
|
|
|
EXPECT_TRUE(matches("enum X { A, B, C };", NamedX));
|
|
|
|
|
|
|
|
EXPECT_TRUE(notMatches("#define X 1", NamedX));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, NamedDecl_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DeclarationMatcher NamedX = namedDecl(hasName("X"));
|
|
|
|
EXPECT_TRUE(matches("class foo { virtual void X(); };", NamedX));
|
|
|
|
EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", NamedX));
|
|
|
|
EXPECT_TRUE(matches("namespace X { }", NamedX));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, MatchesNameRE) {
|
2016-05-18 03:22:57 +08:00
|
|
|
DeclarationMatcher NamedX = namedDecl(matchesName("::X"));
|
|
|
|
EXPECT_TRUE(matches("typedef int Xa;", NamedX));
|
|
|
|
EXPECT_TRUE(matches("int Xb;", NamedX));
|
|
|
|
EXPECT_TRUE(matches("void foo() { int Xgh; }", NamedX));
|
|
|
|
EXPECT_TRUE(matches("enum X { A, B, C };", NamedX));
|
|
|
|
|
|
|
|
EXPECT_TRUE(notMatches("#define Xkl 1", NamedX));
|
|
|
|
|
|
|
|
DeclarationMatcher StartsWithNo = namedDecl(matchesName("::no"));
|
|
|
|
EXPECT_TRUE(matches("int no_foo;", StartsWithNo));
|
|
|
|
|
|
|
|
DeclarationMatcher Abc = namedDecl(matchesName("a.*b.*c"));
|
|
|
|
EXPECT_TRUE(matches("int abc;", Abc));
|
|
|
|
EXPECT_TRUE(matches("int aFOObBARc;", Abc));
|
|
|
|
EXPECT_TRUE(notMatches("int cab;", Abc));
|
|
|
|
EXPECT_TRUE(matches("int cabc;", Abc));
|
|
|
|
|
|
|
|
DeclarationMatcher StartsWithK = namedDecl(matchesName(":k[^:]*$"));
|
|
|
|
EXPECT_TRUE(matches("int k;", StartsWithK));
|
|
|
|
EXPECT_TRUE(matches("int kAbc;", StartsWithK));
|
2020-06-29 18:47:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, MatchesNameRE_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DeclarationMatcher NamedX = namedDecl(matchesName("::X"));
|
|
|
|
EXPECT_TRUE(matches("class foo { virtual void Xc(); };", NamedX));
|
|
|
|
EXPECT_TRUE(matches("void foo() try { } catch(int Xdef) { }", NamedX));
|
|
|
|
EXPECT_TRUE(matches("namespace Xij { }", NamedX));
|
|
|
|
|
|
|
|
DeclarationMatcher StartsWithNo = namedDecl(matchesName("::no"));
|
|
|
|
EXPECT_TRUE(matches("class foo { virtual void nobody(); };", StartsWithNo));
|
|
|
|
|
|
|
|
DeclarationMatcher StartsWithK = namedDecl(matchesName(":k[^:]*$"));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("namespace x { int kTest; }", StartsWithK));
|
|
|
|
EXPECT_TRUE(matches("class C { int k; };", StartsWithK));
|
|
|
|
EXPECT_TRUE(notMatches("class C { int ckc; };", StartsWithK));
|
2020-07-02 21:52:24 +08:00
|
|
|
EXPECT_TRUE(notMatches("int K;", StartsWithK));
|
|
|
|
|
|
|
|
DeclarationMatcher StartsWithKIgnoreCase =
|
|
|
|
namedDecl(matchesName(":k[^:]*$", llvm::Regex::IgnoreCase));
|
|
|
|
EXPECT_TRUE(matches("int k;", StartsWithKIgnoreCase));
|
|
|
|
EXPECT_TRUE(matches("int K;", StartsWithKIgnoreCase));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, DeclarationMatcher_MatchClass) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
DeclarationMatcher ClassX = recordDecl(recordDecl(hasName("X")));
|
|
|
|
EXPECT_TRUE(matches("class X;", ClassX));
|
|
|
|
EXPECT_TRUE(matches("class X {};", ClassX));
|
|
|
|
EXPECT_TRUE(matches("template<class T> class X {};", ClassX));
|
|
|
|
EXPECT_TRUE(notMatches("", ClassX));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, TranslationUnitDecl) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
// FIXME: Add a test for `translationUnitDecl()` that does not depend on
|
|
|
|
// C++.
|
|
|
|
return;
|
|
|
|
}
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef Code = "int MyVar1;\n"
|
|
|
|
"namespace NameSpace {\n"
|
|
|
|
"int MyVar2;\n"
|
|
|
|
"} // namespace NameSpace\n";
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches(
|
2020-07-13 11:19:40 +08:00
|
|
|
Code, varDecl(hasName("MyVar1"), hasDeclContext(translationUnitDecl()))));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_FALSE(matches(
|
2020-07-13 11:19:40 +08:00
|
|
|
Code, varDecl(hasName("MyVar2"), hasDeclContext(translationUnitDecl()))));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches(
|
2020-07-13 11:19:40 +08:00
|
|
|
Code,
|
|
|
|
varDecl(hasName("MyVar2"),
|
|
|
|
hasDeclContext(decl(hasDeclContext(translationUnitDecl()))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, LinkageSpecDecl) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("extern \"C\" { void foo() {}; }", linkageSpecDecl()));
|
|
|
|
EXPECT_TRUE(notMatches("void foo() {};", linkageSpecDecl()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ClassTemplateDecl_DoesNotMatchClass) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
DeclarationMatcher ClassX = classTemplateDecl(hasName("X"));
|
|
|
|
EXPECT_TRUE(notMatches("class X;", ClassX));
|
|
|
|
EXPECT_TRUE(notMatches("class X {};", ClassX));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ClassTemplateDecl_MatchesClassTemplate) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
DeclarationMatcher ClassX = classTemplateDecl(hasName("X"));
|
|
|
|
EXPECT_TRUE(matches("template<typename T> class X {};", ClassX));
|
|
|
|
EXPECT_TRUE(matches("class Z { template<class T> class X {}; };", ClassX));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest,
|
|
|
|
ClassTemplateDecl_DoesNotMatchClassTemplateExplicitSpecialization) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
"template<typename T> class X { };"
|
|
|
|
"template<> class X<int> { int a; };",
|
|
|
|
classTemplateDecl(hasName("X"), hasDescendant(fieldDecl(hasName("a"))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest,
|
|
|
|
ClassTemplateDecl_DoesNotMatchClassTemplatePartialSpecialization) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
"template<typename T, typename U> class X { };"
|
|
|
|
"template<typename T> class X<T, int> { int a; };",
|
|
|
|
classTemplateDecl(hasName("X"), hasDescendant(fieldDecl(hasName("a"))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST(ASTMatchersTestCUDA, CUDAKernelCallExpr) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matchesWithCuda("__global__ void f() { }"
|
2020-07-13 11:19:40 +08:00
|
|
|
"void g() { f<<<1, 2>>>(); }",
|
2016-05-18 03:22:57 +08:00
|
|
|
cudaKernelCallExpr()));
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(notMatchesWithCuda("void f() {}", cudaKernelCallExpr()));
|
2020-06-29 18:47:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ASTMatchersTestCUDA, HasAttrCUDA) {
|
|
|
|
EXPECT_TRUE(matchesWithCuda("__attribute__((device)) void f() {}",
|
|
|
|
hasAttr(clang::attr::CUDADevice)));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_FALSE(notMatchesWithCuda("__attribute__((global)) void f() {}",
|
|
|
|
hasAttr(clang::attr::CUDAGlobal)));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ValueDecl) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
// FIXME: Fix this test in non-C++ language modes.
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("enum EnumType { EnumValue };",
|
|
|
|
valueDecl(hasType(asString("enum EnumType")))));
|
|
|
|
EXPECT_TRUE(matches("void FunctionDecl();",
|
|
|
|
valueDecl(hasType(asString("void (void)")))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, FriendDecl) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2018-06-18 17:23:08 +08:00
|
|
|
EXPECT_TRUE(matches("class Y { friend class X; };",
|
|
|
|
friendDecl(hasType(asString("class X")))));
|
|
|
|
EXPECT_TRUE(matches("class Y { friend class X; };",
|
|
|
|
friendDecl(hasType(recordDecl(hasName("X"))))));
|
|
|
|
|
|
|
|
EXPECT_TRUE(matches("class Y { friend void f(); };",
|
|
|
|
functionDecl(hasName("f"), hasParent(friendDecl()))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, EnumDecl_DoesNotMatchClasses) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("class X {};", enumDecl(hasName("X"))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, EnumDecl_MatchesEnums) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
// FIXME: Fix this test in non-C++ language modes.
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("enum X {};", enumDecl(hasName("X"))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, EnumConstantDecl) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
// FIXME: Fix this test in non-C++ language modes.
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
DeclarationMatcher Matcher = enumConstantDecl(hasName("A"));
|
|
|
|
EXPECT_TRUE(matches("enum X{ A };", Matcher));
|
|
|
|
EXPECT_TRUE(notMatches("enum X{ B };", Matcher));
|
|
|
|
EXPECT_TRUE(notMatches("enum X {};", Matcher));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, TagDecl) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
// FIXME: Fix this test in non-C++ language modes.
|
|
|
|
return;
|
|
|
|
}
|
2020-01-29 20:57:27 +08:00
|
|
|
EXPECT_TRUE(matches("struct X {};", tagDecl(hasName("X"))));
|
|
|
|
EXPECT_TRUE(matches("union U {};", tagDecl(hasName("U"))));
|
|
|
|
EXPECT_TRUE(matches("enum E {};", tagDecl(hasName("E"))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, TagDecl_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(matches("class C {};", tagDecl(hasName("C"))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, UnresolvedLookupExpr) {
|
|
|
|
if (!GetParam().isCXX() || GetParam().hasDelayedTemplateParsing()) {
|
|
|
|
// FIXME: Fix this test to work with delayed template parsing.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPECT_TRUE(matches("template<typename T>"
|
|
|
|
"T foo() { T a; return a; }"
|
|
|
|
"template<typename T>"
|
|
|
|
"void bar() {"
|
|
|
|
" foo<T>();"
|
|
|
|
"}",
|
|
|
|
unresolvedLookupExpr()));
|
2016-05-18 20:53:59 +08:00
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, UsesADL) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
[AST] Store "UsesADL" information in CallExpr.
Summary:
Currently the Clang AST doesn't store information about how the callee of a CallExpr was found. Specifically if it was found using ADL.
However, this information is invaluable to tooling. Consider a tool which renames usages of a function. If the originally CallExpr was formed using ADL, then the tooling may need to additionally qualify the replacement.
Without information about how the callee was found, the tooling is left scratching it's head. Additionally, we want to be able to match ADL calls as quickly as possible, which means avoiding computing the answer on the fly.
This patch changes `CallExpr` to store whether it's callee was found using ADL. It does not change the size of any AST nodes.
Reviewers: fowles, rsmith, klimek, shafik
Reviewed By: rsmith
Subscribers: aaron.ballman, riccibruno, calabrese, titus, cfe-commits
Differential Revision: https://reviews.llvm.org/D55534
llvm-svn: 348977
2018-12-13 05:50:55 +08:00
|
|
|
StatementMatcher ADLMatch = callExpr(usesADL());
|
|
|
|
StatementMatcher ADLMatchOper = cxxOperatorCallExpr(usesADL());
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef NS_Str = R"cpp(
|
[AST] Store "UsesADL" information in CallExpr.
Summary:
Currently the Clang AST doesn't store information about how the callee of a CallExpr was found. Specifically if it was found using ADL.
However, this information is invaluable to tooling. Consider a tool which renames usages of a function. If the originally CallExpr was formed using ADL, then the tooling may need to additionally qualify the replacement.
Without information about how the callee was found, the tooling is left scratching it's head. Additionally, we want to be able to match ADL calls as quickly as possible, which means avoiding computing the answer on the fly.
This patch changes `CallExpr` to store whether it's callee was found using ADL. It does not change the size of any AST nodes.
Reviewers: fowles, rsmith, klimek, shafik
Reviewed By: rsmith
Subscribers: aaron.ballman, riccibruno, calabrese, titus, cfe-commits
Differential Revision: https://reviews.llvm.org/D55534
llvm-svn: 348977
2018-12-13 05:50:55 +08:00
|
|
|
namespace NS {
|
|
|
|
struct X {};
|
|
|
|
void f(X);
|
|
|
|
void operator+(X, X);
|
|
|
|
}
|
|
|
|
struct MyX {};
|
|
|
|
void f(...);
|
|
|
|
void operator+(MyX, MyX);
|
|
|
|
)cpp";
|
|
|
|
|
2020-06-03 04:20:58 +08:00
|
|
|
auto MkStr = [&](StringRef Body) {
|
|
|
|
return (NS_Str + "void test_fn() { " + Body + " }").str();
|
[AST] Store "UsesADL" information in CallExpr.
Summary:
Currently the Clang AST doesn't store information about how the callee of a CallExpr was found. Specifically if it was found using ADL.
However, this information is invaluable to tooling. Consider a tool which renames usages of a function. If the originally CallExpr was formed using ADL, then the tooling may need to additionally qualify the replacement.
Without information about how the callee was found, the tooling is left scratching it's head. Additionally, we want to be able to match ADL calls as quickly as possible, which means avoiding computing the answer on the fly.
This patch changes `CallExpr` to store whether it's callee was found using ADL. It does not change the size of any AST nodes.
Reviewers: fowles, rsmith, klimek, shafik
Reviewed By: rsmith
Subscribers: aaron.ballman, riccibruno, calabrese, titus, cfe-commits
Differential Revision: https://reviews.llvm.org/D55534
llvm-svn: 348977
2018-12-13 05:50:55 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
EXPECT_TRUE(matches(MkStr("NS::X x; f(x);"), ADLMatch));
|
|
|
|
EXPECT_TRUE(notMatches(MkStr("NS::X x; NS::f(x);"), ADLMatch));
|
|
|
|
EXPECT_TRUE(notMatches(MkStr("MyX x; f(x);"), ADLMatch));
|
|
|
|
EXPECT_TRUE(notMatches(MkStr("NS::X x; using NS::f; f(x);"), ADLMatch));
|
|
|
|
|
|
|
|
// Operator call expressions
|
|
|
|
EXPECT_TRUE(matches(MkStr("NS::X x; x + x;"), ADLMatch));
|
|
|
|
EXPECT_TRUE(matches(MkStr("NS::X x; x + x;"), ADLMatchOper));
|
|
|
|
EXPECT_TRUE(notMatches(MkStr("MyX x; x + x;"), ADLMatch));
|
|
|
|
EXPECT_TRUE(notMatches(MkStr("MyX x; x + x;"), ADLMatchOper));
|
|
|
|
EXPECT_TRUE(matches(MkStr("NS::X x; operator+(x, x);"), ADLMatch));
|
|
|
|
EXPECT_TRUE(notMatches(MkStr("NS::X x; NS::operator+(x, x);"), ADLMatch));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CallExpr_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
// FIXME: Add a test for `callExpr()` that does not depend on C++.
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
// FIXME: Do we want to overload Call() to directly take
|
|
|
|
// Matcher<Decl>, too?
|
|
|
|
StatementMatcher MethodX =
|
2020-07-13 11:19:40 +08:00
|
|
|
callExpr(hasDeclaration(cxxMethodDecl(hasName("x"))));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(matches("class Y { void x() { x(); } };", MethodX));
|
|
|
|
EXPECT_TRUE(notMatches("class Y { void x() {} };", MethodX));
|
|
|
|
|
|
|
|
StatementMatcher MethodOnY =
|
2020-07-13 11:19:40 +08:00
|
|
|
cxxMemberCallExpr(on(hasType(recordDecl(hasName("Y")))));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
|
|
|
|
MethodOnY));
|
|
|
|
EXPECT_TRUE(matches("class Y { public: void x(); }; void z(Y &y) { y.x(); }",
|
|
|
|
MethodOnY));
|
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
"class Y { public: void x(); }; void z(Y *&y) { y->x(); }", MethodOnY));
|
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
"class Y { public: void x(); }; void z(Y y[]) { y->x(); }", MethodOnY));
|
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
"class Y { public: void x(); }; void z() { Y *y; y->x(); }", MethodOnY));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
StatementMatcher MethodOnYPointer =
|
2020-07-13 11:19:40 +08:00
|
|
|
cxxMemberCallExpr(on(hasType(pointsTo(recordDecl(hasName("Y"))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("class Y { public: void x(); }; void z() { Y *y; y->x(); }",
|
|
|
|
MethodOnYPointer));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("class Y { public: void x(); }; void z(Y *&y) { y->x(); }",
|
|
|
|
MethodOnYPointer));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("class Y { public: void x(); }; void z(Y y[]) { y->x(); }",
|
|
|
|
MethodOnYPointer));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
notMatches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
|
|
|
|
MethodOnYPointer));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
notMatches("class Y { public: void x(); }; void z(Y &y) { y.x(); }",
|
|
|
|
MethodOnYPointer));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
2020-06-29 18:47:51 +08:00
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, LambdaExpr) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("auto f = [] (int i) { return i; };", lambdaExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CXXForRangeStmt) {
|
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches("void f() { for (int i; i<5; ++i); }", cxxForRangeStmt()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, CXXForRangeStmt_CXX11) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("int as[] = { 1, 2, 3 };"
|
2020-07-13 11:19:40 +08:00
|
|
|
"void f() { for (auto &a : as); }",
|
2016-05-18 03:22:57 +08:00
|
|
|
cxxForRangeStmt()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, SubstNonTypeTemplateParmExpr) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_FALSE(matches("template<int N>\n"
|
2020-07-13 11:19:40 +08:00
|
|
|
"struct A { static const int n = 0; };\n"
|
|
|
|
"struct B : public A<42> {};",
|
|
|
|
traverse(TK_AsIs, substNonTypeTemplateParmExpr())));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("template<int N>\n"
|
2020-07-13 11:19:40 +08:00
|
|
|
"struct A { static const int n = N; };\n"
|
|
|
|
"struct B : public A<42> {};",
|
|
|
|
traverse(TK_AsIs, substNonTypeTemplateParmExpr())));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, NonTypeTemplateParmDecl) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("template <int N> void f();",
|
|
|
|
nonTypeTemplateParmDecl(hasName("N"))));
|
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
notMatches("template <typename T> void f();", nonTypeTemplateParmDecl()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, TemplateTypeParmDecl) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("template <typename T> void f();",
|
|
|
|
templateTypeParmDecl(hasName("T"))));
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(notMatches("template <int N> void f();", templateTypeParmDecl()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-08-11 22:54:15 +08:00
|
|
|
TEST_P(ASTMatchersTest, TemplateTemplateParmDecl) {
|
|
|
|
if (!GetParam().isCXX())
|
|
|
|
return;
|
|
|
|
EXPECT_TRUE(matches("template <template <typename> class Z> void f();",
|
|
|
|
templateTemplateParmDecl(hasName("Z"))));
|
|
|
|
EXPECT_TRUE(notMatches("template <typename, int> void f();",
|
|
|
|
templateTemplateParmDecl()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, UserDefinedLiteral) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("constexpr char operator \"\" _inc (const char i) {"
|
2020-07-13 11:19:40 +08:00
|
|
|
" return i + 1;"
|
|
|
|
"}"
|
|
|
|
"char c = 'a'_inc;",
|
2016-05-18 03:22:57 +08:00
|
|
|
userDefinedLiteral()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, FlowControl) {
|
|
|
|
EXPECT_TRUE(matches("void f() { while(1) { break; } }", breakStmt()));
|
|
|
|
EXPECT_TRUE(matches("void f() { while(1) { continue; } }", continueStmt()));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void f() { goto FOO; FOO: ;}", gotoStmt()));
|
|
|
|
EXPECT_TRUE(matches("void f() { goto FOO; FOO: ;}",
|
2020-07-13 11:19:40 +08:00
|
|
|
labelStmt(hasDeclaration(labelDecl(hasName("FOO"))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void f() { FOO: ; void *ptr = &&FOO; goto *ptr; }",
|
|
|
|
addrLabelExpr()));
|
|
|
|
EXPECT_TRUE(matches("void f() { return; }", returnStmt()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CXXOperatorCallExpr) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-18 03:22:57 +08:00
|
|
|
StatementMatcher OpCall = cxxOperatorCallExpr();
|
|
|
|
// Unary operator
|
|
|
|
EXPECT_TRUE(matches("class Y { }; "
|
2020-07-13 11:19:40 +08:00
|
|
|
"bool operator!(Y x) { return false; }; "
|
|
|
|
"Y y; bool c = !y;",
|
|
|
|
OpCall));
|
2016-05-18 03:22:57 +08:00
|
|
|
// No match -- special operators like "new", "delete"
|
|
|
|
// FIXME: operator new takes size_t, for which we need stddef.h, for which
|
|
|
|
// we need to figure out include paths in the test.
|
|
|
|
// EXPECT_TRUE(NotMatches("#include <stddef.h>\n"
|
|
|
|
// "class Y { }; "
|
|
|
|
// "void *operator new(size_t size) { return 0; } "
|
|
|
|
// "Y *y = new Y;", OpCall));
|
|
|
|
EXPECT_TRUE(notMatches("class Y { }; "
|
2020-07-13 11:19:40 +08:00
|
|
|
"void operator delete(void *p) { } "
|
|
|
|
"void a() {Y *y = new Y; delete y;}",
|
|
|
|
OpCall));
|
2016-05-18 03:22:57 +08:00
|
|
|
// Binary operator
|
|
|
|
EXPECT_TRUE(matches("class Y { }; "
|
2020-07-13 11:19:40 +08:00
|
|
|
"bool operator&&(Y x, Y y) { return true; }; "
|
|
|
|
"Y a; Y b; bool c = a && b;",
|
2016-05-18 03:22:57 +08:00
|
|
|
OpCall));
|
|
|
|
// No match -- normal operator, not an overloaded one.
|
|
|
|
EXPECT_TRUE(notMatches("bool x = true, y = true; bool t = x && y;", OpCall));
|
|
|
|
EXPECT_TRUE(notMatches("int t = 5 << 2;", OpCall));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ThisPointerType) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-11 07:52:35 +08:00
|
|
|
StatementMatcher MethodOnY = traverse(
|
|
|
|
TK_AsIs, cxxMemberCallExpr(thisPointerType(recordDecl(hasName("Y")))));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
|
|
|
|
MethodOnY));
|
|
|
|
EXPECT_TRUE(matches("class Y { public: void x(); }; void z(Y &y) { y.x(); }",
|
|
|
|
MethodOnY));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches(
|
2020-07-13 11:19:40 +08:00
|
|
|
"class Y { public: void x(); }; void z(Y *&y) { y->x(); }", MethodOnY));
|
|
|
|
EXPECT_TRUE(matches(
|
|
|
|
"class Y { public: void x(); }; void z(Y y[]) { y->x(); }", MethodOnY));
|
|
|
|
EXPECT_TRUE(matches(
|
|
|
|
"class Y { public: void x(); }; void z() { Y *y; y->x(); }", MethodOnY));
|
|
|
|
|
|
|
|
EXPECT_TRUE(matches("class Y {"
|
|
|
|
" public: virtual void x();"
|
|
|
|
"};"
|
|
|
|
"class X : public Y {"
|
|
|
|
" public: virtual void x();"
|
|
|
|
"};"
|
|
|
|
"void z() { X *x; x->Y::x(); }",
|
|
|
|
MethodOnY));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, DeclRefExpr) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
// FIXME: Add a test for `declRefExpr()` that does not depend on C++.
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
StatementMatcher Reference = declRefExpr(to(varDecl(hasInitializer(
|
|
|
|
cxxMemberCallExpr(thisPointerType(recordDecl(hasName("Y"))))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("class Y {"
|
|
|
|
" public:"
|
|
|
|
" bool x() const;"
|
|
|
|
"};"
|
|
|
|
"void z(const Y &y) {"
|
|
|
|
" bool b = y.x();"
|
|
|
|
" if (b) {}"
|
|
|
|
"}",
|
|
|
|
Reference));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(notMatches("class Y {"
|
|
|
|
" public:"
|
|
|
|
" bool x() const;"
|
|
|
|
"};"
|
|
|
|
"void z(const Y &y) {"
|
|
|
|
" bool b = y.x();"
|
|
|
|
"}",
|
|
|
|
Reference));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CXXMemberCallExpr) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
StatementMatcher CallOnVariableY =
|
2020-07-13 11:19:40 +08:00
|
|
|
cxxMemberCallExpr(on(declRefExpr(to(varDecl(hasName("y"))))));
|
|
|
|
|
|
|
|
EXPECT_TRUE(matches("class Y { public: void x() { Y y; y.x(); } };",
|
|
|
|
CallOnVariableY));
|
|
|
|
EXPECT_TRUE(matches("class Y { public: void x() const { Y y; y.x(); } };",
|
|
|
|
CallOnVariableY));
|
|
|
|
EXPECT_TRUE(matches("class Y { public: void x(); };"
|
|
|
|
"class X : public Y { void z() { X y; y.x(); } };",
|
|
|
|
CallOnVariableY));
|
|
|
|
EXPECT_TRUE(matches("class Y { public: void x(); };"
|
|
|
|
"class X : public Y { void z() { X *y; y->x(); } };",
|
|
|
|
CallOnVariableY));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches(
|
2020-07-13 11:19:40 +08:00
|
|
|
"class Y { public: void x(); };"
|
2016-05-18 03:22:57 +08:00
|
|
|
"class X : public Y { void z() { unsigned long y; ((X*)y)->x(); } };",
|
2020-07-13 11:19:40 +08:00
|
|
|
CallOnVariableY));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, UnaryExprOrTypeTraitExpr) {
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("void x() { int a = sizeof(a); }", unaryExprOrTypeTraitExpr()));
|
2020-06-29 18:47:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, AlignOfExpr) {
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches("void x() { int a = sizeof(a); }", alignOfExpr(anything())));
|
2016-05-18 03:22:57 +08:00
|
|
|
// FIXME: Uncomment once alignof is enabled.
|
|
|
|
// EXPECT_TRUE(matches("void x() { int a = alignof(a); }",
|
|
|
|
// unaryExprOrTypeTraitExpr()));
|
|
|
|
// EXPECT_TRUE(notMatches("void x() { int a = alignof(a); }",
|
|
|
|
// sizeOfExpr()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, MemberExpr_DoesNotMatchClasses) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("class Y { void x() {} };", memberExpr()));
|
2018-08-13 01:34:36 +08:00
|
|
|
EXPECT_TRUE(notMatches("class Y { void x() {} };", unresolvedMemberExpr()));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches("class Y { void x() {} };", cxxDependentScopeMemberExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, MemberExpr_MatchesMemberFunctionCall) {
|
|
|
|
if (!GetParam().isCXX() || GetParam().hasDelayedTemplateParsing()) {
|
|
|
|
// FIXME: Fix this test to work with delayed template parsing.
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("class Y { void x() { x(); } };", memberExpr()));
|
2018-08-13 01:34:36 +08:00
|
|
|
EXPECT_TRUE(matches("class Y { template <class T> void x() { x<T>(); } };",
|
|
|
|
unresolvedMemberExpr()));
|
|
|
|
EXPECT_TRUE(matches("template <class T> void x() { T t; t.f(); }",
|
|
|
|
cxxDependentScopeMemberExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, MemberExpr_MatchesVariable) {
|
|
|
|
if (!GetParam().isCXX() || GetParam().hasDelayedTemplateParsing()) {
|
|
|
|
// FIXME: Fix this test to work with delayed template parsing.
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("class Y { void x() { this->y; } int y; };", memberExpr()));
|
|
|
|
EXPECT_TRUE(matches("class Y { void x() { y; } int y; };", memberExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("class Y { void x() { Y y; y.y; } int y; };", memberExpr()));
|
2018-08-13 01:34:36 +08:00
|
|
|
EXPECT_TRUE(matches("template <class T>"
|
|
|
|
"class X : T { void f() { this->T::v; } };",
|
|
|
|
cxxDependentScopeMemberExpr()));
|
|
|
|
EXPECT_TRUE(matches("template <class T> class X : T { void f() { T::v; } };",
|
|
|
|
cxxDependentScopeMemberExpr()));
|
|
|
|
EXPECT_TRUE(matches("template <class T> void x() { T t; t.v; }",
|
|
|
|
cxxDependentScopeMemberExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, MemberExpr_MatchesStaticVariable) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("class Y { void x() { this->y; } static int y; };",
|
|
|
|
memberExpr()));
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches("class Y { void x() { y; } static int y; };", memberExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("class Y { void x() { Y::y; } static int y; };",
|
|
|
|
memberExpr()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, FunctionDecl) {
|
2016-05-18 03:22:57 +08:00
|
|
|
StatementMatcher CallFunctionF = callExpr(callee(functionDecl(hasName("f"))));
|
|
|
|
|
|
|
|
EXPECT_TRUE(matches("void f() { f(); }", CallFunctionF));
|
|
|
|
EXPECT_TRUE(notMatches("void f() { }", CallFunctionF));
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(notMatches("void f(int);", functionDecl(isVariadic())));
|
|
|
|
EXPECT_TRUE(notMatches("void f();", functionDecl(isVariadic())));
|
|
|
|
EXPECT_TRUE(matches("void f(int, ...);", functionDecl(parameterCountIs(1))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, FunctionDecl_C) {
|
|
|
|
if (!GetParam().isC()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(notMatches("void f();", functionDecl(isVariadic())));
|
|
|
|
EXPECT_TRUE(matches("void f();", functionDecl(parameterCountIs(0))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, FunctionDecl_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
StatementMatcher CallFunctionF = callExpr(callee(functionDecl(hasName("f"))));
|
|
|
|
|
|
|
|
if (!GetParam().hasDelayedTemplateParsing()) {
|
|
|
|
// FIXME: Fix this test to work with delayed template parsing.
|
2016-05-18 03:22:57 +08:00
|
|
|
// Dependent contexts, but a non-dependent call.
|
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("void f(); template <int N> void g() { f(); }", CallFunctionF));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("void f(); template <int N> struct S { void g() { f(); } };",
|
|
|
|
CallFunctionF));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Depedent calls don't match.
|
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
notMatches("void f(int); template <typename T> void g(T t) { f(t); }",
|
|
|
|
CallFunctionF));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
notMatches("void f(int);"
|
2016-05-18 03:22:57 +08:00
|
|
|
"template <typename T> struct S { void g(T t) { f(t); } };",
|
2020-07-13 11:19:40 +08:00
|
|
|
CallFunctionF));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(matches("void f(...);", functionDecl(isVariadic())));
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(matches("void f(...);", functionDecl(parameterCountIs(0))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, FunctionDecl_CXX11) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("template <typename... Ts> void f(Ts...);",
|
|
|
|
functionDecl(isVariadic())));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest,
|
|
|
|
FunctionTemplateDecl_MatchesFunctionTemplateDeclarations) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("template <typename T> void f(T t) {}",
|
|
|
|
functionTemplateDecl(hasName("f"))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, FunctionTemplate_DoesNotMatchFunctionDeclarations) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(
|
2020-06-29 18:47:51 +08:00
|
|
|
notMatches("void f(double d);", functionTemplateDecl(hasName("f"))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches("void f(int t) {}", functionTemplateDecl(hasName("f"))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest,
|
|
|
|
FunctionTemplateDecl_DoesNotMatchFunctionTemplateSpecializations) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
"void g(); template <typename T> void f(T t) {}"
|
|
|
|
"template <> void f(int t) { g(); }",
|
|
|
|
functionTemplateDecl(hasName("f"), hasDescendant(declRefExpr(to(
|
|
|
|
functionDecl(hasName("g"))))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ClassTemplateSpecializationDecl) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("template<typename T> struct A {};"
|
2020-07-13 11:19:40 +08:00
|
|
|
"template<> struct A<int> {};",
|
2016-05-18 03:22:57 +08:00
|
|
|
classTemplateSpecializationDecl()));
|
|
|
|
EXPECT_TRUE(matches("template<typename T> struct A {}; A<int> a;",
|
|
|
|
classTemplateSpecializationDecl()));
|
|
|
|
EXPECT_TRUE(notMatches("template<typename T> struct A {};",
|
|
|
|
classTemplateSpecializationDecl()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, DeclaratorDecl) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("int x;", declaratorDecl()));
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(notMatches("struct A {};", declaratorDecl()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, DeclaratorDecl_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("class A {};", declaratorDecl()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ParmVarDecl) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void f(int x);", parmVarDecl()));
|
|
|
|
EXPECT_TRUE(notMatches("void f();", parmVarDecl()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, Matcher_ConstructorCall) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-11 07:52:35 +08:00
|
|
|
StatementMatcher Constructor = traverse(TK_AsIs, cxxConstructExpr());
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("class X { public: X(); }; void x() { X x; }", Constructor));
|
|
|
|
EXPECT_TRUE(matches("class X { public: X(); }; void x() { X x = X(); }",
|
|
|
|
Constructor));
|
|
|
|
EXPECT_TRUE(matches("class X { public: X(int); }; void x() { X x = 0; }",
|
|
|
|
Constructor));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("class X {}; void x(int) { X x; }", Constructor));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, Match_ConstructorInitializers) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-09-27 01:04:27 +08:00
|
|
|
EXPECT_TRUE(matches("class C { int i; public: C(int ii) : i(ii) {} };",
|
|
|
|
cxxCtorInitializer(forField(hasName("i")))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, Matcher_ThisExpr) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("struct X { int a; int f () { return a; } };", cxxThisExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
notMatches("struct X { int f () { int a; return a; } };", cxxThisExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, Matcher_BindTemporaryExpression) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-11 07:52:35 +08:00
|
|
|
StatementMatcher TempExpression = traverse(TK_AsIs, cxxBindTemporaryExpr());
|
2016-05-18 03:22:57 +08:00
|
|
|
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef ClassString = "class string { public: string(); ~string(); }; ";
|
2016-05-18 03:22:57 +08:00
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches(
|
|
|
|
ClassString + "string GetStringByValue();"
|
|
|
|
"void FunctionTakesString(string s);"
|
|
|
|
"void run() { FunctionTakesString(GetStringByValue()); }",
|
|
|
|
TempExpression));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(notMatches(ClassString +
|
|
|
|
"string* GetStringPointer(); "
|
|
|
|
"void FunctionTakesStringPtr(string* s);"
|
|
|
|
"void run() {"
|
|
|
|
" string* s = GetStringPointer();"
|
|
|
|
" FunctionTakesStringPtr(GetStringPointer());"
|
|
|
|
" FunctionTakesStringPtr(s);"
|
|
|
|
"}",
|
|
|
|
TempExpression));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(notMatches("class no_dtor {};"
|
|
|
|
"no_dtor GetObjByValue();"
|
|
|
|
"void ConsumeObj(no_dtor param);"
|
|
|
|
"void run() { ConsumeObj(GetObjByValue()); }",
|
|
|
|
TempExpression));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, MaterializeTemporaryExpr_MatchesTemporaryCXX11CXX14) {
|
|
|
|
if (GetParam().Language != Lang_CXX11 && GetParam().Language != Lang_CXX14) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-12 21:29:40 +08:00
|
|
|
StatementMatcher TempExpression =
|
2020-12-11 07:52:35 +08:00
|
|
|
traverse(TK_AsIs, materializeTemporaryExpr());
|
2016-05-18 03:22:57 +08:00
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(matches("class string { public: string(); }; "
|
|
|
|
"string GetStringByValue();"
|
|
|
|
"void FunctionTakesString(string s);"
|
|
|
|
"void run() { FunctionTakesString(GetStringByValue()); }",
|
|
|
|
TempExpression));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, MaterializeTemporaryExpr_MatchesTemporary) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ClassString = "class string { public: string(); int length(); }; ";
|
|
|
|
StatementMatcher TempExpression =
|
2020-12-11 07:52:35 +08:00
|
|
|
traverse(TK_AsIs, materializeTemporaryExpr());
|
2019-11-12 21:29:40 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(notMatches(ClassString +
|
|
|
|
"string* GetStringPointer(); "
|
|
|
|
"void FunctionTakesStringPtr(string* s);"
|
|
|
|
"void run() {"
|
|
|
|
" string* s = GetStringPointer();"
|
|
|
|
" FunctionTakesStringPtr(GetStringPointer());"
|
|
|
|
" FunctionTakesStringPtr(s);"
|
|
|
|
"}",
|
|
|
|
TempExpression));
|
|
|
|
|
|
|
|
EXPECT_TRUE(matches(ClassString +
|
|
|
|
"string GetStringByValue();"
|
|
|
|
"void run() { int k = GetStringByValue().length(); }",
|
|
|
|
TempExpression));
|
|
|
|
|
|
|
|
EXPECT_TRUE(notMatches(ClassString + "string GetStringByValue();"
|
|
|
|
"void run() { GetStringByValue(); }",
|
|
|
|
TempExpression));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, Matcher_NewExpression) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-18 03:22:57 +08:00
|
|
|
StatementMatcher New = cxxNewExpr();
|
|
|
|
|
|
|
|
EXPECT_TRUE(matches("class X { public: X(); }; void x() { new X; }", New));
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("class X { public: X(); }; void x() { new X(); }", New));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("class X { public: X(int); }; void x() { new X(0); }", New));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("class X {}; void x(int) { new X; }", New));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, Matcher_DeleteExpression) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("struct A {}; void f(A* a) { delete a; }", cxxDeleteExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, Matcher_NoexceptExpression) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-01-28 21:12:08 +08:00
|
|
|
StatementMatcher NoExcept = cxxNoexceptExpr();
|
|
|
|
EXPECT_TRUE(matches("void foo(); bool bar = noexcept(foo());", NoExcept));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("void foo() noexcept; bool bar = noexcept(foo());", NoExcept));
|
|
|
|
EXPECT_TRUE(notMatches("void foo() noexcept;", NoExcept));
|
2021-08-06 22:26:39 +08:00
|
|
|
EXPECT_TRUE(notMatches("void foo() noexcept(0+1);", NoExcept));
|
2020-01-28 21:12:08 +08:00
|
|
|
EXPECT_TRUE(matches("void foo() noexcept(noexcept(1+1));", NoExcept));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, Matcher_DefaultArgument) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
StatementMatcher Arg = cxxDefaultArgExpr();
|
|
|
|
EXPECT_TRUE(matches("void x(int, int = 0) { int y; x(y); }", Arg));
|
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("class X { void x(int, int = 0) { int y; x(y); } };", Arg));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("void x(int, int = 0) { int y; x(y, 0); }", Arg));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, StringLiteral) {
|
2016-05-18 03:22:57 +08:00
|
|
|
StatementMatcher Literal = stringLiteral();
|
|
|
|
EXPECT_TRUE(matches("const char *s = \"string\";", Literal));
|
|
|
|
// with escaped characters
|
|
|
|
EXPECT_TRUE(matches("const char *s = \"\x05five\";", Literal));
|
|
|
|
// no matching -- though the data type is the same, there is no string literal
|
|
|
|
EXPECT_TRUE(notMatches("const char s[1] = {'a'};", Literal));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, StringLiteral_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(matches("const wchar_t *s = L\"string\";", stringLiteral()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, CharacterLiteral) {
|
|
|
|
EXPECT_TRUE(matches("const char c = 'c';", characterLiteral()));
|
|
|
|
EXPECT_TRUE(notMatches("const char c = 0x1;", characterLiteral()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, CharacterLiteral_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
// wide character
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(matches("const char c = L'c';", characterLiteral()));
|
2016-05-18 03:22:57 +08:00
|
|
|
// wide character, Hex encoded, NOT MATCHED!
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(notMatches("const wchar_t c = 0x2126;", characterLiteral()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, IntegerLiteral) {
|
2016-05-18 03:22:57 +08:00
|
|
|
StatementMatcher HasIntLiteral = integerLiteral();
|
|
|
|
EXPECT_TRUE(matches("int i = 10;", HasIntLiteral));
|
|
|
|
EXPECT_TRUE(matches("int i = 0x1AB;", HasIntLiteral));
|
|
|
|
EXPECT_TRUE(matches("int i = 10L;", HasIntLiteral));
|
|
|
|
EXPECT_TRUE(matches("int i = 10U;", HasIntLiteral));
|
|
|
|
|
|
|
|
// Non-matching cases (character literals, float and double)
|
|
|
|
EXPECT_TRUE(notMatches("int i = L'a';",
|
2020-07-13 11:19:40 +08:00
|
|
|
HasIntLiteral)); // this is actually a character
|
2016-05-18 03:22:57 +08:00
|
|
|
// literal cast to int
|
|
|
|
EXPECT_TRUE(notMatches("int i = 'a';", HasIntLiteral));
|
|
|
|
EXPECT_TRUE(notMatches("int i = 1e10;", HasIntLiteral));
|
|
|
|
EXPECT_TRUE(notMatches("int i = 10.0;", HasIntLiteral));
|
2017-07-11 23:45:22 +08:00
|
|
|
|
|
|
|
// Negative integers.
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("int i = -10;",
|
|
|
|
unaryOperator(hasOperatorName("-"),
|
|
|
|
hasUnaryOperand(integerLiteral(equals(10))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, FloatLiteral) {
|
2016-05-18 03:22:57 +08:00
|
|
|
StatementMatcher HasFloatLiteral = floatLiteral();
|
|
|
|
EXPECT_TRUE(matches("float i = 10.0;", HasFloatLiteral));
|
|
|
|
EXPECT_TRUE(matches("float i = 10.0f;", HasFloatLiteral));
|
|
|
|
EXPECT_TRUE(matches("double i = 10.0;", HasFloatLiteral));
|
|
|
|
EXPECT_TRUE(matches("double i = 10.0L;", HasFloatLiteral));
|
|
|
|
EXPECT_TRUE(matches("double i = 1e10;", HasFloatLiteral));
|
|
|
|
EXPECT_TRUE(matches("double i = 5.0;", floatLiteral(equals(5.0))));
|
|
|
|
EXPECT_TRUE(matches("double i = 5.0;", floatLiteral(equals(5.0f))));
|
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("double i = 5.0;", floatLiteral(equals(llvm::APFloat(5.0)))));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(notMatches("float i = 10;", HasFloatLiteral));
|
|
|
|
EXPECT_TRUE(notMatches("double i = 5.0;", floatLiteral(equals(6.0))));
|
|
|
|
EXPECT_TRUE(notMatches("double i = 5.0;", floatLiteral(equals(6.0f))));
|
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
notMatches("double i = 5.0;", floatLiteral(equals(llvm::APFloat(6.0)))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CXXNullPtrLiteralExpr) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("int* i = nullptr;", cxxNullPtrLiteralExpr()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ChooseExpr) {
|
|
|
|
EXPECT_TRUE(matches("void f() { (void)__builtin_choose_expr(1, 2, 3); }",
|
|
|
|
chooseExpr()));
|
[ASTImporter] Add support for importing ChooseExpr AST nodes.
Summary:
This allows ASTs to be merged when they contain ChooseExpr (the GNU
__builtin_choose_expr construction). This is needed, for example, for
cross-CTU analysis of C code that makes use of __builtin_choose_expr.
The node is already supported in the AST, but it didn't have a matcher
in ASTMatchers. So, this change adds the matcher and adds support to
ASTImporter.
This was originally reviewed and approved in
https://reviews.llvm.org/D58292 and submitted as r354832. It was
reverted in r354839 due to failures on the Windows CI builds.
This version fixes the test failures on Windows, which were caused by
differences in template expansion between versions of clang on different
OSes. The version of clang built with MSVC and running on Windows never
expands the template in the C++ test in ImportExpr.ImportChooseExpr in
clang/unittests/AST/ASTImporter.cpp, but the version on Linux does for
the empty arguments and -fms-compatibility.
So, this version of the patch drops the C++ test for
__builtin_choose_expr, since that version was written to catch
regressions of the logic for isConditionTrue() in the AST import code
for ChooseExpr, and those regressions are also caught by
ASTImporterOptionSpecificTestBase.ImportChooseExpr, which does work on
Windows.
Reviewers: shafik, a_sidorin, martong, aaron.ballman, rnk, a.sidorin
Subscribers: cfe-commits, jdoerfert, rnkovacs, aaron.ballman
Tags: #clang
Differential Revision: https://reviews.llvm.org/D58663
llvm-svn: 354916
2019-02-27 03:26:41 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, GNUNullExpr) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("int* i = __null;", gnuNullExpr()));
|
|
|
|
}
|
|
|
|
|
2020-12-02 09:23:55 +08:00
|
|
|
TEST_P(ASTMatchersTest, GenericSelectionExpr) {
|
|
|
|
EXPECT_TRUE(matches("void f() { (void)_Generic(1, int: 1, float: 2.0); }",
|
|
|
|
genericSelectionExpr()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, AtomicExpr) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void foo() { int *ptr; __atomic_load_n(ptr, 1); }",
|
|
|
|
atomicExpr()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, Initializers_C99) {
|
|
|
|
if (!GetParam().isC99OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(matches(
|
|
|
|
"void foo() { struct point { double x; double y; };"
|
|
|
|
" struct point ptarray[10] = "
|
|
|
|
" { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; }",
|
2020-06-04 23:40:38 +08:00
|
|
|
initListExpr(hasSyntacticForm(initListExpr(
|
|
|
|
has(designatedInitExpr(designatorCountIs(2),
|
|
|
|
hasDescendant(floatLiteral(equals(1.0))),
|
|
|
|
hasDescendant(integerLiteral(equals(2))))),
|
|
|
|
has(designatedInitExpr(designatorCountIs(2),
|
|
|
|
hasDescendant(floatLiteral(equals(2.0))),
|
|
|
|
hasDescendant(integerLiteral(equals(2))))),
|
|
|
|
has(designatedInitExpr(
|
|
|
|
designatorCountIs(2), hasDescendant(floatLiteral(equals(1.0))),
|
|
|
|
hasDescendant(integerLiteral(equals(0))))))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, Initializers_CXX) {
|
|
|
|
if (GetParam().Language != Lang_CXX03) {
|
|
|
|
// FIXME: Make this test pass with other C++ standard versions.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(matches(
|
|
|
|
"void foo() { struct point { double x; double y; };"
|
|
|
|
" struct point ptarray[10] = "
|
|
|
|
" { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; }",
|
|
|
|
initListExpr(
|
|
|
|
has(cxxConstructExpr(requiresZeroInitialization())),
|
|
|
|
has(initListExpr(
|
|
|
|
hasType(asString("struct point")), has(floatLiteral(equals(1.0))),
|
|
|
|
has(implicitValueInitExpr(hasType(asString("double")))))),
|
|
|
|
has(initListExpr(hasType(asString("struct point")),
|
|
|
|
has(floatLiteral(equals(2.0))),
|
|
|
|
has(floatLiteral(equals(1.0))))))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, ParenListExpr) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("template<typename T> class foo { void bar() { foo X(*this); } };"
|
2016-05-18 03:22:57 +08:00
|
|
|
"template class foo<int>;",
|
2020-07-13 11:19:40 +08:00
|
|
|
varDecl(hasInitializer(parenListExpr(has(unaryOperator()))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, StmtExpr) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void declToImport() { int C = ({int X=4; X;}); }",
|
|
|
|
varDecl(hasInitializer(stmtExpr()))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, PredefinedExpr) {
|
2016-05-18 03:22:57 +08:00
|
|
|
// __func__ expands as StringLiteral("foo")
|
|
|
|
EXPECT_TRUE(matches("void foo() { __func__; }",
|
2021-10-15 05:48:17 +08:00
|
|
|
predefinedExpr(hasType(asString("const char [4]")),
|
2020-07-13 11:19:40 +08:00
|
|
|
has(stringLiteral()))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, AsmStatement) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void foo() { __asm(\"mov al, 2\"); }", asmStmt()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, HasCondition) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
// FIXME: Add a test for `hasCondition()` that does not depend on C++.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-18 03:22:57 +08:00
|
|
|
StatementMatcher Condition =
|
2020-07-13 11:19:40 +08:00
|
|
|
ifStmt(hasCondition(cxxBoolLiteral(equals(true))));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(matches("void x() { if (true) {} }", Condition));
|
|
|
|
EXPECT_TRUE(notMatches("void x() { if (false) {} }", Condition));
|
|
|
|
EXPECT_TRUE(notMatches("void x() { bool a = true; if (a) {} }", Condition));
|
|
|
|
EXPECT_TRUE(notMatches("void x() { if (true || false) {} }", Condition));
|
|
|
|
EXPECT_TRUE(notMatches("void x() { if (1) {} }", Condition));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ConditionalOperator) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
// FIXME: Add a test for `conditionalOperator()` that does not depend on
|
|
|
|
// C++.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
StatementMatcher Conditional =
|
|
|
|
conditionalOperator(hasCondition(cxxBoolLiteral(equals(true))),
|
|
|
|
hasTrueExpression(cxxBoolLiteral(equals(false))));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(matches("void x() { true ? false : true; }", Conditional));
|
|
|
|
EXPECT_TRUE(notMatches("void x() { false ? false : true; }", Conditional));
|
|
|
|
EXPECT_TRUE(notMatches("void x() { true ? true : false; }", Conditional));
|
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
StatementMatcher ConditionalFalse =
|
|
|
|
conditionalOperator(hasFalseExpression(cxxBoolLiteral(equals(false))));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(matches("void x() { true ? true : false; }", ConditionalFalse));
|
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
notMatches("void x() { true ? false : true; }", ConditionalFalse));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(matches("void x() { true ? true : false; }", ConditionalFalse));
|
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
notMatches("void x() { true ? false : true; }", ConditionalFalse));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, BinaryConditionalOperator) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
// FIXME: This test should work in non-C++ language modes.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-11 07:52:35 +08:00
|
|
|
StatementMatcher AlwaysOne = traverse(
|
|
|
|
TK_AsIs, binaryConditionalOperator(
|
2019-11-12 21:29:40 +08:00
|
|
|
hasCondition(implicitCastExpr(has(opaqueValueExpr(
|
|
|
|
hasSourceExpression((integerLiteral(equals(1)))))))),
|
|
|
|
hasFalseExpression(integerLiteral(equals(0)))));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(matches("void x() { 1 ?: 0; }", AlwaysOne));
|
|
|
|
|
|
|
|
StatementMatcher FourNotFive = binaryConditionalOperator(
|
2020-07-13 11:19:40 +08:00
|
|
|
hasTrueExpression(
|
|
|
|
opaqueValueExpr(hasSourceExpression((integerLiteral(equals(4)))))),
|
|
|
|
hasFalseExpression(integerLiteral(equals(5))));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(matches("void x() { 4 ?: 5; }", FourNotFive));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ArraySubscriptExpr) {
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("int i[2]; void f() { i[1] = 1; }", arraySubscriptExpr()));
|
|
|
|
EXPECT_TRUE(notMatches("int i; void f() { i = 1; }", arraySubscriptExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ForStmt) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void f() { for(;;); }", forStmt()));
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(matches("void f() { if(1) for(;;); }", forStmt()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, ForStmt_CXX11) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("int as[] = { 1, 2, 3 };"
|
2020-06-29 18:47:51 +08:00
|
|
|
"void f() { for (auto &a : as); }",
|
2016-05-18 03:22:57 +08:00
|
|
|
forStmt()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ForStmt_NoFalsePositives) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("void f() { ; }", forStmt()));
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(notMatches("void f() { if(1); }", forStmt()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CompoundStatement) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("void f();", compoundStmt()));
|
|
|
|
EXPECT_TRUE(matches("void f() {}", compoundStmt()));
|
|
|
|
EXPECT_TRUE(matches("void f() {{}}", compoundStmt()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CompoundStatement_DoesNotMatchEmptyStruct) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
// FIXME: Add a similar test that does not depend on C++.
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
// It's not a compound statement just because there's "{}" in the source
|
|
|
|
// text. This is an AST search, not grep.
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(notMatches("namespace n { struct S {}; }", compoundStmt()));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("namespace n { struct S { void f() {{}} }; }", compoundStmt()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CastExpr_MatchesExplicitCasts) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void *p = (void *)(&p);", castExpr()));
|
2020-06-29 18:47:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, CastExpr_MatchesExplicitCasts_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(matches("char *p = reinterpret_cast<char *>(&p);", castExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("char q, *p = const_cast<char *>(&q);", castExpr()));
|
|
|
|
EXPECT_TRUE(matches("char c = char(0);", castExpr()));
|
|
|
|
}
|
2020-06-29 18:47:51 +08:00
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, CastExpression_MatchesImplicitCasts) {
|
2016-05-18 03:22:57 +08:00
|
|
|
// This test creates an implicit cast from int to char.
|
2020-12-11 07:52:35 +08:00
|
|
|
EXPECT_TRUE(matches("char c = 0;", traverse(TK_AsIs, castExpr())));
|
2016-05-18 03:22:57 +08:00
|
|
|
// This test creates an implicit cast from lvalue to rvalue.
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(matches("void f() { char c = 0, d = c; }",
|
2020-12-11 07:52:35 +08:00
|
|
|
traverse(TK_AsIs, castExpr())));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CastExpr_DoesNotMatchNonCasts) {
|
2020-07-03 03:46:27 +08:00
|
|
|
if (GetParam().Language == Lang_C89 || GetParam().Language == Lang_C99) {
|
|
|
|
// This does have a cast in C
|
|
|
|
EXPECT_TRUE(matches("char c = '0';", implicitCastExpr()));
|
|
|
|
} else {
|
|
|
|
EXPECT_TRUE(notMatches("char c = '0';", castExpr()));
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("int i = (0);", castExpr()));
|
|
|
|
EXPECT_TRUE(notMatches("int i = 0;", castExpr()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CastExpr_DoesNotMatchNonCasts_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(notMatches("char c, &q = c;", castExpr()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, CXXReinterpretCastExpr) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("char* p = reinterpret_cast<char*>(&p);",
|
|
|
|
cxxReinterpretCastExpr()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CXXReinterpretCastExpr_DoesNotMatchOtherCasts) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("char* p = (char*)(&p);", cxxReinterpretCastExpr()));
|
|
|
|
EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);",
|
|
|
|
cxxReinterpretCastExpr()));
|
|
|
|
EXPECT_TRUE(notMatches("void* p = static_cast<void*>(&p);",
|
|
|
|
cxxReinterpretCastExpr()));
|
|
|
|
EXPECT_TRUE(notMatches("struct B { virtual ~B() {} }; struct D : B {};"
|
2020-07-13 11:19:40 +08:00
|
|
|
"B b;"
|
|
|
|
"D* p = dynamic_cast<D*>(&b);",
|
2016-05-18 03:22:57 +08:00
|
|
|
cxxReinterpretCastExpr()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CXXFunctionalCastExpr_MatchesSimpleCase) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef foo_class = "class Foo { public: Foo(const char*); };";
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches(foo_class + "void r() { Foo f = Foo(\"hello world\"); }",
|
|
|
|
cxxFunctionalCastExpr()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CXXFunctionalCastExpr_DoesNotMatchOtherCasts) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef FooClass = "class Foo { public: Foo(const char*); };";
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
notMatches(FooClass + "void r() { Foo f = (Foo) \"hello world\"; }",
|
|
|
|
cxxFunctionalCastExpr()));
|
|
|
|
EXPECT_TRUE(notMatches(FooClass + "void r() { Foo f = \"hello world\"; }",
|
|
|
|
cxxFunctionalCastExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CXXDynamicCastExpr) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("struct B { virtual ~B() {} }; struct D : B {};"
|
2020-07-13 11:19:40 +08:00
|
|
|
"B b;"
|
|
|
|
"D* p = dynamic_cast<D*>(&b);",
|
2016-05-18 03:22:57 +08:00
|
|
|
cxxDynamicCastExpr()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CXXStaticCastExpr_MatchesSimpleCase) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("void* p(static_cast<void*>(&p));", cxxStaticCastExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CXXStaticCastExpr_DoesNotMatchOtherCasts) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("char* p = (char*)(&p);", cxxStaticCastExpr()));
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches("char q, *p = const_cast<char*>(&q);", cxxStaticCastExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("void* p = reinterpret_cast<char*>(&p);",
|
|
|
|
cxxStaticCastExpr()));
|
|
|
|
EXPECT_TRUE(notMatches("struct B { virtual ~B() {} }; struct D : B {};"
|
2020-07-13 11:19:40 +08:00
|
|
|
"B b;"
|
|
|
|
"D* p = dynamic_cast<D*>(&b);",
|
2016-05-18 03:22:57 +08:00
|
|
|
cxxStaticCastExpr()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CStyleCastExpr_MatchesSimpleCase) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("int i = (int) 2.2f;", cStyleCastExpr()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CStyleCastExpr_DoesNotMatchOtherCasts) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("char* p = static_cast<char*>(0);"
|
2020-07-13 11:19:40 +08:00
|
|
|
"char q, *r = const_cast<char*>(&q);"
|
|
|
|
"void* s = reinterpret_cast<char*>(&s);"
|
|
|
|
"struct B { virtual ~B() {} }; struct D : B {};"
|
|
|
|
"B b;"
|
|
|
|
"D* t = dynamic_cast<D*>(&b);",
|
2016-05-18 03:22:57 +08:00
|
|
|
cStyleCastExpr()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ImplicitCastExpr_MatchesSimpleCase) {
|
2016-05-18 03:22:57 +08:00
|
|
|
// This test creates an implicit const cast.
|
2020-12-11 07:52:35 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("void f() { int x = 0; const int y = x; }",
|
|
|
|
traverse(TK_AsIs, varDecl(hasInitializer(implicitCastExpr())))));
|
2016-05-18 03:22:57 +08:00
|
|
|
// This test creates an implicit cast from int to char.
|
2020-12-11 07:52:35 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("char c = 0;",
|
|
|
|
traverse(TK_AsIs, varDecl(hasInitializer(implicitCastExpr())))));
|
2016-05-18 03:22:57 +08:00
|
|
|
// This test creates an implicit array-to-pointer cast.
|
2020-12-11 07:52:35 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("int arr[6]; int *p = arr;",
|
|
|
|
traverse(TK_AsIs, varDecl(hasInitializer(implicitCastExpr())))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ImplicitCastExpr_DoesNotMatchIncorrectly) {
|
2020-07-13 11:19:40 +08:00
|
|
|
// This test verifies that implicitCastExpr() matches exactly when implicit
|
|
|
|
// casts are present, and that it ignores explicit and paren casts.
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
// These two test cases have no casts.
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches("int x = 0;", varDecl(hasInitializer(implicitCastExpr()))));
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches("int x = (0);", varDecl(hasInitializer(implicitCastExpr()))));
|
|
|
|
EXPECT_TRUE(notMatches("void f() { int x = 0; double d = (double) x; }",
|
2016-05-18 03:22:57 +08:00
|
|
|
varDecl(hasInitializer(implicitCastExpr()))));
|
2020-06-29 18:47:51 +08:00
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ImplicitCastExpr_DoesNotMatchIncorrectly_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(notMatches("int x = 0, &y = x;",
|
2016-05-18 03:22:57 +08:00
|
|
|
varDecl(hasInitializer(implicitCastExpr()))));
|
|
|
|
EXPECT_TRUE(notMatches("const int *p; int *q = const_cast<int *>(p);",
|
|
|
|
varDecl(hasInitializer(implicitCastExpr()))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, Stmt_DoesNotMatchDeclarations) {
|
|
|
|
EXPECT_TRUE(notMatches("struct X {};", stmt()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, Stmt_MatchesCompoundStatments) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void x() {}", stmt()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, DeclStmt_DoesNotMatchCompoundStatements) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("void x() {}", declStmt()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, DeclStmt_MatchesVariableDeclarationStatements) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void x() { int a; }", declStmt()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ExprWithCleanups_MatchesExprWithCleanups) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-12-11 07:52:35 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("struct Foo { ~Foo(); };"
|
|
|
|
"const Foo f = Foo();",
|
|
|
|
traverse(TK_AsIs, varDecl(hasInitializer(exprWithCleanups())))));
|
|
|
|
EXPECT_FALSE(
|
|
|
|
matches("struct Foo { }; Foo a;"
|
|
|
|
"const Foo f = a;",
|
|
|
|
traverse(TK_AsIs, varDecl(hasInitializer(exprWithCleanups())))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, InitListExpr) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("int a[] = { 1, 2 };",
|
2021-10-15 05:48:17 +08:00
|
|
|
initListExpr(hasType(asString("int [2]")))));
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(matches("struct B { int x, y; }; struct B b = { 5, 6 };",
|
2016-05-18 03:22:57 +08:00
|
|
|
initListExpr(hasType(recordDecl(hasName("B"))))));
|
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("int i[1] = {42, [0] = 43};", integerLiteral(equals(42))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, InitListExpr_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(matches("struct S { S(void (*a)()); };"
|
|
|
|
"void f();"
|
|
|
|
"S s[1] = { &f };",
|
|
|
|
declRefExpr(to(functionDecl(hasName("f"))))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest,
|
|
|
|
CXXStdInitializerListExpression_MatchesCXXStdInitializerListExpression) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef code = "namespace std {"
|
|
|
|
"template <typename> class initializer_list {"
|
|
|
|
" public: initializer_list() noexcept {}"
|
|
|
|
"};"
|
|
|
|
"}"
|
|
|
|
"struct A {"
|
|
|
|
" A(std::initializer_list<int>) {}"
|
|
|
|
"};";
|
2020-12-11 07:52:35 +08:00
|
|
|
EXPECT_TRUE(matches(
|
|
|
|
code + "A a{0};",
|
|
|
|
traverse(TK_AsIs, cxxConstructExpr(has(cxxStdInitializerListExpr()),
|
|
|
|
hasDeclaration(cxxConstructorDecl(
|
|
|
|
ofClass(hasName("A"))))))));
|
|
|
|
EXPECT_TRUE(matches(
|
|
|
|
code + "A a = {0};",
|
|
|
|
traverse(TK_AsIs, cxxConstructExpr(has(cxxStdInitializerListExpr()),
|
|
|
|
hasDeclaration(cxxConstructorDecl(
|
|
|
|
ofClass(hasName("A"))))))));
|
2017-05-06 05:01:12 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(notMatches("int a[] = { 1, 2 };", cxxStdInitializerListExpr()));
|
|
|
|
EXPECT_TRUE(notMatches("struct B { int x, y; }; B b = { 5, 6 };",
|
|
|
|
cxxStdInitializerListExpr()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, UsingDecl_MatchesUsingDeclarations) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("namespace X { int x; } using X::x;", usingDecl()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, UsingDecl_MatchesShadowUsingDelcarations) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("namespace f { int a; } using f::a;",
|
|
|
|
usingDecl(hasAnyUsingShadowDecl(hasName("a")))));
|
|
|
|
}
|
|
|
|
|
2021-05-05 23:55:02 +08:00
|
|
|
TEST_P(ASTMatchersTest, UsingEnumDecl_MatchesUsingEnumDeclarations) {
|
|
|
|
if (!GetParam().isCXX20OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("namespace X { enum x {}; } using enum X::x;", usingEnumDecl()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, UsingEnumDecl_MatchesShadowUsingDeclarations) {
|
|
|
|
if (!GetParam().isCXX20OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(matches("namespace f { enum a {b}; } using enum f::a;",
|
|
|
|
usingEnumDecl(hasAnyUsingShadowDecl(hasName("b")))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, UsingDirectiveDecl_MatchesUsingNamespace) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("namespace X { int x; } using namespace X;",
|
|
|
|
usingDirectiveDecl()));
|
|
|
|
EXPECT_FALSE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("namespace X { int x; } using X::x;", usingDirectiveDecl()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, WhileStmt) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("void x() {}", whileStmt()));
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(matches("void x() { while(1); }", whileStmt()));
|
|
|
|
EXPECT_TRUE(notMatches("void x() { do {} while(1); }", whileStmt()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, DoStmt_MatchesDoLoops) {
|
|
|
|
EXPECT_TRUE(matches("void x() { do {} while(1); }", doStmt()));
|
|
|
|
EXPECT_TRUE(matches("void x() { do ; while(0); }", doStmt()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, DoStmt_DoesNotMatchWhileLoops) {
|
|
|
|
EXPECT_TRUE(notMatches("void x() { while(1) {} }", doStmt()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, SwitchCase_MatchesCase) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void x() { switch(42) { case 42:; } }", switchCase()));
|
|
|
|
EXPECT_TRUE(matches("void x() { switch(42) { default:; } }", switchCase()));
|
|
|
|
EXPECT_TRUE(matches("void x() { switch(42) default:; }", switchCase()));
|
|
|
|
EXPECT_TRUE(notMatches("void x() { switch(42) {} }", switchCase()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, SwitchCase_MatchesSwitch) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void x() { switch(42) { case 42:; } }", switchStmt()));
|
|
|
|
EXPECT_TRUE(matches("void x() { switch(42) { default:; } }", switchStmt()));
|
|
|
|
EXPECT_TRUE(matches("void x() { switch(42) default:; }", switchStmt()));
|
|
|
|
EXPECT_TRUE(notMatches("void x() {}", switchStmt()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, CxxExceptionHandling_SimpleCases) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", cxxCatchStmt()));
|
|
|
|
EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", cxxTryStmt()));
|
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
notMatches("void foo() try { } catch(int X) { }", cxxThrowExpr()));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("void foo() try { throw; } catch(int X) { }", cxxThrowExpr()));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("void foo() try { throw 5;} catch(int X) { }", cxxThrowExpr()));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void foo() try { throw; } catch(...) { }",
|
|
|
|
cxxCatchStmt(isCatchAll())));
|
|
|
|
EXPECT_TRUE(notMatches("void foo() try { throw; } catch(int) { }",
|
|
|
|
cxxCatchStmt(isCatchAll())));
|
|
|
|
EXPECT_TRUE(matches("void foo() try {} catch(int X) { }",
|
|
|
|
varDecl(isExceptionVariable())));
|
|
|
|
EXPECT_TRUE(notMatches("void foo() try { int X; } catch (...) { }",
|
|
|
|
varDecl(isExceptionVariable())));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ParenExpr_SimpleCases) {
|
2020-12-11 07:52:35 +08:00
|
|
|
EXPECT_TRUE(matches("int i = (3);", traverse(TK_AsIs, parenExpr())));
|
|
|
|
EXPECT_TRUE(matches("int i = (3 + 7);", traverse(TK_AsIs, parenExpr())));
|
|
|
|
EXPECT_TRUE(notMatches("int i = 3;", traverse(TK_AsIs, parenExpr())));
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(notMatches("int f() { return 1; }; void g() { int a = f(); }",
|
2020-12-11 07:52:35 +08:00
|
|
|
traverse(TK_AsIs, parenExpr())));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, IgnoringParens) {
|
2020-12-11 07:52:35 +08:00
|
|
|
EXPECT_FALSE(matches("const char* str = (\"my-string\");",
|
|
|
|
traverse(TK_AsIs, implicitCastExpr(hasSourceExpression(
|
|
|
|
stringLiteral())))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("const char* str = (\"my-string\");",
|
|
|
|
traverse(TK_AsIs, implicitCastExpr(hasSourceExpression(
|
|
|
|
ignoringParens(stringLiteral()))))));
|
2018-11-10 04:54:06 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, QualType) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("struct S {};", qualType().bind("loc")));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ConstantArrayType) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("int a[2];", constantArrayType()));
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(notMatches("void f() { int a[] = { 2, 3 }; int b[a[0]]; }",
|
|
|
|
constantArrayType(hasElementType(builtinType()))));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
EXPECT_TRUE(matches("int a[42];", constantArrayType(hasSize(42))));
|
|
|
|
EXPECT_TRUE(matches("int b[2*21];", constantArrayType(hasSize(42))));
|
|
|
|
EXPECT_TRUE(notMatches("int c[41], d[43];", constantArrayType(hasSize(42))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, DependentSizedArrayType) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("template <typename T, int Size> class array { T data[Size]; };",
|
|
|
|
dependentSizedArrayType()));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches("int a[42]; int b[] = { 2, 3 }; void f() { int c[b[0]]; }",
|
|
|
|
dependentSizedArrayType()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, IncompleteArrayType) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("int a[] = { 2, 3 };", incompleteArrayType()));
|
|
|
|
EXPECT_TRUE(matches("void f(int a[]) {}", incompleteArrayType()));
|
|
|
|
|
|
|
|
EXPECT_TRUE(notMatches("int a[42]; void f() { int b[a[0]]; }",
|
|
|
|
incompleteArrayType()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, VariableArrayType) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void f(int b) { int a[b]; }", variableArrayType()));
|
|
|
|
EXPECT_TRUE(notMatches("int a[] = {2, 3}; int b[42];", variableArrayType()));
|
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("void f(int b) { int a[b]; }",
|
|
|
|
variableArrayType(hasSizeExpr(ignoringImpCasts(
|
|
|
|
declRefExpr(to(varDecl(hasName("b")))))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, AtomicType) {
|
2016-05-18 03:22:57 +08:00
|
|
|
if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getOS() !=
|
2020-07-13 11:19:40 +08:00
|
|
|
llvm::Triple::Win32) {
|
2016-05-18 03:22:57 +08:00
|
|
|
// FIXME: Make this work for MSVC.
|
|
|
|
EXPECT_TRUE(matches("_Atomic(int) i;", atomicType()));
|
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("_Atomic(int) i;", atomicType(hasValueType(isInteger()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches("_Atomic(float) f;", atomicType(hasValueType(isInteger()))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, AutoType) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("auto i = 2;", autoType()));
|
|
|
|
EXPECT_TRUE(matches("int v[] = { 2, 3 }; void f() { for (int i : v) {} }",
|
|
|
|
autoType()));
|
|
|
|
|
2017-08-05 02:59:19 +08:00
|
|
|
EXPECT_TRUE(matches("auto i = 2;", varDecl(hasType(isInteger()))));
|
|
|
|
EXPECT_TRUE(matches("struct X{}; auto x = X{};",
|
|
|
|
varDecl(hasType(recordDecl(hasName("X"))))));
|
|
|
|
|
2016-05-18 03:22:57 +08:00
|
|
|
// FIXME: Matching against the type-as-written can't work here, because the
|
|
|
|
// type as written was not deduced.
|
2020-07-13 11:19:40 +08:00
|
|
|
// EXPECT_TRUE(matches("auto a = 1;",
|
2016-05-18 03:22:57 +08:00
|
|
|
// autoType(hasDeducedType(isInteger()))));
|
2020-07-13 11:19:40 +08:00
|
|
|
// EXPECT_TRUE(notMatches("auto b = 2.0;",
|
2016-05-18 03:22:57 +08:00
|
|
|
// autoType(hasDeducedType(isInteger()))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, DecltypeType) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
2018-07-23 23:59:27 +08:00
|
|
|
EXPECT_TRUE(matches("decltype(1 + 1) sum = 1 + 1;", decltypeType()));
|
|
|
|
EXPECT_TRUE(matches("decltype(1 + 1) sum = 1 + 1;",
|
|
|
|
decltypeType(hasUnderlyingType(isInteger()))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, FunctionType) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("int (*f)(int);", functionType()));
|
|
|
|
EXPECT_TRUE(matches("void f(int i) {}", functionType()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, IgnoringParens_Type) {
|
2016-06-07 02:52:17 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches("void (*fp)(void);", pointerType(pointee(functionType()))));
|
|
|
|
EXPECT_TRUE(matches("void (*fp)(void);",
|
|
|
|
pointerType(pointee(ignoringParens(functionType())))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, FunctionProtoType) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("int (*f)(int);", functionProtoType()));
|
|
|
|
EXPECT_TRUE(matches("void f(int i);", functionProtoType()));
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(matches("void f(void);", functionProtoType(parameterCountIs(0))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, FunctionProtoType_C) {
|
|
|
|
if (!GetParam().isC()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(notMatches("void f();", functionProtoType()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, FunctionProtoType_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void f();", functionProtoType(parameterCountIs(0))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, ParenType) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(
|
2020-07-13 11:19:40 +08:00
|
|
|
matches("int (*array)[4];", varDecl(hasType(pointsTo(parenType())))));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("int *array[4];", varDecl(hasType(parenType()))));
|
|
|
|
|
|
|
|
EXPECT_TRUE(matches(
|
2020-07-13 11:19:40 +08:00
|
|
|
"int (*ptr_to_func)(int);",
|
|
|
|
varDecl(hasType(pointsTo(parenType(innerType(functionType())))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches(
|
2020-07-13 11:19:40 +08:00
|
|
|
"int (*ptr_to_array)[4];",
|
|
|
|
varDecl(hasType(pointsTo(parenType(innerType(functionType())))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, PointerType) {
|
2016-05-18 03:22:57 +08:00
|
|
|
// FIXME: Reactive when these tests can be more specific (not matching
|
|
|
|
// implicit code on certain platforms), likely when we have hasDescendant for
|
|
|
|
// Types/TypeLocs.
|
2020-07-13 11:19:40 +08:00
|
|
|
// EXPECT_TRUE(matchAndVerifyResultTrue(
|
2016-05-18 03:22:57 +08:00
|
|
|
// "int* a;",
|
|
|
|
// pointerTypeLoc(pointeeLoc(typeLoc().bind("loc"))),
|
2019-08-15 07:04:18 +08:00
|
|
|
// std::make_unique<VerifyIdIsBoundTo<TypeLoc>>("loc", 1)));
|
2020-07-13 11:19:40 +08:00
|
|
|
// EXPECT_TRUE(matchAndVerifyResultTrue(
|
2016-05-18 03:22:57 +08:00
|
|
|
// "int* a;",
|
|
|
|
// pointerTypeLoc().bind("loc"),
|
2019-08-15 07:04:18 +08:00
|
|
|
// std::make_unique<VerifyIdIsBoundTo<TypeLoc>>("loc", 1)));
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("int** a;", loc(pointerType(pointee(qualType())))));
|
|
|
|
EXPECT_TRUE(matches("int** a;", loc(pointerType(pointee(pointerType())))));
|
|
|
|
EXPECT_TRUE(matches("int* b; int* * const a = &b;",
|
|
|
|
loc(qualType(isConstQualified(), pointerType()))));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
StringRef Fragment = "int *ptr;";
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(notMatches(Fragment,
|
|
|
|
varDecl(hasName("ptr"), hasType(blockPointerType()))));
|
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
Fragment, varDecl(hasName("ptr"), hasType(memberPointerType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches(Fragment, varDecl(hasName("ptr"), hasType(pointerType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches(Fragment, varDecl(hasName("ptr"), hasType(referenceType()))));
|
2020-06-29 18:47:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, PointerType_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
StringRef Fragment = "struct A { int i; }; int A::* ptr = &A::i;";
|
|
|
|
EXPECT_TRUE(notMatches(Fragment,
|
|
|
|
varDecl(hasName("ptr"), hasType(blockPointerType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches(Fragment, varDecl(hasName("ptr"), hasType(memberPointerType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches(Fragment, varDecl(hasName("ptr"), hasType(pointerType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches(Fragment, varDecl(hasName("ptr"), hasType(referenceType()))));
|
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
Fragment, varDecl(hasName("ptr"), hasType(lValueReferenceType()))));
|
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
Fragment, varDecl(hasName("ptr"), hasType(rValueReferenceType()))));
|
2016-05-18 03:22:57 +08:00
|
|
|
|
|
|
|
Fragment = "int a; int &ref = a;";
|
2020-06-29 18:47:51 +08:00
|
|
|
EXPECT_TRUE(notMatches(Fragment,
|
|
|
|
varDecl(hasName("ref"), hasType(blockPointerType()))));
|
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
Fragment, varDecl(hasName("ref"), hasType(memberPointerType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches(Fragment, varDecl(hasName("ref"), hasType(pointerType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches(Fragment, varDecl(hasName("ref"), hasType(referenceType()))));
|
|
|
|
EXPECT_TRUE(matches(Fragment,
|
|
|
|
varDecl(hasName("ref"), hasType(lValueReferenceType()))));
|
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
Fragment, varDecl(hasName("ref"), hasType(rValueReferenceType()))));
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, PointerType_CXX11) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
StringRef Fragment = "int &&ref = 2;";
|
|
|
|
EXPECT_TRUE(notMatches(Fragment,
|
|
|
|
varDecl(hasName("ref"), hasType(blockPointerType()))));
|
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
Fragment, varDecl(hasName("ref"), hasType(memberPointerType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches(Fragment, varDecl(hasName("ref"), hasType(pointerType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches(Fragment, varDecl(hasName("ref"), hasType(referenceType()))));
|
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
Fragment, varDecl(hasName("ref"), hasType(lValueReferenceType()))));
|
|
|
|
EXPECT_TRUE(matches(Fragment,
|
|
|
|
varDecl(hasName("ref"), hasType(rValueReferenceType()))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, AutoRefTypes) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef Fragment = "auto a = 1;"
|
|
|
|
"auto b = a;"
|
|
|
|
"auto &c = a;"
|
|
|
|
"auto &&d = c;"
|
|
|
|
"auto &&e = 2;";
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches(Fragment, varDecl(hasName("a"), hasType(referenceType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches(Fragment, varDecl(hasName("b"), hasType(referenceType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches(Fragment, varDecl(hasName("c"), hasType(referenceType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches(Fragment, varDecl(hasName("c"), hasType(lValueReferenceType()))));
|
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
Fragment, varDecl(hasName("c"), hasType(rValueReferenceType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches(Fragment, varDecl(hasName("d"), hasType(referenceType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches(Fragment, varDecl(hasName("d"), hasType(lValueReferenceType()))));
|
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
Fragment, varDecl(hasName("d"), hasType(rValueReferenceType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches(Fragment, varDecl(hasName("e"), hasType(referenceType()))));
|
|
|
|
EXPECT_TRUE(notMatches(
|
|
|
|
Fragment, varDecl(hasName("e"), hasType(lValueReferenceType()))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches(Fragment, varDecl(hasName("e"), hasType(rValueReferenceType()))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, EnumType) {
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("enum Color { Green }; enum Color color;", loc(enumType())));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, EnumType_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("enum Color { Green }; Color color;", loc(enumType())));
|
2020-06-29 18:47:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, EnumType_CXX11) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("enum class Color { Green }; Color color;", loc(enumType())));
|
2016-06-30 15:50:01 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, PointerType_MatchesPointersToConstTypes) {
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("int b; int * const a = &b;", loc(pointerType())));
|
|
|
|
EXPECT_TRUE(matches("int b; int * const a = &b;", loc(pointerType())));
|
|
|
|
EXPECT_TRUE(matches("int b; const int * a = &b;",
|
|
|
|
loc(pointerType(pointee(builtinType())))));
|
|
|
|
EXPECT_TRUE(matches("int b; const int * a = &b;",
|
|
|
|
pointerType(pointee(builtinType()))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, TypedefType) {
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("typedef int X; X a;",
|
|
|
|
varDecl(hasName("a"), hasType(typedefType()))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, TemplateSpecializationType) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("template <typename T> class A{}; A<int> a;",
|
|
|
|
templateSpecializationType()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, DeducedTemplateSpecializationType) {
|
|
|
|
if (!GetParam().isCXX17OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-06-04 23:40:38 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("template <typename T> class A{ public: A(T) {} }; A a(1);",
|
2020-06-29 18:47:51 +08:00
|
|
|
deducedTemplateSpecializationType()));
|
2020-02-03 19:10:56 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, RecordType) {
|
|
|
|
EXPECT_TRUE(matches("struct S {}; struct S s;",
|
2016-05-18 03:22:57 +08:00
|
|
|
recordType(hasDeclaration(recordDecl(hasName("S"))))));
|
|
|
|
EXPECT_TRUE(notMatches("int i;",
|
|
|
|
recordType(hasDeclaration(recordDecl(hasName("S"))))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, RecordType_CXX) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(matches("class C {}; C c;", recordType()));
|
|
|
|
EXPECT_TRUE(matches("struct S {}; S s;",
|
|
|
|
recordType(hasDeclaration(recordDecl(hasName("S"))))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, ElaboratedType) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
// FIXME: Add a test for `elaboratedType()` that does not depend on C++.
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("namespace N {"
|
|
|
|
" namespace M {"
|
|
|
|
" class D {};"
|
|
|
|
" }"
|
|
|
|
"}"
|
|
|
|
"N::M::D d;",
|
|
|
|
elaboratedType()));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("class C {} c;", elaboratedType()));
|
|
|
|
EXPECT_TRUE(notMatches("class C {}; C c;", elaboratedType()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, SubstTemplateTypeParmType) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef code = "template <typename T>"
|
|
|
|
"int F() {"
|
|
|
|
" return 1 + T();"
|
|
|
|
"}"
|
|
|
|
"int i = F<int>();";
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_FALSE(matches(code, binaryOperator(hasLHS(
|
2020-07-13 11:19:40 +08:00
|
|
|
expr(hasType(substTemplateTypeParmType()))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches(code, binaryOperator(hasRHS(
|
2020-07-13 11:19:40 +08:00
|
|
|
expr(hasType(substTemplateTypeParmType()))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, NestedNameSpecifier) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("namespace ns { struct A {}; } ns::A a;", nestedNameSpecifier()));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("template <typename T> class A { typename T::B b; };",
|
|
|
|
nestedNameSpecifier()));
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("struct A { void f(); }; void A::f() {}", nestedNameSpecifier()));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("namespace a { namespace b {} } namespace ab = a::b;",
|
|
|
|
nestedNameSpecifier()));
|
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matches("struct A { static void f() {} }; void g() { A::f(); }",
|
|
|
|
nestedNameSpecifier()));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches("struct A { static void f() {} }; void g(A* a) { a->f(); }",
|
|
|
|
nestedNameSpecifier()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2021-08-07 04:28:31 +08:00
|
|
|
TEST_P(ASTMatchersTest, Attr) {
|
|
|
|
// Windows adds some implicit attributes.
|
|
|
|
bool AutomaticAttributes = StringRef(GetParam().Target).contains("win32");
|
|
|
|
if (GetParam().isCXX11OrLater()) {
|
|
|
|
EXPECT_TRUE(matches("struct [[clang::warn_unused_result]] F{};", attr()));
|
|
|
|
|
|
|
|
// Unknown attributes are not parsed into an AST node.
|
|
|
|
if (!AutomaticAttributes) {
|
|
|
|
EXPECT_TRUE(notMatches("int x [[unknownattr]];", attr()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (GetParam().isCXX17OrLater()) {
|
|
|
|
EXPECT_TRUE(matches("struct [[nodiscard]] F{};", attr()));
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(matches("int x(int * __attribute__((nonnull)) );", attr()));
|
|
|
|
if (!AutomaticAttributes) {
|
|
|
|
EXPECT_TRUE(notMatches("struct F{}; int x(int *);", attr()));
|
|
|
|
// Some known attributes are not parsed into an AST node.
|
|
|
|
EXPECT_TRUE(notMatches("typedef int x __attribute__((ext_vector_type(1)));",
|
|
|
|
attr()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, NullStmt) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("void f() {int i;;}", nullStmt()));
|
|
|
|
EXPECT_TRUE(notMatches("void f() {int i;}", nullStmt()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, NamespaceAliasDecl) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("namespace test {} namespace alias = ::test;",
|
|
|
|
namespaceAliasDecl(hasName("alias"))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, NestedNameSpecifier_MatchesTypes) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
NestedNameSpecifierMatcher Matcher = nestedNameSpecifier(
|
2020-07-13 11:19:40 +08:00
|
|
|
specifiesType(hasDeclaration(recordDecl(hasName("A")))));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("struct A { struct B {}; }; A::B b;", Matcher));
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(
|
|
|
|
matches("struct A { struct B { struct C {}; }; }; A::B::C c;", Matcher));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("namespace A { struct B {}; } A::B b;", Matcher));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, NestedNameSpecifier_MatchesNamespaceDecls) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 11:19:40 +08:00
|
|
|
NestedNameSpecifierMatcher Matcher =
|
|
|
|
nestedNameSpecifier(specifiesNamespace(hasName("ns")));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("namespace ns { struct A {}; } ns::A a;", Matcher));
|
|
|
|
EXPECT_TRUE(notMatches("namespace xx { struct A {}; } xx::A a;", Matcher));
|
|
|
|
EXPECT_TRUE(notMatches("struct ns { struct A {}; }; ns::A a;", Matcher));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest,
|
|
|
|
NestedNameSpecifier_MatchesNestedNameSpecifierPrefixes) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches(
|
2020-07-13 11:19:40 +08:00
|
|
|
"struct A { struct B { struct C {}; }; }; A::B::C c;",
|
|
|
|
nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A"))))));
|
|
|
|
EXPECT_TRUE(matches("struct A { struct B { struct C {}; }; }; A::B::C c;",
|
|
|
|
nestedNameSpecifierLoc(hasPrefix(specifiesTypeLoc(
|
|
|
|
loc(qualType(asString("struct A"))))))));
|
2018-06-18 16:59:16 +08:00
|
|
|
EXPECT_TRUE(matches(
|
2020-07-13 11:19:40 +08:00
|
|
|
"namespace N { struct A { struct B { struct C {}; }; }; } N::A::B::C c;",
|
|
|
|
nestedNameSpecifierLoc(hasPrefix(
|
|
|
|
specifiesTypeLoc(loc(qualType(asString("struct N::A"))))))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
class VerifyAncestorHasChildIsEqual : public BoundNodesCallback {
|
|
|
|
public:
|
|
|
|
bool run(const BoundNodes *Nodes) override { return false; }
|
|
|
|
|
|
|
|
bool run(const BoundNodes *Nodes, ASTContext *Context) override {
|
|
|
|
const T *Node = Nodes->getNodeAs<T>("");
|
|
|
|
return verify(*Nodes, *Context, Node);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool verify(const BoundNodes &Nodes, ASTContext &Context, const Stmt *Node) {
|
|
|
|
// Use the original typed pointer to verify we can pass pointers to subtypes
|
|
|
|
// to equalsNode.
|
|
|
|
const T *TypedNode = cast<T>(Node);
|
|
|
|
return selectFirst<T>(
|
2020-07-13 11:19:40 +08:00
|
|
|
"", match(stmt(hasParent(
|
|
|
|
stmt(has(stmt(equalsNode(TypedNode)))).bind(""))),
|
|
|
|
*Node, Context)) != nullptr;
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
bool verify(const BoundNodes &Nodes, ASTContext &Context, const Decl *Node) {
|
|
|
|
// Use the original typed pointer to verify we can pass pointers to subtypes
|
|
|
|
// to equalsNode.
|
|
|
|
const T *TypedNode = cast<T>(Node);
|
|
|
|
return selectFirst<T>(
|
2020-07-13 11:19:40 +08:00
|
|
|
"", match(decl(hasParent(
|
|
|
|
decl(has(decl(equalsNode(TypedNode)))).bind(""))),
|
|
|
|
*Node, Context)) != nullptr;
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
bool verify(const BoundNodes &Nodes, ASTContext &Context, const Type *Node) {
|
|
|
|
// Use the original typed pointer to verify we can pass pointers to subtypes
|
|
|
|
// to equalsNode.
|
|
|
|
const T *TypedNode = cast<T>(Node);
|
|
|
|
const auto *Dec = Nodes.getNodeAs<FieldDecl>("decl");
|
|
|
|
return selectFirst<T>(
|
2020-07-13 11:19:40 +08:00
|
|
|
"", match(fieldDecl(hasParent(decl(has(fieldDecl(
|
|
|
|
hasType(type(equalsNode(TypedNode)).bind(""))))))),
|
|
|
|
*Dec, Context)) != nullptr;
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, IsEqualTo_MatchesNodesByIdentity) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
2020-06-29 18:47:51 +08:00
|
|
|
"void f() { if (1) if(1) {} }", ifStmt().bind(""),
|
|
|
|
std::make_unique<VerifyAncestorHasChildIsEqual<IfStmt>>()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, IsEqualTo_MatchesNodesByIdentity_Cxx) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
2020-06-29 18:47:51 +08:00
|
|
|
"class X { class Y {}; };", recordDecl(hasName("::X::Y")).bind(""),
|
|
|
|
std::make_unique<VerifyAncestorHasChildIsEqual<CXXRecordDecl>>()));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
2020-06-29 18:47:51 +08:00
|
|
|
"class X { class Y {} y; };",
|
|
|
|
fieldDecl(hasName("y"), hasType(type().bind(""))).bind("decl"),
|
|
|
|
std::make_unique<VerifyAncestorHasChildIsEqual<Type>>()));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, TypedefDecl) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("typedef int typedefDeclTest;",
|
|
|
|
typedefDecl(hasName("typedefDeclTest"))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, TypedefDecl_Cxx) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(notMatches("using typedefDeclTest = int;",
|
|
|
|
typedefDecl(hasName("typedefDeclTest"))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, TypeAliasDecl) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatches("typedef int typeAliasTest;",
|
|
|
|
typeAliasDecl(hasName("typeAliasTest"))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, TypeAliasDecl_CXX) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(matches("using typeAliasTest = int;",
|
|
|
|
typeAliasDecl(hasName("typeAliasTest"))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, TypedefNameDecl) {
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matches("typedef int typedefNameDeclTest1;",
|
|
|
|
typedefNameDecl(hasName("typedefNameDeclTest1"))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST_P(ASTMatchersTest, TypedefNameDecl_CXX) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(matches("using typedefNameDeclTest = int;",
|
|
|
|
typedefNameDecl(hasName("typedefNameDeclTest"))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest, TypeAliasTemplateDecl) {
|
|
|
|
if (!GetParam().isCXX11OrLater()) {
|
|
|
|
return;
|
|
|
|
}
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef Code = R"(
|
2017-03-28 20:56:47 +08:00
|
|
|
template <typename T>
|
|
|
|
class X { T t; };
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
using typeAliasTemplateDecl = X<T>;
|
|
|
|
|
|
|
|
using typeAliasDecl = X<int>;
|
|
|
|
)";
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matches(Code, typeAliasTemplateDecl(hasName("typeAliasTemplateDecl"))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatches(Code, typeAliasTemplateDecl(hasName("typeAliasDecl"))));
|
|
|
|
}
|
|
|
|
|
2021-10-09 01:42:06 +08:00
|
|
|
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 <typename T> class C {}; template class C<int>;",
|
|
|
|
classTemplateSpecializationDecl(
|
|
|
|
hasName("C"), hasTypeLoc(templateSpecializationTypeLoc()))));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(ASTMatchersTest,
|
|
|
|
TemplateSpecializationTypeLocTest_BindsToVarDeclTemplateSpecialization) {
|
|
|
|
if (!GetParam().isCXX()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
EXPECT_TRUE(matches(
|
|
|
|
"template <typename T> class C {}; C<char> 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) {
|
|
|
|
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()))));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST(ASTMatchersTestObjC, ObjCMessageExpr) {
|
|
|
|
// Don't find ObjCMessageExpr where none are present.
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(notMatchesObjC("", objcMessageExpr(anything())));
|
|
|
|
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef Objc1String = "@interface Str "
|
|
|
|
" - (Str *)uppercaseString;"
|
|
|
|
"@end "
|
|
|
|
"@interface foo "
|
|
|
|
"- (void)contents;"
|
|
|
|
"- (void)meth:(Str *)text;"
|
|
|
|
"@end "
|
|
|
|
" "
|
|
|
|
"@implementation foo "
|
|
|
|
"- (void) meth:(Str *)text { "
|
|
|
|
" [self contents];"
|
|
|
|
" Str *up = [text uppercaseString];"
|
|
|
|
"} "
|
|
|
|
"@end ";
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matchesObjC(Objc1String, objcMessageExpr(anything())));
|
2018-03-29 08:51:12 +08:00
|
|
|
EXPECT_TRUE(matchesObjC(Objc1String,
|
2020-07-13 11:19:40 +08:00
|
|
|
objcMessageExpr(hasAnySelector({"contents", "meth:"}))
|
2018-03-29 08:51:12 +08:00
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matchesObjC(Objc1String, objcMessageExpr(hasSelector("contents"))));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_TRUE(matchesObjC(
|
2020-07-13 11:19:40 +08:00
|
|
|
Objc1String, objcMessageExpr(hasAnySelector("contents", "contentsA"))));
|
2016-05-18 03:22:57 +08:00
|
|
|
EXPECT_FALSE(matchesObjC(
|
2020-07-13 11:19:40 +08:00
|
|
|
Objc1String, objcMessageExpr(hasAnySelector("contentsB", "contentsC"))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matchesObjC(Objc1String, objcMessageExpr(matchesSelector("cont*"))));
|
|
|
|
EXPECT_FALSE(
|
|
|
|
matchesObjC(Objc1String, objcMessageExpr(matchesSelector("?cont*"))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
notMatchesObjC(Objc1String, objcMessageExpr(hasSelector("contents"),
|
|
|
|
hasNullSelector())));
|
|
|
|
EXPECT_TRUE(matchesObjC(Objc1String, objcMessageExpr(hasSelector("contents"),
|
|
|
|
hasUnarySelector())));
|
|
|
|
EXPECT_TRUE(matchesObjC(Objc1String, objcMessageExpr(hasSelector("contents"),
|
|
|
|
numSelectorArgs(0))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matchesObjC(Objc1String, objcMessageExpr(matchesSelector("uppercase*"),
|
|
|
|
argumentCountIs(0))));
|
2016-05-18 03:22:57 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST(ASTMatchersTestObjC, ObjCDecls) {
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef ObjCString = "@protocol Proto "
|
|
|
|
"- (void)protoDidThing; "
|
|
|
|
"@end "
|
|
|
|
"@interface Thing "
|
|
|
|
"@property int enabled; "
|
|
|
|
"@end "
|
|
|
|
"@interface Thing (ABC) "
|
|
|
|
"- (void)abc_doThing; "
|
|
|
|
"@end "
|
|
|
|
"@implementation Thing "
|
|
|
|
"{ id _ivar; } "
|
|
|
|
"- (void)anything {} "
|
|
|
|
"@end "
|
|
|
|
"@implementation Thing (ABC) "
|
|
|
|
"- (void)abc_doThing {} "
|
|
|
|
"@end ";
|
2017-03-16 04:14:25 +08:00
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matchesObjC(ObjCString, objcProtocolDecl(hasName("Proto"))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matchesObjC(ObjCString, objcImplementationDecl(hasName("Thing"))));
|
|
|
|
EXPECT_TRUE(matchesObjC(ObjCString, objcCategoryDecl(hasName("ABC"))));
|
|
|
|
EXPECT_TRUE(matchesObjC(ObjCString, objcCategoryImplDecl(hasName("ABC"))));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
matchesObjC(ObjCString, objcMethodDecl(hasName("protoDidThing"))));
|
|
|
|
EXPECT_TRUE(matchesObjC(ObjCString, objcMethodDecl(hasName("abc_doThing"))));
|
|
|
|
EXPECT_TRUE(matchesObjC(ObjCString, objcMethodDecl(hasName("anything"))));
|
|
|
|
EXPECT_TRUE(matchesObjC(ObjCString, objcIvarDecl(hasName("_ivar"))));
|
|
|
|
EXPECT_TRUE(matchesObjC(ObjCString, objcPropertyDecl(hasName("enabled"))));
|
2017-03-16 04:14:25 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST(ASTMatchersTestObjC, ObjCExceptionStmts) {
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef ObjCString = "void f(id obj) {"
|
|
|
|
" @try {"
|
|
|
|
" @throw obj;"
|
|
|
|
" } @catch (...) {"
|
|
|
|
" } @finally {}"
|
|
|
|
"}";
|
2017-11-12 06:46:15 +08:00
|
|
|
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(matchesObjC(ObjCString, objcTryStmt()));
|
|
|
|
EXPECT_TRUE(matchesObjC(ObjCString, objcThrowStmt()));
|
|
|
|
EXPECT_TRUE(matchesObjC(ObjCString, objcCatchStmt()));
|
|
|
|
EXPECT_TRUE(matchesObjC(ObjCString, objcFinallyStmt()));
|
2017-11-12 06:46:15 +08:00
|
|
|
}
|
|
|
|
|
2021-01-30 23:50:44 +08:00
|
|
|
TEST(ASTMatchersTest, DecompositionDecl) {
|
|
|
|
StringRef Code = R"cpp(
|
|
|
|
void foo()
|
|
|
|
{
|
|
|
|
int arr[3];
|
|
|
|
auto &[f, s, t] = arr;
|
|
|
|
|
|
|
|
f = 42;
|
|
|
|
}
|
|
|
|
)cpp";
|
|
|
|
EXPECT_TRUE(matchesConditionally(
|
|
|
|
Code, decompositionDecl(hasBinding(0, bindingDecl(hasName("f")))), true,
|
|
|
|
{"-std=c++17"}));
|
|
|
|
EXPECT_FALSE(matchesConditionally(
|
|
|
|
Code, decompositionDecl(hasBinding(42, bindingDecl(hasName("f")))), true,
|
|
|
|
{"-std=c++17"}));
|
|
|
|
EXPECT_FALSE(matchesConditionally(
|
|
|
|
Code, decompositionDecl(hasBinding(0, bindingDecl(hasName("s")))), true,
|
|
|
|
{"-std=c++17"}));
|
|
|
|
EXPECT_TRUE(matchesConditionally(
|
|
|
|
Code, decompositionDecl(hasBinding(1, bindingDecl(hasName("s")))), true,
|
|
|
|
{"-std=c++17"}));
|
|
|
|
|
|
|
|
EXPECT_TRUE(matchesConditionally(
|
|
|
|
Code,
|
|
|
|
bindingDecl(decl().bind("self"), hasName("f"),
|
|
|
|
forDecomposition(decompositionDecl(
|
|
|
|
hasAnyBinding(bindingDecl(equalsBoundNode("self")))))),
|
|
|
|
true, {"-std=c++17"}));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST(ASTMatchersTestObjC, ObjCAutoreleasePoolStmt) {
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef ObjCString = "void f() {"
|
|
|
|
"@autoreleasepool {"
|
|
|
|
" int x = 1;"
|
|
|
|
"}"
|
|
|
|
"}";
|
2018-07-07 05:36:04 +08:00
|
|
|
EXPECT_TRUE(matchesObjC(ObjCString, autoreleasePoolStmt()));
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef ObjCStringNoPool = "void f() { int x = 1; }";
|
2018-07-07 05:36:04 +08:00
|
|
|
EXPECT_FALSE(matchesObjC(ObjCStringNoPool, autoreleasePoolStmt()));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST(ASTMatchersTestOpenMP, OMPExecutableDirective) {
|
2019-03-21 23:33:10 +08:00
|
|
|
auto Matcher = stmt(ompExecutableDirective());
|
|
|
|
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef Source0 = R"(
|
2019-03-21 23:33:10 +08:00
|
|
|
void x() {
|
|
|
|
#pragma omp parallel
|
|
|
|
;
|
|
|
|
})";
|
|
|
|
EXPECT_TRUE(matchesWithOpenMP(Source0, Matcher));
|
|
|
|
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef Source1 = R"(
|
2019-03-21 23:33:10 +08:00
|
|
|
void x() {
|
|
|
|
#pragma omp taskyield
|
|
|
|
;
|
|
|
|
})";
|
|
|
|
EXPECT_TRUE(matchesWithOpenMP(Source1, Matcher));
|
|
|
|
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef Source2 = R"(
|
2019-03-21 23:33:10 +08:00
|
|
|
void x() {
|
|
|
|
;
|
|
|
|
})";
|
|
|
|
EXPECT_TRUE(notMatchesWithOpenMP(Source2, Matcher));
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST(ASTMatchersTestOpenMP, OMPDefaultClause) {
|
[ASTTypeTraits][ASTMatchers][OpenMP] OMPClause handling
Summary:
`OMPClause` is the base class, it is not descendant from **any**
other class, therefore for it to work with e.g.
`VariadicDynCastAllOfMatcher<>`, it needs to be handled here.
Reviewers: sbenza, bkramer, pcc, klimek, hokein, gribozavr, aaron.ballman, george.karpenkov
Reviewed By: gribozavr, aaron.ballman
Subscribers: guansong, jdoerfert, alexfh, ABataev, cfe-commits
Tags: #openmp, #clang
Differential Revision: https://reviews.llvm.org/D57112
llvm-svn: 356675
2019-03-21 23:33:24 +08:00
|
|
|
auto Matcher = ompExecutableDirective(hasAnyClause(ompDefaultClause()));
|
|
|
|
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef Source0 = R"(
|
[ASTTypeTraits][ASTMatchers][OpenMP] OMPClause handling
Summary:
`OMPClause` is the base class, it is not descendant from **any**
other class, therefore for it to work with e.g.
`VariadicDynCastAllOfMatcher<>`, it needs to be handled here.
Reviewers: sbenza, bkramer, pcc, klimek, hokein, gribozavr, aaron.ballman, george.karpenkov
Reviewed By: gribozavr, aaron.ballman
Subscribers: guansong, jdoerfert, alexfh, ABataev, cfe-commits
Tags: #openmp, #clang
Differential Revision: https://reviews.llvm.org/D57112
llvm-svn: 356675
2019-03-21 23:33:24 +08:00
|
|
|
void x() {
|
|
|
|
;
|
|
|
|
})";
|
|
|
|
EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
|
|
|
|
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef Source1 = R"(
|
[ASTTypeTraits][ASTMatchers][OpenMP] OMPClause handling
Summary:
`OMPClause` is the base class, it is not descendant from **any**
other class, therefore for it to work with e.g.
`VariadicDynCastAllOfMatcher<>`, it needs to be handled here.
Reviewers: sbenza, bkramer, pcc, klimek, hokein, gribozavr, aaron.ballman, george.karpenkov
Reviewed By: gribozavr, aaron.ballman
Subscribers: guansong, jdoerfert, alexfh, ABataev, cfe-commits
Tags: #openmp, #clang
Differential Revision: https://reviews.llvm.org/D57112
llvm-svn: 356675
2019-03-21 23:33:24 +08:00
|
|
|
void x() {
|
|
|
|
#pragma omp parallel
|
|
|
|
;
|
|
|
|
})";
|
|
|
|
EXPECT_TRUE(notMatchesWithOpenMP(Source1, Matcher));
|
|
|
|
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef Source2 = R"(
|
[ASTTypeTraits][ASTMatchers][OpenMP] OMPClause handling
Summary:
`OMPClause` is the base class, it is not descendant from **any**
other class, therefore for it to work with e.g.
`VariadicDynCastAllOfMatcher<>`, it needs to be handled here.
Reviewers: sbenza, bkramer, pcc, klimek, hokein, gribozavr, aaron.ballman, george.karpenkov
Reviewed By: gribozavr, aaron.ballman
Subscribers: guansong, jdoerfert, alexfh, ABataev, cfe-commits
Tags: #openmp, #clang
Differential Revision: https://reviews.llvm.org/D57112
llvm-svn: 356675
2019-03-21 23:33:24 +08:00
|
|
|
void x() {
|
|
|
|
#pragma omp parallel default(none)
|
|
|
|
;
|
|
|
|
})";
|
|
|
|
EXPECT_TRUE(matchesWithOpenMP(Source2, Matcher));
|
|
|
|
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef Source3 = R"(
|
[ASTTypeTraits][ASTMatchers][OpenMP] OMPClause handling
Summary:
`OMPClause` is the base class, it is not descendant from **any**
other class, therefore for it to work with e.g.
`VariadicDynCastAllOfMatcher<>`, it needs to be handled here.
Reviewers: sbenza, bkramer, pcc, klimek, hokein, gribozavr, aaron.ballman, george.karpenkov
Reviewed By: gribozavr, aaron.ballman
Subscribers: guansong, jdoerfert, alexfh, ABataev, cfe-commits
Tags: #openmp, #clang
Differential Revision: https://reviews.llvm.org/D57112
llvm-svn: 356675
2019-03-21 23:33:24 +08:00
|
|
|
void x() {
|
|
|
|
#pragma omp parallel default(shared)
|
|
|
|
;
|
|
|
|
})";
|
|
|
|
EXPECT_TRUE(matchesWithOpenMP(Source3, Matcher));
|
|
|
|
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef Source4 = R"(
|
2020-07-13 11:19:40 +08:00
|
|
|
void x() {
|
|
|
|
#pragma omp parallel default(firstprivate)
|
|
|
|
;
|
|
|
|
})";
|
|
|
|
EXPECT_TRUE(matchesWithOpenMP51(Source4, Matcher));
|
|
|
|
|
|
|
|
StringRef Source5 = R"(
|
[ASTTypeTraits][ASTMatchers][OpenMP] OMPClause handling
Summary:
`OMPClause` is the base class, it is not descendant from **any**
other class, therefore for it to work with e.g.
`VariadicDynCastAllOfMatcher<>`, it needs to be handled here.
Reviewers: sbenza, bkramer, pcc, klimek, hokein, gribozavr, aaron.ballman, george.karpenkov
Reviewed By: gribozavr, aaron.ballman
Subscribers: guansong, jdoerfert, alexfh, ABataev, cfe-commits
Tags: #openmp, #clang
Differential Revision: https://reviews.llvm.org/D57112
llvm-svn: 356675
2019-03-21 23:33:24 +08:00
|
|
|
void x(int x) {
|
|
|
|
#pragma omp parallel num_threads(x)
|
|
|
|
;
|
|
|
|
})";
|
2020-07-13 11:19:40 +08:00
|
|
|
EXPECT_TRUE(notMatchesWithOpenMP(Source5, Matcher));
|
[ASTTypeTraits][ASTMatchers][OpenMP] OMPClause handling
Summary:
`OMPClause` is the base class, it is not descendant from **any**
other class, therefore for it to work with e.g.
`VariadicDynCastAllOfMatcher<>`, it needs to be handled here.
Reviewers: sbenza, bkramer, pcc, klimek, hokein, gribozavr, aaron.ballman, george.karpenkov
Reviewed By: gribozavr, aaron.ballman
Subscribers: guansong, jdoerfert, alexfh, ABataev, cfe-commits
Tags: #openmp, #clang
Differential Revision: https://reviews.llvm.org/D57112
llvm-svn: 356675
2019-03-21 23:33:24 +08:00
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST(ASTMatchersTest, Finder_DynamicOnlyAcceptsSomeMatchers) {
|
|
|
|
MatchFinder Finder;
|
|
|
|
EXPECT_TRUE(Finder.addDynamicMatcher(decl(), nullptr));
|
|
|
|
EXPECT_TRUE(Finder.addDynamicMatcher(callExpr(), nullptr));
|
|
|
|
EXPECT_TRUE(
|
|
|
|
Finder.addDynamicMatcher(constantArrayType(hasSize(42)), nullptr));
|
|
|
|
|
|
|
|
// Do not accept non-toplevel matchers.
|
|
|
|
EXPECT_FALSE(Finder.addDynamicMatcher(isMain(), nullptr));
|
|
|
|
EXPECT_FALSE(Finder.addDynamicMatcher(hasName("x"), nullptr));
|
|
|
|
}
|
2019-12-07 07:50:07 +08:00
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
TEST(MatchFinderAPI, MatchesDynamic) {
|
2020-06-03 04:20:58 +08:00
|
|
|
StringRef SourceCode = "struct A { void f() {} };";
|
2019-12-07 07:50:07 +08:00
|
|
|
auto Matcher = functionDecl(isDefinition()).bind("method");
|
|
|
|
|
|
|
|
auto astUnit = tooling::buildASTFromCode(SourceCode);
|
|
|
|
|
|
|
|
auto GlobalBoundNodes = matchDynamic(Matcher, astUnit->getASTContext());
|
|
|
|
|
|
|
|
EXPECT_EQ(GlobalBoundNodes.size(), 1u);
|
|
|
|
EXPECT_EQ(GlobalBoundNodes[0].getMap().size(), 1u);
|
|
|
|
|
|
|
|
auto GlobalMethodNode = GlobalBoundNodes[0].getNodeAs<FunctionDecl>("method");
|
|
|
|
EXPECT_TRUE(GlobalMethodNode != nullptr);
|
|
|
|
|
|
|
|
auto MethodBoundNodes =
|
|
|
|
matchDynamic(Matcher, *GlobalMethodNode, astUnit->getASTContext());
|
|
|
|
EXPECT_EQ(MethodBoundNodes.size(), 1u);
|
|
|
|
EXPECT_EQ(MethodBoundNodes[0].getMap().size(), 1u);
|
|
|
|
|
|
|
|
auto MethodNode = MethodBoundNodes[0].getNodeAs<FunctionDecl>("method");
|
|
|
|
EXPECT_EQ(MethodNode, GlobalMethodNode);
|
|
|
|
}
|
|
|
|
|
2020-06-29 18:47:51 +08:00
|
|
|
static std::vector<TestClangConfig> allTestClangConfigs() {
|
|
|
|
std::vector<TestClangConfig> all_configs;
|
|
|
|
for (TestLanguage lang : {Lang_C89, Lang_C99, Lang_CXX03, Lang_CXX11,
|
|
|
|
Lang_CXX14, Lang_CXX17, Lang_CXX20}) {
|
|
|
|
TestClangConfig config;
|
|
|
|
config.Language = lang;
|
|
|
|
|
|
|
|
// Use an unknown-unknown triple so we don't instantiate the full system
|
|
|
|
// toolchain. On Linux, instantiating the toolchain involves stat'ing
|
|
|
|
// large portions of /usr/lib, and this slows down not only this test, but
|
|
|
|
// all other tests, via contention in the kernel.
|
|
|
|
//
|
|
|
|
// FIXME: This is a hack to work around the fact that there's no way to do
|
|
|
|
// the equivalent of runToolOnCodeWithArgs without instantiating a full
|
|
|
|
// Driver. We should consider having a function, at least for tests, that
|
|
|
|
// invokes cc1.
|
|
|
|
config.Target = "i386-unknown-unknown";
|
|
|
|
all_configs.push_back(config);
|
|
|
|
|
|
|
|
// Windows target is interesting to test because it enables
|
|
|
|
// `-fdelayed-template-parsing`.
|
|
|
|
config.Target = "x86_64-pc-win32-msvc";
|
|
|
|
all_configs.push_back(config);
|
|
|
|
}
|
|
|
|
return all_configs;
|
|
|
|
}
|
|
|
|
|
2021-05-15 01:15:20 +08:00
|
|
|
INSTANTIATE_TEST_SUITE_P(ASTMatchersTests, ASTMatchersTest,
|
|
|
|
testing::ValuesIn(allTestClangConfigs()));
|
2020-06-29 18:47:51 +08:00
|
|
|
|
2016-05-18 03:22:57 +08:00
|
|
|
} // namespace ast_matchers
|
|
|
|
} // namespace clang
|