blob: d210e7fa6b98d60ae26a970eb764a35b341fcea3 [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 Gribenko742c4c32023-07-31 12:32:09 -07007#include <memory>
Googler113194c2023-07-12 11:03:47 -07008#include <optional>
Googlere9210aa2023-07-13 10:55:06 -07009#include <string>
Googler6acdc642023-10-19 08:03:40 -070010#include <string_view>
Googlere9210aa2023-07-13 10:55:06 -070011#include <utility>
Googler113194c2023-07-12 11:03:47 -070012#include <vector>
13
Dmitri Gribenko742c4c32023-07-31 12:32:09 -070014#include "absl/log/check.h"
Googlerf1f793d2023-10-19 07:51:34 -070015#include "nullability/inference/inferable.h"
Googler113194c2023-07-12 11:03:47 -070016#include "nullability/inference/inference.proto.h"
Googlerf1f793d2023-10-19 07:51:34 -070017#include "nullability/inference/slot_fingerprint.h"
Googlere9210aa2023-07-13 10:55:06 -070018#include "nullability/pointer_nullability.h"
Googler113194c2023-07-12 11:03:47 -070019#include "nullability/pointer_nullability_analysis.h"
20#include "nullability/pointer_nullability_lattice.h"
Sam McCallbd1a6e52023-07-14 01:04:11 -070021#include "nullability/type_nullability.h"
Googler113194c2023-07-12 11:03:47 -070022#include "clang/AST/ASTContext.h"
23#include "clang/AST/Decl.h"
24#include "clang/AST/DeclBase.h"
Googlere9210aa2023-07-13 10:55:06 -070025#include "clang/AST/Expr.h"
Googler2e9a7972023-07-24 06:02:13 -070026#include "clang/AST/ExprCXX.h"
Googlere9210aa2023-07-13 10:55:06 -070027#include "clang/AST/OperationKinds.h"
Sam McCall296d0702023-07-14 13:32:57 -070028#include "clang/AST/RecursiveASTVisitor.h"
Googler113194c2023-07-12 11:03:47 -070029#include "clang/AST/Stmt.h"
30#include "clang/AST/Type.h"
31#include "clang/Analysis/CFG.h"
Googlere1504a62023-07-18 14:03:23 -070032#include "clang/Analysis/FlowSensitive/Arena.h"
Googler113194c2023-07-12 11:03:47 -070033#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
34#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
35#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
36#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
Googlere1504a62023-07-18 14:03:23 -070037#include "clang/Analysis/FlowSensitive/Formula.h"
Googlere9210aa2023-07-13 10:55:06 -070038#include "clang/Analysis/FlowSensitive/Value.h"
Googler113194c2023-07-12 11:03:47 -070039#include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
40#include "clang/Basic/LLVM.h"
Googler43114e82023-09-26 10:51:01 -070041#include "clang/Basic/SourceLocation.h"
Sam McCallbd1a6e52023-07-14 01:04:11 -070042#include "clang/Basic/Specifiers.h"
Googler113194c2023-07-12 11:03:47 -070043#include "clang/Index/USRGeneration.h"
Googlerf1f793d2023-10-19 07:51:34 -070044#include "llvm/ADT/DenseSet.h"
Sam McCallebcc1232023-07-14 11:36:44 -070045#include "llvm/ADT/FunctionExtras.h"
46#include "llvm/ADT/STLFunctionalExtras.h"
Googler113194c2023-07-12 11:03:47 -070047#include "llvm/Support/Error.h"
48#include "llvm/Support/raw_ostream.h"
49
50namespace clang::tidy::nullability {
51using ::clang::dataflow::DataflowAnalysisContext;
52using ::clang::dataflow::Environment;
Googlerac9ac802023-10-19 09:09:35 -070053using ::clang::dataflow::Formula;
Googler113194c2023-07-12 11:03:47 -070054
Googler6acdc642023-10-19 08:03:40 -070055std::string_view getOrGenerateUSR(USRCache &Cache, const Decl &Decl) {
56 auto [It, Inserted] = Cache.try_emplace(&Decl);
57 if (Inserted) {
58 llvm::SmallString<128> USR;
59 if (!index::generateUSRForDecl(&Decl, USR)) It->second = USR.str();
60 }
61 return It->second;
62}
63
Sam McCallebcc1232023-07-14 11:36:44 -070064llvm::unique_function<EvidenceEmitter> evidenceEmitter(
Googler6acdc642023-10-19 08:03:40 -070065 llvm::unique_function<void(const Evidence &) const> Emit,
66 nullability::USRCache &USRCache) {
Sam McCallebcc1232023-07-14 11:36:44 -070067 class EvidenceEmitterImpl {
68 public:
69 EvidenceEmitterImpl(
Googler6acdc642023-10-19 08:03:40 -070070 llvm::unique_function<void(const Evidence &) const> Emit,
71 nullability::USRCache &USRCache)
72 : Emit(std::move(Emit)), USRCache(USRCache) {}
Sam McCallebcc1232023-07-14 11:36:44 -070073
Sam McCallcfd2dd12023-07-18 19:35:21 -070074 void operator()(const Decl &Target, Slot S, Evidence::Kind Kind,
75 SourceLocation Loc) const {
Googler66045312023-09-11 12:28:58 -070076 CHECK(isInferenceTarget(Target))
77 << "Evidence emitted for a Target which is not an inference target.";
78
Sam McCallebcc1232023-07-14 11:36:44 -070079 Evidence E;
Sam McCall83bc55c2023-07-17 09:47:17 -070080 E.set_slot(S);
81 E.set_kind(Kind);
Sam McCallebcc1232023-07-14 11:36:44 -070082
Googler6acdc642023-10-19 08:03:40 -070083 std::string_view USR = getOrGenerateUSR(USRCache, Target);
84 if (USR.empty()) return; // Can't emit without a USR
85 E.mutable_symbol()->set_usr(USR);
Sam McCallebcc1232023-07-14 11:36:44 -070086
Sam McCallcfd2dd12023-07-18 19:35:21 -070087 // TODO: make collecting and propagating location information optional?
88 auto &SM =
89 Target.getDeclContext()->getParentASTContext().getSourceManager();
90 // TODO: are macro locations actually useful enough for debugging?
91 // we could leave them out, and make room for non-macro samples.
92 if (Loc = SM.getFileLoc(Loc); Loc.isValid())
93 E.set_location(Loc.printToString(SM));
94
Sam McCallebcc1232023-07-14 11:36:44 -070095 Emit(E);
96 }
97
98 private:
Sam McCallebcc1232023-07-14 11:36:44 -070099 llvm::unique_function<void(const Evidence &) const> Emit;
Googler6acdc642023-10-19 08:03:40 -0700100 nullability::USRCache &USRCache;
Sam McCallebcc1232023-07-14 11:36:44 -0700101 };
Googler6acdc642023-10-19 08:03:40 -0700102 return EvidenceEmitterImpl(std::move(Emit), USRCache);
Sam McCallebcc1232023-07-14 11:36:44 -0700103}
104
Googlere9210aa2023-07-13 10:55:06 -0700105namespace {
Googlere1504a62023-07-18 14:03:23 -0700106
Sam McCall5f2bb242023-09-14 07:02:56 -0700107// If Element is a dereference, returns its target and location.
108std::pair<Expr *, SourceLocation> describeDereference(
109 const CFGElement &Element) {
110 if (auto CFGStmt = Element.getAs<clang::CFGStmt>()) {
111 if (auto *Op = dyn_cast<UnaryOperator>(CFGStmt->getStmt());
112 Op && Op->getOpcode() == UO_Deref) {
113 return {Op->getSubExpr(), Op->getOperatorLoc()};
114 }
115 if (auto *ME = dyn_cast<MemberExpr>(CFGStmt->getStmt());
116 ME && ME->isArrow()) {
117 return {ME->getBase(), ME->getOperatorLoc()};
118 }
119 }
120 return {nullptr, SourceLocation()};
121}
122
Googler43114e82023-09-26 10:51:01 -0700123// Records evidence derived from the assumption that Value is nonnull.
124// It may be dereferenced, passed as a nonnull param, etc, per EvidenceKind.
125void collectMustBeNonnullEvidence(
126 const dataflow::PointerValue &Value, const dataflow::Environment &Env,
127 SourceLocation Loc,
Googlerf1f793d2023-10-19 07:51:34 -0700128 std::vector<std::pair<PointerTypeNullability, Slot>> &InferableSlots,
Googler43114e82023-09-26 10:51:01 -0700129 Evidence::Kind EvidenceKind, llvm::function_ref<EvidenceEmitter> Emit) {
130 auto &A = Env.getDataflowAnalysisContext().arena();
131 auto &NotIsNull = A.makeNot(getPointerNullState(Value).IsNull);
132
133 // If the flow conditions already imply that Value is not null, then we don't
134 // have any new evidence of a necessary annotation.
135 if (Env.flowConditionImplies(NotIsNull)) return;
136
Googlerf1f793d2023-10-19 07:51:34 -0700137 // Otherwise, if an inferable slot being annotated Nonnull would imply that
Googler43114e82023-09-26 10:51:01 -0700138 // Value is not null, then we have evidence suggesting that slot should be
139 // annotated. For now, we simply choose the first such slot, sidestepping
140 // complexities around the possibility of multiple such slots, any one of
141 // which would be sufficient if annotated Nonnull.
Googlerf1f793d2023-10-19 07:51:34 -0700142 for (auto &[Nullability, Slot] : InferableSlots) {
Googler43114e82023-09-26 10:51:01 -0700143 auto &SlotNonnullImpliesValueNonnull =
144 A.makeImplies(Nullability.isNonnull(A), NotIsNull);
145 if (Env.flowConditionImplies(SlotNonnullImpliesValueNonnull))
146 Emit(*Env.getCurrentFunc(), Slot, EvidenceKind, Loc);
147 }
148}
149
Sam McCallebcc1232023-07-14 11:36:44 -0700150void collectEvidenceFromDereference(
Googlerf1f793d2023-10-19 07:51:34 -0700151 std::vector<std::pair<PointerTypeNullability, Slot>> &InferableSlots,
Googler3e3ae482023-07-19 08:50:59 -0700152 const CFGElement &Element, const dataflow::Environment &Env,
Sam McCallebcc1232023-07-14 11:36:44 -0700153 llvm::function_ref<EvidenceEmitter> Emit) {
Sam McCall5f2bb242023-09-14 07:02:56 -0700154 auto [Target, Loc] = describeDereference(Element);
155 if (!Target || !Target->getType()->isPointerType()) return;
Googlere9210aa2023-07-13 10:55:06 -0700156
157 // It is a dereference of a pointer. Now gather evidence from it.
Googler66045312023-09-11 12:28:58 -0700158
Sam McCall5f2bb242023-09-14 07:02:56 -0700159 // Skip gathering evidence about the current function if the current
160 // function is not an inference target.
Googler66045312023-09-11 12:28:58 -0700161 if (!isInferenceTarget(*Env.getCurrentFunc())) return;
162
Googlere9210aa2023-07-13 10:55:06 -0700163 dataflow::PointerValue *DereferencedValue =
Sam McCall5f2bb242023-09-14 07:02:56 -0700164 getPointerValueFromExpr(Target, Env);
Sam McCallebcc1232023-07-14 11:36:44 -0700165 if (!DereferencedValue) return;
Googlerf1f793d2023-10-19 07:51:34 -0700166 collectMustBeNonnullEvidence(*DereferencedValue, Env, Loc, InferableSlots,
Googler43114e82023-09-26 10:51:01 -0700167 Evidence::UNCHECKED_DEREFERENCE, Emit);
Googlere9210aa2023-07-13 10:55:06 -0700168}
169
Googlerf1f793d2023-10-19 07:51:34 -0700170// Inferable slots are nullability slots not explicitly annotated in source
171// code that we are currently capable of handling. This returns a boolean
172// constraint representing these slots having a) the nullability inferred from
173// the previous round for this slot or b) Unknown nullability if no inference
174// was made in the previous round or there was no previous round.
Googler31cc2d32023-10-23 15:48:20 -0700175const Formula &getInferableSlotsAsInferredOrUnknownConstraint(
Googlerf1f793d2023-10-19 07:51:34 -0700176 std::vector<std::pair<PointerTypeNullability, Slot>> &InferableSlots,
Googler71919492023-10-23 15:44:06 -0700177 const PreviousInferences &PreviousInferences, USRCache &USRCache,
178 dataflow::Arena &A, const Decl &CurrentFunc) {
179 const Formula *Constraint = &A.makeLiteral(true);
180 std::string_view USR = getOrGenerateUSR(USRCache, CurrentFunc);
Googlerf1f793d2023-10-19 07:51:34 -0700181 for (auto &[Nullability, Slot] : InferableSlots) {
Googlerac9ac802023-10-19 09:09:35 -0700182 SlotFingerprint Fingerprint = fingerprint(USR, Slot);
Googler71919492023-10-23 15:44:06 -0700183 const Formula &Nullable = PreviousInferences.Nullable.contains(Fingerprint)
Googlerac9ac802023-10-19 09:09:35 -0700184 ? Nullability.isNullable(A)
185 : A.makeNot(Nullability.isNullable(A));
Googler71919492023-10-23 15:44:06 -0700186 const Formula &Nonnull = PreviousInferences.Nonnull.contains(Fingerprint)
Googlerac9ac802023-10-19 09:09:35 -0700187 ? Nullability.isNonnull(A)
188 : A.makeNot(Nullability.isNonnull(A));
Googler71919492023-10-23 15:44:06 -0700189 Constraint = &A.makeAnd(*Constraint, A.makeAnd(Nullable, Nonnull));
Googler3e3ae482023-07-19 08:50:59 -0700190 }
Googler31cc2d32023-10-23 15:48:20 -0700191 return *Constraint;
Googler3e3ae482023-07-19 08:50:59 -0700192}
193
Googler43114e82023-09-26 10:51:01 -0700194void collectEvidenceFromParamAnnotation(
195 TypeNullability &ParamNullability, const dataflow::PointerValue &ArgPV,
Googlerf1f793d2023-10-19 07:51:34 -0700196 std::vector<std::pair<PointerTypeNullability, Slot>> &InferableCallerSlots,
Googler43114e82023-09-26 10:51:01 -0700197 const dataflow::Environment &Env, SourceLocation ArgLoc,
198 llvm::function_ref<EvidenceEmitter> Emit) {
199 // TODO: Account for variance and each layer of nullability when we handle
200 // more than top-level pointers.
201 if (ParamNullability.empty()) return;
202 if (ParamNullability[0].concrete() == NullabilityKind::NonNull) {
Googlerf1f793d2023-10-19 07:51:34 -0700203 collectMustBeNonnullEvidence(ArgPV, Env, ArgLoc, InferableCallerSlots,
Googler43114e82023-09-26 10:51:01 -0700204 Evidence::PASSED_TO_NONNULL, Emit);
205 }
206}
207
Googlere1504a62023-07-18 14:03:23 -0700208void collectEvidenceFromCallExpr(
Googlerf1f793d2023-10-19 07:51:34 -0700209 std::vector<std::pair<PointerTypeNullability, Slot>> &InferableCallerSlots,
Googler31cc2d32023-10-23 15:48:20 -0700210 const Formula &InferableSlotsConstraint, const CFGElement &Element,
Googlerac9ac802023-10-19 09:09:35 -0700211 const dataflow::Environment &Env,
Googlere1504a62023-07-18 14:03:23 -0700212 llvm::function_ref<EvidenceEmitter> Emit) {
213 // Is this CFGElement a call to a function?
214 auto CFGStmt = Element.getAs<clang::CFGStmt>();
215 if (!CFGStmt) return;
216 auto *CallExpr = dyn_cast_or_null<clang::CallExpr>(CFGStmt->getStmt());
217 if (!CallExpr || !CallExpr->getCalleeDecl()) return;
218 auto *CalleeDecl =
219 dyn_cast_or_null<clang::FunctionDecl>(CallExpr->getCalleeDecl());
220 if (!CalleeDecl || !isInferenceTarget(*CalleeDecl)) return;
221
Googler2e9a7972023-07-24 06:02:13 -0700222 unsigned ParamI = 0;
223 unsigned ArgI = 0;
224 // Member operator calls hold the function object as the first argument,
225 // offsetting the indices of parameters and corresponding arguments by 1.
226 // For example: Given struct S { bool operator+(int*); }
227 // The CXXMethodDecl has one parameter, but a call S{}+p is a
228 // CXXOperatorCallExpr with two arguments: an S and an int*.
229 if (isa<clang::CXXOperatorCallExpr>(CallExpr) &&
230 isa<clang::CXXMethodDecl>(CalleeDecl))
231 ++ArgI;
232
233 // For each pointer parameter of the callee, ...
234 for (; ParamI < CalleeDecl->param_size(); ++ParamI, ++ArgI) {
Googler43114e82023-09-26 10:51:01 -0700235 auto ParamType =
236 CalleeDecl->getParamDecl(ParamI)->getType().getNonReferenceType();
237 if (!isSupportedPointerType(ParamType)) continue;
Googler2e9a7972023-07-24 06:02:13 -0700238 // the corresponding argument should also be a pointer.
Googler779d3da2023-09-07 10:22:58 -0700239 CHECK(isSupportedPointerType(CallExpr->getArg(ArgI)->getType()));
Googlere1504a62023-07-18 14:03:23 -0700240
Googlere1504a62023-07-18 14:03:23 -0700241 dataflow::PointerValue *PV =
Googler2e9a7972023-07-24 06:02:13 -0700242 getPointerValueFromExpr(CallExpr->getArg(ArgI), Env);
243 if (!PV) continue;
Googlere1504a62023-07-18 14:03:23 -0700244
Googler43114e82023-09-26 10:51:01 -0700245 SourceLocation ArgLoc = CallExpr->getArg(ArgI)->getExprLoc();
246
247 // TODO: Include inferred annotations from previous rounds when propagating.
248 auto ParamNullability = getNullabilityAnnotationsFromType(ParamType);
249
250 // Collect evidence from the binding of the argument to the parameter's
251 // nullability, if known.
Googlerf1f793d2023-10-19 07:51:34 -0700252 collectEvidenceFromParamAnnotation(ParamNullability, *PV,
253 InferableCallerSlots, Env, ArgLoc, Emit);
Googlere1504a62023-07-18 14:03:23 -0700254
Googler2e9a7972023-07-24 06:02:13 -0700255 // Emit evidence of the parameter's nullability. First, calculate that
Googlerf1f793d2023-10-19 07:51:34 -0700256 // nullability based on InferableSlots for the caller being assigned to
Googlere1504a62023-07-18 14:03:23 -0700257 // Unknown, to reflect the current annotations and not all possible
258 // annotations for them.
Googlerf1f793d2023-10-19 07:51:34 -0700259 NullabilityKind ArgNullability =
Googler31cc2d32023-10-23 15:48:20 -0700260 getNullability(*PV, Env, &InferableSlotsConstraint);
Googlere1504a62023-07-18 14:03:23 -0700261 Evidence::Kind ArgEvidenceKind;
262 switch (ArgNullability) {
263 case NullabilityKind::Nullable:
264 ArgEvidenceKind = Evidence::NULLABLE_ARGUMENT;
265 break;
266 case NullabilityKind::NonNull:
267 ArgEvidenceKind = Evidence::NONNULL_ARGUMENT;
268 break;
269 default:
270 ArgEvidenceKind = Evidence::UNKNOWN_ARGUMENT;
271 }
Googler43114e82023-09-26 10:51:01 -0700272 Emit(*CalleeDecl, paramSlot(ParamI), ArgEvidenceKind, ArgLoc);
Googlere1504a62023-07-18 14:03:23 -0700273 }
274}
275
Googler3e3ae482023-07-19 08:50:59 -0700276void collectEvidenceFromReturn(
Googlerf1f793d2023-10-19 07:51:34 -0700277 std::vector<std::pair<PointerTypeNullability, Slot>> &InferableSlots,
Googler31cc2d32023-10-23 15:48:20 -0700278 const Formula &InferableSlotsConstraint, const CFGElement &Element,
Googlerac9ac802023-10-19 09:09:35 -0700279 const dataflow::Environment &Env,
Googler3e3ae482023-07-19 08:50:59 -0700280 llvm::function_ref<EvidenceEmitter> Emit) {
281 // Is this CFGElement a return statement?
282 auto CFGStmt = Element.getAs<clang::CFGStmt>();
283 if (!CFGStmt) return;
284 auto *ReturnStmt = dyn_cast_or_null<clang::ReturnStmt>(CFGStmt->getStmt());
285 if (!ReturnStmt) return;
286 auto *ReturnExpr = ReturnStmt->getRetValue();
Martin Brænne7a8d25c2023-08-23 03:52:30 -0700287 if (!ReturnExpr || !isSupportedPointerType(ReturnExpr->getType())) return;
Googler3e3ae482023-07-19 08:50:59 -0700288
Googler66045312023-09-11 12:28:58 -0700289 // Skip gathering evidence about the current function if the current function
290 // is not an inference target.
291 if (!isInferenceTarget(*Env.getCurrentFunc())) return;
292
Googler3e3ae482023-07-19 08:50:59 -0700293 NullabilityKind ReturnNullability =
Googler31cc2d32023-10-23 15:48:20 -0700294 getNullability(ReturnExpr, Env, &InferableSlotsConstraint);
Googler3e3ae482023-07-19 08:50:59 -0700295 Evidence::Kind ReturnEvidenceKind;
296 switch (ReturnNullability) {
297 case NullabilityKind::Nullable:
298 ReturnEvidenceKind = Evidence::NULLABLE_RETURN;
299 break;
300 case NullabilityKind::NonNull:
301 ReturnEvidenceKind = Evidence::NONNULL_RETURN;
302 break;
303 default:
304 ReturnEvidenceKind = Evidence::UNKNOWN_RETURN;
305 }
306 Emit(*Env.getCurrentFunc(), SLOT_RETURN_TYPE, ReturnEvidenceKind,
307 ReturnExpr->getExprLoc());
308}
309
Sam McCallebcc1232023-07-14 11:36:44 -0700310void collectEvidenceFromElement(
Googlerf1f793d2023-10-19 07:51:34 -0700311 std::vector<std::pair<PointerTypeNullability, Slot>> InferableSlots,
Googler31cc2d32023-10-23 15:48:20 -0700312 const Formula &InferableSlotsConstraint, const CFGElement &Element,
Googler71919492023-10-23 15:44:06 -0700313 const Environment &Env, llvm::function_ref<EvidenceEmitter> Emit) {
Googlerf1f793d2023-10-19 07:51:34 -0700314 collectEvidenceFromDereference(InferableSlots, Element, Env, Emit);
Googler71919492023-10-23 15:44:06 -0700315 collectEvidenceFromCallExpr(InferableSlots, InferableSlotsConstraint, Element,
316 Env, Emit);
317 collectEvidenceFromReturn(InferableSlots, InferableSlotsConstraint, Element,
318 Env, Emit);
Googlere9210aa2023-07-13 10:55:06 -0700319 // TODO: add more heuristic collections here
320}
Sam McCallbd1a6e52023-07-14 01:04:11 -0700321
Sam McCall83bc55c2023-07-17 09:47:17 -0700322std::optional<Evidence::Kind> evidenceKindFromDeclaredType(QualType T) {
Martin Brænne7a8d25c2023-08-23 03:52:30 -0700323 if (!isSupportedPointerType(T.getNonReferenceType())) return std::nullopt;
Sam McCallbd1a6e52023-07-14 01:04:11 -0700324 auto Nullability = getNullabilityAnnotationsFromType(T);
Sam McCalle644e1d2023-07-18 19:19:12 -0700325 switch (Nullability.front().concrete()) {
Sam McCallbd1a6e52023-07-14 01:04:11 -0700326 default:
327 return std::nullopt;
Sam McCall83bc55c2023-07-17 09:47:17 -0700328 case NullabilityKind::NonNull:
329 return Evidence::ANNOTATED_NONNULL;
330 case NullabilityKind::Nullable:
331 return Evidence::ANNOTATED_NULLABLE;
Sam McCallbd1a6e52023-07-14 01:04:11 -0700332 }
333}
Googlere9210aa2023-07-13 10:55:06 -0700334} // namespace
335
Sam McCallebcc1232023-07-14 11:36:44 -0700336llvm::Error collectEvidenceFromImplementation(
Googlerf1f793d2023-10-19 07:51:34 -0700337 const Decl &Decl, llvm::function_ref<EvidenceEmitter> Emit,
Googler71919492023-10-23 15:44:06 -0700338 USRCache &USRCache, const PreviousInferences PreviousInferences) {
Sam McCallebcc1232023-07-14 11:36:44 -0700339 const FunctionDecl *Func = dyn_cast<FunctionDecl>(&Decl);
340 if (!Func || !Func->doesThisDeclarationHaveABody()) {
341 return llvm::createStringError(
342 llvm::inconvertibleErrorCode(),
343 "Implementation must be a function with a body.");
Googler113194c2023-07-12 11:03:47 -0700344 }
Googler113194c2023-07-12 11:03:47 -0700345
Googlere9210aa2023-07-13 10:55:06 -0700346 llvm::Expected<dataflow::ControlFlowContext> ControlFlowContext =
Sam McCallebcc1232023-07-14 11:36:44 -0700347 dataflow::ControlFlowContext::build(*Func);
Googler113194c2023-07-12 11:03:47 -0700348 if (!ControlFlowContext) return ControlFlowContext.takeError();
349
350 DataflowAnalysisContext AnalysisContext(
Sam McCallb23bf3b2023-09-14 09:06:17 -0700351 std::make_unique<dataflow::WatchedLiteralsSolver>(100000));
Sam McCallebcc1232023-07-14 11:36:44 -0700352 Environment Environment(AnalysisContext, *Func);
353 PointerNullabilityAnalysis Analysis(
354 Decl.getDeclContext()->getParentASTContext());
Googlerf1f793d2023-10-19 07:51:34 -0700355 std::vector<std::pair<PointerTypeNullability, Slot>> InferableSlots;
Sam McCallebcc1232023-07-14 11:36:44 -0700356 auto Parameters = Func->parameters();
Sam McCall83bc55c2023-07-17 09:47:17 -0700357 for (auto I = 0; I < Parameters.size(); ++I) {
Googler1cf79e42023-07-17 14:31:35 -0700358 auto T = Parameters[I]->getType().getNonReferenceType();
Martin Brænne7a8d25c2023-08-23 03:52:30 -0700359 if (isSupportedPointerType(T) && !evidenceKindFromDeclaredType(T)) {
Googlerf1f793d2023-10-19 07:51:34 -0700360 InferableSlots.push_back(
Googlere9210aa2023-07-13 10:55:06 -0700361 std::make_pair(Analysis.assignNullabilityVariable(
Sam McCall83bc55c2023-07-17 09:47:17 -0700362 Parameters[I], AnalysisContext.arena()),
363 paramSlot(I)));
Googlere9210aa2023-07-13 10:55:06 -0700364 }
365 }
Googler31cc2d32023-10-23 15:48:20 -0700366 const auto &InferableSlotsConstraint =
Googler71919492023-10-23 15:44:06 -0700367 getInferableSlotsAsInferredOrUnknownConstraint(
368 InferableSlots, PreviousInferences, USRCache, AnalysisContext.arena(),
369 Decl);
Googler113194c2023-07-12 11:03:47 -0700370
Sam McCallb23bf3b2023-09-14 09:06:17 -0700371 return dataflow::runDataflowAnalysis(
372 *ControlFlowContext, Analysis, Environment,
373 [&](const CFGElement &Element,
374 const dataflow::DataflowAnalysisState<
375 PointerNullabilityLattice> &State) {
Googlerac9ac802023-10-19 09:09:35 -0700376 collectEvidenceFromElement(InferableSlots,
Googler71919492023-10-23 15:44:06 -0700377 InferableSlotsConstraint, Element,
378 State.Env, Emit);
Sam McCallb23bf3b2023-09-14 09:06:17 -0700379 })
380 .takeError();
Googler113194c2023-07-12 11:03:47 -0700381}
Sam McCallbd1a6e52023-07-14 01:04:11 -0700382
Sam McCallebcc1232023-07-14 11:36:44 -0700383void collectEvidenceFromTargetDeclaration(
384 const clang::Decl &D, llvm::function_ref<EvidenceEmitter> Emit) {
Sam McCallbd1a6e52023-07-14 01:04:11 -0700385 // For now, we can only describe the nullability of functions.
386 const auto *Fn = dyn_cast<clang::FunctionDecl>(&D);
Sam McCallebcc1232023-07-14 11:36:44 -0700387 if (!Fn) return;
Sam McCallbd1a6e52023-07-14 01:04:11 -0700388
Sam McCall83bc55c2023-07-17 09:47:17 -0700389 if (auto K = evidenceKindFromDeclaredType(Fn->getReturnType()))
Sam McCallcfd2dd12023-07-18 19:35:21 -0700390 Emit(*Fn, SLOT_RETURN_TYPE, *K, Fn->getReturnTypeSourceRange().getBegin());
Sam McCallbd1a6e52023-07-14 01:04:11 -0700391 for (unsigned I = 0; I < Fn->param_size(); ++I) {
Sam McCall83bc55c2023-07-17 09:47:17 -0700392 if (auto K = evidenceKindFromDeclaredType(Fn->getParamDecl(I)->getType()))
Sam McCallcfd2dd12023-07-18 19:35:21 -0700393 Emit(*Fn, paramSlot(I), *K, Fn->getParamDecl(I)->getTypeSpecStartLoc());
Sam McCallbd1a6e52023-07-14 01:04:11 -0700394 }
Sam McCallbd1a6e52023-07-14 01:04:11 -0700395}
396
Sam McCall296d0702023-07-14 13:32:57 -0700397EvidenceSites EvidenceSites::discover(ASTContext &Ctx) {
398 struct Walker : public RecursiveASTVisitor<Walker> {
399 EvidenceSites Out;
400
401 // We do want to see concrete code, including function instantiations.
402 bool shouldVisitTemplateInstantiations() const { return true; }
403
404 bool VisitFunctionDecl(const FunctionDecl *FD) {
405 if (isInferenceTarget(*FD)) Out.Declarations.push_back(FD);
406
407 // Visiting template instantiations is fine, these are valid functions!
408 // But we'll be limited in what we can infer.
409 bool IsUsefulImplementation =
410 FD->doesThisDeclarationHaveABody() &&
411 // We will not get anywhere with dependent code.
412 !FD->isDependentContext();
413 if (IsUsefulImplementation) Out.Implementations.push_back(FD);
414
415 return true;
416 }
417 };
418
419 Walker W;
420 W.TraverseAST(Ctx);
421 return std::move(W.Out);
422}
423
Googler113194c2023-07-12 11:03:47 -0700424} // namespace clang::tidy::nullability