blob: 5b739ab194a1c456083274c4bca14290b81a9e1b [file] [log] [blame]
Wei Yi Tee543af742022-06-01 06:52:24 -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_verification/pointer_nullability_analysis.h"
6
Wei Yi Tee543af742022-06-01 06:52:24 -07007#include <string>
8
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -07009#include "absl/log/check.h"
Wei Yi Tee8b58e192022-08-02 10:15:40 -070010#include "nullability_verification/pointer_nullability.h"
Dani Ferreira Franco Moura3d56a222022-11-29 03:12:55 -080011#include "nullability_verification/pointer_nullability_lattice.h"
Wei Yi Tee543af742022-06-01 06:52:24 -070012#include "nullability_verification/pointer_nullability_matchers.h"
13#include "clang/AST/ASTContext.h"
14#include "clang/AST/Expr.h"
Wei Yi Tee1cd62af2022-06-09 00:56:46 -070015#include "clang/AST/OperationKinds.h"
16#include "clang/AST/Stmt.h"
17#include "clang/AST/Type.h"
Dani Ferreira Franco Mouraa90de3d2022-11-28 12:44:16 -080018#include "clang/AST/TypeVisitor.h"
Wei Yi Tee543af742022-06-01 06:52:24 -070019#include "clang/ASTMatchers/ASTMatchFinder.h"
Wei Yi Tee217eb5f2022-09-15 03:18:28 -070020#include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h"
Wei Yi Tee543af742022-06-01 06:52:24 -070021#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
Wei Yi Tee543af742022-06-01 06:52:24 -070022#include "clang/Analysis/FlowSensitive/Value.h"
23#include "clang/Basic/LLVM.h"
Wei Yi Teef5e8e572022-08-02 11:31:12 -070024#include "clang/Basic/Specifiers.h"
Wei Yi Tee543af742022-06-01 06:52:24 -070025
26namespace clang {
27namespace tidy {
28namespace nullability {
29
30using ast_matchers::MatchFinder;
31using dataflow::BoolValue;
Wei Yi Tee217eb5f2022-09-15 03:18:28 -070032using dataflow::CFGMatchSwitchBuilder;
Wei Yi Tee543af742022-06-01 06:52:24 -070033using dataflow::Environment;
Wei Yi Tee721ee972022-08-11 01:14:54 -070034using dataflow::PointerValue;
Wei Yi Tee543af742022-06-01 06:52:24 -070035using dataflow::SkipPast;
36using dataflow::TransferState;
37using dataflow::Value;
38
39namespace {
40
Dani Ferreira Franco Mouraa90de3d2022-11-28 12:44:16 -080041class GetNullabilityAnnotationsFromTypeVisitor
42 : public TypeVisitor<GetNullabilityAnnotationsFromTypeVisitor> {
43 std::vector<NullabilityKind> NullabilityAnnotations;
44
45 public:
46 std::vector<NullabilityKind> getNullabilityAnnotations() && {
47 return std::move(NullabilityAnnotations);
48 }
49
50 void Visit(QualType T) { TypeVisitor::Visit(T.getTypePtr()); }
51
52 void VisitElaboratedType(const ElaboratedType* ET) {
53 Visit(ET->getNamedType());
54 }
55
56 void VisitTemplateSpecializationType(const TemplateSpecializationType* TST) {
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -080057 for (auto TA : TST->template_arguments()) {
58 if (TA.getKind() == TemplateArgument::Type) {
Dani Ferreira Franco Mouraa90de3d2022-11-28 12:44:16 -080059 Visit(TA.getAsType());
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -080060 }
61 }
Dani Ferreira Franco Mouraa90de3d2022-11-28 12:44:16 -080062 }
63
64 void VisitAttributedType(const AttributedType* AT) {
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -080065 Optional<NullabilityKind> NK = AT->getImmediateNullability();
66 if (NK.has_value()) {
Dani Ferreira Franco Mouraa90de3d2022-11-28 12:44:16 -080067 NullabilityAnnotations.push_back(AT->getImmediateNullability().value());
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -080068 QualType MT = AT->getModifiedType();
69 if (auto PT = MT->getAs<PointerType>()) {
Dani Ferreira Franco Mouraa90de3d2022-11-28 12:44:16 -080070 Visit(PT->getPointeeType());
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -080071 } else {
72 // TODO: Handle this unusual yet possible (e.g. through typedefs)
73 // case.
Dani Ferreira Franco Mouraa90de3d2022-11-28 12:44:16 -080074 llvm::dbgs() << "\nThe type " << AT
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -080075 << "contains a nullability annotation that is not "
76 << "succeeded by a pointer type. "
77 << "This occurence is not currently handled.\n";
78 }
79 } else {
Dani Ferreira Franco Mouraa90de3d2022-11-28 12:44:16 -080080 Visit(AT->getModifiedType());
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -080081 }
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -080082 }
Dani Ferreira Franco Mouraa90de3d2022-11-28 12:44:16 -080083
84 void VisitPointerType(const PointerType* PT) {
85 NullabilityAnnotations.push_back(NullabilityKind::Unspecified);
86 Visit(PT->getPointeeType());
87 }
88};
Dani Ferreira Franco Moura309f2d72022-11-15 07:09:00 -080089
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -080090/// Traverse over a type to get its nullability. For example, if T is the type
91/// Struct3Arg<int * _Nonnull, int, pair<int * _Nullable, int *>> * _Nonnull,
92/// the resulting nullability annotations will be {_Nonnull, _Nonnull,
93/// _Nullable, _Unknown}. Note that non-pointer elements (e.g., the second
94/// argument of Struct3Arg) do not get a nullability annotation.
95std::vector<NullabilityKind> getNullabilityAnnotationsFromType(QualType T) {
Dani Ferreira Franco Mouraa90de3d2022-11-28 12:44:16 -080096 GetNullabilityAnnotationsFromTypeVisitor AnnotationVisitor;
97 AnnotationVisitor.Visit(T);
98 return std::move(AnnotationVisitor).getNullabilityAnnotations();
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -080099}
Dani Ferreira Franco Moura309f2d72022-11-15 07:09:00 -0800100
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800101class CountPointersInTypeVisitor
102 : public TypeVisitor<CountPointersInTypeVisitor> {
103 unsigned count = 0;
104
105 public:
106 CountPointersInTypeVisitor() {}
107
108 unsigned getCount() { return count; }
109
Googler9ceb4982023-01-17 06:01:35 -0800110 void Visit(QualType T) {
111 CHECK(T.isCanonical());
112 TypeVisitor::Visit(T.getTypePtrOrNull());
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800113 }
114
115 void VisitPointerType(const PointerType* PT) {
116 count += 1;
117 Visit(PT->getPointeeType());
118 }
119
120 void Visit(TemplateArgument TA) {
121 if (TA.getKind() == TemplateArgument::Type) {
122 Visit(TA.getAsType());
123 }
124 }
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800125
126 void VisitRecordType(const RecordType* RT) {
127 if (auto* CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl())) {
128 for (auto& TA : CTSD->getTemplateArgs().asArray()) {
129 Visit(TA);
130 }
131 }
132 }
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800133};
134
135unsigned countPointersInType(QualType T) {
136 CountPointersInTypeVisitor PointerCountVisitor;
Googler9ceb4982023-01-17 06:01:35 -0800137 PointerCountVisitor.Visit(T.getCanonicalType());
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800138 return PointerCountVisitor.getCount();
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -0800139}
140
141unsigned countPointersInType(TemplateArgument TA) {
142 if (TA.getKind() == TemplateArgument::Type) {
Googler9ceb4982023-01-17 06:01:35 -0800143 return countPointersInType(TA.getAsType().getCanonicalType());
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -0800144 }
145 return 0;
146}
147
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800148class SubstituteNullabilityAnnotationsInTemplateVisitor
149 : public TypeVisitor<SubstituteNullabilityAnnotationsInTemplateVisitor> {
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800150 std::vector<NullabilityKind> NullabilityAnnotations;
Dani Ferreira Franco Mouraa29a2a02023-01-17 10:57:45 -0800151 std::function<std::vector<NullabilityKind>(
152 const SubstTemplateTypeParmType* ST)>
153 GetSubstitutedNullability;
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800154
155 public:
Dani Ferreira Franco Mouraa29a2a02023-01-17 10:57:45 -0800156 explicit SubstituteNullabilityAnnotationsInTemplateVisitor(
157 std::function<
158 std::vector<NullabilityKind>(const SubstTemplateTypeParmType* ST)>
159 GetSubstitutedNullability)
160 : GetSubstitutedNullability(std::move(GetSubstitutedNullability)) {}
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800161
162 std::vector<NullabilityKind> getNullabilityAnnotations() && {
163 return std::move(NullabilityAnnotations);
164 }
165
166 void Visit(QualType T) { TypeVisitor::Visit(T.getTypePtr()); }
167
Dani Ferreira Franco Moura826c8b32023-01-04 07:24:10 -0800168 void VisitFunctionProtoType(const FunctionProtoType* FPT) {
169 Visit(FPT->getReturnType());
170 // TODO: Visit arguments.
171 }
172
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800173 void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType* ST) {
Dani Ferreira Franco Mouraa29a2a02023-01-17 10:57:45 -0800174 for (auto NK : GetSubstitutedNullability(ST)) {
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800175 NullabilityAnnotations.push_back(NK);
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -0800176 }
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800177 }
178
179 void VisitPointerType(const PointerType* PT) {
180 NullabilityAnnotations.push_back(NullabilityKind::Unspecified);
181 Visit(PT->getPointeeType());
182 }
183
184 void VisitElaboratedType(const ElaboratedType* ET) {
185 Visit(ET->getNamedType());
186 }
187
188 void VisitTemplateSpecializationType(const TemplateSpecializationType* TST) {
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -0800189 for (auto TA : TST->template_arguments()) {
190 if (TA.getKind() == TemplateArgument::Type) {
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800191 Visit(TA.getAsType());
Dani Ferreira Franco Moura309f2d72022-11-15 07:09:00 -0800192 }
193 }
194 }
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800195};
Dani Ferreira Franco Moura309f2d72022-11-15 07:09:00 -0800196
Dani Ferreira Franco Moura82c17582023-01-17 10:58:53 -0800197/// Compute the nullability annotation of type `T`, which contains types
198/// originally written as a class template type parameter.
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -0800199///
Dani Ferreira Franco Moura82c17582023-01-17 10:58:53 -0800200/// Example:
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -0800201///
Dani Ferreira Franco Moura82c17582023-01-17 10:58:53 -0800202/// \code
203/// template <typename F, typename S>
204/// struct pair {
205/// S *_Nullable getNullablePtrToSecond();
206/// };
207/// \endcode
208///
209/// Consider the following member call:
210///
211/// \code
212/// pair<int *, int *_Nonnull> x;
213/// x.getNullablePtrToSecond();
214/// \endcode
215///
216/// The class template specialization `x` has the following substitutions:
217///
218/// F=int *, whose nullability is [_Unspecified]
219/// S=int * _Nonnull, whose nullability is [_Nonnull]
220///
221/// The return type of the member call `x.getNullablePtrToSecond()` is
222/// S * _Nullable.
223///
224/// When we call `substituteNullabilityAnnotationsInClassTemplate` with the type
225/// `S * _Nullable` and the `base` node of the member call (in this case, a
226/// `DeclRefExpr`), it returns the nullability of the given type after applying
227/// substitutions, which in this case is [_Nullable, _Nonnull].
Dani Ferreira Franco Mouraa29a2a02023-01-17 10:57:45 -0800228std::vector<NullabilityKind> substituteNullabilityAnnotationsInClassTemplate(
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -0800229 QualType T, ArrayRef<NullabilityKind> BaseNullabilityAnnotations,
230 QualType BaseType) {
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800231 SubstituteNullabilityAnnotationsInTemplateVisitor AnnotationVisitor(
Dani Ferreira Franco Mouraa29a2a02023-01-17 10:57:45 -0800232 [&](const SubstTemplateTypeParmType* ST) {
Dani Ferreira Franco Moura82c17582023-01-17 10:58:53 -0800233 unsigned PointerCount = 0;
234 unsigned ArgIndex = ST->getIndex();
235 if (auto RT = BaseType->getAs<RecordType>()) {
236 if (auto CTSD =
237 dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl())) {
238 auto TemplateArgs = CTSD->getTemplateArgs().asArray();
239
240 // TODO: Correctly handle the indexing of nested templates (e.g.
241 // PointerNullabilityTest.MemberFunctionTemplateOfTemplateStruct),
242 // then remove this fallback.
243 if (TemplateArgs.size() <= ArgIndex &&
244 ST->getReplacedParameter()->getDepth() == 0) {
245 return std::vector<NullabilityKind>();
246 }
247
248 for (auto TA : TemplateArgs.take_front(ArgIndex)) {
249 PointerCount += countPointersInType(TA);
250 }
251 unsigned SliceSize = countPointersInType(TemplateArgs[ArgIndex]);
252 if (BaseNullabilityAnnotations.size() < PointerCount + SliceSize) {
253 // TODO: Currently, BaseNullabilityAnnotations can be erroneously
254 // empty due to lack of expression coverage. Use the dataflow
255 // lattice to retrieve correct base type annotations. Then, remove
256 // this fallback.
257 return std::vector<NullabilityKind>();
258 } else {
259 return BaseNullabilityAnnotations.slice(PointerCount, SliceSize)
260 .vec();
261 }
262 }
263 }
264 return std::vector<NullabilityKind>();
Dani Ferreira Franco Mouraa29a2a02023-01-17 10:57:45 -0800265 });
266 AnnotationVisitor.Visit(T);
267 return std::move(AnnotationVisitor).getNullabilityAnnotations();
268}
269
Dani Ferreira Franco Moura82c17582023-01-17 10:58:53 -0800270/// Compute nullability annotations of `T`, which might contain template type
Dani Ferreira Franco Mouraa29a2a02023-01-17 10:57:45 -0800271/// variable substitutions bound by the call `CE`.
272///
273/// Example:
274///
275/// \code
276/// template<typename F, typename S>
277/// std::pair<S, F> flip(std::pair<F, S> p);
278/// \endcode
279///
280/// Consider the following CallExpr:
281///
Dani Ferreira Franco Moura82c17582023-01-17 10:58:53 -0800282/// \code
Dani Ferreira Franco Mouraa29a2a02023-01-17 10:57:45 -0800283/// flip<int * _Nonnull, int * _Nullable>(std::make_pair(&x, &y));
Dani Ferreira Franco Moura82c17582023-01-17 10:58:53 -0800284/// \endcode
Dani Ferreira Franco Mouraa29a2a02023-01-17 10:57:45 -0800285///
286/// This CallExpr has the following substitutions:
287/// F=int * _Nonnull, whose nullability is [_Nonnull]
288/// S=int * _Nullable, whose nullability is [_Nullable]
289///
290/// The return type of this CallExpr is `std::pair<S, F>`.
291///
292/// When we call `substituteNullabilityAnnotationsInFunctionTemplate` with the
293/// type `std::pair<S, F>` and the above CallExpr, it returns the nullability
294/// the given type after applying substitutions, which in this case is
295/// [_Nullable, _Nonnull].
296std::vector<NullabilityKind> substituteNullabilityAnnotationsInFunctionTemplate(
297 QualType T, const CallExpr* CE) {
298 SubstituteNullabilityAnnotationsInTemplateVisitor AnnotationVisitor(
299 [&](const SubstTemplateTypeParmType* ST) {
300 // TODO: Handle calls that use template argument deduction.
301 // TODO: Handle nested templates (...->getDepth() > 0).
302 if (auto* DRE =
303 dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreImpCasts());
304 ST->getReplacedParameter()->getDepth() == 0 &&
305 DRE->hasExplicitTemplateArgs()) {
306 return getNullabilityAnnotationsFromType(
307 DRE->template_arguments()[ST->getIndex()]
308 .getTypeSourceInfo()
309 ->getType());
310 }
311 return std::vector<NullabilityKind>();
312 });
Dani Ferreira Franco Moura24739d02022-11-30 05:12:47 -0800313 AnnotationVisitor.Visit(T);
314 return std::move(AnnotationVisitor).getNullabilityAnnotations();
Dani Ferreira Franco Moura7ca32fc2022-11-24 04:19:16 -0800315}
316
Dani Ferreira Franco Moura1d41c112022-12-21 08:43:32 -0800317NullabilityKind getPointerNullability(const Expr* E,
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800318 PointerNullabilityAnalysis::Lattice& L) {
Dani Ferreira Franco Moura309f2d72022-11-15 07:09:00 -0800319 QualType ExprType = E->getType();
Dani Ferreira Franco Moura1d41c112022-12-21 08:43:32 -0800320 Optional<NullabilityKind> Nullability = ExprType->getNullability();
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800321
322 // If the expression's type does not contain nullability information, it may
323 // be a template instantiation. Look up the nullability in the
324 // `ExprToNullability` map.
325 if (Nullability.value_or(NullabilityKind::Unspecified) ==
326 NullabilityKind::Unspecified) {
327 if (auto MaybeNullability = L.getExprNullability(E)) {
328 if (!MaybeNullability->empty()) {
329 // Return the nullability of the topmost pointer in the type.
330 Nullability = (*MaybeNullability)[0];
331 }
332 }
333 }
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800334 return Nullability.value_or(NullabilityKind::Unspecified);
Dani Ferreira Franco Moura309f2d72022-11-15 07:09:00 -0800335}
336
Dani Ferreira Franco Moura1d41c112022-12-21 08:43:32 -0800337void initPointerFromAnnotations(
338 PointerValue& PointerVal, const Expr* E,
339 TransferState<PointerNullabilityLattice>& State) {
340 NullabilityKind Nullability = getPointerNullability(E, State.Lattice);
Wei Yi Teef5e8e572022-08-02 11:31:12 -0700341 switch (Nullability) {
342 case NullabilityKind::NonNull:
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800343 initNotNullPointer(PointerVal, State.Env);
Wei Yi Teef5e8e572022-08-02 11:31:12 -0700344 break;
Wei Yi Teeae43f392022-08-02 11:33:23 -0700345 case NullabilityKind::Nullable:
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800346 initNullablePointer(PointerVal, State.Env);
Wei Yi Teeae43f392022-08-02 11:33:23 -0700347 break;
348 default:
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800349 initUnknownPointer(PointerVal, State.Env);
Wei Yi Tee8374c8f2022-08-11 01:18:41 -0700350 }
351}
352
Dani Ferreira Franco Moura5d2aff42023-01-03 03:42:01 -0800353void transferFlowSensitiveNullPointer(
354 const Expr* NullPointer, const MatchFinder::MatchResult&,
355 TransferState<PointerNullabilityLattice>& State) {
Wei Yi Tee8374c8f2022-08-11 01:18:41 -0700356 if (auto* PointerVal = getPointerValueFromExpr(NullPointer, State.Env)) {
357 initNullPointer(*PointerVal, State.Env);
358 }
359}
360
Dani Ferreira Franco Moura5d2aff42023-01-03 03:42:01 -0800361void transferFlowSensitiveNotNullPointer(
362 const Expr* NotNullPointer, const MatchFinder::MatchResult&,
363 TransferState<PointerNullabilityLattice>& State) {
Wei Yi Tee8374c8f2022-08-11 01:18:41 -0700364 if (auto* PointerVal = getPointerValueFromExpr(NotNullPointer, State.Env)) {
365 initNotNullPointer(*PointerVal, State.Env);
366 }
367}
368
Dani Ferreira Franco Moura5d2aff42023-01-03 03:42:01 -0800369void transferFlowSensitivePointer(
370 const Expr* PointerExpr, const MatchFinder::MatchResult& Result,
371 TransferState<PointerNullabilityLattice>& State) {
Wei Yi Tee8374c8f2022-08-11 01:18:41 -0700372 if (auto* PointerVal = getPointerValueFromExpr(PointerExpr, State.Env)) {
Dani Ferreira Franco Moura1d41c112022-12-21 08:43:32 -0800373 initPointerFromAnnotations(*PointerVal, PointerExpr, State);
Wei Yi Teef5e8e572022-08-02 11:31:12 -0700374 }
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700375}
376
Wei Yi Tee8b58e192022-08-02 10:15:40 -0700377// TODO(b/233582219): Implement promotion of nullability knownness for initially
378// unknown pointers when there is evidence that it is nullable, for example
379// when the pointer is compared to nullptr, or casted to boolean.
Dani Ferreira Franco Moura5d2aff42023-01-03 03:42:01 -0800380void transferFlowSensitiveNullCheckComparison(
Dani Ferreira Franco Moura3d56a222022-11-29 03:12:55 -0800381 const BinaryOperator* BinaryOp, const MatchFinder::MatchResult& result,
382 TransferState<PointerNullabilityLattice>& State) {
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700383 // Boolean representing the comparison between the two pointer values,
Dani Ferreira Franco Moura309f2d72022-11-15 07:09:00 -0800384 // automatically created by the dataflow framework.
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700385 auto& PointerComparison =
386 *cast<BoolValue>(State.Env.getValue(*BinaryOp, SkipPast::None));
Wei Yi Tee543af742022-06-01 06:52:24 -0700387
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700388 CHECK(BinaryOp->getOpcode() == BO_EQ || BinaryOp->getOpcode() == BO_NE);
389 auto& PointerEQ = BinaryOp->getOpcode() == BO_EQ
390 ? PointerComparison
391 : State.Env.makeNot(PointerComparison);
392 auto& PointerNE = BinaryOp->getOpcode() == BO_EQ
393 ? State.Env.makeNot(PointerComparison)
394 : PointerComparison;
395
Wei Yi Tee8374c8f2022-08-11 01:18:41 -0700396 auto* LHS = getPointerValueFromExpr(BinaryOp->getLHS(), State.Env);
397 auto* RHS = getPointerValueFromExpr(BinaryOp->getRHS(), State.Env);
398
399 if (!LHS || !RHS) return;
400
Dani Ferreira Franco Mouraa0649822022-11-11 07:55:05 -0800401 auto [LHSKnown, LHSNull] = getPointerNullState(*LHS, State.Env);
402 auto [RHSKnown, RHSNull] = getPointerNullState(*RHS, State.Env);
403 auto& LHSKnownNotNull =
404 State.Env.makeAnd(LHSKnown, State.Env.makeNot(LHSNull));
405 auto& RHSKnownNotNull =
406 State.Env.makeAnd(RHSKnown, State.Env.makeNot(RHSNull));
407 auto& LHSKnownNull = State.Env.makeAnd(LHSKnown, LHSNull);
408 auto& RHSKnownNull = State.Env.makeAnd(RHSKnown, RHSNull);
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700409
Wei Yi Tee06f06962022-08-02 09:49:50 -0700410 // nullptr == nullptr
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700411 State.Env.addToFlowCondition(State.Env.makeImplication(
Wei Yi Tee06f06962022-08-02 09:49:50 -0700412 State.Env.makeAnd(LHSKnownNull, RHSKnownNull), PointerEQ));
413 // nullptr != notnull
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700414 State.Env.addToFlowCondition(State.Env.makeImplication(
Wei Yi Tee06f06962022-08-02 09:49:50 -0700415 State.Env.makeAnd(LHSKnownNull, RHSKnownNotNull), PointerNE));
416 // notnull != nullptr
Wei Yi Tee1cd62af2022-06-09 00:56:46 -0700417 State.Env.addToFlowCondition(State.Env.makeImplication(
Wei Yi Tee06f06962022-08-02 09:49:50 -0700418 State.Env.makeAnd(LHSKnownNotNull, RHSKnownNull), PointerNE));
Wei Yi Tee543af742022-06-01 06:52:24 -0700419}
420
Dani Ferreira Franco Moura5d2aff42023-01-03 03:42:01 -0800421void transferFlowSensitiveNullCheckImplicitCastPtrToBool(
Dani Ferreira Franco Moura3d56a222022-11-29 03:12:55 -0800422 const Expr* CastExpr, const MatchFinder::MatchResult&,
423 TransferState<PointerNullabilityLattice>& State) {
Wei Yi Tee8374c8f2022-08-11 01:18:41 -0700424 auto* PointerVal =
425 getPointerValueFromExpr(CastExpr->IgnoreImplicit(), State.Env);
426 if (!PointerVal) return;
427
Dani Ferreira Franco Mouraa0649822022-11-11 07:55:05 -0800428 auto [PointerKnown, PointerNull] =
Wei Yi Tee8374c8f2022-08-11 01:18:41 -0700429 getPointerNullState(*PointerVal, State.Env);
Wei Yi Teec46666a2022-08-02 09:38:40 -0700430 auto& CastExprLoc = State.Env.createStorageLocation(*CastExpr);
Dani Ferreira Franco Mouraa0649822022-11-11 07:55:05 -0800431 State.Env.setValue(CastExprLoc, State.Env.makeNot(PointerNull));
Wei Yi Teec46666a2022-08-02 09:38:40 -0700432 State.Env.setStorageLocation(*CastExpr, CastExprLoc);
Wei Yi Tee543af742022-06-01 06:52:24 -0700433}
434
Dani Ferreira Franco Moura5d2aff42023-01-03 03:42:01 -0800435void transferFlowSensitiveCallExpr(
436 const CallExpr* CallExpr, const MatchFinder::MatchResult& Result,
437 TransferState<PointerNullabilityLattice>& State) {
Wei Yi Teec1e1d862022-08-19 14:11:28 -0700438 auto ReturnType = CallExpr->getType();
439 if (!ReturnType->isAnyPointerType()) return;
440
441 auto* PointerVal = getPointerValueFromExpr(CallExpr, State.Env);
442 if (!PointerVal) {
443 PointerVal = cast<PointerValue>(State.Env.createValue(ReturnType));
444 auto& CallExprLoc = State.Env.createStorageLocation(*CallExpr);
445 State.Env.setValue(CallExprLoc, *PointerVal);
446 State.Env.setStorageLocation(*CallExpr, CallExprLoc);
447 }
Dani Ferreira Franco Moura1d41c112022-12-21 08:43:32 -0800448 initPointerFromAnnotations(*PointerVal, CallExpr, State);
Wei Yi Teec1e1d862022-08-19 14:11:28 -0700449}
450
Dani Ferreira Franco Moura5d2aff42023-01-03 03:42:01 -0800451void transferNonFlowSensitiveDeclRefExpr(
452 const DeclRefExpr* DRE, const MatchFinder::MatchResult& MR,
453 TransferState<PointerNullabilityLattice>& State) {
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800454 State.Lattice.insertExprNullabilityIfAbsent(
455 DRE, [&]() { return getNullabilityAnnotationsFromType(DRE->getType()); });
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800456}
457
Dani Ferreira Franco Moura5d2aff42023-01-03 03:42:01 -0800458void transferNonFlowSensitiveMemberExpr(
459 const MemberExpr* ME, const MatchFinder::MatchResult& MR,
460 TransferState<PointerNullabilityLattice>& State) {
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800461 State.Lattice.insertExprNullabilityIfAbsent(ME, [&]() {
462 auto BaseNullability = State.Lattice.getExprNullability(ME->getBase());
463 if (BaseNullability.has_value()) {
Dani Ferreira Franco Moura826c8b32023-01-04 07:24:10 -0800464 QualType MemberType = ME->getType();
465 // When a MemberExpr is a part of a member function call
466 // (a child of CXXMemberCallExpr), the MemberExpr models a
467 // partially-applied member function, which isn't a real C++ construct.
468 // The AST does not provide rich type information for such MemberExprs.
469 // Instead, the AST specifies a placeholder type, specifically
470 // BuiltinType::BoundMember. So we have to look at the type of the member
471 // function declaration.
472 if (ME->hasPlaceholderType(BuiltinType::BoundMember)) {
473 MemberType = ME->getMemberDecl()->getType();
474 }
Dani Ferreira Franco Mouraa29a2a02023-01-17 10:57:45 -0800475 return substituteNullabilityAnnotationsInClassTemplate(
Dani Ferreira Franco Moura826c8b32023-01-04 07:24:10 -0800476 MemberType, *BaseNullability, ME->getBase()->getType());
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800477 } else {
478 // Since we process child nodes before parents, we should already have
479 // computed the base (child) nullability. However, this is not true in all
480 // test cases. So, we return unspecified nullability annotations.
Dani Ferreira Franco Moura826c8b32023-01-04 07:24:10 -0800481 // TODO: Fix this issue, add a CHECK(BaseNullability.has_value()) and
482 // remove the else branch.
483 llvm::dbgs() << "Nullability of child node not found\n";
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800484 return std::vector<NullabilityKind>(countPointersInType(ME->getType()),
485 NullabilityKind::Unspecified);
486 }
487 });
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800488}
489
Dani Ferreira Franco Moura826c8b32023-01-04 07:24:10 -0800490void transferNonFlowSensitiveMemberCallExpr(
491 const CXXMemberCallExpr* MCE, const MatchFinder::MatchResult& MR,
492 TransferState<PointerNullabilityLattice>& State) {
493 State.Lattice.insertExprNullabilityIfAbsent(MCE, [&]() {
494 auto BaseNullability = State.Lattice.getExprNullability(MCE->getCallee());
495 if (BaseNullability.has_value()) {
496 return BaseNullability->vec();
497 } else {
498 // Since we process child nodes before parents, we should already have
499 // computed the base (child) nullability. However, this is not true in all
500 // test cases. So, we return unspecified nullability annotations.
501 // TODO: Fix this issue, add a CHECK(BaseNullability.has_value()) and
502 // remove the else branch.
503 llvm::dbgs() << "Nullability of child node not found\n";
504 return std::vector<NullabilityKind>(countPointersInType(MCE->getType()),
505 NullabilityKind::Unspecified);
506 }
507 });
508}
509
Dani Ferreira Franco Moura933a69b2023-01-12 11:03:42 -0800510void transferNonFlowSensitiveCastExpr(
511 const CastExpr* CE, const MatchFinder::MatchResult& MR,
512 TransferState<PointerNullabilityLattice>& State) {
513 // TODO: Handle casts where the input and output types can have different
514 // numbers of pointers, and therefore different nullability. For example, a
515 // reinterpret_cast from `int *` to int.
516 State.Lattice.insertExprNullabilityIfAbsent(CE, [&]() {
517 auto BaseNullability = State.Lattice.getExprNullability(CE->getSubExpr());
518 if (BaseNullability.has_value()) {
519 return BaseNullability->vec();
520 } else {
521 // Since we process child nodes before parents, we should already have
522 // computed the base (child) nullability. However, this is not true in all
523 // test cases. So, we return unspecified nullability annotations.
524 // TODO: Fix this issue, add a CHECK(BaseNullability.has_value()) and
525 // remove the else branch.
526 llvm::dbgs() << "Nullability of child node not found\n";
527 return std::vector<NullabilityKind>(countPointersInType(CE->getType()),
528 NullabilityKind::Unspecified);
529 }
530 });
531}
532
Dani Ferreira Franco Mouraaa2211d2023-01-17 09:40:30 -0800533void transferNonFlowSensitiveMaterializeTemporaryExpr(
534 const MaterializeTemporaryExpr* MTE, const MatchFinder::MatchResult& MR,
535 TransferState<PointerNullabilityLattice>& State) {
536 State.Lattice.insertExprNullabilityIfAbsent(MTE, [&]() {
537 auto BaseNullability = State.Lattice.getExprNullability(MTE->getSubExpr());
538 if (BaseNullability.has_value()) {
539 return BaseNullability->vec();
540 } else {
541 // Since we process child nodes before parents, we should already have
542 // computed the base (child) nullability. However, this is not true in all
543 // test cases. So, we return unspecified nullability annotations.
544 // TODO: Fix this issue, add a CHECK(BaseNullability.has_value()) and
545 // remove the else branch.
546 llvm::dbgs() << "Nullability of child node not found\n";
547 return std::vector<NullabilityKind>(countPointersInType(MTE->getType()),
548 NullabilityKind::Unspecified);
549 }
550 });
551}
552
Dani Ferreira Franco Mouraa29a2a02023-01-17 10:57:45 -0800553void transferNonFlowSensitiveCallExpr(
554 const CallExpr* CE, const MatchFinder::MatchResult& MR,
555 TransferState<PointerNullabilityLattice>& State) {
556 // TODO: Check CallExpr arguments in the diagnoser against the nullability of
557 // parameters.
558 State.Lattice.insertExprNullabilityIfAbsent(CE, [&]() {
559 return substituteNullabilityAnnotationsInFunctionTemplate(CE->getType(),
560 CE);
561 });
562}
563
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800564auto buildNonFlowSensitiveTransferer() {
565 return CFGMatchSwitchBuilder<TransferState<PointerNullabilityLattice>>()
566 .CaseOfCFGStmt<DeclRefExpr>(ast_matchers::declRefExpr(),
Dani Ferreira Franco Moura5d2aff42023-01-03 03:42:01 -0800567 transferNonFlowSensitiveDeclRefExpr)
568 .CaseOfCFGStmt<MemberExpr>(ast_matchers::memberExpr(),
569 transferNonFlowSensitiveMemberExpr)
Dani Ferreira Franco Moura826c8b32023-01-04 07:24:10 -0800570 .CaseOfCFGStmt<CXXMemberCallExpr>(ast_matchers::cxxMemberCallExpr(),
571 transferNonFlowSensitiveMemberCallExpr)
Dani Ferreira Franco Moura933a69b2023-01-12 11:03:42 -0800572 .CaseOfCFGStmt<CastExpr>(ast_matchers::castExpr(),
573 transferNonFlowSensitiveCastExpr)
Dani Ferreira Franco Mouraaa2211d2023-01-17 09:40:30 -0800574 .CaseOfCFGStmt<MaterializeTemporaryExpr>(
575 ast_matchers::materializeTemporaryExpr(),
576 transferNonFlowSensitiveMaterializeTemporaryExpr)
Dani Ferreira Franco Mouraa29a2a02023-01-17 10:57:45 -0800577 .CaseOfCFGStmt<CallExpr>(ast_matchers::callExpr(),
578 transferNonFlowSensitiveCallExpr)
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800579 .Build();
580}
581
582auto buildFlowSensitiveTransferer() {
Dani Ferreira Franco Moura3d56a222022-11-29 03:12:55 -0800583 return CFGMatchSwitchBuilder<TransferState<PointerNullabilityLattice>>()
Dani Ferreira Franco Moura309f2d72022-11-15 07:09:00 -0800584 // Handles initialization of the null states of pointers.
Dani Ferreira Franco Moura5d2aff42023-01-03 03:42:01 -0800585 .CaseOfCFGStmt<Expr>(isCXXThisExpr(), transferFlowSensitiveNotNullPointer)
586 .CaseOfCFGStmt<Expr>(isAddrOf(), transferFlowSensitiveNotNullPointer)
587 .CaseOfCFGStmt<Expr>(isNullPointerLiteral(),
588 transferFlowSensitiveNullPointer)
589 .CaseOfCFGStmt<CallExpr>(isCallExpr(), transferFlowSensitiveCallExpr)
590 .CaseOfCFGStmt<Expr>(isPointerExpr(), transferFlowSensitivePointer)
Dani Ferreira Franco Moura309f2d72022-11-15 07:09:00 -0800591 // Handles comparison between 2 pointers.
Wei Yi Tee217eb5f2022-09-15 03:18:28 -0700592 .CaseOfCFGStmt<BinaryOperator>(isPointerCheckBinOp(),
Dani Ferreira Franco Moura5d2aff42023-01-03 03:42:01 -0800593 transferFlowSensitiveNullCheckComparison)
Dani Ferreira Franco Moura309f2d72022-11-15 07:09:00 -0800594 // Handles checking of pointer as boolean.
Wei Yi Tee217eb5f2022-09-15 03:18:28 -0700595 .CaseOfCFGStmt<Expr>(isImplicitCastPointerToBool(),
Dani Ferreira Franco Moura5d2aff42023-01-03 03:42:01 -0800596 transferFlowSensitiveNullCheckImplicitCastPtrToBool)
Wei Yi Tee543af742022-06-01 06:52:24 -0700597 .Build();
598}
599} // namespace
600
601PointerNullabilityAnalysis::PointerNullabilityAnalysis(ASTContext& Context)
Dani Ferreira Franco Moura3d56a222022-11-29 03:12:55 -0800602 : DataflowAnalysis<PointerNullabilityAnalysis, PointerNullabilityLattice>(
603 Context),
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800604 NonFlowSensitiveTransferer(buildNonFlowSensitiveTransferer()),
605 FlowSensitiveTransferer(buildFlowSensitiveTransferer()) {}
Wei Yi Tee543af742022-06-01 06:52:24 -0700606
Wei Yi Tee217eb5f2022-09-15 03:18:28 -0700607void PointerNullabilityAnalysis::transfer(const CFGElement* Elt,
Dani Ferreira Franco Moura3d56a222022-11-29 03:12:55 -0800608 PointerNullabilityLattice& Lattice,
Wei Yi Tee543af742022-06-01 06:52:24 -0700609 Environment& Env) {
Dani Ferreira Franco Moura3d56a222022-11-29 03:12:55 -0800610 TransferState<PointerNullabilityLattice> State(Lattice, Env);
Dani Ferreira Franco Moura97f5c612022-12-17 13:28:24 -0800611 NonFlowSensitiveTransferer(*Elt, getASTContext(), State);
612 FlowSensitiveTransferer(*Elt, getASTContext(), State);
Wei Yi Tee543af742022-06-01 06:52:24 -0700613}
614
Wei Yi Tee721ee972022-08-11 01:14:54 -0700615BoolValue& mergeBoolValues(BoolValue& Bool1, const Environment& Env1,
616 BoolValue& Bool2, const Environment& Env2,
617 Environment& MergedEnv) {
618 if (&Bool1 == &Bool2) {
619 return Bool1;
620 }
621
622 auto& MergedBool = MergedEnv.makeAtomicBoolValue();
623
624 // If `Bool1` and `Bool2` is constrained to the same true / false value,
625 // `MergedBool` can be constrained similarly without needing to consider the
626 // path taken - this simplifies the flow condition tracked in `MergedEnv`.
627 // Otherwise, information about which path was taken is used to associate
628 // `MergedBool` with `Bool1` and `Bool2`.
629 if (Env1.flowConditionImplies(Bool1) && Env2.flowConditionImplies(Bool2)) {
630 MergedEnv.addToFlowCondition(MergedBool);
631 } else if (Env1.flowConditionImplies(Env1.makeNot(Bool1)) &&
632 Env2.flowConditionImplies(Env2.makeNot(Bool2))) {
633 MergedEnv.addToFlowCondition(MergedEnv.makeNot(MergedBool));
634 } else {
635 // TODO(b/233582219): Flow conditions are not necessarily mutually
Dani Ferreira Franco Moura309f2d72022-11-15 07:09:00 -0800636 // exclusive, a fix is in order: https://reviews.llvm.org/D130270. Update
637 // this section when the patch is commited.
Wei Yi Tee721ee972022-08-11 01:14:54 -0700638 auto& FC1 = Env1.getFlowConditionToken();
639 auto& FC2 = Env2.getFlowConditionToken();
640 MergedEnv.addToFlowCondition(MergedEnv.makeOr(
641 MergedEnv.makeAnd(FC1, MergedEnv.makeIff(MergedBool, Bool1)),
642 MergedEnv.makeAnd(FC2, MergedEnv.makeIff(MergedBool, Bool2))));
643 }
644 return MergedBool;
645}
646
Wei Yi Tee543af742022-06-01 06:52:24 -0700647bool PointerNullabilityAnalysis::merge(QualType Type, const Value& Val1,
648 const Environment& Env1,
649 const Value& Val2,
650 const Environment& Env2,
651 Value& MergedVal,
652 Environment& MergedEnv) {
Wei Yi Tee721ee972022-08-11 01:14:54 -0700653 if (!Type->isAnyPointerType()) {
654 return false;
655 }
656
Dani Ferreira Franco Mouraa0649822022-11-11 07:55:05 -0800657 auto [Known1, Null1] = getPointerNullState(cast<PointerValue>(Val1), Env1);
658 auto [Known2, Null2] = getPointerNullState(cast<PointerValue>(Val2), Env2);
Wei Yi Tee721ee972022-08-11 01:14:54 -0700659
660 auto& Known = mergeBoolValues(Known1, Env1, Known2, Env2, MergedEnv);
Dani Ferreira Franco Mouraa0649822022-11-11 07:55:05 -0800661 auto& Null = mergeBoolValues(Null1, Env1, Null2, Env2, MergedEnv);
Wei Yi Tee721ee972022-08-11 01:14:54 -0700662
Dani Ferreira Franco Mouraa0649822022-11-11 07:55:05 -0800663 initPointerNullState(cast<PointerValue>(MergedVal), MergedEnv, &Known, &Null);
Wei Yi Tee721ee972022-08-11 01:14:54 -0700664
665 return true;
Wei Yi Tee543af742022-06-01 06:52:24 -0700666}
667} // namespace nullability
668} // namespace tidy
669} // namespace clang