[ELF] Replace inExpr with lexState. NFC
[llvm-project.git] / clang / unittests / Analysis / FlowSensitive / RecordOpsTest.cpp
blob88b92668c850c6129b67ecd8020f5afd4eea7fba
1 //===- unittests/Analysis/FlowSensitive/RecordOpsTest.cpp -----------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
9 #include "clang/Analysis/FlowSensitive/RecordOps.h"
10 #include "TestingSupport.h"
11 #include "llvm/Testing/Support/Error.h"
12 #include "gtest/gtest.h"
14 namespace clang {
15 namespace dataflow {
16 namespace test {
17 namespace {
19 void runDataflow(
20 llvm::StringRef Code,
21 std::function<llvm::StringMap<QualType>(QualType)> SyntheticFieldCallback,
22 std::function<
23 void(const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
24 ASTContext &)>
25 VerifyResults) {
26 ASSERT_THAT_ERROR(checkDataflowWithNoopAnalysis(
27 Code, ast_matchers::hasName("target"), VerifyResults,
28 {BuiltinOptions()}, LangStandard::lang_cxx17,
29 SyntheticFieldCallback),
30 llvm::Succeeded());
33 const FieldDecl *getFieldNamed(RecordDecl *RD, llvm::StringRef Name) {
34 for (const FieldDecl *FD : RD->fields())
35 if (FD->getName() == Name)
36 return FD;
37 assert(false);
38 return nullptr;
41 TEST(RecordOpsTest, CopyRecord) {
42 std::string Code = R"(
43 struct S {
44 int outer_int;
45 int &ref;
46 struct {
47 int inner_int;
48 } inner;
50 void target(S s1, S s2) {
51 (void)s1.outer_int;
52 (void)s1.ref;
53 (void)s1.inner.inner_int;
54 // [[p]]
56 )";
57 runDataflow(
58 Code,
59 [](QualType Ty) -> llvm::StringMap<QualType> {
60 if (Ty.getAsString() != "S")
61 return {};
62 QualType IntTy =
63 getFieldNamed(Ty->getAsRecordDecl(), "outer_int")->getType();
64 return {{"synth_int", IntTy}};
66 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
67 ASTContext &ASTCtx) {
68 Environment Env = getEnvironmentAtAnnotation(Results, "p").fork();
70 const ValueDecl *OuterIntDecl = findValueDecl(ASTCtx, "outer_int");
71 const ValueDecl *RefDecl = findValueDecl(ASTCtx, "ref");
72 const ValueDecl *InnerDecl = findValueDecl(ASTCtx, "inner");
73 const ValueDecl *InnerIntDecl = findValueDecl(ASTCtx, "inner_int");
75 auto &S1 = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s1");
76 auto &S2 = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s2");
77 auto &Inner1 = *cast<RecordStorageLocation>(S1.getChild(*InnerDecl));
78 auto &Inner2 = *cast<RecordStorageLocation>(S2.getChild(*InnerDecl));
80 EXPECT_NE(getFieldValue(&S1, *OuterIntDecl, Env),
81 getFieldValue(&S2, *OuterIntDecl, Env));
82 EXPECT_NE(S1.getChild(*RefDecl), S2.getChild(*RefDecl));
83 EXPECT_NE(getFieldValue(&Inner1, *InnerIntDecl, Env),
84 getFieldValue(&Inner2, *InnerIntDecl, Env));
85 EXPECT_NE(Env.getValue(S1.getSyntheticField("synth_int")),
86 Env.getValue(S2.getSyntheticField("synth_int")));
88 copyRecord(S1, S2, Env);
90 EXPECT_EQ(getFieldValue(&S1, *OuterIntDecl, Env),
91 getFieldValue(&S2, *OuterIntDecl, Env));
92 EXPECT_EQ(S1.getChild(*RefDecl), S2.getChild(*RefDecl));
93 EXPECT_EQ(getFieldValue(&Inner1, *InnerIntDecl, Env),
94 getFieldValue(&Inner2, *InnerIntDecl, Env));
95 EXPECT_EQ(Env.getValue(S1.getSyntheticField("synth_int")),
96 Env.getValue(S2.getSyntheticField("synth_int")));
97 });
100 TEST(RecordOpsTest, RecordsEqual) {
101 std::string Code = R"(
102 struct S {
103 int outer_int;
104 int &ref;
105 struct {
106 int inner_int;
107 } inner;
109 void target(S s1, S s2) {
110 (void)s1.outer_int;
111 (void)s1.ref;
112 (void)s1.inner.inner_int;
113 // [[p]]
116 runDataflow(
117 Code,
118 [](QualType Ty) -> llvm::StringMap<QualType> {
119 if (Ty.getAsString() != "S")
120 return {};
121 QualType IntTy =
122 getFieldNamed(Ty->getAsRecordDecl(), "outer_int")->getType();
123 return {{"synth_int", IntTy}};
125 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
126 ASTContext &ASTCtx) {
127 Environment Env = getEnvironmentAtAnnotation(Results, "p").fork();
129 const ValueDecl *OuterIntDecl = findValueDecl(ASTCtx, "outer_int");
130 const ValueDecl *RefDecl = findValueDecl(ASTCtx, "ref");
131 const ValueDecl *InnerDecl = findValueDecl(ASTCtx, "inner");
132 const ValueDecl *InnerIntDecl = findValueDecl(ASTCtx, "inner_int");
134 auto &S1 = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s1");
135 auto &S2 = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s2");
136 auto &Inner2 = *cast<RecordStorageLocation>(S2.getChild(*InnerDecl));
138 Env.setValue(S1.getSyntheticField("synth_int"),
139 Env.create<IntegerValue>());
141 // Strategy: Create two equal records, then verify each of the various
142 // ways in which records can differ causes recordsEqual to return false.
143 // changes we can make to the record.
145 // This test reuses the same objects for multiple checks, which isn't
146 // great, but seems better than duplicating the setup code for every
147 // check.
149 copyRecord(S1, S2, Env);
150 EXPECT_TRUE(recordsEqual(S1, S2, Env));
152 // S2 has a different outer_int.
153 Env.setValue(*S2.getChild(*OuterIntDecl), Env.create<IntegerValue>());
154 EXPECT_FALSE(recordsEqual(S1, S2, Env));
155 copyRecord(S1, S2, Env);
156 EXPECT_TRUE(recordsEqual(S1, S2, Env));
158 // S2 doesn't have outer_int at all.
159 Env.clearValue(*S2.getChild(*OuterIntDecl));
160 EXPECT_FALSE(recordsEqual(S1, S2, Env));
161 copyRecord(S1, S2, Env);
162 EXPECT_TRUE(recordsEqual(S1, S2, Env));
164 // S2 has a different ref.
165 S2.setChild(*RefDecl, &Env.createStorageLocation(
166 RefDecl->getType().getNonReferenceType()));
167 EXPECT_FALSE(recordsEqual(S1, S2, Env));
168 copyRecord(S1, S2, Env);
169 EXPECT_TRUE(recordsEqual(S1, S2, Env));
171 // S2 as a different inner_int.
172 Env.setValue(*Inner2.getChild(*InnerIntDecl),
173 Env.create<IntegerValue>());
174 EXPECT_FALSE(recordsEqual(S1, S2, Env));
175 copyRecord(S1, S2, Env);
176 EXPECT_TRUE(recordsEqual(S1, S2, Env));
178 // S2 has a different synth_int.
179 Env.setValue(S2.getSyntheticField("synth_int"),
180 Env.create<IntegerValue>());
181 EXPECT_FALSE(recordsEqual(S1, S2, Env));
182 copyRecord(S1, S2, Env);
183 EXPECT_TRUE(recordsEqual(S1, S2, Env));
185 // S2 doesn't have a value for synth_int.
186 Env.clearValue(S2.getSyntheticField("synth_int"));
187 EXPECT_FALSE(recordsEqual(S1, S2, Env));
188 copyRecord(S1, S2, Env);
189 EXPECT_TRUE(recordsEqual(S1, S2, Env));
193 TEST(TransferTest, CopyRecordBetweenDerivedAndBase) {
194 std::string Code = R"(
195 struct A {
196 int i;
199 struct B : public A {
202 void target(A a, B b) {
203 (void)a.i;
204 // [[p]]
207 auto SyntheticFieldCallback = [](QualType Ty) -> llvm::StringMap<QualType> {
208 CXXRecordDecl *ADecl = nullptr;
209 if (Ty.getAsString() == "A")
210 ADecl = Ty->getAsCXXRecordDecl();
211 else if (Ty.getAsString() == "B")
212 ADecl = Ty->getAsCXXRecordDecl()
213 ->bases_begin()
214 ->getType()
215 ->getAsCXXRecordDecl();
216 else
217 return {};
218 QualType IntTy = getFieldNamed(ADecl, "i")->getType();
219 return {{"synth_int", IntTy}};
221 // Test copying derived to base class.
222 runDataflow(
223 Code, SyntheticFieldCallback,
224 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
225 ASTContext &ASTCtx) {
226 Environment Env = getEnvironmentAtAnnotation(Results, "p").fork();
228 const ValueDecl *IDecl = findValueDecl(ASTCtx, "i");
229 auto &A = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "a");
230 auto &B = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "b");
232 EXPECT_NE(Env.getValue(*A.getChild(*IDecl)),
233 Env.getValue(*B.getChild(*IDecl)));
234 EXPECT_NE(Env.getValue(A.getSyntheticField("synth_int")),
235 Env.getValue(B.getSyntheticField("synth_int")));
237 copyRecord(B, A, Env);
239 EXPECT_EQ(Env.getValue(*A.getChild(*IDecl)),
240 Env.getValue(*B.getChild(*IDecl)));
241 EXPECT_EQ(Env.getValue(A.getSyntheticField("synth_int")),
242 Env.getValue(B.getSyntheticField("synth_int")));
244 // Test copying base to derived class.
245 runDataflow(
246 Code, SyntheticFieldCallback,
247 [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
248 ASTContext &ASTCtx) {
249 Environment Env = getEnvironmentAtAnnotation(Results, "p").fork();
251 const ValueDecl *IDecl = findValueDecl(ASTCtx, "i");
252 auto &A = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "a");
253 auto &B = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "b");
255 EXPECT_NE(Env.getValue(*A.getChild(*IDecl)),
256 Env.getValue(*B.getChild(*IDecl)));
257 EXPECT_NE(Env.getValue(A.getSyntheticField("synth_int")),
258 Env.getValue(B.getSyntheticField("synth_int")));
260 copyRecord(A, B, Env);
262 EXPECT_EQ(Env.getValue(*A.getChild(*IDecl)),
263 Env.getValue(*B.getChild(*IDecl)));
264 EXPECT_EQ(Env.getValue(A.getSyntheticField("synth_int")),
265 Env.getValue(B.getSyntheticField("synth_int")));
269 } // namespace
270 } // namespace test
271 } // namespace dataflow
272 } // namespace clang