blob: dec1ae3b2b4bff88fc61c2c65e4e440b075ddc3b [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- Consumed.h -----------------------------------------------*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// 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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
7//===----------------------------------------------------------------------===//
8//
9// A intra-procedural analysis for checking consumed properties. This is based,
10// in part, on research on linear types.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H
15#define LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H
16
17#include "clang/Analysis/Analyses/PostOrderCFGView.h"
18#include "clang/Analysis/CFG.h"
19#include "clang/Basic/LLVM.h"
20#include "clang/Basic/PartialDiagnostic.h"
21#include "clang/Basic/SourceLocation.h"
22#include "llvm/ADT/DenseMap.h"
23#include "llvm/ADT/SmallVector.h"
24#include "llvm/ADT/StringRef.h"
25#include <list>
26#include <memory>
27#include <utility>
28#include <vector>
29
30namespace clang {
31
32class AnalysisDeclContext;
33class CXXBindTemporaryExpr;
34class FunctionDecl;
35class PostOrderCFGView;
36class Stmt;
37class VarDecl;
38
39namespace consumed {
Andrew Scullcdfcccc2018-10-05 20:58:37 +010040
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010041 class ConsumedStmtVisitor;
42
43 enum ConsumedState {
44 // No state information for the given variable.
45 CS_None,
Andrew Scullcdfcccc2018-10-05 20:58:37 +010046
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010047 CS_Unknown,
48 CS_Unconsumed,
49 CS_Consumed
50 };
Andrew Scullcdfcccc2018-10-05 20:58:37 +010051
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010052 using OptionalNotes = SmallVector<PartialDiagnosticAt, 1>;
53 using DelayedDiag = std::pair<PartialDiagnosticAt, OptionalNotes>;
54 using DiagList = std::list<DelayedDiag>;
55
56 class ConsumedWarningsHandlerBase {
57 public:
58 virtual ~ConsumedWarningsHandlerBase();
59
Andrew Scullcdfcccc2018-10-05 20:58:37 +010060 /// Emit the warnings and notes left by the analysis.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010061 virtual void emitDiagnostics() {}
Andrew Scullcdfcccc2018-10-05 20:58:37 +010062
63 /// Warn that a variable's state doesn't match at the entry and exit
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010064 /// of a loop.
65 ///
66 /// \param Loc -- The location of the end of the loop.
67 ///
68 /// \param VariableName -- The name of the variable that has a mismatched
69 /// state.
70 virtual void warnLoopStateMismatch(SourceLocation Loc,
71 StringRef VariableName) {}
Andrew Scullcdfcccc2018-10-05 20:58:37 +010072
73 /// Warn about parameter typestate mismatches upon return.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010074 ///
75 /// \param Loc -- The SourceLocation of the return statement.
76 ///
77 /// \param ExpectedState -- The state the return value was expected to be
78 /// in.
79 ///
80 /// \param ObservedState -- The state the return value was observed to be
81 /// in.
82 virtual void warnParamReturnTypestateMismatch(SourceLocation Loc,
83 StringRef VariableName,
84 StringRef ExpectedState,
85 StringRef ObservedState) {}
Andrew Scullcdfcccc2018-10-05 20:58:37 +010086
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010087 // FIXME: Add documentation.
88 virtual void warnParamTypestateMismatch(SourceLocation LOC,
89 StringRef ExpectedState,
90 StringRef ObservedState) {}
Andrew Scullcdfcccc2018-10-05 20:58:37 +010091
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010092 // FIXME: This can be removed when the attr propagation fix for templated
93 // classes lands.
Andrew Scullcdfcccc2018-10-05 20:58:37 +010094 /// Warn about return typestates set for unconsumable types.
95 ///
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010096 /// \param Loc -- The location of the attributes.
97 ///
98 /// \param TypeName -- The name of the unconsumable type.
99 virtual void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
100 StringRef TypeName) {}
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100101
102 /// Warn about return typestate mismatches.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100103 ///
104 /// \param Loc -- The SourceLocation of the return statement.
105 ///
106 /// \param ExpectedState -- The state the return value was expected to be
107 /// in.
108 ///
109 /// \param ObservedState -- The state the return value was observed to be
110 /// in.
111 virtual void warnReturnTypestateMismatch(SourceLocation Loc,
112 StringRef ExpectedState,
113 StringRef ObservedState) {}
114
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100115 /// Warn about use-while-consumed errors.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100116 /// \param MethodName -- The name of the method that was incorrectly
117 /// invoked.
118 ///
119 /// \param State -- The state the object was used in.
120 ///
121 /// \param Loc -- The SourceLocation of the method invocation.
122 virtual void warnUseOfTempInInvalidState(StringRef MethodName,
123 StringRef State,
124 SourceLocation Loc) {}
125
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100126 /// Warn about use-while-consumed errors.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100127 /// \param MethodName -- The name of the method that was incorrectly
128 /// invoked.
129 ///
130 /// \param State -- The state the object was used in.
131 ///
132 /// \param VariableName -- The name of the variable that holds the unique
133 /// value.
134 ///
135 /// \param Loc -- The SourceLocation of the method invocation.
136 virtual void warnUseInInvalidState(StringRef MethodName,
137 StringRef VariableName,
138 StringRef State,
139 SourceLocation Loc) {}
140 };
141
142 class ConsumedStateMap {
143 using VarMapType = llvm::DenseMap<const VarDecl *, ConsumedState>;
144 using TmpMapType =
145 llvm::DenseMap<const CXXBindTemporaryExpr *, ConsumedState>;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100146
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100147 protected:
148 bool Reachable = true;
149 const Stmt *From = nullptr;
150 VarMapType VarMap;
151 TmpMapType TmpMap;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100152
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100153 public:
154 ConsumedStateMap() = default;
155 ConsumedStateMap(const ConsumedStateMap &Other)
156 : Reachable(Other.Reachable), From(Other.From), VarMap(Other.VarMap),
157 TmpMap() {}
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100158
159 /// Warn if any of the parameters being tracked are not in the state
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100160 /// they were declared to be in upon return from a function.
161 void checkParamsForReturnTypestate(SourceLocation BlameLoc,
162 ConsumedWarningsHandlerBase &WarningsHandler) const;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100163
164 /// Clear the TmpMap.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100165 void clearTemporaries();
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100166
167 /// Get the consumed state of a given variable.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100168 ConsumedState getState(const VarDecl *Var) const;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100169
170 /// Get the consumed state of a given temporary value.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100171 ConsumedState getState(const CXXBindTemporaryExpr *Tmp) const;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100172
173 /// Merge this state map with another map.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100174 void intersect(const ConsumedStateMap &Other);
175
176 void intersectAtLoopHead(const CFGBlock *LoopHead, const CFGBlock *LoopBack,
177 const ConsumedStateMap *LoopBackStates,
178 ConsumedWarningsHandlerBase &WarningsHandler);
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100179
180 /// Return true if this block is reachable.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100181 bool isReachable() const { return Reachable; }
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100182
183 /// Mark the block as unreachable.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100184 void markUnreachable();
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100185
186 /// Set the source for a decision about the branching of states.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100187 /// \param Source -- The statement that was the origin of a branching
188 /// decision.
189 void setSource(const Stmt *Source) { this->From = Source; }
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100190
191 /// Set the consumed state of a given variable.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100192 void setState(const VarDecl *Var, ConsumedState State);
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100193
194 /// Set the consumed state of a given temporary value.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100195 void setState(const CXXBindTemporaryExpr *Tmp, ConsumedState State);
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100196
197 /// Remove the temporary value from our state map.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100198 void remove(const CXXBindTemporaryExpr *Tmp);
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100199
200 /// Tests to see if there is a mismatch in the states stored in two
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100201 /// maps.
202 ///
203 /// \param Other -- The second map to compare against.
204 bool operator!=(const ConsumedStateMap *Other) const;
205 };
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100206
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100207 class ConsumedBlockInfo {
208 std::vector<std::unique_ptr<ConsumedStateMap>> StateMapsArray;
209 std::vector<unsigned int> VisitOrder;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100210
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100211 public:
212 ConsumedBlockInfo() = default;
213
214 ConsumedBlockInfo(unsigned int NumBlocks, PostOrderCFGView *SortedGraph)
215 : StateMapsArray(NumBlocks), VisitOrder(NumBlocks, 0) {
216 unsigned int VisitOrderCounter = 0;
217 for (const auto BI : *SortedGraph)
218 VisitOrder[BI->getBlockID()] = VisitOrderCounter++;
219 }
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100220
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100221 bool allBackEdgesVisited(const CFGBlock *CurrBlock,
222 const CFGBlock *TargetBlock);
223
224 void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap,
225 std::unique_ptr<ConsumedStateMap> &OwnedStateMap);
226 void addInfo(const CFGBlock *Block,
227 std::unique_ptr<ConsumedStateMap> StateMap);
228
229 ConsumedStateMap* borrowInfo(const CFGBlock *Block);
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100230
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100231 void discardInfo(const CFGBlock *Block);
232
233 std::unique_ptr<ConsumedStateMap> getInfo(const CFGBlock *Block);
234
235 bool isBackEdge(const CFGBlock *From, const CFGBlock *To);
236 bool isBackEdgeTarget(const CFGBlock *Block);
237 };
238
239 /// A class that handles the analysis of uniqueness violations.
240 class ConsumedAnalyzer {
241 ConsumedBlockInfo BlockInfo;
242 std::unique_ptr<ConsumedStateMap> CurrStates;
243
244 ConsumedState ExpectedReturnState;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100245
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100246 void determineExpectedReturnState(AnalysisDeclContext &AC,
247 const FunctionDecl *D);
248 bool splitState(const CFGBlock *CurrBlock,
249 const ConsumedStmtVisitor &Visitor);
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100250
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100251 public:
252 ConsumedWarningsHandlerBase &WarningsHandler;
253
254 ConsumedAnalyzer(ConsumedWarningsHandlerBase &WarningsHandler)
255 : WarningsHandler(WarningsHandler) {}
256
257 ConsumedState getExpectedReturnState() const { return ExpectedReturnState; }
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100258
259 /// Check a function's CFG for consumed violations.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100260 ///
261 /// We traverse the blocks in the CFG, keeping track of the state of each
262 /// value who's type has uniquness annotations. If methods are invoked in
263 /// the wrong state a warning is issued. Each block in the CFG is traversed
264 /// exactly once.
265 void run(AnalysisDeclContext &AC);
266 };
267
268} // namespace consumed
269
270} // namespace clang
271
272#endif // LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H