blob: 115c3bfc518a420be97974b5c9606bdf1135fc9f [file] [log] [blame]
Googler113194c2023-07-12 11:03:47 -07001// Part of the Crubit project, under the Apache License v2.0 with LLVM
2// Exceptions. See /LICENSE for license information.
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5#include "nullability/inference/collect_evidence.h"
6
Dmitri Gribenko61645e12023-07-17 04:46:21 -07007#include <string>
Sam McCallebcc1232023-07-14 11:36:44 -07008#include <utility>
Googler113194c2023-07-12 11:03:47 -07009#include <vector>
10
Googler113194c2023-07-12 11:03:47 -070011#include "nullability/inference/inference.proto.h"
Googlerac9ac802023-10-19 09:09:35 -070012#include "nullability/inference/slot_fingerprint.h"
Googler113194c2023-07-12 11:03:47 -070013#include "clang/AST/Decl.h"
Sam McCall296d0702023-07-14 13:32:57 -070014#include "clang/AST/DeclBase.h"
Googler66045312023-09-11 12:28:58 -070015#include "clang/ASTMatchers/ASTMatchFinder.h"
16#include "clang/ASTMatchers/ASTMatchers.h"
Googler113194c2023-07-12 11:03:47 -070017#include "clang/Basic/LLVM.h"
18#include "clang/Testing/TestAST.h"
19#include "third_party/llvm/llvm-project/clang/unittests/Analysis/FlowSensitive/TestingSupport.h"
Googler2c9f53f2023-10-24 07:33:00 -070020#include "llvm/ADT/DenseMap.h"
Googlerac9ac802023-10-19 09:09:35 -070021#include "llvm/ADT/DenseSet.h"
Googler113194c2023-07-12 11:03:47 -070022#include "llvm/ADT/StringRef.h"
23#include "llvm/Support/Error.h"
Sam McCall296d0702023-07-14 13:32:57 -070024#include "llvm/Support/raw_ostream.h"
Googlere9210aa2023-07-13 10:55:06 -070025#include "third_party/llvm/llvm-project/third-party/unittest/googlemock/include/gmock/gmock.h" // IWYU pragma: keep
Googler113194c2023-07-12 11:03:47 -070026#include "third_party/llvm/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h"
27
28namespace clang::tidy::nullability {
29namespace {
Googler66045312023-09-11 12:28:58 -070030using ::clang::ast_matchers::functionDecl;
31using ::clang::ast_matchers::hasName;
32using ::clang::ast_matchers::isTemplateInstantiation;
33using ::clang::ast_matchers::match;
Googlere1504a62023-07-18 14:03:23 -070034using ::testing::_;
Googlerac9ac802023-10-19 09:09:35 -070035using ::testing::AllOf;
Googlere1504a62023-07-18 14:03:23 -070036using ::testing::Contains;
Sam McCall296d0702023-07-14 13:32:57 -070037using ::testing::ElementsAre;
Googler113194c2023-07-12 11:03:47 -070038using ::testing::IsEmpty;
Googlerac9ac802023-10-19 09:09:35 -070039using ::testing::IsSupersetOf;
Googlere1504a62023-07-18 14:03:23 -070040using ::testing::Not;
Googlerac9ac802023-10-19 09:09:35 -070041using ::testing::ResultOf;
Googler66045312023-09-11 12:28:58 -070042using ::testing::SizeIs;
Googlere9210aa2023-07-13 10:55:06 -070043using ::testing::UnorderedElementsAre;
Googler113194c2023-07-12 11:03:47 -070044
Googlere1504a62023-07-18 14:03:23 -070045MATCHER_P3(isEvidenceMatcher, SlotMatcher, KindMatcher, SymbolMatcher, "") {
46 return SlotMatcher.Matches(static_cast<Slot>(arg.slot())) &&
47 KindMatcher.Matches(arg.kind()) && SymbolMatcher.Matches(arg.symbol());
Sam McCallbd1a6e52023-07-14 01:04:11 -070048}
49
50testing::Matcher<const Evidence&> evidence(
Googlere1504a62023-07-18 14:03:23 -070051 testing::Matcher<Slot> S, testing::Matcher<Evidence::Kind> Kind,
Sam McCallbd1a6e52023-07-14 01:04:11 -070052 testing::Matcher<const Symbol&> SymbolMatcher = testing::_) {
Sam McCall83bc55c2023-07-17 09:47:17 -070053 return isEvidenceMatcher(S, Kind, SymbolMatcher);
Sam McCallbd1a6e52023-07-14 01:04:11 -070054}
55
56MATCHER_P(functionNamed, Name, "") {
57 return llvm::StringRef(arg.usr()).contains(
58 ("@" + llvm::StringRef(Name) + "#").str());
59}
Sam McCallbd1a6e52023-07-14 01:04:11 -070060
Googler1cf79e42023-07-17 14:31:35 -070061clang::TestInputs getInputsWithAnnotationDefinitions(llvm::StringRef Source) {
62 clang::TestInputs Inputs = Source;
63 Inputs.ExtraFiles["nullability.h"] = R"cc(
64 template <typename T>
65 using Nullable [[clang::annotate("Nullable")]] = T;
66 template <typename T>
67 using Nonnull [[clang::annotate("Nonnull")]] = T;
Googler0b222ba2023-11-03 08:02:58 -070068 template <typename T>
69 using Unknown [[clang::annotate("Nullability_Unspecified")]] = T;
Googler1cf79e42023-07-17 14:31:35 -070070 )cc";
71 Inputs.ExtraArgs.push_back("-include");
72 Inputs.ExtraArgs.push_back("nullability.h");
73 return Inputs;
74}
75
Googler113194c2023-07-12 11:03:47 -070076std::vector<Evidence> collectEvidenceFromTargetFunction(
Googler71919492023-10-23 15:44:06 -070077 llvm::StringRef Source, PreviousInferences PreviousInferences = {}) {
Sam McCallebcc1232023-07-14 11:36:44 -070078 std::vector<Evidence> Results;
Googler1cf79e42023-07-17 14:31:35 -070079 clang::TestAST AST(getInputsWithAnnotationDefinitions(Source));
Googler6acdc642023-10-19 08:03:40 -070080 USRCache usr_cache;
Sam McCallebcc1232023-07-14 11:36:44 -070081 auto Err = collectEvidenceFromImplementation(
82 cast<FunctionDecl>(
83 *dataflow::test::findValueDecl(AST.context(), "target")),
Googler6acdc642023-10-19 08:03:40 -070084 evidenceEmitter([&](const Evidence& E) { Results.push_back(E); },
85 usr_cache),
Googler71919492023-10-23 15:44:06 -070086 usr_cache, PreviousInferences);
Sam McCallebcc1232023-07-14 11:36:44 -070087 if (Err) ADD_FAILURE() << toString(std::move(Err));
88 return Results;
Googler113194c2023-07-12 11:03:47 -070089}
90
Sam McCallbd1a6e52023-07-14 01:04:11 -070091std::vector<Evidence> collectEvidenceFromTargetDecl(llvm::StringRef Source) {
Sam McCallebcc1232023-07-14 11:36:44 -070092 std::vector<Evidence> Results;
Googler1cf79e42023-07-17 14:31:35 -070093 clang::TestAST AST(getInputsWithAnnotationDefinitions(Source));
Googler6acdc642023-10-19 08:03:40 -070094 USRCache usr_cache;
Sam McCallebcc1232023-07-14 11:36:44 -070095 collectEvidenceFromTargetDeclaration(
96 *dataflow::test::findValueDecl(AST.context(), "target"),
Googler6acdc642023-10-19 08:03:40 -070097 evidenceEmitter([&](const Evidence& E) { Results.push_back(E); },
98 usr_cache));
Sam McCallebcc1232023-07-14 11:36:44 -070099 return Results;
Googlere9210aa2023-07-13 10:55:06 -0700100}
101
Googlere1504a62023-07-18 14:03:23 -0700102TEST(CollectEvidenceFromImplementationTest, NoParams) {
Googler113194c2023-07-12 11:03:47 -0700103 static constexpr llvm::StringRef Src = R"cc(
104 void target() {}
105 )cc";
106 EXPECT_THAT(collectEvidenceFromTargetFunction(Src), IsEmpty());
107}
108
Googlere1504a62023-07-18 14:03:23 -0700109TEST(CollectEvidenceFromImplementationTest, OneParamUnused) {
Googler113194c2023-07-12 11:03:47 -0700110 static constexpr llvm::StringRef Src = R"cc(
111 void target(int *p0) {}
112 )cc";
113 EXPECT_THAT(collectEvidenceFromTargetFunction(Src), IsEmpty());
114}
115
Googlere1504a62023-07-18 14:03:23 -0700116TEST(CollectEvidenceFromImplementationTest, OneParamUsedWithoutRestriction) {
Googler113194c2023-07-12 11:03:47 -0700117 static constexpr llvm::StringRef Src = R"cc(
118 void takesUnknown(int *unknown) {}
119
120 void target(int *p0) { takesUnknown(p0); }
121 )cc";
Googlere1504a62023-07-18 14:03:23 -0700122 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
123 Not(Contains(evidence(_, _, functionNamed("target")))));
Googler113194c2023-07-12 11:03:47 -0700124}
125
Googlere1504a62023-07-18 14:03:23 -0700126TEST(CollectEvidenceFromImplementationTest, Deref) {
Googlere9210aa2023-07-13 10:55:06 -0700127 static constexpr llvm::StringRef Src = R"cc(
128 void target(int *p0, int *p1) {
129 int a = *p0;
130 if (p1 != nullptr) {
131 int b = *p1;
132 }
133 }
134 )cc";
135 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
Sam McCall83bc55c2023-07-17 09:47:17 -0700136 UnorderedElementsAre(
137 evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE)));
Googlere9210aa2023-07-13 10:55:06 -0700138}
Sam McCall5f2bb242023-09-14 07:02:56 -0700139TEST(CollectEvidenceFromImplementationTest, DerefArrow) {
140 static constexpr llvm::StringRef Src = R"cc(
141 struct S {
142 int x;
143 int y();
144 };
145 void target(S *a, S *b) {
146 a->x;
147 b->y();
148 }
149 )cc";
150 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
151 UnorderedElementsAre(
152 evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE),
153 evidence(paramSlot(1), Evidence::UNCHECKED_DEREFERENCE)));
154}
Googler1cf79e42023-07-17 14:31:35 -0700155TEST(InferAnnotationsTest, DerefOfNonnull) {
156 static constexpr llvm::StringRef Src = R"cc(
157 void target(Nonnull<int *> p) {
158 *p;
159 }
160 )cc";
161 EXPECT_THAT(collectEvidenceFromTargetFunction(Src), IsEmpty());
162}
Googlere9210aa2023-07-13 10:55:06 -0700163
Sam McCallcfd2dd12023-07-18 19:35:21 -0700164TEST(InferAnnotationsTest, Location) {
165 llvm::StringRef Code = "void target(int *p) { *p; }";
166 // 12345678901234567890123456
167 // 0 1 2
168
169 auto Evidence = collectEvidenceFromTargetFunction(Code);
170 ASSERT_THAT(Evidence, ElementsAre(evidence(paramSlot(0),
171 Evidence::UNCHECKED_DEREFERENCE)));
172 EXPECT_EQ("input.mm:1:23", Evidence.front().location());
173}
174
Googlere1504a62023-07-18 14:03:23 -0700175TEST(CollectEvidenceFromImplementationTest, DereferenceBeforeAssignment) {
Googlere9210aa2023-07-13 10:55:06 -0700176 static constexpr llvm::StringRef Src = R"cc(
177 void target(int *p) {
178 *p;
179 int i = 1;
180 p = &i;
181 }
182 )cc";
183 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
Sam McCall83bc55c2023-07-17 09:47:17 -0700184 UnorderedElementsAre(
185 evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE)));
Googlere9210aa2023-07-13 10:55:06 -0700186}
187
Googlere1504a62023-07-18 14:03:23 -0700188TEST(CollectEvidenceFromImplementationTest, DereferenceAfterAssignment) {
Googlere9210aa2023-07-13 10:55:06 -0700189 static constexpr llvm::StringRef Src = R"cc(
190 void target(int *p) {
191 int i = 1;
192 p = &i;
193 *p;
194 }
195 )cc";
196 EXPECT_THAT(collectEvidenceFromTargetFunction(Src), IsEmpty());
197}
198
Googlere1504a62023-07-18 14:03:23 -0700199TEST(CollectEvidenceFromImplementationTest, DerefOfPtrRef) {
Googlere9210aa2023-07-13 10:55:06 -0700200 static constexpr llvm::StringRef Src = R"cc(
201 void target(int *&p0, int *&p1) {
202 int a = *p0;
203 if (p1 != nullptr) {
204 int b = *p1;
205 }
206 }
207 )cc";
208 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
Sam McCall83bc55c2023-07-17 09:47:17 -0700209 UnorderedElementsAre(
210 evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE)));
Googlere9210aa2023-07-13 10:55:06 -0700211}
212
Googlere1504a62023-07-18 14:03:23 -0700213TEST(CollectEvidenceFromImplementationTest, UnrelatedCondition) {
Googlere9210aa2023-07-13 10:55:06 -0700214 static constexpr llvm::StringRef Src = R"cc(
215 void target(int *p0, int *p1, int *p2, bool b) {
216 if (b) {
217 int a = *p0;
218 int b = *p1;
219 } else {
220 int a = *p0;
221 int c = *p2;
222 }
223 }
224 )cc";
225 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
226 UnorderedElementsAre(
Sam McCall83bc55c2023-07-17 09:47:17 -0700227 evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE),
228 evidence(paramSlot(1), Evidence::UNCHECKED_DEREFERENCE),
Googlere9210aa2023-07-13 10:55:06 -0700229 // We collect two Evidence values for two dereferences of p0
Sam McCall83bc55c2023-07-17 09:47:17 -0700230 evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE),
231 evidence(paramSlot(2), Evidence::UNCHECKED_DEREFERENCE)));
Googlere9210aa2023-07-13 10:55:06 -0700232}
233
Googlere1504a62023-07-18 14:03:23 -0700234TEST(CollectEvidenceFromImplementationTest, LaterDeref) {
Googlere9210aa2023-07-13 10:55:06 -0700235 static constexpr llvm::StringRef Src = R"cc(
236 void target(int *p0) {
237 if (p0 == nullptr) {
238 (void)0;
239 } else {
240 (void)0;
241 }
242 int a = *p0;
243 }
244 )cc";
245 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
Sam McCall83bc55c2023-07-17 09:47:17 -0700246 UnorderedElementsAre(
247 evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE)));
Googlere9210aa2023-07-13 10:55:06 -0700248}
249
Googlere1504a62023-07-18 14:03:23 -0700250TEST(CollectEvidenceFromImplementationTest, DerefBeforeGuardedDeref) {
Googlere9210aa2023-07-13 10:55:06 -0700251 static constexpr llvm::StringRef Src = R"cc(
252 void target(int *p0) {
253 int a = *p0;
254 if (p0 != nullptr) {
255 int b = *p0;
256 }
257 }
258 )cc";
259 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
Sam McCall83bc55c2023-07-17 09:47:17 -0700260 UnorderedElementsAre(
261 evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE)));
Googlere9210aa2023-07-13 10:55:06 -0700262}
263
Googlere1504a62023-07-18 14:03:23 -0700264TEST(CollectEvidenceFromImplementationTest, EarlyReturn) {
Googlere9210aa2023-07-13 10:55:06 -0700265 static constexpr llvm::StringRef Src = R"cc(
266 void target(int *p0) {
267 if (!p0) {
268 return;
269 }
270 int a = *p0;
271 }
272 )cc";
273 EXPECT_THAT(collectEvidenceFromTargetFunction(Src), IsEmpty());
274}
275
Googlere1504a62023-07-18 14:03:23 -0700276TEST(CollectEvidenceFromImplementationTest, UnreachableCode) {
Googlere9210aa2023-07-13 10:55:06 -0700277 static constexpr llvm::StringRef Src = R"cc(
278 void target(int *p0, int *p1, int *p2, int *p3) {
279 if (true) {
280 int a = *p0;
281 } else {
282 int a = *p1;
283 }
284
285 if (false) {
286 int a = *p2;
287 }
288
289 return;
290 int a = *p3;
291 }
292 )cc";
293 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
Sam McCall83bc55c2023-07-17 09:47:17 -0700294 UnorderedElementsAre(
295 evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE)));
Sam McCallbd1a6e52023-07-14 01:04:11 -0700296}
297
Googlere1504a62023-07-18 14:03:23 -0700298TEST(CollectEvidenceFromImplementationTest, NullableArgPassed) {
299 static constexpr llvm::StringRef Src = R"cc(
300 void callee(int *q);
301 void target(Nullable<int *> p) { callee(p); }
302 )cc";
303 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
304 Contains(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT,
305 functionNamed("callee"))));
306}
307
308TEST(CollectEvidenceFromImplementationTest, NonnullArgPassed) {
309 static constexpr llvm::StringRef Src = R"cc(
310 void callee(int *q);
311 void target(Nonnull<int *> p) { callee(p); }
312 )cc";
313 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
314 Contains(evidence(paramSlot(0), Evidence::NONNULL_ARGUMENT,
315 functionNamed("callee"))));
316}
317
318TEST(CollectEvidenceFromImplementationTest, UnknownArgPassed) {
319 static constexpr llvm::StringRef Src = R"cc(
320 void callee(int *q);
321 void target(int *p) { callee(p); }
322 )cc";
323 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
324 Contains(evidence(paramSlot(0), Evidence::UNKNOWN_ARGUMENT,
325 functionNamed("callee"))));
326}
327
328TEST(CollectEvidenceFromImplementationTest, CheckedArgPassed) {
329 static constexpr llvm::StringRef Src = R"cc(
330 void callee(int *q);
331 void target(int *p) {
332 if (p) callee(p);
333 }
334 )cc";
335 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
336 Contains(evidence(paramSlot(0), Evidence::NONNULL_ARGUMENT,
337 functionNamed("callee"))));
338}
339
340TEST(CollectEvidenceFromImplementationTest, NullptrPassed) {
341 static constexpr llvm::StringRef Src = R"cc(
342 void callee(int* q);
343 void target() {
344 callee(nullptr);
345 int* p = nullptr;
346 callee(nullptr);
347 }
348 )cc";
349 EXPECT_THAT(
350 collectEvidenceFromTargetFunction(Src),
351 UnorderedElementsAre(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT,
352 functionNamed("callee")),
353 evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT,
354 functionNamed("callee"))));
355}
356
357TEST(CollectEvidenceFromImplementationTest, NonPtrArgPassed) {
358 static constexpr llvm::StringRef Src = R"cc(
359 void callee(int q);
360 void target(int p) { callee(p); }
361 )cc";
362 EXPECT_THAT(collectEvidenceFromTargetFunction(Src), IsEmpty());
363}
364
Googler3e3ae482023-07-19 08:50:59 -0700365TEST(CollectEvidenceFromImplementationTest, NullableReturn) {
366 static constexpr llvm::StringRef Src = R"cc(
367 int* target() { return nullptr; }
368 )cc";
369 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
370 Contains(evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN,
371 functionNamed("target"))));
372}
373
374TEST(CollectEvidenceFromImplementationTest, NonnullReturn) {
375 static constexpr llvm::StringRef Src = R"cc(
376 int* target(Nonnull<int*> p) {
377 return p;
378 }
379 )cc";
380 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
381 Contains(evidence(SLOT_RETURN_TYPE, Evidence::NONNULL_RETURN,
382 functionNamed("target"))));
383}
384
385TEST(CollectEvidenceFromImplementationTest, UnknownReturn) {
386 static constexpr llvm::StringRef Src = R"cc(
387 int* target(int* p) { return p; }
388 )cc";
389 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
390 Contains(evidence(SLOT_RETURN_TYPE, Evidence::UNKNOWN_RETURN,
391 functionNamed("target"))));
392}
393
394TEST(CollectEvidenceFromImplementationTest, MultipleReturns) {
395 static constexpr llvm::StringRef Src = R"cc(
396 int* target(Nonnull<int*> p, Nullable<int*> q, bool b, bool c) {
397 if (b) return q;
398 if (c) return nullptr;
399 return p;
400 }
401 )cc";
402 EXPECT_THAT(
403 collectEvidenceFromTargetFunction(Src),
404 UnorderedElementsAre(evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN,
405 functionNamed("target")),
406 evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN,
407 functionNamed("target")),
408 evidence(SLOT_RETURN_TYPE, Evidence::NONNULL_RETURN,
409 functionNamed("target"))));
410}
411
Googler2e9a7972023-07-24 06:02:13 -0700412TEST(CollectEvidenceFromImplementationTest, MemberOperatorCall) {
413 static constexpr llvm::StringRef Src = R"cc(
414 struct S {
415 bool operator+(int*);
416 };
417 void target() { S{} + nullptr; }
418 )cc";
419 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
420 Contains(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT,
421 functionNamed("operator+"))));
422}
423
424TEST(CollectEvidenceFromImplementationTest, NonMemberOperatorCall) {
425 static constexpr llvm::StringRef Src = R"cc(
426 struct S {};
427 bool operator+(const S&, int*);
428 void target() { S{} + nullptr; }
429 )cc";
430 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
431 Contains(evidence(paramSlot(1), Evidence::NULLABLE_ARGUMENT,
432 functionNamed("operator+"))));
433}
434
435TEST(CollectEvidenceFromImplementationTest, VarArgs) {
436 static constexpr llvm::StringRef Src = R"cc(
437 void callee(int*...);
438 void target() { callee(nullptr, nullptr); }
439 )cc";
440 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
441 Contains(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT,
442 functionNamed("callee"))));
443}
444
445TEST(CollectEvidenceFromImplementationTest, MemberOperatorCallVarArgs) {
446 static constexpr llvm::StringRef Src = R"cc(
447 struct S {
448 bool operator()(int*...);
449 };
450 void target() { S{}(nullptr, nullptr); }
451 )cc";
452 EXPECT_THAT(collectEvidenceFromTargetFunction(Src),
453 Contains(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT,
454 functionNamed("operator()"))));
455}
456
Googlere2ee60c2023-11-02 11:07:30 -0700457TEST(CollectEvidenceFromImplementationTest, ConstructorCall) {
458 static constexpr llvm::StringRef Src = R"cc(
459 class S {
460 public:
461 S(Nonnull<int*> a);
462 };
463 void target(int* p) { S s(p); }
464 )cc";
465 EXPECT_THAT(
466 collectEvidenceFromTargetFunction(Src),
467 UnorderedElementsAre(evidence(paramSlot(0), Evidence::BOUND_TO_NONNULL,
468 functionNamed("target")),
469 evidence(paramSlot(0), Evidence::UNKNOWN_ARGUMENT,
470 functionNamed("S"))));
471}
472
Googler43114e82023-09-26 10:51:01 -0700473TEST(CollectEvidenceFromImplementationTest, PassedToNonnull) {
474 static constexpr llvm::StringRef Src = R"cc(
475 void callee(Nonnull<int*> i);
476
477 void target(int* p) { callee(p); }
478 )cc";
Googler477b00d2023-11-02 10:38:52 -0700479 EXPECT_THAT(
480 collectEvidenceFromTargetFunction(Src),
481 UnorderedElementsAre(evidence(paramSlot(0), Evidence::BOUND_TO_NONNULL,
482 functionNamed("target")),
483 evidence(paramSlot(0), Evidence::UNKNOWN_ARGUMENT,
484 functionNamed("callee"))));
485}
486
487TEST(CollectEvidenceFromImplementationTest, AssignedToNonnull) {
488 static constexpr llvm::StringRef Src = R"cc(
489 void target(int* p, int* q, int* r) {
490 Nonnull<int*> a = p, b = q;
491 a = r;
492 }
493 )cc";
494 EXPECT_THAT(
495 collectEvidenceFromTargetFunction(Src),
496 UnorderedElementsAre(evidence(paramSlot(0), Evidence::BOUND_TO_NONNULL,
497 functionNamed("target")),
498 evidence(paramSlot(1), Evidence::BOUND_TO_NONNULL,
499 functionNamed("target")),
500 evidence(paramSlot(2), Evidence::BOUND_TO_NONNULL,
501 functionNamed("target"))));
Googler43114e82023-09-26 10:51:01 -0700502}
503
Googler0b222ba2023-11-03 08:02:58 -0700504TEST(CollectEvidenceFromImplementationTest, AssignedToNullableOrUnknown) {
505 static constexpr llvm::StringRef Src = R"cc(
506 void target(int* p, int* q, int* r) {
507 Nullable<int*> a = p;
508 int* b = q;
509 Unknown<int*> c = r;
510 q = r;
511 }
512 )cc";
513 EXPECT_THAT(collectEvidenceFromTargetFunction(Src), IsEmpty());
514}
515
Googler1f3b8da2023-10-31 10:59:05 -0700516// A crash repro involving callable parameters.
517TEST(CollectEvidenceFromImplementationTest, FunctionPointerParam) {
518 static constexpr llvm::StringRef Src = R"cc(
519 void target(void (*f)()) { f(); }
520 )cc";
521 EXPECT_THAT(collectEvidenceFromTargetFunction(Src), IsEmpty());
522}
523
Googler66045312023-09-11 12:28:58 -0700524TEST(CollectEvidenceFromImplementationTest, NotInferenceTarget) {
525 static constexpr llvm::StringRef Src = R"cc(
526 template <typename T>
527 T* target(T* p) {
528 *p;
529 return nullptr;
530 }
531
532 void instantiate() { target<int>(nullptr); }
533 )cc";
534
535 clang::TestAST AST(getInputsWithAnnotationDefinitions(Src));
536 auto TargetInstantiationNodes = match(
537 functionDecl(hasName("target"), isTemplateInstantiation()).bind("target"),
538 AST.context());
539 ASSERT_THAT(TargetInstantiationNodes, SizeIs(1));
540 auto* const InstantiationDecl = ast_matchers::selectFirst<FunctionDecl>(
541 "target", TargetInstantiationNodes);
542 ASSERT_NE(InstantiationDecl, nullptr);
543
Googler6acdc642023-10-19 08:03:40 -0700544 USRCache usr_cache;
Googler66045312023-09-11 12:28:58 -0700545 std::vector<Evidence> Results;
546 auto Err = collectEvidenceFromImplementation(
547 *InstantiationDecl,
Googler6acdc642023-10-19 08:03:40 -0700548 evidenceEmitter([&](const Evidence& E) { Results.push_back(E); },
549 usr_cache),
550 usr_cache);
Googler66045312023-09-11 12:28:58 -0700551 if (Err) ADD_FAILURE() << toString(std::move(Err));
552 EXPECT_THAT(Results, IsEmpty());
553}
554
Googlerac9ac802023-10-19 09:09:35 -0700555TEST(CollectEvidenceFromImplementationTest, PropagatesPreviousInferences) {
556 static constexpr llvm::StringRef Src = R"cc(
557 void calledWithToBeNullable(int* x);
558 void calledWithToBeNonnull(int* a);
559 void target(int* p, int* q) {
560 target(nullptr, q);
561 calledWithToBeNullable(p);
562 *q;
563 calledWithToBeNonnull(q);
564 }
565 )cc";
566 std::string TargetUsr = "c:@F@target#*I#S0_#";
567 std::vector ExpectedBothRoundResults = {
568 evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT,
569 AllOf(functionNamed("target"),
570 // Double-check that target's usr is as expected before we
571 // use it to create SlotFingerprints.
572 ResultOf([](Symbol S) { return S.usr(); }, TargetUsr))),
573 evidence(paramSlot(1), Evidence::UNCHECKED_DEREFERENCE,
574 functionNamed("target")),
575 };
576 std::vector ExpectedSecondRoundResults = {
577 evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT,
578 functionNamed("calledWithToBeNullable")),
579 evidence(paramSlot(0), Evidence::NONNULL_ARGUMENT,
580 functionNamed("calledWithToBeNonnull"))};
581
582 // Only proceed if we have the correct USR for target and the first round
583 // results contain the evidence needed to produce our expected inferences and
584 // do not contain the evidence only found from propagating inferences from the
585 // first round.
586 auto FirstRoundResults = collectEvidenceFromTargetFunction(Src);
587 ASSERT_THAT(FirstRoundResults, IsSupersetOf(ExpectedBothRoundResults));
588 for (const auto& E : ExpectedSecondRoundResults) {
589 ASSERT_THAT(FirstRoundResults, Not(Contains(E)));
590 }
591
Googler71919492023-10-23 15:44:06 -0700592 EXPECT_THAT(collectEvidenceFromTargetFunction(
593 Src, {/*Nullable=*/{fingerprint(TargetUsr, paramSlot(0))},
594 /*Nonnull=*/{fingerprint(TargetUsr, paramSlot(1))}}),
595 AllOf(IsSupersetOf(ExpectedBothRoundResults),
596 IsSupersetOf(ExpectedSecondRoundResults)));
Googlerac9ac802023-10-19 09:09:35 -0700597}
598
Googler2c9f53f2023-10-24 07:33:00 -0700599TEST(CollectEvidenceFromImplementationTest,
600 AnalysisUsesPreviousInferencesForSlotsOutsideTargetImplementation) {
601 static constexpr llvm::StringRef Src = R"cc(
602 int* returnsToBeNonnull(int* a) {
603 return a;
604 }
605 int* target(int* q) {
606 *q;
607 return returnsToBeNonnull(q);
608 }
609 )cc";
610 std::string TargetUsr = "c:@F@target#*I#";
611 std::string ReturnsToBeNonnullUsr = "c:@F@returnsToBeNonnull#*I#";
612 const llvm::DenseMap<int, std::vector<testing::Matcher<const Evidence&>>>
613 ExpectedNewResultsPerRound = {
Googler0b222ba2023-11-03 08:02:58 -0700614 {0,
615 {evidence(
616 paramSlot(0), Evidence::UNCHECKED_DEREFERENCE,
617 AllOf(functionNamed("target"),
618 // Double-check that target's usr is as expected before
619 // we use it to create SlotFingerprints.
620 ResultOf([](Symbol S) { return S.usr(); }, TargetUsr)))}},
621 {1,
622 {evidence(
623 paramSlot(0), Evidence::NONNULL_ARGUMENT,
624 AllOf(functionNamed("returnsToBeNonnull"),
625 // Double-check that returnsToBeNonnull's usr is as
626 // expected before we use it to create SlotFingerprints.
627 ResultOf([](Symbol S) { return S.usr(); },
628 ReturnsToBeNonnullUsr)))}},
629 {2,
630 {
631 // No new evidence from target's implementation in this round,
632 // but in a full-TU analysis, this would be the round where we
633 // decide returnsToBeNonnull returns Nonnull, based on the
634 // now-Nonnull argument that is the only return value.
635 }},
636 {3,
637 {evidence(SLOT_RETURN_TYPE, Evidence::NONNULL_RETURN,
638 functionNamed("target"))}}};
Googler2c9f53f2023-10-24 07:33:00 -0700639
640 // Assert first round results because they don't rely on previous inference
641 // propagation at all and in this case are test setup and preconditions.
642 auto FirstRoundResults = collectEvidenceFromTargetFunction(Src);
643 ASSERT_THAT(FirstRoundResults,
644 IsSupersetOf(ExpectedNewResultsPerRound.at(0)));
645 for (const auto& E : ExpectedNewResultsPerRound.at(1)) {
646 ASSERT_THAT(FirstRoundResults, Not(Contains(E)));
647 }
648
649 auto SecondRoundResults = collectEvidenceFromTargetFunction(
650 Src, {.Nonnull = {fingerprint(TargetUsr, paramSlot(0))}});
651 EXPECT_THAT(SecondRoundResults,
652 AllOf(IsSupersetOf(ExpectedNewResultsPerRound.at(0)),
653 IsSupersetOf(ExpectedNewResultsPerRound.at(1))));
654 for (const auto& E : ExpectedNewResultsPerRound.at(2)) {
655 ASSERT_THAT(SecondRoundResults, Not(Contains(E)));
656 }
657
658 auto ThirdRoundResults = collectEvidenceFromTargetFunction(
659 Src, {.Nonnull = {fingerprint(TargetUsr, paramSlot(0)),
660 fingerprint(ReturnsToBeNonnullUsr, paramSlot(0))}});
661 EXPECT_THAT(ThirdRoundResults,
662 AllOf(IsSupersetOf(ExpectedNewResultsPerRound.at(0)),
663 IsSupersetOf(ExpectedNewResultsPerRound.at(1)),
664 IsSupersetOf(ExpectedNewResultsPerRound.at(2))));
665 for (const auto& E : ExpectedNewResultsPerRound.at(3)) {
666 ASSERT_THAT(ThirdRoundResults, Not(Contains(E)));
667 }
668
669 auto FourthRoundResults = collectEvidenceFromTargetFunction(
670 Src,
671 {.Nonnull = {
672 fingerprint(TargetUsr, paramSlot(0)),
673 fingerprint(ReturnsToBeNonnullUsr, paramSlot(0)),
674 // As noted in the Evidence matcher list above, we don't infer the
675 // return type of returnsToBeNonnull from only collecting evidence
676 // from target's implementation, but for the sake of this test, let's
677 // pretend we collected evidence from the entire TU.
678 fingerprint(ReturnsToBeNonnullUsr, SLOT_RETURN_TYPE)}});
679 EXPECT_THAT(FourthRoundResults,
680 AllOf(IsSupersetOf(ExpectedNewResultsPerRound.at(0)),
681 IsSupersetOf(ExpectedNewResultsPerRound.at(1)),
682 IsSupersetOf(ExpectedNewResultsPerRound.at(2)),
683 IsSupersetOf(ExpectedNewResultsPerRound.at(3))));
684}
685
Googler0b222ba2023-11-03 08:02:58 -0700686TEST(CollectEvidenceFromImplementationTest,
687 PreviousInferencesOfNonTargetParameterNullabilitiesPropagate) {
688 static constexpr llvm::StringRef Src = R"cc(
689 void takesToBeNonnull(int* a) {
690 // Not read when collecting evidence only from Target, but corresponding
691 // inference is explicitly input below.
692 *a;
693 }
694 void target(int* q) { takesToBeNonnull(q); }
695 )cc";
696 std::string TakesToBeNonnullUsr = "c:@F@takesToBeNonnull#*I#";
697
698 // Pretend that in a first round of inferring for all functions, we made this
699 // inference about takesToBeNonnull's first parameter.
700 // This test confirms that we use that information when collecting from
701 // target's implementation.
702 EXPECT_THAT(
703 collectEvidenceFromTargetFunction(
704 Src, {.Nonnull = {fingerprint(TakesToBeNonnullUsr, paramSlot(0))}}),
705 Contains(evidence(paramSlot(0), Evidence::BOUND_TO_NONNULL,
706 functionNamed("target"))));
707}
708
Googlere1504a62023-07-18 14:03:23 -0700709TEST(CollectEvidenceFromDeclarationTest, VariableDeclIgnored) {
Sam McCallbd1a6e52023-07-14 01:04:11 -0700710 llvm::StringLiteral Src = "Nullable<int *> target;";
711 EXPECT_THAT(collectEvidenceFromTargetDecl(Src), IsEmpty());
712}
713
Googlere1504a62023-07-18 14:03:23 -0700714TEST(CollectEvidenceFromDeclarationTest, FunctionDeclReturnType) {
Sam McCallbd1a6e52023-07-14 01:04:11 -0700715 llvm::StringLiteral Src = "Nonnull<int *> target();";
Sam McCall83bc55c2023-07-17 09:47:17 -0700716 EXPECT_THAT(
717 collectEvidenceFromTargetDecl(Src),
718 ElementsAre(evidence(SLOT_RETURN_TYPE, Evidence::ANNOTATED_NONNULL,
719 functionNamed("target"))));
Sam McCallbd1a6e52023-07-14 01:04:11 -0700720}
721
Googlere1504a62023-07-18 14:03:23 -0700722TEST(CollectEvidenceFromDeclarationTest, FunctionDeclParams) {
Sam McCallbd1a6e52023-07-14 01:04:11 -0700723 llvm::StringLiteral Src = "void target(Nullable<int*>, int*, Nonnull<int*>);";
724 EXPECT_THAT(collectEvidenceFromTargetDecl(Src),
Sam McCall83bc55c2023-07-17 09:47:17 -0700725 ElementsAre(evidence(paramSlot(0), Evidence::ANNOTATED_NULLABLE),
726 evidence(paramSlot(2), Evidence::ANNOTATED_NONNULL)));
Sam McCallbd1a6e52023-07-14 01:04:11 -0700727}
728
Googlere1504a62023-07-18 14:03:23 -0700729TEST(CollectEvidenceFromDeclarationTest, FunctionDeclNonTopLevel) {
Sam McCallbd1a6e52023-07-14 01:04:11 -0700730 llvm::StringLiteral Src = "Nonnull<int*>** target(Nullable<int*>*);";
731 EXPECT_THAT(collectEvidenceFromTargetDecl(Src), IsEmpty());
Googlere9210aa2023-07-13 10:55:06 -0700732}
733
Sam McCalldba68972023-07-19 11:01:10 -0700734TEST(CollectEvidenceFromDeclarationTest, FunctionTemplateIgnored) {
735 // We used to inspect the type of `target` and crash.
736 llvm::StringLiteral Src = R"cc(
737 template <class A>
738 struct S {
739 template <class B>
740 static void target(const S<B>&) {}
741 };
742 )cc";
743 EXPECT_THAT(collectEvidenceFromTargetDecl(Src), IsEmpty());
744}
745
Sam McCall296d0702023-07-14 13:32:57 -0700746MATCHER_P(declNamed, Name, "") {
747 std::string Actual;
748 llvm::raw_string_ostream OS(Actual);
749 if (auto* ND = dyn_cast<NamedDecl>(arg))
750 ND->getNameForDiagnostic(
751 OS, arg->getDeclContext()->getParentASTContext().getPrintingPolicy(),
752 /*Qualified=*/true);
753 return ::testing::ExplainMatchResult(Name, Actual, result_listener);
754}
755
756TEST(EvidenceSitesTest, Functions) {
757 TestAST AST(R"cc(
758 void foo();
759 void bar();
760 void bar() {}
761 void baz() {}
762 auto Lambda = []() {}; // Not analyzed yet.
763
764 struct S {
Googlere2ee60c2023-11-02 11:07:30 -0700765 S() {}
Sam McCall296d0702023-07-14 13:32:57 -0700766 void member();
767 };
768 void S::member() {}
769 )cc");
770 auto Sites = EvidenceSites::discover(AST.context());
771 EXPECT_THAT(Sites.Declarations,
772 ElementsAre(declNamed("foo"), declNamed("bar"), declNamed("bar"),
Googlere2ee60c2023-11-02 11:07:30 -0700773 declNamed("baz"), declNamed("S::S"),
774 declNamed("S::member"), declNamed("S::member")));
775 EXPECT_THAT(Sites.Implementations,
776 ElementsAre(declNamed("bar"), declNamed("baz"), declNamed("S::S"),
Sam McCall296d0702023-07-14 13:32:57 -0700777 declNamed("S::member")));
Sam McCall296d0702023-07-14 13:32:57 -0700778}
779
780TEST(EvidenceSitesTest, Variables) {
781 TestAST AST(R"cc(
782 int* x = true ? nullptr : nullptr;
783 struct S {
784 int* s;
785 };
786 )cc");
787 auto Sites = EvidenceSites::discover(AST.context());
Googlerf1f793d2023-10-19 07:51:34 -0700788 // For now, variables are not inferable.
Sam McCall296d0702023-07-14 13:32:57 -0700789 EXPECT_THAT(Sites.Declarations, IsEmpty());
790 // For now, we don't examine variable initializers.
791 EXPECT_THAT(Sites.Implementations, IsEmpty());
792}
793
794TEST(EvidenceSitesTest, Templates) {
795 TestAST AST(R"cc(
796 template <int I>
797 int f() {
798 return I;
799 }
800 template <>
801 int f<1>() {
802 return 1;
803 }
804
805 struct S {
806 template <int I>
807 int f() {
808 return I;
809 }
810 };
811
812 template <int I>
813 struct T {
814 int f() { return I; }
815 };
816
817 auto Unused = f<0>() + f<1>() + S{}.f<0>() + T<0>{}.f();
818 )cc");
819 auto Sites = EvidenceSites::discover(AST.context());
820
Sam McCalldba68972023-07-19 11:01:10 -0700821 // Relevant declarations are the written ones that are not templates.
822 EXPECT_THAT(Sites.Declarations, ElementsAre(declNamed("f<1>")));
Sam McCall296d0702023-07-14 13:32:57 -0700823 // Instantiations are relevant inference targets.
824 EXPECT_THAT(Sites.Implementations,
825 ElementsAre(declNamed("f<0>"), declNamed("f<1>"),
826 declNamed("S::f<0>"), declNamed("T<0>::f")));
827}
828
Googler66045312023-09-11 12:28:58 -0700829TEST(EvidenceEmitterTest, NotInferenceTarget) {
830 TestAST AST(R"cc(
831 template <int I>
832 int target() {
833 return I;
834 })cc");
835
836 const auto* TargetDecl =
837 dataflow::test::findValueDecl(AST.context(), "target");
838 ASSERT_NE(TargetDecl, nullptr);
839
Googler6acdc642023-10-19 08:03:40 -0700840 USRCache usr_cache;
841 EXPECT_DEATH(evidenceEmitter([](const Evidence& e) {}, usr_cache)(
Googler66045312023-09-11 12:28:58 -0700842 *TargetDecl, Slot{}, Evidence::ANNOTATED_UNKNOWN,
843 TargetDecl->getLocation()),
844 "not an inference target");
845}
846
Googler113194c2023-07-12 11:03:47 -0700847} // namespace
848} // namespace clang::tidy::nullability