1 //===- Consumed.h -----------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // A intra-procedural analysis for checking consumed properties. This is based, 11 // in part, on research on linear types. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H 16 #define LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H 17 18 #include "clang/Analysis/Analyses/PostOrderCFGView.h" 19 #include "clang/Analysis/CFG.h" 20 #include "clang/Basic/LLVM.h" 21 #include "clang/Basic/PartialDiagnostic.h" 22 #include "clang/Basic/SourceLocation.h" 23 #include "llvm/ADT/DenseMap.h" 24 #include "llvm/ADT/SmallVector.h" 25 #include "llvm/ADT/StringRef.h" 26 #include <list> 27 #include <memory> 28 #include <utility> 29 #include <vector> 30 31 namespace clang { 32 33 class AnalysisDeclContext; 34 class CXXBindTemporaryExpr; 35 class FunctionDecl; 36 class PostOrderCFGView; 37 class Stmt; 38 class VarDecl; 39 40 namespace consumed { 41 42 class ConsumedStmtVisitor; 43 44 enum ConsumedState { 45 // No state information for the given variable. 46 CS_None, 47 48 CS_Unknown, 49 CS_Unconsumed, 50 CS_Consumed 51 }; 52 53 using OptionalNotes = SmallVector<PartialDiagnosticAt, 1>; 54 using DelayedDiag = std::pair<PartialDiagnosticAt, OptionalNotes>; 55 using DiagList = std::list<DelayedDiag>; 56 57 class ConsumedWarningsHandlerBase { 58 public: 59 virtual ~ConsumedWarningsHandlerBase(); 60 61 /// Emit the warnings and notes left by the analysis. emitDiagnostics()62 virtual void emitDiagnostics() {} 63 64 /// Warn that a variable's state doesn't match at the entry and exit 65 /// of a loop. 66 /// 67 /// \param Loc -- The location of the end of the loop. 68 /// 69 /// \param VariableName -- The name of the variable that has a mismatched 70 /// state. warnLoopStateMismatch(SourceLocation Loc,StringRef VariableName)71 virtual void warnLoopStateMismatch(SourceLocation Loc, 72 StringRef VariableName) {} 73 74 /// Warn about parameter typestate mismatches upon return. 75 /// 76 /// \param Loc -- The SourceLocation of the return statement. 77 /// 78 /// \param ExpectedState -- The state the return value was expected to be 79 /// in. 80 /// 81 /// \param ObservedState -- The state the return value was observed to be 82 /// in. warnParamReturnTypestateMismatch(SourceLocation Loc,StringRef VariableName,StringRef ExpectedState,StringRef ObservedState)83 virtual void warnParamReturnTypestateMismatch(SourceLocation Loc, 84 StringRef VariableName, 85 StringRef ExpectedState, 86 StringRef ObservedState) {} 87 88 // FIXME: Add documentation. warnParamTypestateMismatch(SourceLocation LOC,StringRef ExpectedState,StringRef ObservedState)89 virtual void warnParamTypestateMismatch(SourceLocation LOC, 90 StringRef ExpectedState, 91 StringRef ObservedState) {} 92 93 // FIXME: This can be removed when the attr propagation fix for templated 94 // classes lands. 95 /// Warn about return typestates set for unconsumable types. 96 /// 97 /// \param Loc -- The location of the attributes. 98 /// 99 /// \param TypeName -- The name of the unconsumable type. warnReturnTypestateForUnconsumableType(SourceLocation Loc,StringRef TypeName)100 virtual void warnReturnTypestateForUnconsumableType(SourceLocation Loc, 101 StringRef TypeName) {} 102 103 /// Warn about return typestate mismatches. 104 /// 105 /// \param Loc -- The SourceLocation of the return statement. 106 /// 107 /// \param ExpectedState -- The state the return value was expected to be 108 /// in. 109 /// 110 /// \param ObservedState -- The state the return value was observed to be 111 /// in. warnReturnTypestateMismatch(SourceLocation Loc,StringRef ExpectedState,StringRef ObservedState)112 virtual void warnReturnTypestateMismatch(SourceLocation Loc, 113 StringRef ExpectedState, 114 StringRef ObservedState) {} 115 116 /// Warn about use-while-consumed errors. 117 /// \param MethodName -- The name of the method that was incorrectly 118 /// invoked. 119 /// 120 /// \param State -- The state the object was used in. 121 /// 122 /// \param Loc -- The SourceLocation of the method invocation. warnUseOfTempInInvalidState(StringRef MethodName,StringRef State,SourceLocation Loc)123 virtual void warnUseOfTempInInvalidState(StringRef MethodName, 124 StringRef State, 125 SourceLocation Loc) {} 126 127 /// Warn about use-while-consumed errors. 128 /// \param MethodName -- The name of the method that was incorrectly 129 /// invoked. 130 /// 131 /// \param State -- The state the object was used in. 132 /// 133 /// \param VariableName -- The name of the variable that holds the unique 134 /// value. 135 /// 136 /// \param Loc -- The SourceLocation of the method invocation. warnUseInInvalidState(StringRef MethodName,StringRef VariableName,StringRef State,SourceLocation Loc)137 virtual void warnUseInInvalidState(StringRef MethodName, 138 StringRef VariableName, 139 StringRef State, 140 SourceLocation Loc) {} 141 }; 142 143 class ConsumedStateMap { 144 using VarMapType = llvm::DenseMap<const VarDecl *, ConsumedState>; 145 using TmpMapType = 146 llvm::DenseMap<const CXXBindTemporaryExpr *, ConsumedState>; 147 148 protected: 149 bool Reachable = true; 150 const Stmt *From = nullptr; 151 VarMapType VarMap; 152 TmpMapType TmpMap; 153 154 public: 155 ConsumedStateMap() = default; ConsumedStateMap(const ConsumedStateMap & Other)156 ConsumedStateMap(const ConsumedStateMap &Other) 157 : Reachable(Other.Reachable), From(Other.From), VarMap(Other.VarMap), 158 TmpMap() {} 159 160 /// Warn if any of the parameters being tracked are not in the state 161 /// they were declared to be in upon return from a function. 162 void checkParamsForReturnTypestate(SourceLocation BlameLoc, 163 ConsumedWarningsHandlerBase &WarningsHandler) const; 164 165 /// Clear the TmpMap. 166 void clearTemporaries(); 167 168 /// Get the consumed state of a given variable. 169 ConsumedState getState(const VarDecl *Var) const; 170 171 /// Get the consumed state of a given temporary value. 172 ConsumedState getState(const CXXBindTemporaryExpr *Tmp) const; 173 174 /// Merge this state map with another map. 175 void intersect(const ConsumedStateMap &Other); 176 177 void intersectAtLoopHead(const CFGBlock *LoopHead, const CFGBlock *LoopBack, 178 const ConsumedStateMap *LoopBackStates, 179 ConsumedWarningsHandlerBase &WarningsHandler); 180 181 /// Return true if this block is reachable. isReachable()182 bool isReachable() const { return Reachable; } 183 184 /// Mark the block as unreachable. 185 void markUnreachable(); 186 187 /// Set the source for a decision about the branching of states. 188 /// \param Source -- The statement that was the origin of a branching 189 /// decision. setSource(const Stmt * Source)190 void setSource(const Stmt *Source) { this->From = Source; } 191 192 /// Set the consumed state of a given variable. 193 void setState(const VarDecl *Var, ConsumedState State); 194 195 /// Set the consumed state of a given temporary value. 196 void setState(const CXXBindTemporaryExpr *Tmp, ConsumedState State); 197 198 /// Remove the temporary value from our state map. 199 void remove(const CXXBindTemporaryExpr *Tmp); 200 201 /// Tests to see if there is a mismatch in the states stored in two 202 /// maps. 203 /// 204 /// \param Other -- The second map to compare against. 205 bool operator!=(const ConsumedStateMap *Other) const; 206 }; 207 208 class ConsumedBlockInfo { 209 std::vector<std::unique_ptr<ConsumedStateMap>> StateMapsArray; 210 std::vector<unsigned int> VisitOrder; 211 212 public: 213 ConsumedBlockInfo() = default; 214 ConsumedBlockInfo(unsigned int NumBlocks,PostOrderCFGView * SortedGraph)215 ConsumedBlockInfo(unsigned int NumBlocks, PostOrderCFGView *SortedGraph) 216 : StateMapsArray(NumBlocks), VisitOrder(NumBlocks, 0) { 217 unsigned int VisitOrderCounter = 0; 218 for (const auto BI : *SortedGraph) 219 VisitOrder[BI->getBlockID()] = VisitOrderCounter++; 220 } 221 222 bool allBackEdgesVisited(const CFGBlock *CurrBlock, 223 const CFGBlock *TargetBlock); 224 225 void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap, 226 std::unique_ptr<ConsumedStateMap> &OwnedStateMap); 227 void addInfo(const CFGBlock *Block, 228 std::unique_ptr<ConsumedStateMap> StateMap); 229 230 ConsumedStateMap* borrowInfo(const CFGBlock *Block); 231 232 void discardInfo(const CFGBlock *Block); 233 234 std::unique_ptr<ConsumedStateMap> getInfo(const CFGBlock *Block); 235 236 bool isBackEdge(const CFGBlock *From, const CFGBlock *To); 237 bool isBackEdgeTarget(const CFGBlock *Block); 238 }; 239 240 /// A class that handles the analysis of uniqueness violations. 241 class ConsumedAnalyzer { 242 ConsumedBlockInfo BlockInfo; 243 std::unique_ptr<ConsumedStateMap> CurrStates; 244 245 ConsumedState ExpectedReturnState; 246 247 void determineExpectedReturnState(AnalysisDeclContext &AC, 248 const FunctionDecl *D); 249 bool splitState(const CFGBlock *CurrBlock, 250 const ConsumedStmtVisitor &Visitor); 251 252 public: 253 ConsumedWarningsHandlerBase &WarningsHandler; 254 ConsumedAnalyzer(ConsumedWarningsHandlerBase & WarningsHandler)255 ConsumedAnalyzer(ConsumedWarningsHandlerBase &WarningsHandler) 256 : WarningsHandler(WarningsHandler) {} 257 getExpectedReturnState()258 ConsumedState getExpectedReturnState() const { return ExpectedReturnState; } 259 260 /// Check a function's CFG for consumed violations. 261 /// 262 /// We traverse the blocks in the CFG, keeping track of the state of each 263 /// value who's type has uniquness annotations. If methods are invoked in 264 /// the wrong state a warning is issued. Each block in the CFG is traversed 265 /// exactly once. 266 void run(AnalysisDeclContext &AC); 267 }; 268 269 } // namespace consumed 270 271 } // namespace clang 272 273 #endif // LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H 274