1 //===- unittests/Analysis/FlowSensitive/ASTOpsTest.cpp --------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "clang/Analysis/FlowSensitive/ASTOps.h"
10 #include "TestingSupport.h"
11 #include "clang/AST/Decl.h"
12 #include "clang/AST/DeclCXX.h"
13 #include "clang/ASTMatchers/ASTMatchers.h"
14 #include "clang/Basic/LLVM.h"
15 #include "clang/Frontend/ASTUnit.h"
16 #include "clang/Tooling/Tooling.h"
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
24 using namespace clang
;
25 using namespace dataflow
;
27 using ast_matchers::cxxMethodDecl
;
28 using ast_matchers::cxxRecordDecl
;
29 using ast_matchers::hasName
;
30 using ast_matchers::hasType
;
31 using ast_matchers::initListExpr
;
32 using ast_matchers::match
;
33 using ast_matchers::selectFirst
;
34 using test::findValueDecl
;
35 using testing::IsEmpty
;
36 using testing::UnorderedElementsAre
;
38 TEST(ASTOpsTest
, RecordInitListHelperOnEmptyUnionInitList
) {
39 // This is a regression test: The `RecordInitListHelper` used to assert-fail
40 // when called for the `InitListExpr` of an empty union.
41 std::string Code
= R
"cc(
48 std::unique_ptr
<ASTUnit
> Unit
=
49 tooling::buildASTFromCodeWithArgs(Code
, {"-fsyntax-only", "-std=c++17"});
50 auto &ASTCtx
= Unit
->getASTContext();
52 ASSERT_EQ(ASTCtx
.getDiagnostics().getClient()->getNumErrors(), 0U);
54 auto *InitList
= selectFirst
<InitListExpr
>(
56 match(initListExpr(hasType(cxxRecordDecl(hasName("U")))).bind("init"),
58 ASSERT_NE(InitList
, nullptr);
60 RecordInitListHelper
Helper(InitList
);
61 EXPECT_THAT(Helper
.base_inits(), IsEmpty());
62 EXPECT_THAT(Helper
.field_inits(), IsEmpty());
65 TEST(ASTOpsTest
, ReferencedDeclsOnUnionInitList
) {
66 // This is a regression test: `getReferencedDecls()` used to return a null
67 // `FieldDecl` in this case (in addition to the correct non-null `FieldDecl`)
68 // because `getInitializedFieldInUnion()` returns null for the syntactic form
69 // of the `InitListExpr`.
70 std::string Code
= R
"cc(
79 std::unique_ptr
<ASTUnit
> Unit
=
80 tooling::buildASTFromCodeWithArgs(Code
, {"-fsyntax-only", "-std=c++17"});
81 auto &ASTCtx
= Unit
->getASTContext();
83 ASSERT_EQ(ASTCtx
.getDiagnostics().getClient()->getNumErrors(), 0U);
85 auto *InitList
= selectFirst
<InitListExpr
>(
87 match(initListExpr(hasType(cxxRecordDecl(hasName("U")))).bind("init"),
89 ASSERT_NE(InitList
, nullptr);
90 auto *IDecl
= cast
<FieldDecl
>(findValueDecl(ASTCtx
, "I"));
92 EXPECT_THAT(getReferencedDecls(*InitList
).Fields
,
93 UnorderedElementsAre(IDecl
));
96 TEST(ASTOpsTest
, ReferencedDeclsLocalsNotParamsOrStatics
) {
97 std::string Code
= R
"cc(
98 void func(int Param) {
99 static int Static = 0;
104 std::unique_ptr
<ASTUnit
> Unit
=
105 tooling::buildASTFromCodeWithArgs(Code
, {"-fsyntax-only", "-std=c++17"});
106 auto &ASTCtx
= Unit
->getASTContext();
108 ASSERT_EQ(ASTCtx
.getDiagnostics().getClient()->getNumErrors(), 0U);
110 auto *Func
= cast
<FunctionDecl
>(findValueDecl(ASTCtx
, "func"));
111 ASSERT_NE(Func
, nullptr);
112 auto *LocalDecl
= cast
<VarDecl
>(findValueDecl(ASTCtx
, "Local"));
114 EXPECT_THAT(getReferencedDecls(*Func
).Locals
,
115 UnorderedElementsAre(LocalDecl
));
118 TEST(ASTOpsTest
, LambdaCaptures
) {
119 std::string Code
= R
"cc(
120 void func(int CapturedByRef, int CapturedByValue, int NotCaptured) {
122 auto Lambda = [&CapturedByRef, CapturedByValue, &Local](int LambdaParam) {
126 std::unique_ptr
<ASTUnit
> Unit
=
127 tooling::buildASTFromCodeWithArgs(Code
, {"-fsyntax-only", "-std=c++17"});
128 auto &ASTCtx
= Unit
->getASTContext();
130 ASSERT_EQ(ASTCtx
.getDiagnostics().getClient()->getNumErrors(), 0U);
132 auto *LambdaCallOp
= selectFirst
<CXXMethodDecl
>(
133 "l", match(cxxMethodDecl(hasName("operator()")).bind("l"), ASTCtx
));
134 ASSERT_NE(LambdaCallOp
, nullptr);
135 auto *Func
= cast
<FunctionDecl
>(findValueDecl(ASTCtx
, "func"));
136 ASSERT_NE(Func
, nullptr);
137 auto *CapturedByRefDecl
= Func
->getParamDecl(0);
138 ASSERT_NE(CapturedByRefDecl
, nullptr);
139 auto *CapturedByValueDecl
= Func
->getParamDecl(1);
140 ASSERT_NE(CapturedByValueDecl
, nullptr);
142 EXPECT_THAT(getReferencedDecls(*Func
).LambdaCapturedParams
, IsEmpty());
143 ReferencedDecls ForLambda
= getReferencedDecls(*LambdaCallOp
);
144 EXPECT_THAT(ForLambda
.LambdaCapturedParams
,
145 UnorderedElementsAre(CapturedByRefDecl
, CapturedByValueDecl
));
146 // Captured locals must be seen in the body for them to appear in
148 EXPECT_THAT(ForLambda
.Locals
, IsEmpty());