blob: fde9b7481f7c4ab8d2de0752c0c0b933d7e06c71 [file] [log] [blame]
Luca Versari99fddff2022-05-25 10:22:32 -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 "lifetime_analysis/analyze.h"
6
7#include <algorithm>
Dmitri Gribenkoa087d232023-07-10 08:03:46 -07008#include <cassert>
9#include <cstddef>
10#include <cstdint>
Luca Versari99fddff2022-05-25 10:22:32 -070011#include <map>
12#include <memory>
13#include <optional>
14#include <string>
15#include <utility>
16#include <variant>
17#include <vector>
18
19#include "absl/strings/str_cat.h"
20#include "absl/strings/str_format.h"
21#include "absl/strings/str_join.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070022#include "absl/strings/string_view.h"
Luca Versari99fddff2022-05-25 10:22:32 -070023#include "lifetime_analysis/lifetime_analysis.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070024#include "lifetime_analysis/lifetime_constraints.h"
Luca Versari99fddff2022-05-25 10:22:32 -070025#include "lifetime_analysis/lifetime_lattice.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070026#include "lifetime_analysis/object.h"
Luca Versari99fddff2022-05-25 10:22:32 -070027#include "lifetime_analysis/object_repository.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070028#include "lifetime_analysis/object_set.h"
29#include "lifetime_analysis/points_to_map.h"
Luca Versari99fddff2022-05-25 10:22:32 -070030#include "lifetime_analysis/template_placeholder_support.h"
Luca Versari99fddff2022-05-25 10:22:32 -070031#include "lifetime_annotations/function_lifetimes.h"
32#include "lifetime_annotations/lifetime.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070033#include "lifetime_annotations/lifetime_annotations.h"
Luca Versari99fddff2022-05-25 10:22:32 -070034#include "lifetime_annotations/lifetime_substitutions.h"
Luca Versari99fddff2022-05-25 10:22:32 -070035#include "lifetime_annotations/type_lifetimes.h"
36#include "clang/AST/Decl.h"
37#include "clang/AST/DeclCXX.h"
38#include "clang/AST/DeclTemplate.h"
39#include "clang/AST/Expr.h"
40#include "clang/AST/ExprCXX.h"
41#include "clang/AST/Type.h"
42#include "clang/ASTMatchers/ASTMatchFinder.h"
43#include "clang/ASTMatchers/ASTMatchers.h"
44#include "clang/Analysis/CFG.h"
45#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
46#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070047#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
Luca Versari99fddff2022-05-25 10:22:32 -070048#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
49#include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070050#include "clang/Basic/DiagnosticIDs.h"
51#include "clang/Basic/LLVM.h"
52#include "clang/Basic/SourceLocation.h"
Luca Versari99fddff2022-05-25 10:22:32 -070053#include "clang/Index/USRGeneration.h"
54#include "clang/Lex/Lexer.h"
55#include "llvm/ADT/ArrayRef.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070056#include "llvm/ADT/DenseMap.h"
57#include "llvm/ADT/DenseSet.h"
Luca Versari99fddff2022-05-25 10:22:32 -070058#include "llvm/ADT/SmallPtrSet.h"
59#include "llvm/ADT/StringRef.h"
60#include "llvm/Support/Error.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070061#include "llvm/Support/ErrorHandling.h"
62#include "llvm/Support/raw_ostream.h"
Luca Versari99fddff2022-05-25 10:22:32 -070063
64namespace clang {
65namespace tidy {
66namespace lifetimes {
67namespace {
68
69struct VisitedCallStackEntry {
70 const clang::FunctionDecl* func;
71 bool in_cycle;
72 bool in_overrides_traversal;
73};
74
75// A map from base methods to overriding methods.
76using BaseToOverrides =
77 llvm::DenseMap<const clang::CXXMethodDecl*,
78 llvm::SmallPtrSet<const clang::CXXMethodDecl*, 2>>;
79
80// Enforce the invariant that an object of static lifetime should only point at
81// other objects of static lifetime.
Martin Brænneb9a5e0f2022-06-30 02:08:45 -070082llvm::Error PropagateStaticToPointees(LifetimeSubstitutions& subst,
83 const PointsToMap& points_to_map) {
Martin Brænnea5098e12022-07-01 06:22:28 -070084 std::vector<const Object*> pointees =
Luca Versari99fddff2022-05-25 10:22:32 -070085 points_to_map.GetAllPointersWithLifetime(Lifetime::Static());
86
Martin Brænnea5098e12022-07-01 06:22:28 -070087 llvm::DenseSet<const Object*> visited;
Luca Versari99fddff2022-05-25 10:22:32 -070088
89 while (!pointees.empty()) {
Martin Brænnea5098e12022-07-01 06:22:28 -070090 const Object* cur = pointees.back();
Luca Versari99fddff2022-05-25 10:22:32 -070091 pointees.pop_back();
92 visited.insert(cur);
Martin Brænnea5098e12022-07-01 06:22:28 -070093 if (cur->GetLifetime().IsLocal()) {
Martin Brænneb9a5e0f2022-06-30 02:08:45 -070094 return llvm::createStringError(
95 llvm::inconvertibleErrorCode(),
96 "attempted to make a pointer of static lifetime point at an object "
97 "of local lifetime");
98 }
Martin Brænnea5098e12022-07-01 06:22:28 -070099 if (cur->GetLifetime() != Lifetime::Static()) {
100 subst.Add(cur->GetLifetime(), Lifetime::Static());
Luca Versari99fddff2022-05-25 10:22:32 -0700101 }
102
Martin Brænne4d8cdfd2022-07-01 06:16:36 -0700103 for (const Object* pointee : points_to_map.GetPointerPointsToSet(cur)) {
Martin Brænnea5098e12022-07-01 06:22:28 -0700104 if (!visited.count(pointee)) {
105 pointees.push_back(pointee);
Luca Versari99fddff2022-05-25 10:22:32 -0700106 }
107 }
108 }
Martin Brænneb9a5e0f2022-06-30 02:08:45 -0700109
110 return llvm::Error::success();
Luca Versari99fddff2022-05-25 10:22:32 -0700111}
112
113// DO NOT use this function on untrusted input.
114// TODO(veluca): ideally, this function should be replaced with one from a
115// fuzzed library. However, as the way it is used doesn't have significant
116// security implications (its input is trusted, coming from tests, and its
117// output is unused except sometimes to produce a graphviz .dot file), and as
118// the logic for HTML escaping is simple enough, this function is reasonable to
119// use here.
120std::string EscapeHtmlChars(absl::string_view input) {
121 std::string escaped;
122 escaped.reserve(input.size());
123 for (auto c : input) {
124 switch (c) {
125 case '\'':
126 escaped += "&#39;";
127 break;
128 case '"':
129 escaped += "&quot;";
130 break;
131 case '<':
132 escaped += "&lt;";
133 break;
134 case '>':
135 escaped += "&gt;";
136 break;
137 case '&':
138 escaped += "&amp;";
139 break;
140 default:
141 escaped += c;
142 }
143 }
144 return escaped;
145}
146
Martin Brænne57e0bfa2022-07-01 13:27:14 -0700147std::string VariableLabel(absl::string_view name, const Object* object) {
Luca Versari99fddff2022-05-25 10:22:32 -0700148 return absl::StrFormat("<<b>%s</b> (%s)>", EscapeHtmlChars(name),
Martin Brænne57e0bfa2022-07-01 13:27:14 -0700149 EscapeHtmlChars(object->DebugString()));
Luca Versari99fddff2022-05-25 10:22:32 -0700150}
151
152std::string PointsToEdgesDot(const ObjectRepository& object_repository,
153 const PointsToMap& points_to_map,
154 absl::string_view name_prefix) {
155 std::vector<std::string> lines;
Martin Brænnea5098e12022-07-01 06:22:28 -0700156 llvm::DenseSet<const Object*> all_objects, var_objects;
Luca Versari99fddff2022-05-25 10:22:32 -0700157
158 for (auto [pointer, points_to_set] : points_to_map.PointerPointsTos()) {
159 all_objects.insert(pointer);
160 for (auto points_to : points_to_set) {
Martin Brænnea5098e12022-07-01 06:22:28 -0700161 all_objects.insert(points_to);
Luca Versari99fddff2022-05-25 10:22:32 -0700162 lines.push_back(absl::StrFormat(R"("%1$s%2$s" -> "%1$s%3$s")",
Martin Brænnea5098e12022-07-01 06:22:28 -0700163 name_prefix, pointer->DebugString(),
Martin Brænne4d8cdfd2022-07-01 06:16:36 -0700164 points_to->DebugString()));
Luca Versari99fddff2022-05-25 10:22:32 -0700165 }
166 }
167
168 for (auto [key, field_object] : object_repository.GetFieldObjects()) {
169 auto [struct_object, field] = key;
170 lines.push_back(absl::StrFormat(
171 R"("%1$s%2$s" -> "%1$s%3$s" [style=dashed label="%4$s"])", name_prefix,
Martin Brænne1b98ac62022-07-01 06:24:52 -0700172 struct_object->DebugString(), field_object->DebugString(),
Luca Versari99fddff2022-05-25 10:22:32 -0700173 field->getNameAsString()));
174 }
175
176 for (auto [key, base_object] : object_repository.GetBaseObjects()) {
177 auto [struct_object, base] = key;
178 lines.push_back(absl::StrFormat(
179 R"("%1$s%2$s" -> "%1$s%3$s" [style=dashed label="%4$s"])", name_prefix,
Martin Brænne1b98ac62022-07-01 06:24:52 -0700180 struct_object->DebugString(), base_object->DebugString(),
Luca Versari99fddff2022-05-25 10:22:32 -0700181 clang::QualType(base, 0).getAsString()));
182 }
183
184 if (object_repository.GetThisObject().has_value()) {
Martin Brænnea5098e12022-07-01 06:22:28 -0700185 var_objects.insert(*object_repository.GetThisObject());
Luca Versari99fddff2022-05-25 10:22:32 -0700186 lines.push_back(absl::StrFormat(
187 "\"%s%s\"[label=%s]", name_prefix,
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700188 (*object_repository.GetThisObject())->DebugString(),
Martin Brænne57e0bfa2022-07-01 13:27:14 -0700189 VariableLabel("this", *object_repository.GetThisObject())));
Luca Versari99fddff2022-05-25 10:22:32 -0700190 }
191
192 for (auto [decl, object] : object_repository) {
Martin Brænnea5098e12022-07-01 06:22:28 -0700193 var_objects.insert(object);
Martin Brænnee9a4a472022-07-01 02:26:55 -0700194 lines.push_back(absl::StrFormat(
195 "\"%s%s\"[label=%s]", name_prefix, object->DebugString(),
Martin Brænne57e0bfa2022-07-01 13:27:14 -0700196 VariableLabel(decl->getNameAsString(), object)));
Luca Versari99fddff2022-05-25 10:22:32 -0700197 }
198
Martin Brænnea5098e12022-07-01 06:22:28 -0700199 var_objects.insert(object_repository.GetReturnObject());
Luca Versari99fddff2022-05-25 10:22:32 -0700200 lines.push_back(absl::StrFormat(
201 "\"%s%s\"[label=%s]", name_prefix,
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700202 object_repository.GetReturnObject()->DebugString(),
Martin Brænne57e0bfa2022-07-01 13:27:14 -0700203 VariableLabel("return", object_repository.GetReturnObject())));
Luca Versari99fddff2022-05-25 10:22:32 -0700204
Martin Brænnea5098e12022-07-01 06:22:28 -0700205 for (const Object* object : all_objects) {
Luca Versari99fddff2022-05-25 10:22:32 -0700206 if (!var_objects.contains(object)) {
207 lines.push_back(absl::StrFormat(R"("%1$s%2$s"[label="%2$s"])",
Martin Brænnea5098e12022-07-01 06:22:28 -0700208 name_prefix, object->DebugString()));
Luca Versari99fddff2022-05-25 10:22:32 -0700209 }
210 }
211
212 for (auto [_, object] : object_repository.GetFieldObjects()) {
Martin Brænnea5098e12022-07-01 06:22:28 -0700213 if (!var_objects.contains(object)) {
Luca Versari99fddff2022-05-25 10:22:32 -0700214 lines.push_back(absl::StrFormat(R"("%1$s%2$s"[label="%2$s"])",
Martin Brænneb6764af2022-07-01 02:01:49 -0700215 name_prefix, object->DebugString()));
Luca Versari99fddff2022-05-25 10:22:32 -0700216 }
217 }
218
219 for (auto [_, object] : object_repository.GetBaseObjects()) {
Martin Brænnea5098e12022-07-01 06:22:28 -0700220 if (!var_objects.contains(object)) {
Luca Versari99fddff2022-05-25 10:22:32 -0700221 lines.push_back(absl::StrFormat(R"("%1$s%2$s"[label="%2$s"])",
222 name_prefix,
Martin Brænne57e0bfa2022-07-01 13:27:14 -0700223 VariableLabel("this", object)));
Luca Versari99fddff2022-05-25 10:22:32 -0700224 }
225 }
226
227 lines.push_back("");
228
229 return absl::StrJoin(lines, ";\n");
230}
231
232std::string PointsToGraphDot(const ObjectRepository& object_repository,
233 const PointsToMap& points_to_map) {
234 return absl::StrCat("digraph d {\n",
235 PointsToEdgesDot(object_repository, points_to_map, ""),
236 "}");
237}
238
Luca Versarie06f94b2022-09-02 02:44:06 -0700239std::string ConstraintsEdgesDot(const ObjectRepository& object_repository,
240 const LifetimeConstraints& constraints,
241 absl::string_view name_prefix) {
242 std::vector<std::string> lines;
243
244 llvm::DenseSet<Lifetime> all_lifetimes;
245 for (const auto& cstr : constraints.AllConstraints()) {
246 lines.push_back(absl::StrFormat(R"("%1$s%2$d" -> "%1$s%3$d")", name_prefix,
247 cstr.second.Id(), cstr.first.Id()));
248 all_lifetimes.insert(cstr.first);
249 all_lifetimes.insert(cstr.second);
250 }
251
252 for (auto lftm : all_lifetimes) {
253 lines.push_back(absl::StrFormat(R"("%s%d"[label="%s"])", name_prefix,
254 lftm.Id(), lftm.DebugString()));
255 }
256
257 return absl::StrJoin(lines, ";\n");
258}
259
260std::string ConstraintsDot(const ObjectRepository& object_repository,
261 const LifetimeConstraints& constraints) {
262 return absl::StrCat("digraph d {\n",
263 ConstraintsEdgesDot(object_repository, constraints, ""),
264 "}");
265}
266
Luca Versari99fddff2022-05-25 10:22:32 -0700267std::string CfgBlockLabel(const clang::CFGBlock* block, const clang::CFG& cfg,
268 const clang::ASTContext& ast_context) {
269 std::string block_name = absl::StrCat("B", block->getBlockID());
270 if (block == &cfg.getEntry()) {
271 absl::StrAppend(&block_name, " (ENTRY)");
272 } else if (block == &cfg.getExit()) {
273 absl::StrAppend(&block_name, " (EXIT)");
274 }
275
276 std::string label =
277 absl::StrFormat("<tr><td>%s</td></tr>", EscapeHtmlChars(block_name));
278
279 clang::SourceRange range;
280 for (const auto& element : *block) {
281 if (auto cfg_stmt = element.getAs<clang::CFGStmt>()) {
282 clang::SourceRange stmt_range = cfg_stmt->getStmt()->getSourceRange();
283 if (range.isInvalid()) {
284 range = stmt_range;
285 } else {
286 if (stmt_range.getBegin() < range.getBegin()) {
287 range.setBegin(stmt_range.getBegin());
288 }
289 if (stmt_range.getEnd() > range.getEnd()) {
290 range.setEnd(stmt_range.getEnd());
291 }
292 }
293 }
294 }
295
296 if (range.isValid()) {
297 const clang::SourceManager& source_manager = ast_context.getSourceManager();
298 clang::StringRef filename = source_manager.getFilename(range.getBegin());
299 unsigned line_begin =
300 source_manager.getSpellingLineNumber(range.getBegin());
301 unsigned col_begin =
302 source_manager.getSpellingColumnNumber(range.getBegin());
303 unsigned line_end = source_manager.getSpellingLineNumber(range.getEnd());
304 unsigned col_end = source_manager.getSpellingColumnNumber(range.getEnd());
305
306 absl::StrAppendFormat(&label, "<tr><td>%s:%u:%u-%u:%u</td></tr>",
307 EscapeHtmlChars(filename.str()), line_begin,
308 col_begin, line_end, col_end);
309
310 absl::StrAppendFormat(
311 &label, "<tr><td>%s</td></tr>",
312 EscapeHtmlChars(clang::Lexer::getSourceText(
313 clang::CharSourceRange::getTokenRange(range),
314 source_manager, ast_context.getLangOpts())
315 .str()));
316 }
317
318 return absl::StrFormat("<<table border=\"0\">%s</table>>", label);
319}
320
321std::string CreateCfgDot(
322 const clang::CFG& cfg, const clang::ASTContext& ast_context,
Googlerbad70522023-01-31 04:37:38 -0800323 const std::vector<
324 std::optional<clang::dataflow::DataflowAnalysisState<LifetimeLattice>>>&
Luca Versari99fddff2022-05-25 10:22:32 -0700325 block_to_output_state,
326 const ObjectRepository& object_repository) {
327 std::string result = "digraph d {\ncompound=true;\nedge [minlen=2];\n";
328
329 for (const clang::CFGBlock* block : cfg) {
330 unsigned id = block->getBlockID();
331
332 absl::StrAppendFormat(&result, "subgraph cluster%u {\n", id);
333
334 absl::StrAppendFormat(&result, "label=%s;\n",
335 CfgBlockLabel(block, cfg, ast_context));
336
337 absl::StrAppend(&result, "{\nrank=source;\n");
338 absl::StrAppendFormat(
339 &result,
340 "B%usource [style=\"invis\",width=0,height=0,fixedsize=true];\n", id);
341 absl::StrAppend(&result, "}\n");
342 absl::StrAppend(&result, "{\nrank=sink;\n");
343 absl::StrAppendFormat(
344 &result, "B%usink [style=\"invis\",width=0,height=0,fixedsize=true];\n",
345 id);
346 absl::StrAppend(&result, "}\n");
347
Fangrui Song3e1289b2023-06-26 14:52:01 -0700348 const auto& block_state = block_to_output_state[id];
Luca Versari99fddff2022-05-25 10:22:32 -0700349 if (block_state) {
350 auto lattice = block_state->Lattice;
351 if (!lattice.IsError()) {
352 absl::StrAppend(&result,
353 PointsToEdgesDot(object_repository, lattice.PointsTo(),
354 absl::StrCat("B", id, "_")));
Luca Versarie06f94b2022-09-02 02:44:06 -0700355 absl::StrAppend(&result, ConstraintsEdgesDot(
356 object_repository, lattice.Constraints(),
357 absl::StrCat("B", id, "_cstr_")));
Luca Versari99fddff2022-05-25 10:22:32 -0700358 }
359 }
360
361 absl::StrAppend(&result, "}\n");
362 }
363
364 for (const clang::CFGBlock* block : cfg) {
Kinuko Yasuda45fd4be2023-05-03 02:11:57 -0700365 if (!block) continue;
366 for (const auto& succ : block->succs()) {
367 if (!succ.isReachable()) continue;
Luca Versari99fddff2022-05-25 10:22:32 -0700368 absl::StrAppendFormat(
369 &result,
370 "B%1$usink -> B%2$usource [ltail=cluster%1$u,lhead=cluster%2$u];\n",
371 block->getBlockID(), succ->getBlockID());
372 }
373 }
374
375 absl::StrAppend(&result, "}");
376
377 return result;
378}
379
Luca Versari99fddff2022-05-25 10:22:32 -0700380// TODO(veluca): this really ought to happen in the dataflow framework/CFG, but
381// at the moment only the *expressions* in initializers get added, not
382// initialization itself.
Luca Versari1f9fc2e2022-08-17 07:06:00 -0700383void ExtendPointsToMapAndConstraintsWithInitializers(
Luca Versari99fddff2022-05-25 10:22:32 -0700384 const clang::CXXConstructorDecl* constructor,
Luca Versari1f9fc2e2022-08-17 07:06:00 -0700385 const ObjectRepository& object_repository, PointsToMap& points_to_map,
386 LifetimeConstraints& constraints) {
Luca Versari99fddff2022-05-25 10:22:32 -0700387 auto this_object = object_repository.GetThisObject();
388 if (!this_object.has_value()) {
389 assert(false);
390 return;
391 }
392 for (const auto* init : constructor->inits()) {
393 if (!init->isAnyMemberInitializer()) continue;
394 const clang::FieldDecl* field = init->getMember();
395 const auto* init_expr = init->getInit();
396 if (clang::isa<clang::CXXDefaultInitExpr>(init_expr)) {
397 init_expr = field->getInClassInitializer();
398 }
399 if (!IsInitExprInitializingARecordObject(init_expr)) {
400 TransferInitializer(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700401 object_repository.GetFieldObject(this_object.value(), field),
Luca Versariefeaf272023-01-16 10:19:28 -0800402 field->getType(), object_repository, init_expr,
403 TargetPointeeBehavior::kKeep, points_to_map, constraints);
Luca Versari99fddff2022-05-25 10:22:32 -0700404 }
405 }
406}
407
Luca Versari7f2929c2023-01-16 10:15:54 -0800408llvm::Error ConstrainLifetimes(FunctionLifetimes& base,
409 const FunctionLifetimes& constraining) {
410 auto constraints =
411 LifetimeConstraints::ForCallableSubstitution(base, constraining);
412 return constraints.ApplyToFunctionLifetimes(base);
Luca Versari99fddff2022-05-25 10:22:32 -0700413}
414
415struct FunctionAnalysis {
416 ObjectRepository object_repository;
417 PointsToMap points_to_map;
Luca Versari1f9fc2e2022-08-17 07:06:00 -0700418 LifetimeConstraints constraints;
Luca Versari99fddff2022-05-25 10:22:32 -0700419 LifetimeSubstitutions subst;
420};
421
Martin Brænne239a2212022-06-30 07:07:27 -0700422const CXXConstructorDecl* GetDefaultConstructor(const CXXRecordDecl* record) {
423 for (const CXXConstructorDecl* ctor : record->ctors()) {
424 if (ctor->isDefaultConstructor()) {
425 return ctor;
426 }
427 }
428 return nullptr;
429}
430
431llvm::Error TransferDefaultConstructor(
Martin Brænne565b8eb2022-07-01 06:11:06 -0700432 const clang::CXXConstructorDecl* default_ctor, const Object* this_object,
Martin Brænne239a2212022-06-30 07:07:27 -0700433 ObjectRepository& object_repository, PointsToMap& points_to_map,
Luca Versari53a2f582023-01-16 10:09:29 -0800434 LifetimeConstraints& constraints, ObjectSet& single_valued_objects,
Martin Brænne239a2212022-06-30 07:07:27 -0700435 const llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>&
436 callee_lifetimes) {
437 assert(callee_lifetimes.count(default_ctor->getCanonicalDecl()));
438
439 const FunctionLifetimesOrError& ctor_lifetimes_or_error =
440 callee_lifetimes.lookup(default_ctor->getCanonicalDecl());
441 if (!std::holds_alternative<FunctionLifetimes>(ctor_lifetimes_or_error)) {
442 return llvm::createStringError(
443 llvm::inconvertibleErrorCode(),
444 absl::StrCat("No lifetimes for constructor ",
445 default_ctor->getNameAsString()));
446 }
447 const FunctionLifetimes& ctor_lifetimes =
448 std::get<FunctionLifetimes>(ctor_lifetimes_or_error);
449
Luca Versariefeaf272023-01-16 10:19:28 -0800450 // Similar to handling of constructor calls; however, this is simpler because
451 // there is only the "this" argument (as this is the default constructor).
452 // Moreover, since we don't run dataflow, we create the objects on the fly.
453 clang::QualType this_type = default_ctor->getThisType();
454 // "object" for the `this` pointer itself.
Luca Versaria12c9d52023-02-23 08:40:48 -0800455 const Object* placeholder_this_ptr_object = object_repository.CreateObject(
456 ObjectLifetimes(Lifetime::CreateVariable(),
457 ctor_lifetimes.GetThisLifetimes()),
458 points_to_map);
Luca Versariefeaf272023-01-16 10:19:28 -0800459 HandlePointsToSetExtension({placeholder_this_ptr_object}, {this_object},
460 this_type, object_repository, points_to_map,
461 constraints);
Martin Brænne239a2212022-06-30 07:07:27 -0700462 return llvm::Error::success();
463}
464
465llvm::Error AnalyzeDefaultedDefaultConstructor(
466 const clang::CXXConstructorDecl* ctor,
467 const llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>&
468 callee_lifetimes,
Luca Versari187176a2022-09-02 02:42:23 -0700469 ObjectRepository& object_repository, PointsToMap& points_to_map,
Luca Versari53a2f582023-01-16 10:09:29 -0800470 LifetimeConstraints& constraints, ObjectSet& single_valued_objects) {
Martin Brænne239a2212022-06-30 07:07:27 -0700471 assert(ctor->isDefaulted() && ctor->isDefaultConstructor());
472
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700473 std::optional<const Object*> this_object_maybe =
474 object_repository.GetThisObject();
Martin Brænne239a2212022-06-30 07:07:27 -0700475 if (!this_object_maybe.has_value()) {
476 llvm::report_fatal_error("didn't find `this` object for constructor");
477 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700478 const Object* this_object = *this_object_maybe;
Martin Brænne239a2212022-06-30 07:07:27 -0700479
480 const clang::CXXRecordDecl* record = ctor->getParent();
481 for (const CXXBaseSpecifier& base : record->bases()) {
482 if (const clang::CXXRecordDecl* base_record =
483 base.getType()->getAsCXXRecordDecl()) {
484 if (const clang::CXXConstructorDecl* base_ctor =
485 GetDefaultConstructor(base_record)) {
Martin Brænnee08ac882022-07-01 02:24:49 -0700486 const Object* base_this_object =
Martin Brænne1b98ac62022-07-01 06:24:52 -0700487 object_repository.GetBaseClassObject(this_object, base.getType());
Martin Brænne239a2212022-06-30 07:07:27 -0700488 if (llvm::Error err = TransferDefaultConstructor(
Martin Brænne565b8eb2022-07-01 06:11:06 -0700489 base_ctor, base_this_object, object_repository, points_to_map,
Luca Versari53a2f582023-01-16 10:09:29 -0800490 constraints, single_valued_objects, callee_lifetimes)) {
Martin Brænne239a2212022-06-30 07:07:27 -0700491 return err;
492 }
493 }
494 }
495 }
496 for (const clang::FieldDecl* field : record->fields()) {
497 if (const clang::CXXRecordDecl* field_record =
498 field->getType()->getAsCXXRecordDecl()) {
499 if (const clang::CXXConstructorDecl* field_ctor =
500 GetDefaultConstructor(field_record)) {
Martin Brænne46f1a572022-07-01 02:07:07 -0700501 const Object* field_this_object =
Martin Brænne1b98ac62022-07-01 06:24:52 -0700502 object_repository.GetFieldObject(this_object, field);
Martin Brænne239a2212022-06-30 07:07:27 -0700503 if (llvm::Error err = TransferDefaultConstructor(
Martin Brænne565b8eb2022-07-01 06:11:06 -0700504 field_ctor, field_this_object, object_repository, points_to_map,
Luca Versari53a2f582023-01-16 10:09:29 -0800505 constraints, single_valued_objects, callee_lifetimes)) {
Martin Brænne239a2212022-06-30 07:07:27 -0700506 return err;
507 }
508 }
509 }
510 }
511
512 return llvm::Error::success();
513}
514
Martin Brænne7438ce12022-06-30 06:24:24 -0700515llvm::Error AnalyzeDefaultedFunction(
Luca Versari99fddff2022-05-25 10:22:32 -0700516 const clang::FunctionDecl* func,
517 const llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>&
Martin Brænne239a2212022-06-30 07:07:27 -0700518 callee_lifetimes,
Luca Versari187176a2022-09-02 02:42:23 -0700519 ObjectRepository& object_repository, PointsToMap& points_to_map,
Luca Versari53a2f582023-01-16 10:09:29 -0800520 LifetimeConstraints& constraints, ObjectSet& single_valued_objects) {
Luca Versari99fddff2022-05-25 10:22:32 -0700521 assert(func->isDefaulted());
522
523 // TODO(b/230693710): Add complete support for defaulted functions.
524
525 if (const auto* ctor = clang::dyn_cast<clang::CXXConstructorDecl>(func)) {
526 if (ctor->isDefaultConstructor()) {
Luca Versari53a2f582023-01-16 10:09:29 -0800527 return AnalyzeDefaultedDefaultConstructor(
528 ctor, callee_lifetimes, object_repository, points_to_map, constraints,
529 single_valued_objects);
Luca Versari99fddff2022-05-25 10:22:32 -0700530 }
531 }
532
533 return llvm::createStringError(llvm::inconvertibleErrorCode(),
534 "unsupported type of defaulted function");
535}
536
Martin Brænne7438ce12022-06-30 06:24:24 -0700537llvm::Error AnalyzeFunctionBody(
Luca Versari99fddff2022-05-25 10:22:32 -0700538 const clang::FunctionDecl* func,
539 const llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>&
540 callee_lifetimes,
Martin Brænne7438ce12022-06-30 06:24:24 -0700541 const DiagnosticReporter& diag_reporter,
542 ObjectRepository& object_repository, PointsToMap& points_to_map,
Luca Versari1f9fc2e2022-08-17 07:06:00 -0700543 LifetimeConstraints& constraints, std::string* cfg_dot) {
Martin Brænne43b36692023-05-31 02:59:32 -0700544 auto cfctx = clang::dataflow::ControlFlowContext::build(*func);
Luca Versari99fddff2022-05-25 10:22:32 -0700545 if (!cfctx) return cfctx.takeError();
546
547 clang::dataflow::DataflowAnalysisContext analysis_context(
548 std::make_unique<clang::dataflow::WatchedLiteralsSolver>());
549 clang::dataflow::Environment environment(analysis_context);
550
Luca Versari99fddff2022-05-25 10:22:32 -0700551 LifetimeAnalysis analysis(func, object_repository, callee_lifetimes,
552 diag_reporter);
553
554 llvm::Expected<std::vector<
Googlerbad70522023-01-31 04:37:38 -0800555 std::optional<clang::dataflow::DataflowAnalysisState<LifetimeLattice>>>>
Luca Versari99fddff2022-05-25 10:22:32 -0700556 maybe_block_to_output_state =
557 clang::dataflow::runDataflowAnalysis(*cfctx, analysis, environment);
558 if (!maybe_block_to_output_state) {
559 return maybe_block_to_output_state.takeError();
560 }
561 auto& block_to_output_state = *maybe_block_to_output_state;
562
Fangrui Song3e1289b2023-06-26 14:52:01 -0700563 const auto& exit_block_state =
564 block_to_output_state[cfctx->getCFG().getExit().getBlockID()];
Dmitri Gribenko57ddcf92022-07-20 10:24:33 -0700565 if (!exit_block_state.has_value()) {
Luca Versari99fddff2022-05-25 10:22:32 -0700566 assert(false);
567 return llvm::createStringError(
568 llvm::inconvertibleErrorCode(),
569 absl::StrCat("CFG exit block for '", func->getNameAsString(),
570 "' unexpectedly does not exist"));
571 }
572
Dmitri Gribenko57ddcf92022-07-20 10:24:33 -0700573 auto exit_lattice = exit_block_state->Lattice;
Luca Versari99fddff2022-05-25 10:22:32 -0700574 if (exit_lattice.IsError()) {
575 return llvm::createStringError(llvm::inconvertibleErrorCode(),
576 exit_lattice.Error());
577 }
578
Martin Brænne7438ce12022-06-30 06:24:24 -0700579 points_to_map = exit_lattice.PointsTo();
Luca Versari91a56ff2022-08-22 01:58:33 -0700580 constraints = exit_lattice.Constraints();
Luca Versari99fddff2022-05-25 10:22:32 -0700581
582 // Adding initializers to the PointsToMap *before* dataflow analysis is
583 // problematic because the expressions do not have a lifetime yet in the map
584 // itself.
585 // However, member access in a struct does not ever produce lifetimes that
586 // depend on what those members are initialized to - lifetimes of members
587 // (or things that members point to) are either the same as the lifetime of
588 // this, or a lifetime parameter of the struct, so processing initializers
589 // afterwards is correct.
590 if (auto* constructor = clang::dyn_cast<clang::CXXConstructorDecl>(func)) {
Luca Versari1f9fc2e2022-08-17 07:06:00 -0700591 ExtendPointsToMapAndConstraintsWithInitializers(
592 constructor, object_repository, points_to_map, constraints);
Luca Versari99fddff2022-05-25 10:22:32 -0700593 }
594
Luca Versarie04717b2022-09-16 02:05:25 -0700595 // Extend the constraint set with constraints of the form "'a >= 'static" for
596 // every object that is (transitively) reachable from a 'static object.
597 std::vector<const Object*> stack =
598 points_to_map.GetAllPointersWithLifetime(Lifetime::Static());
599 llvm::DenseSet<const Object*> visited;
600 while (!stack.empty()) {
601 const Object* obj = stack.back();
602 stack.pop_back();
603 if (visited.contains(obj)) {
604 continue;
605 }
606 visited.insert(obj);
607 constraints.AddOutlivesConstraint(Lifetime::Static(), obj->GetLifetime());
608 for (auto pointee : points_to_map.GetPointerPointsToSet(obj)) {
609 stack.push_back(pointee);
610 }
611 }
612
Martin Brænne7438ce12022-06-30 06:24:24 -0700613 if (cfg_dot) {
614 *cfg_dot = CreateCfgDot(cfctx->getCFG(), func->getASTContext(),
615 block_to_output_state, object_repository);
616 }
617
618 return llvm::Error::success();
619}
620
621llvm::Expected<FunctionAnalysis> AnalyzeSingleFunction(
622 const clang::FunctionDecl* func,
Luca Versaria12c9d52023-02-23 08:40:48 -0800623 const FunctionLifetimesMap& callee_lifetimes,
Martin Brænne7438ce12022-06-30 06:24:24 -0700624 const DiagnosticReporter& diag_reporter, FunctionDebugInfoMap* debug_info) {
Luca Versaria12c9d52023-02-23 08:40:48 -0800625 llvm::Expected<ObjectRepository> object_repository =
626 ObjectRepository::Create(func, callee_lifetimes);
627 if (auto err = object_repository.takeError()) {
Lukasz Anforowiczb8ac1602023-05-02 08:42:09 -0700628 return std::move(err);
Luca Versaria12c9d52023-02-23 08:40:48 -0800629 }
630 FunctionAnalysis analysis{.object_repository = std::move(*object_repository)};
Martin Brænne7438ce12022-06-30 06:24:24 -0700631
632 const auto* cxxmethod = clang::dyn_cast<clang::CXXMethodDecl>(func);
633 if (cxxmethod && cxxmethod->isPure()) {
634 return analysis;
635 }
636
637 func = func->getDefinition();
638 assert(func != nullptr);
639
Martin Brænne239a2212022-06-30 07:07:27 -0700640 // Unconditionally use our custom logic to analyze defaulted functions, even
641 // if they happen to have a body (because something caused Sema to create a
642 // body for them). We don't want the code path for defaulted functions to
643 // change based on whether a body happened to be created for them, and we
644 // want to make sure we always exercise our logic for defaulted functions in
645 // tests.
646 // TODO(b/230693710): We currently only support analyzing defaulted default
647 // constructors, so for other defaulted functions, we currently fall back to
648 // AnalyzeFunctionBody() (if they do have a body).
649 const auto* ctor = clang::dyn_cast<clang::CXXConstructorDecl>(func);
650 bool can_analyze_defaulted_func =
651 ctor != nullptr && ctor->isDefaultConstructor();
652 if (func->isDefaulted() && can_analyze_defaulted_func) {
Luca Versari53a2f582023-01-16 10:09:29 -0800653 // Single-valued objects are only used during the analysis itself, so no
654 // need to keep track of them past this point.
655 ObjectSet single_valued_objects =
656 analysis.object_repository.InitialSingleValuedObjects();
Luca Versari187176a2022-09-02 02:42:23 -0700657 if (llvm::Error err = AnalyzeDefaultedFunction(
658 func, callee_lifetimes, analysis.object_repository,
Luca Versari53a2f582023-01-16 10:09:29 -0800659 analysis.points_to_map, analysis.constraints,
660 single_valued_objects)) {
Martin Brænne239a2212022-06-30 07:07:27 -0700661 return std::move(err);
662 }
663 } else if (func->getBody()) {
Martin Brænne7438ce12022-06-30 06:24:24 -0700664 std::string* cfg_dot = debug_info ? &(*debug_info)[func].cfg_dot : nullptr;
665 if (llvm::Error err = AnalyzeFunctionBody(
666 func, callee_lifetimes, diag_reporter, analysis.object_repository,
Luca Versari1f9fc2e2022-08-17 07:06:00 -0700667 analysis.points_to_map, analysis.constraints, cfg_dot)) {
Martin Brænne7438ce12022-06-30 06:24:24 -0700668 return std::move(err);
669 }
670 } else {
Martin Brænne239a2212022-06-30 07:07:27 -0700671 return llvm::createStringError(llvm::inconvertibleErrorCode(),
672 "Declaration-only!");
Martin Brænne7438ce12022-06-30 06:24:24 -0700673 }
674
Luca Versari99fddff2022-05-25 10:22:32 -0700675 if (debug_info) {
676 std::string ast;
677 llvm::raw_string_ostream os(ast);
678 func->dump(os);
679 os.flush();
680 (*debug_info)[func].ast = std::move(ast);
Martin Brænne7438ce12022-06-30 06:24:24 -0700681 (*debug_info)[func].object_repository =
682 analysis.object_repository.DebugString();
Luca Versari99fddff2022-05-25 10:22:32 -0700683 (*debug_info)[func].points_to_map_dot =
Martin Brænne7438ce12022-06-30 06:24:24 -0700684 PointsToGraphDot(analysis.object_repository, analysis.points_to_map);
Luca Versarie06f94b2022-09-02 02:44:06 -0700685 (*debug_info)[func].constraints_dot =
686 ConstraintsDot(analysis.object_repository, analysis.constraints);
Luca Versari99fddff2022-05-25 10:22:32 -0700687 }
688
Martin Brænne7438ce12022-06-30 06:24:24 -0700689 if (llvm::Error err =
690 PropagateStaticToPointees(analysis.subst, analysis.points_to_map)) {
Martin Brænneb9a5e0f2022-06-30 02:08:45 -0700691 return std::move(err);
692 }
Luca Versari99fddff2022-05-25 10:22:32 -0700693
Martin Brænne7438ce12022-06-30 06:24:24 -0700694 return analysis;
Luca Versari99fddff2022-05-25 10:22:32 -0700695}
696
697llvm::Error DiagnoseReturnLocal(const clang::FunctionDecl* func,
698 const FunctionLifetimes& lifetimes,
699 const DiagnosticReporter& diag_reporter) {
700 auto contains_local = [](const ValueLifetimes& lifetimes) {
701 return lifetimes.HasAny(&Lifetime::IsLocal);
702 };
703
704 for (unsigned i = 0; i < func->getNumParams(); ++i) {
705 const clang::ParmVarDecl* param = func->getParamDecl(i);
706 if (contains_local(lifetimes.GetParamLifetimes(i))) {
707 std::string error_msg = absl::StrFormat(
708 "function returns reference to a local through parameter '%s'",
709 param->getNameAsString());
710 diag_reporter(param->getBeginLoc(), error_msg,
711 clang::DiagnosticIDs::Error);
712 return llvm::createStringError(llvm::inconvertibleErrorCode(), error_msg);
713 }
714 }
715
716 if (const auto* method = clang::dyn_cast<clang::CXXMethodDecl>(func);
717 method && !method->isStatic() &&
718 contains_local(lifetimes.GetThisLifetimes())) {
719 std::string error_msg =
720 "function returns reference to a local through 'this'";
721 diag_reporter(func->getBeginLoc(), error_msg, clang::DiagnosticIDs::Error);
722 return llvm::createStringError(llvm::inconvertibleErrorCode(), error_msg);
723 }
724
725 if (contains_local(lifetimes.GetReturnLifetimes())) {
726 std::string error_msg = "function returns reference to a local";
727 diag_reporter(func->getBeginLoc(), error_msg, clang::DiagnosticIDs::Error);
728 return llvm::createStringError(llvm::inconvertibleErrorCode(), error_msg);
729 }
730
731 return llvm::Error::success();
732}
733
734// Constructs the FunctionLifetimes for a function, given a PointsToMap,
735// ObjectRepository, and LifetimeSubstitutions that have been built from the
736// function's body, which would include the function's parameters. It's also
737// possible to call this function with an empty inputs in order to generate
738// a FunctionLifetimes that matches the function's signature but without any
Luca Versari1f9fc2e2022-08-17 07:06:00 -0700739// constraints (i.e. each lifetime that appears would be independent).
Luca Versari99fddff2022-05-25 10:22:32 -0700740llvm::Expected<FunctionLifetimes> ConstructFunctionLifetimes(
741 const clang::FunctionDecl* func, FunctionAnalysis analysis,
742 const DiagnosticReporter& diag_reporter) {
743 if (func->getDefinition()) {
744 func = func->getDefinition();
745 } else {
746 // This can happen only when `func` is a pure virtual method.
747 const auto* cxxmethod = clang::dyn_cast<clang::CXXMethodDecl>(func);
748 assert(cxxmethod && cxxmethod->isPure());
749 // Pure virtual member functions can only ever have a single declaration,
750 // so we know we're already looking at the canonical declaration.
751 if (++cxxmethod->redecls_begin() != cxxmethod->redecls_end()) {
752 assert(false);
753 func = func->getCanonicalDecl();
754 }
755 }
756
Luca Versari1f9fc2e2022-08-17 07:06:00 -0700757 auto& [object_repository, points_to_map, constraints, subst] = analysis;
Luca Versari99fddff2022-05-25 10:22:32 -0700758
Luca Versari91a56ff2022-08-22 01:58:33 -0700759 FunctionLifetimes result;
Luca Versari99fddff2022-05-25 10:22:32 -0700760
Luca Versarid1b2e692023-01-18 13:07:25 -0800761 result = object_repository.GetOriginalFunctionLifetimes();
762 if (llvm::Error err = constraints.ApplyToFunctionLifetimes(result)) {
763 return std::move(err);
Luca Versari99fddff2022-05-25 10:22:32 -0700764 }
765
Luca Versari99fddff2022-05-25 10:22:32 -0700766 if (llvm::Error err = DiagnoseReturnLocal(func, result, diag_reporter)) {
767 return std::move(err);
768 }
769
770 return result;
771}
772
773llvm::Expected<llvm::DenseSet<const clang::FunctionDecl*>>
774GetDefaultedFunctionCallees(const clang::FunctionDecl* func) {
775 assert(func->isDefaulted());
776
777 // TODO(b/230693710): Add complete support for defaulted functions.
778
779 if (const auto* ctor = clang::dyn_cast<clang::CXXConstructorDecl>(func)) {
780 if (ctor->isDefaultConstructor()) {
Martin Brænne239a2212022-06-30 07:07:27 -0700781 llvm::DenseSet<const clang::FunctionDecl*> callees;
Luca Versari99fddff2022-05-25 10:22:32 -0700782 const clang::CXXRecordDecl* record = ctor->getParent();
Martin Brænne239a2212022-06-30 07:07:27 -0700783 for (const CXXBaseSpecifier& base : record->bases()) {
784 if (const clang::CXXRecordDecl* base_record =
785 base.getType()->getAsCXXRecordDecl()) {
786 if (const clang::CXXConstructorDecl* base_ctor =
787 GetDefaultConstructor(base_record)) {
788 callees.insert(base_ctor);
789 }
790 }
Luca Versari99fddff2022-05-25 10:22:32 -0700791 }
Martin Brænne239a2212022-06-30 07:07:27 -0700792 for (const clang::FieldDecl* field : record->fields()) {
793 if (const clang::CXXRecordDecl* field_record =
794 field->getType()->getAsCXXRecordDecl()) {
795 if (const clang::CXXConstructorDecl* field_ctor =
796 GetDefaultConstructor(field_record)) {
797 callees.insert(field_ctor);
798 }
799 }
800 }
801 return callees;
Luca Versari99fddff2022-05-25 10:22:32 -0700802 }
803 }
804
805 return llvm::createStringError(llvm::inconvertibleErrorCode(),
806 "unsupported type of defaulted function");
807}
808
809llvm::Expected<llvm::DenseSet<const clang::FunctionDecl*>> GetCallees(
810 const clang::FunctionDecl* func) {
811 using clang::ast_matchers::anyOf;
812 using clang::ast_matchers::cxxConstructExpr;
813 using clang::ast_matchers::declRefExpr;
814 using clang::ast_matchers::expr;
815 using clang::ast_matchers::findAll;
816 using clang::ast_matchers::functionDecl;
817 using clang::ast_matchers::hasDeclaration;
818 using clang::ast_matchers::match;
819 using clang::ast_matchers::memberExpr;
820 using clang::ast_matchers::to;
821
822 func = func->getDefinition();
823
824 if (!func) return llvm::DenseSet<const clang::FunctionDecl*>();
825
826 const clang::Stmt* body = func->getBody();
827 if (!body) {
828 // TODO(b/230693710): Do this unconditionally for defaulted functions, even
829 // if they happen to have a body (because something caused Sema to create a
830 // body for them). We can't do this yet because we don't have full support
831 // for defaulted functions yet, so we would break tests where we happen to
832 // have a body for the defaulted function today.
833 if (func->isDefaulted()) {
834 return GetDefaultedFunctionCallees(func);
835 }
836
837 return llvm::createStringError(llvm::inconvertibleErrorCode(),
838 "Declaration-only!");
839 }
840
841 llvm::SmallVector<const clang::Stmt*> body_parts;
842
843 body_parts.push_back(body);
844
845 if (const auto* constructor =
846 clang::dyn_cast<clang::CXXConstructorDecl>(func)) {
847 for (const auto* init : constructor->inits()) {
848 body_parts.push_back(init->getInit());
849 }
850 }
851
852 llvm::DenseSet<const clang::FunctionDecl*> callees;
853 for (const auto& body_part : body_parts) {
854 for (const auto& node : match(
855 findAll(expr(anyOf(
856 declRefExpr(to(functionDecl().bind("function"))),
857 memberExpr(hasDeclaration(functionDecl().bind("function")))))),
858 *body_part, func->getASTContext())) {
859 const auto* fn = node.getNodeAs<clang::FunctionDecl>("function");
860 callees.insert(fn->getCanonicalDecl());
861 }
862 for (const auto& node :
863 match(findAll(cxxConstructExpr().bind("cxx_construct")), *body_part,
864 func->getASTContext())) {
865 const auto* ctor_exp =
866 node.getNodeAs<clang::CXXConstructExpr>("cxx_construct");
867 if (auto ctor = ctor_exp->getConstructor()) {
868 callees.insert(ctor);
869 }
870 }
871 }
872
873 return std::move(callees);
874}
875
876// Looks for `func` in the `visited_call_stack`. If found it marks `func` and
877// each function that came after it as being part of the cycle. This marking is
878// stored in the `VisitedCallStackEntry`.
879bool FindAndMarkCycleWithFunc(
880 llvm::SmallVectorImpl<VisitedCallStackEntry>& visited_call_stack,
881 const clang::FunctionDecl* func) {
882 // We look for recursive cycles in a simple (but potentially slow for huge
883 // call graphs) way. If we reach a function that is already on the call stack
884 // (i.e. in `visited`), we declare `func`, and every other function after
885 // where `func` was seen in `visited` as being part of a cycle. Then a cycle
886 // graph is a contiguous set of functions in the `visited` call stack that are
887 // marked as being in a cycle.
888 bool found_cycle = false;
889 for (size_t i = visited_call_stack.size(); i > 0; --i) {
890 const auto& stack_entry = visited_call_stack[i - 1];
891 if (stack_entry.func == func) {
892 found_cycle = true;
893 for (; i <= visited_call_stack.size(); ++i) {
894 auto& mut_stack_entry = visited_call_stack[i - 1];
895 mut_stack_entry.in_cycle = true;
896 }
897 break;
898 }
899 }
900 return found_cycle;
901}
902
903llvm::SmallVector<const clang::FunctionDecl*> GetAllFunctionDefinitions(
904 const clang::TranslationUnitDecl* tu) {
905 using clang::ast_matchers::findAll;
906 using clang::ast_matchers::functionDecl;
907 using clang::ast_matchers::hasBody;
908 using clang::ast_matchers::isDefinition;
909 using clang::ast_matchers::match;
910 using clang::ast_matchers::stmt;
911
912 llvm::SmallVector<const clang::FunctionDecl*> functions;
913
914 // For now we specify 'hasBody' to skip functions that don't have a body and
915 // are not called. TODO(veluca): a function might be used in other ways.
916 for (const auto& node : match(
917 findAll(functionDecl(isDefinition(), hasBody(stmt())).bind("func")),
918 tu->getASTContext())) {
919 const auto* func = node.getNodeAs<clang::FunctionDecl>("func");
920 assert(func);
921 functions.push_back(func);
922 }
923
924 return functions;
925}
926
927BaseToOverrides BuildBaseToOverrides(const clang::TranslationUnitDecl* tu) {
928 BaseToOverrides base_to_overrides;
929 for (const clang::FunctionDecl* f : GetAllFunctionDefinitions(tu)) {
930 auto* func = clang::dyn_cast<clang::CXXMethodDecl>(f);
931 if (!func) continue;
932 func = func->getCanonicalDecl();
933 if (!func->isVirtual()) continue;
934 for (const auto* base : func->overridden_methods()) {
935 base_to_overrides[base->getCanonicalDecl()].insert(func);
936 }
937 }
938 return base_to_overrides;
939}
940
941void GetBaseMethods(const clang::CXXMethodDecl* cxxmethod,
942 llvm::DenseSet<const clang::CXXMethodDecl*>& bases) {
943 if (cxxmethod->size_overridden_methods() == 0) {
944 // TODO(kinuko): It is not fully clear if one method may ever have multiple
945 // base methods. If not this can simply return a single CXXMethodDecl rathr
946 // than a set.
947 bases.insert(cxxmethod);
948 return;
949 }
950 for (const auto* base : cxxmethod->overridden_methods()) {
951 // Each method's overridden_methods() only returns an immediate base but not
952 // ancestors of further than that, so recursively call it.
953 GetBaseMethods(base, bases);
954 }
955}
956
957std::optional<FunctionLifetimes> GetFunctionLifetimesFromAnalyzed(
958 const clang::FunctionDecl* canonical_func,
959 const llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>&
960 analyzed) {
961 auto found = analyzed.find(canonical_func);
962 if (found == analyzed.end()) return std::nullopt;
963 auto* lifetimes = std::get_if<FunctionLifetimes>(&found->second);
964 if (!lifetimes) return std::nullopt;
965 return *lifetimes;
966}
967
968// Update the function lifetimes of `func` with its immediate `overrides` so
969// that the lifetimes of the base method will become least permissive. The
970// updates will be reflected from the base to its final overrides as this is
971// recursively called.
Luca Versari7f2929c2023-01-16 10:15:54 -0800972llvm::Error UpdateFunctionLifetimesWithOverrides(
Luca Versari99fddff2022-05-25 10:22:32 -0700973 const clang::FunctionDecl* func,
974 llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>&
975 analyzed,
976 const llvm::SmallPtrSet<const clang::CXXMethodDecl*, 2>& overrides) {
977 const auto* canonical = func->getCanonicalDecl();
978 const auto* method = clang::dyn_cast<clang::CXXMethodDecl>(func);
979 assert(method != nullptr);
980 assert(method->isVirtual());
981 static_cast<void>(method);
982
983 auto opt_lifetimes = GetFunctionLifetimesFromAnalyzed(canonical, analyzed);
Luca Versari7f2929c2023-01-16 10:15:54 -0800984 if (!opt_lifetimes) return llvm::Error::success();
Luca Versari99fddff2022-05-25 10:22:32 -0700985 FunctionLifetimes base_lifetimes = *opt_lifetimes;
986
987 assert(base_lifetimes.IsValidForDecl(func));
988
989 for (const auto* overriding : overrides) {
990 if (overriding->getNumParams() != func->getNumParams()) {
991 llvm::errs() << "Param number mismatches between "
992 << method->getParent()->getNameAsString() << " and "
993 << overriding->getParent()->getNameAsString() << "\n";
994 func->dump();
995 overriding->dump();
Luca Versari7f2929c2023-01-16 10:15:54 -0800996 return llvm::createStringError(
997 llvm::inconvertibleErrorCode(),
998 absl::StrFormat("Param number mismatches between %s and %s\n",
999 method->getParent()->getNameAsString(),
1000 overriding->getParent()->getNameAsString()));
Luca Versari99fddff2022-05-25 10:22:32 -07001001 }
1002 auto opt_override_lifetimes = GetFunctionLifetimesFromAnalyzed(
1003 overriding->getCanonicalDecl(), analyzed);
1004 if (!opt_override_lifetimes) continue;
1005 FunctionLifetimes override_lifetimes = *opt_override_lifetimes;
1006
Luca Versari7f2929c2023-01-16 10:15:54 -08001007 if (llvm::Error err = ConstrainLifetimes(
1008 base_lifetimes, override_lifetimes.ForOverriddenMethod(method))) {
1009 return err;
1010 }
Luca Versari99fddff2022-05-25 10:22:32 -07001011 }
1012 analyzed[canonical] = base_lifetimes;
Luca Versari7f2929c2023-01-16 10:15:54 -08001013 return llvm::Error::success();
Luca Versari99fddff2022-05-25 10:22:32 -07001014}
1015
1016llvm::Error AnalyzeRecursiveFunctions(
Luca Versaria12c9d52023-02-23 08:40:48 -08001017 llvm::ArrayRef<VisitedCallStackEntry> funcs, FunctionLifetimesMap& analyzed,
Luca Versari99fddff2022-05-25 10:22:32 -07001018 const DiagnosticReporter& diag_reporter, FunctionDebugInfoMap* debug_info) {
1019 for (const auto [func, in_cycle, _] : funcs) {
1020 assert(in_cycle);
1021
Luca Versaria12c9d52023-02-23 08:40:48 -08001022 // Construct an initial FunctionLifetimes for each function in the cycle,
Luca Versari99fddff2022-05-25 10:22:32 -07001023 // without doing a dataflow analysis, which would need other functions
1024 // in the cycle to already be analyzed.
Luca Versaria12c9d52023-02-23 08:40:48 -08001025 auto func_lifetimes_result = FunctionLifetimes::CreateForDecl(
1026 func, FunctionLifetimeFactorySingleCallback([](const clang::Expr*) {
1027 return Lifetime::CreateVariable();
1028 }));
Luca Versari99fddff2022-05-25 10:22:32 -07001029 if (!func_lifetimes_result) {
1030 return func_lifetimes_result.takeError();
1031 }
1032 analyzed[func->getCanonicalDecl()] = func_lifetimes_result.get();
1033 }
1034
1035 int64_t expected_iterations = 0;
1036 for (const auto [func, _1, _2] : funcs) {
1037 expected_iterations =
1038 std::max(expected_iterations, int64_t{func->getNumParams()});
1039 }
1040 // Add 1 for the last iteration that sees nothing changed.
1041 expected_iterations += 1;
1042
1043 // Analyze all lifetimes in the cycle repeatedly with dataflow analysis
1044 // until they stabilize.
1045 bool func_lifetimes_changed = true;
1046 for (int64_t count = 0; func_lifetimes_changed; ++count) {
1047 func_lifetimes_changed = false;
1048
1049 if (count > expected_iterations) {
1050 return llvm::createStringError(
1051 llvm::inconvertibleErrorCode(),
1052 absl::StrFormat("Recursive cycle requires more than the expected "
1053 "%u iterations to resolve!",
1054 expected_iterations));
1055 }
1056
1057 for (const auto [func, in_cycle, _] : funcs) {
1058 auto analysis_result =
Martin Brænne7438ce12022-06-30 06:24:24 -07001059 AnalyzeSingleFunction(func, analyzed, diag_reporter, debug_info);
Luca Versari99fddff2022-05-25 10:22:32 -07001060 if (!analysis_result) {
1061 return analysis_result.takeError();
1062 }
1063 auto func_lifetimes_result = ConstructFunctionLifetimes(
1064 func, std::move(analysis_result.get()), diag_reporter);
1065 if (!func_lifetimes_result) {
1066 return func_lifetimes_result.takeError();
1067 }
1068 // TODO(danakj): We can avoid this structural comparison and just do a
1069 // check for equality if AnalyzeSingleFunction would reuse Lifetimes
1070 // from the existing FunctionLifetime for its parameters/return/this.
1071 // Currently it makes a new set of Lifetimes each time we do the analyze
1072 // step, but the actual Lifetime ids aren't meaningful, only where and
1073 // how often a given Lifetime repeats is meaningful.
1074 FunctionLifetimesOrError& existing_result =
1075 analyzed[func->getCanonicalDecl()];
1076 if (std::holds_alternative<FunctionLifetimes>(existing_result) &&
1077 !IsIsomorphic(std::get<FunctionLifetimes>(existing_result),
1078 func_lifetimes_result.get())) {
1079 existing_result = func_lifetimes_result.get();
1080 func_lifetimes_changed = true;
1081 }
1082 }
1083 }
1084
1085 return llvm::Error::success();
1086}
1087
1088// The entry point for analyzing a function named by `func`.
1089//
1090// This function is recursive as it searches for and walks through all CallExpr
1091// instances, calling this function again for each function. This is done to
1092// analyze the leaves of the call graph first, so that when analyzing a given
1093// function, all the functions it calls have already been analyzed.
1094//
1095// This function also handles walking through recursive cycles of function
1096// calls. When a cycle is detected, we:
1097// 1. Do not analyze any of the functions until the cycle is fully explored and
1098// we've returned to the entry point to the cycle.
1099// 2. At that point, we generate a FunctionLifetimes for each function in the
1100// cycle, where the lifetimes are all completely disconnected.
1101// 3. Then we analyze each function in the cycle based on those
1102// FunctionLifetimes, connecting lifetimes within the body of each function.
1103// This changes a given function's resulting FunctionLifetimes, which can
1104// affect the callers to it.
1105// 4. Thus we repeat step 3 until we see that the FunctionLifetimes have stopped
1106// changing when we analyze each function in the cycle.
1107void AnalyzeFunctionRecursive(
1108 llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>&
1109 analyzed,
1110 llvm::SmallVectorImpl<VisitedCallStackEntry>& visited,
1111 const clang::FunctionDecl* func,
1112 const LifetimeAnnotationContext& lifetime_context,
1113 const DiagnosticReporter& diag_reporter, FunctionDebugInfoMap* debug_info,
1114 const BaseToOverrides& base_to_overrides) {
1115 // Make sure we're always using the canonical declaration when using the
1116 // function as a key in maps and sets.
1117 func = func->getCanonicalDecl();
1118
1119 // See if we have finished analyzing the function.
1120 bool is_analyzed = analyzed.count(func) > 0;
1121
1122 auto* cxxmethod = clang::dyn_cast<clang::CXXMethodDecl>(func);
1123 bool is_virtual = cxxmethod != nullptr && cxxmethod->isVirtual();
1124 bool is_pure_virtual = is_virtual && cxxmethod->isPure();
1125
1126 if (func->getBuiltinID() != 0) {
1127 return;
1128 }
1129
1130 if (!func->isDefined() && !is_pure_virtual && !is_analyzed) {
1131 FunctionLifetimes annotations;
1132 if (llvm::Error err = GetLifetimeAnnotations(func, lifetime_context)
1133 .moveInto(annotations)) {
1134 analyzed[func] = FunctionAnalysisError(err);
1135 } else {
1136 analyzed[func] = annotations;
1137 }
1138 return;
1139 }
1140
1141 // Check if we're in an overrides traversal for a virtual method.
1142 bool in_overrides_traversal =
1143 visited.empty() ? false : visited.back().in_overrides_traversal;
1144
1145 if (is_analyzed && !in_overrides_traversal) {
1146 // This function is already analyzed and this analysis is not for an
1147 // overrides traversal (where repeated update may happen).
1148 // TODO(kinuko): Avoid repeatedly visit the same virtual methods again and
1149 // again if all the methods in the same overriding chain are already
1150 // analyzed.
1151 return;
1152 }
1153
1154 if (!in_overrides_traversal && FindAndMarkCycleWithFunc(visited, func)) {
1155 // Defer analyzing the cycle until we have fully explored the recursive
1156 // cycle graph.
1157 // This cycle check should exclude in_overrides_traversal case, because the
1158 // traversal can come back to the same function while traversing from its
1159 // overridden base method, e.g. when we see Child::f() we start the analysis
1160 // from its overridden implementation Base::f() and then recursively look
1161 // into its overrides until it reaches its final overrides (and it should
1162 // see Child::f() on its way.
1163
1164 // TODO(kinuko): We may return here when Base::f() calls f() even when
1165 // it has overrides, and if it happens AnalyzeRecursiveFunctions don't
1166 // look into the overrides so the Base::f() lifetime is not updated.
1167 // See DISABLED_FunctionVirtualInheritanceWithComplexRecursion tests.
1168 return;
1169 }
1170
1171 auto maybe_callees = GetCallees(func);
1172 if (!maybe_callees) {
1173 analyzed[func] = FunctionAnalysisError(maybe_callees.takeError());
1174 return;
1175 }
1176
1177 // Keep track of where `func` is found in the call stack. It may not be at the
1178 // top anymore after we return from calling `AnalyzeFunctionRecursive()` if
1179 // `func` is part of a recursive cycle, as we keep all members of the
1180 // recursive cycle in the `visited` stack until we explore the whole graph and
1181 // then analyze it all.
1182 size_t func_in_visited = visited.size();
1183 visited.emplace_back(VisitedCallStackEntry{
1184 .func = func, .in_cycle = false, .in_overrides_traversal = false});
1185
1186 for (auto& callee : maybe_callees.get()) {
1187 if (analyzed.count(callee)) {
1188 continue;
1189 }
1190 AnalyzeFunctionRecursive(analyzed, visited, callee, lifetime_context,
1191 diag_reporter, debug_info, base_to_overrides);
1192 }
1193
1194 llvm::DenseSet<const clang::CXXMethodDecl*> bases;
1195 llvm::SmallPtrSet<const clang::CXXMethodDecl*, 2> overrides;
1196
1197 // This is a virtual method and we want to recursively analyze the inheritance
1198 // chain and update the base methods with their overrides. The base methods
1199 // may be visited and updated repeatedly.
1200 if (is_virtual) {
1201 assert(cxxmethod != nullptr);
1202 visited[func_in_visited].in_overrides_traversal = true;
1203 if (!in_overrides_traversal) {
1204 // If it's a virtual method and we are not yet in an overrides traversal,
1205 // start from the base method.
1206 GetBaseMethods(cxxmethod, bases);
1207 for (const auto* base : bases) {
1208 AnalyzeFunctionRecursive(analyzed, visited, base, lifetime_context,
1209 diag_reporter, debug_info, base_to_overrides);
1210 }
1211 } else {
1212 // We are in an overrides traversal for a virtual method starting from its
1213 // base method. Recursively look into the overrides that this TU knows
1214 // about, so that the base method's analysis result can be updated with
1215 // the overrides (that are discovered in this TU).
1216 auto iter = base_to_overrides.find(cxxmethod->getCanonicalDecl());
1217 if (iter != base_to_overrides.end()) {
1218 overrides = iter->second;
1219 for (const auto* derived : overrides) {
1220 AnalyzeFunctionRecursive(analyzed, visited, derived, lifetime_context,
1221 diag_reporter, debug_info,
1222 base_to_overrides);
1223 }
1224 }
1225 }
1226 visited[func_in_visited].in_overrides_traversal = false;
1227 }
1228
1229 // Recursing through CallExprs should not remove `func` from the stack, though
1230 // there may be more on the stack after `func` if they are all part of a
1231 // recursive cycle graph.
1232 assert(visited[func_in_visited].func == func);
1233 if (func_in_visited < visited.size() - 1) {
1234 for (size_t i = func_in_visited; i < visited.size(); ++i) {
1235 assert(visited[i].in_cycle);
1236 }
1237 }
1238
1239 // Once we return back here, there are 3 possibilities for `func`.
1240 //
1241 // 1. If `func` is part of a cycle, but was not the first entry point of the
1242 // cycle, then we defer analyzing `func` until we get back to the entry
1243 // point. We look for this by seeing if there is another function marked as
1244 // being in a cycle above `func` in the `visited` call stack. Note that we
1245 // will leave `func` in the `visited` call stack when we return so that
1246 // once we get back to the recursive cycle's entry point, we can see all
1247 // the functions that are part of the cycle graph.
1248 // 2. If `func` was not part of a cycle, we can analyze it and expect it to
1249 // have valid FunctionLifetimes already generated for anything it calls.
1250 // 3. Otherwise, we collect the whole cycle (which may be just the `func` if
1251 // it calls itself directly), and we analyze the cycle as a whole.
1252
1253 if (func_in_visited > 0 && visited[func_in_visited].in_cycle &&
1254 visited[func_in_visited - 1].in_cycle) {
1255 // Case 1. In a recursive cycle, but not the entry point.
1256 return;
1257 }
1258 if (!visited[func_in_visited].in_cycle) {
1259 // Case 2. Not part of a cycle.
1260 if (bases.empty()) {
1261 // This function is not where we initiated an overrides traversal from its
1262 // base methods.
1263 auto analysis_result =
Martin Brænne7438ce12022-06-30 06:24:24 -07001264 AnalyzeSingleFunction(func, analyzed, diag_reporter, debug_info);
Luca Versari99fddff2022-05-25 10:22:32 -07001265 if (!analysis_result) {
1266 analyzed[func] = FunctionAnalysisError(analysis_result.takeError());
1267 } else {
1268 auto func_lifetimes_result = ConstructFunctionLifetimes(
1269 func, std::move(analysis_result.get()), diag_reporter);
1270 if (!func_lifetimes_result) {
1271 analyzed[func] =
1272 FunctionAnalysisError(func_lifetimes_result.takeError());
1273 } else {
1274 analyzed[func] = func_lifetimes_result.get();
1275 }
1276 }
1277 } else {
1278 // In this branch we have initiated (and finished) an overrides
1279 // traversal starting with its base method, and the traversal for this
1280 // function must be already done as a part of the overrides traversal.
1281 assert(is_virtual);
1282 assert(analyzed.count(func) > 0);
1283 }
1284 } else {
1285 // Case 3. The entry point to a recursive cycle.
1286 auto funcs_in_cycle =
1287 llvm::ArrayRef<VisitedCallStackEntry>(visited).drop_front(
1288 func_in_visited);
1289 if (llvm::Error err = AnalyzeRecursiveFunctions(
1290 funcs_in_cycle, analyzed, diag_reporter, debug_info)) {
1291 for (const auto [func_in_cycle, _1, _2] : funcs_in_cycle) {
1292 analyzed[func_in_cycle] = FunctionAnalysisError(err);
1293 }
1294 }
1295 }
1296
1297 // If this has overrides and we're in an overrides traversal, the lifetimes
1298 // need to be (recursively) updated with the results of the overrides.
1299 if (in_overrides_traversal) {
Luca Versari7f2929c2023-01-16 10:15:54 -08001300 if (llvm::Error err =
1301 UpdateFunctionLifetimesWithOverrides(func, analyzed, overrides)) {
1302 analyzed[func] = FunctionAnalysisError(err);
1303 }
Luca Versari99fddff2022-05-25 10:22:32 -07001304 }
1305
1306 // Once we have finished analyzing `func`, we can remove it from the visited
1307 // stack, along with anything it called in a recursive cycle (which will be
1308 // found after `func` in the `visited` call stack.
1309 visited.resize(func_in_visited);
1310}
1311
1312llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>
1313AnalyzeTranslationUnitAndCollectTemplates(
1314 const clang::TranslationUnitDecl* tu,
1315 const LifetimeAnnotationContext& lifetime_context,
1316 const DiagnosticReporter& diag_reporter, FunctionDebugInfoMap* debug_info,
1317 llvm::DenseMap<clang::FunctionTemplateDecl*, const clang::FunctionDecl*>&
1318 uninstantiated_templates,
1319 const BaseToOverrides& base_to_overrides) {
1320 llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError> result;
1321 llvm::SmallVector<VisitedCallStackEntry> visited;
1322
1323 for (const clang::FunctionDecl* func : GetAllFunctionDefinitions(tu)) {
1324 // Skip templated functions.
1325 if (func->isTemplated()) {
1326 clang::FunctionTemplateDecl* template_decl =
1327 func->getDescribedFunctionTemplate();
1328 if (template_decl) {
1329 uninstantiated_templates.insert({template_decl, func});
1330 }
1331 continue;
1332 }
1333
1334 if (func->isFunctionTemplateSpecialization()) {
1335 auto* info = func->getTemplateSpecializationInfo();
1336 uninstantiated_templates.erase(info->getTemplate());
1337 }
1338
1339 // For some reason that's not clear to mboehme@, the AST matcher is
1340 // returning two matches for every function definition; maybe there are two
1341 // different paths from a TranslationUnitDecl to a function definition.
1342 // This doesn't really have any ill effect, however, as
1343 // AnalyzeFunctionRecursive() bails out anyway if it has analyzed the
1344 // function before.
1345
1346 AnalyzeFunctionRecursive(result, visited, func, lifetime_context,
1347 diag_reporter, debug_info, base_to_overrides);
1348 }
1349
1350 return result;
1351}
1352
1353std::string GetFunctionUSRString(const clang::Decl* func) {
1354 llvm::SmallString</*inline size=*/128> usr;
1355 if (clang::index::generateUSRForDecl(func, usr)) {
1356 llvm::errs() << "Could not generate USR for ";
1357 func->dump();
1358 assert(false);
1359 return std::string();
1360 }
1361 return std::string(usr.data(), usr.size());
1362}
1363
1364// Run AnalyzeFunctionRecursive with `context`. Report results through
1365// `result_callback` and update `debug_info` using USR strings to map functions
1366// to the original ASTContext.
1367void AnalyzeTemplateFunctionsInSeparateASTContext(
1368 const LifetimeAnnotationContext& lifetime_context,
1369 const llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>&
1370 initial_result,
1371 const FunctionAnalysisResultCallback& result_callback,
1372 const DiagnosticReporter& diag_reporter, FunctionDebugInfoMap* debug_info,
1373 const std::map<std::string, const clang::FunctionDecl*>&
1374 template_usr_to_decl,
1375 const BaseToOverrides& base_to_overrides, clang::ASTContext& context) {
1376 llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>
1377 inner_result;
1378 llvm::SmallVector<VisitedCallStackEntry> inner_visited;
1379 FunctionDebugInfoMap inner_debug_info;
1380
1381 for (const clang::FunctionDecl* func :
1382 GetAllFunctionDefinitions(context.getTranslationUnitDecl())) {
1383 // Skip templated functions.
1384 if (func->isTemplated()) continue;
1385
1386 AnalyzeFunctionRecursive(inner_result, inner_visited, func,
1387 lifetime_context, diag_reporter, &inner_debug_info,
1388 base_to_overrides);
1389 }
1390
1391 // We need to remap the results with FunctionDecl* in the
1392 // original ASTContext. (Because this context goes away after
1393 // this)
1394 llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>
1395 merged_result = initial_result;
1396 for (const auto& [decl, lifetimes_or_error] : inner_result) {
1397 if (!decl->isFunctionTemplateSpecialization()) continue;
1398 auto* tmpl = decl->getTemplateSpecializationInfo()->getTemplate();
1399 auto iter = template_usr_to_decl.find(GetFunctionUSRString(tmpl));
1400 if (iter != template_usr_to_decl.end()) {
1401 merged_result.insert({iter->second, lifetimes_or_error});
1402 }
1403 }
1404 for (const auto& [decl, lifetimes_or_error] : merged_result) {
1405 result_callback(decl, lifetimes_or_error);
1406 }
1407 for (auto& [decl, info] : inner_debug_info) {
1408 if (!decl->isFunctionTemplateSpecialization()) continue;
1409 auto* tmpl = decl->getTemplateSpecializationInfo()->getTemplate();
1410 auto iter = template_usr_to_decl.find(GetFunctionUSRString(tmpl));
1411 if (iter != template_usr_to_decl.end()) (*debug_info)[iter->second] = info;
1412 }
1413}
1414
1415DiagnosticReporter DiagReporterForDiagEngine(
1416 clang::DiagnosticsEngine& diag_engine) {
1417 return
1418 [&diag_engine](clang::SourceLocation location, clang::StringRef message,
1419 clang::DiagnosticIDs::Level level) {
1420 return diag_engine.Report(
1421 location,
1422 diag_engine.getDiagnosticIDs()->getCustomDiagID(level, message));
1423 };
1424}
1425
1426} // namespace
1427
1428bool IsIsomorphic(const FunctionLifetimes& a, const FunctionLifetimes& b) {
Luca Versari7f2929c2023-01-16 10:15:54 -08001429 return LifetimeConstraints::ForCallableSubstitution(a, b)
1430 .AllConstraints()
1431 .empty() &&
1432 LifetimeConstraints::ForCallableSubstitution(b, a)
1433 .AllConstraints()
1434 .empty();
Luca Versari99fddff2022-05-25 10:22:32 -07001435}
1436
1437FunctionLifetimesOrError AnalyzeFunction(
1438 const clang::FunctionDecl* func,
1439 const LifetimeAnnotationContext& lifetime_context,
1440 FunctionDebugInfo* debug_info) {
1441 llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError> analyzed;
1442 llvm::SmallVector<VisitedCallStackEntry> visited;
1443 std::optional<FunctionDebugInfoMap> debug_info_map;
1444 if (debug_info) {
1445 debug_info_map.emplace();
1446 }
1447 DiagnosticReporter diag_reporter =
1448 DiagReporterForDiagEngine(func->getASTContext().getDiagnostics());
1449 AnalyzeFunctionRecursive(
1450 analyzed, visited, func, lifetime_context, diag_reporter,
1451 debug_info_map ? &debug_info_map.value() : nullptr, BaseToOverrides());
1452 if (debug_info) {
1453 *debug_info = debug_info_map->lookup(func);
1454 }
1455 return analyzed.lookup(func);
1456}
1457
1458llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>
1459AnalyzeTranslationUnit(const clang::TranslationUnitDecl* tu,
1460 const LifetimeAnnotationContext& lifetime_context,
1461 DiagnosticReporter diag_reporter,
1462 FunctionDebugInfoMap* debug_info) {
1463 if (!diag_reporter) {
1464 diag_reporter =
1465 DiagReporterForDiagEngine(tu->getASTContext().getDiagnostics());
1466 }
1467
1468 llvm::DenseMap<clang::FunctionTemplateDecl*, const clang::FunctionDecl*>
1469 uninstantiated_templates;
1470
1471 // Builds a map from a base method to its overrides within this TU. It will
1472 // not find out all the overrides, but still cover (and can partially update)
1473 // all the base methods that this TU implements.
1474 auto base_to_overrides = BuildBaseToOverrides(tu);
1475
1476 llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError> result =
1477 AnalyzeTranslationUnitAndCollectTemplates(
1478 tu, lifetime_context, diag_reporter, debug_info,
1479 uninstantiated_templates, base_to_overrides);
1480
1481 return result;
1482}
1483
1484void AnalyzeTranslationUnitWithTemplatePlaceholder(
1485 const clang::TranslationUnitDecl* tu,
1486 const LifetimeAnnotationContext& lifetime_context,
1487 const FunctionAnalysisResultCallback& result_callback,
1488 DiagnosticReporter diag_reporter, FunctionDebugInfoMap* debug_info) {
1489 if (!diag_reporter) {
1490 diag_reporter =
1491 DiagReporterForDiagEngine(tu->getASTContext().getDiagnostics());
1492 }
1493
1494 llvm::DenseMap<clang::FunctionTemplateDecl*, const clang::FunctionDecl*>
1495 uninstantiated_templates;
1496
1497 // Builds a map from a base method to its overrides within this TU. It will
1498 // not find out all the overrides, but still cover (and can partially update)
1499 // all the base methods that this TU implements.
1500 auto base_to_overrides = BuildBaseToOverrides(tu);
1501
1502 llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>
1503 initial_result = AnalyzeTranslationUnitAndCollectTemplates(
1504 tu, lifetime_context, diag_reporter, debug_info,
1505 uninstantiated_templates, base_to_overrides);
1506
1507 // Make a map from USRString to funcDecls in the original ASTContext.
1508 std::map<std::string, const clang::FunctionDecl*> template_usr_to_decl;
1509 for (const auto& [tmpl, func] : uninstantiated_templates) {
1510 template_usr_to_decl[GetFunctionUSRString(tmpl)] = func;
1511 }
1512
1513 GeneratedCode code_with_placeholder;
1514 if (llvm::Error err =
1515 GenerateTemplateInstantiationCode(tu, uninstantiated_templates)
1516 .moveInto(code_with_placeholder)) {
1517 FunctionAnalysisError analysis_error(err);
1518 for (const auto& [tmpl, func] : uninstantiated_templates) {
1519 result_callback(func, analysis_error);
1520 }
1521 return;
1522 }
1523
1524 // A callback to call AnalyzeFunctionRecursive again with template
1525 // placeholders. This is passed to RunToolOnCodeWithOverlay below.
1526 auto analyze_with_placeholder =
1527 [&lifetime_context, &initial_result, &result_callback, &diag_reporter,
1528 &debug_info, &template_usr_to_decl,
1529 &base_to_overrides](clang::ASTContext& context) {
1530 AnalyzeTemplateFunctionsInSeparateASTContext(
1531 lifetime_context, initial_result, result_callback, diag_reporter,
1532 debug_info, template_usr_to_decl, base_to_overrides, context);
1533 };
1534
1535 // Run `analyze_with_placeholder` in a separate ASTContext on top of an
1536 // overlaid filesystem with the `code_with_placeholder` file.
1537 RunToolOnCodeWithOverlay(tu->getASTContext(), code_with_placeholder.filename,
1538 code_with_placeholder.code,
1539 analyze_with_placeholder);
1540}
1541
1542} // namespace lifetimes
1543} // namespace tidy
1544} // namespace clang