clang 22.0.0git
SmartPointerAccessorCaching.h
Go to the documentation of this file.
1//===-- SmartPointerAccessorCaching.h ---------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines utilities to help cache accessors for smart pointer
10// like objects.
11//
12// These should be combined with CachedConstAccessorsLattice.
13// Beyond basic const accessors, smart pointers may have the following two
14// additional issues:
15//
16// 1) There may be multiple accessors for the same underlying object, e.g.
17// `operator->`, `operator*`, and `get`. Users may use a mixture of these
18// accessors, so the cache should unify them.
19//
20// 2) There may be non-const overloads of accessors. They are still safe to
21// cache, as they don't modify the container object.
22//===----------------------------------------------------------------------===//
23
24#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SMARTPOINTERACCESSORCACHING_H
25#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SMARTPOINTERACCESSORCACHING_H
26
27#include <cassert>
28
29#include "clang/AST/Decl.h"
30#include "clang/AST/Expr.h"
31#include "clang/AST/Stmt.h"
36#include "llvm/ADT/STLFunctionalExtras.h"
37
38namespace clang::dataflow {
39
40/// Matchers:
41/// For now, these match on any class with an `operator*` or `operator->`
42/// where the return types have a similar shape as std::unique_ptr
43/// and std::optional.
44///
45/// - `*` returns a reference to a type `T`
46/// - `->` returns a pointer to `T`
47/// - `get` returns a pointer to `T`
48/// - `value` returns a reference `T`
49///
50/// (1) The `T` should all match across the accessors (ignoring qualifiers).
51///
52/// (2) The specific accessor used in a call isn't required to be const,
53/// but the class must have a const overload of each accessor.
54///
55/// For now, we don't have customization to ignore certain classes.
56/// For example, if writing a ClangTidy check for `std::optional`, these
57/// would also match `std::optional`. In order to have special handling
58/// for `std::optional`, we assume the (Matcher, TransferFunction) case
59/// with custom handling is ordered early so that these generic cases
60/// do not trigger.
66isSmartPointerLikeValueMethodCall(clang::StringRef MethodName = "value");
68isSmartPointerLikeGetMethodCall(clang::StringRef MethodName = "get");
69
70// Common transfer functions.
71
72/// Returns the "canonical" callee for smart pointer operators (`*` and `->`)
73/// as a key for caching.
74///
75/// We choose `*` as the canonical one, since it needs a
76/// StorageLocation anyway.
77///
78/// Note: there may be multiple `operator*` (one const, one non-const).
79/// We pick the const one, which the above provided matchers require to exist.
80const FunctionDecl *
82
83/// A transfer function for `operator*` (and `value`) calls that can be
84/// cached. Runs the `InitializeLoc` callback to initialize any new
85/// StorageLocations.
86///
87/// Requirements:
88///
89/// - LatticeT should use the `CachedConstAccessorsLattice` mixin.
90template <typename LatticeT>
92 const CallExpr *DerefExpr, RecordStorageLocation *SmartPointerLoc,
94 llvm::function_ref<void(StorageLocation &)> InitializeLoc);
95
96/// A transfer function for `operator->` (and `get`) calls that can be cached.
97/// Runs the `InitializeLoc` callback to initialize any new StorageLocations.
98///
99/// Requirements:
100///
101/// - LatticeT should use the `CachedConstAccessorsLattice` mixin.
102template <typename LatticeT>
104 const CallExpr *GetExpr, RecordStorageLocation *SmartPointerLoc,
106 llvm::function_ref<void(StorageLocation &)> InitializeLoc);
107
108template <typename LatticeT>
110 const CallExpr *DerefExpr, RecordStorageLocation *SmartPointerLoc,
112 llvm::function_ref<void(StorageLocation &)> InitializeLoc) {
113 if (State.Env.getStorageLocation(*DerefExpr) != nullptr)
114 return;
115 if (SmartPointerLoc == nullptr)
116 return;
117
118 const FunctionDecl *Callee = DerefExpr->getDirectCallee();
119 if (Callee == nullptr)
120 return;
121 const FunctionDecl *CanonicalCallee =
123 // This shouldn't happen, as we should at least find `Callee` itself.
124 assert(CanonicalCallee != nullptr);
125 if (CanonicalCallee != Callee) {
126 // When using the provided matchers, we should always get a reference to
127 // the same type.
128 assert(CanonicalCallee->getReturnType()->isReferenceType() &&
129 Callee->getReturnType()->isReferenceType());
130 assert(CanonicalCallee->getReturnType()
133 Callee->getReturnType()
134 .getNonReferenceType()
135 ->getCanonicalTypeUnqualified());
136 }
137
138 StorageLocation &LocForValue =
139 State.Lattice.getOrCreateConstMethodReturnStorageLocation(
140 *SmartPointerLoc, CanonicalCallee, State.Env, InitializeLoc);
141 State.Env.setStorageLocation(*DerefExpr, LocForValue);
142}
143
144template <typename LatticeT>
146 const CallExpr *GetExpr, RecordStorageLocation *SmartPointerLoc,
148 llvm::function_ref<void(StorageLocation &)> InitializeLoc) {
149 if (SmartPointerLoc == nullptr)
150 return;
151
152 const FunctionDecl *CanonicalCallee =
154
155 if (CanonicalCallee != nullptr) {
156 auto &LocForValue =
157 State.Lattice.getOrCreateConstMethodReturnStorageLocation(
158 *SmartPointerLoc, CanonicalCallee, State.Env, InitializeLoc);
159 State.Env.setValue(*GetExpr,
160 State.Env.template create<PointerValue>(LocForValue));
161 } else {
162 // Otherwise, just cache the pointer value as if it was a const accessor.
163 Value *Val = State.Lattice.getOrCreateConstMethodReturnValue(
164 *SmartPointerLoc, GetExpr, State.Env);
165 if (Val == nullptr)
166 return;
167 State.Env.setValue(*GetExpr, *Val);
168 }
169}
170
171} // namespace clang::dataflow
172
173#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SMARTPOINTERACCESSORCACHING_H
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2879
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3062
Represents a function declaration or definition.
Definition Decl.h:1999
QualType getReturnType() const
Definition Decl.h:2842
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
Definition TypeBase.h:8470
CanQualType getCanonicalTypeUnqualified() const
bool isReferenceType() const
Definition TypeBase.h:8546
A storage location for a record (struct, class, or union).
Base class for elements of the local variable store and of the heap.
Base class for all values computed by abstract interpretation.
Definition Value.h:33
internal::Matcher< Stmt > StatementMatcher
Dataflow Directional Tag Classes.
Definition AdornedCFG.h:29
ast_matchers::StatementMatcher isSmartPointerLikeValueMethodCall(clang::StringRef MethodName="value")
void transferSmartPointerLikeCachedDeref(const CallExpr *DerefExpr, RecordStorageLocation *SmartPointerLoc, TransferState< LatticeT > &State, llvm::function_ref< void(StorageLocation &)> InitializeLoc)
A transfer function for operator* (and value) calls that can be cached.
ast_matchers::StatementMatcher isPointerLikeOperatorStar()
Matchers: For now, these match on any class with an operator* or operator-> where the return types ha...
void transferSmartPointerLikeCachedGet(const CallExpr *GetExpr, RecordStorageLocation *SmartPointerLoc, TransferState< LatticeT > &State, llvm::function_ref< void(StorageLocation &)> InitializeLoc)
A transfer function for operator-> (and get) calls that can be cached.
ast_matchers::StatementMatcher isSmartPointerLikeOperatorArrow()
const FunctionDecl * getCanonicalSmartPointerLikeOperatorCallee(const CallExpr *CE)
Returns the "canonical" callee for smart pointer operators (* and ->) as a key for caching.
ast_matchers::StatementMatcher isSmartPointerLikeOperatorStar()
ast_matchers::StatementMatcher isSmartPointerLikeGetMethodCall(clang::StringRef MethodName="get")
ast_matchers::StatementMatcher isPointerLikeOperatorArrow()
A common form of state shared between the cases of a transfer function.
Definition MatchSwitch.h:41