10b57cec5SDimitry Andric //=- UninitializedValues.h - Finding uses of uninitialized values -*- C++ -*-=//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines APIs for invoking and reported uninitialized values
100b57cec5SDimitry Andric // warnings.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H
150b57cec5SDimitry Andric #define LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
180b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric namespace clang {
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric class AnalysisDeclContext;
230b57cec5SDimitry Andric class CFG;
240b57cec5SDimitry Andric class DeclContext;
250b57cec5SDimitry Andric class Expr;
260b57cec5SDimitry Andric class Stmt;
270b57cec5SDimitry Andric class VarDecl;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric /// A use of a variable, which might be uninitialized.
300b57cec5SDimitry Andric class UninitUse {
310b57cec5SDimitry Andric public:
320b57cec5SDimitry Andric   struct Branch {
330b57cec5SDimitry Andric     const Stmt *Terminator;
340b57cec5SDimitry Andric     unsigned Output;
350b57cec5SDimitry Andric   };
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric private:
380b57cec5SDimitry Andric   /// The expression which uses this variable.
390b57cec5SDimitry Andric   const Expr *User;
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric   /// Is this use uninitialized whenever the function is called?
420b57cec5SDimitry Andric   bool UninitAfterCall = false;
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric   /// Is this use uninitialized whenever the variable declaration is reached?
450b57cec5SDimitry Andric   bool UninitAfterDecl = false;
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   /// Does this use always see an uninitialized value?
480b57cec5SDimitry Andric   bool AlwaysUninit;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric   /// This use is always uninitialized if it occurs after any of these branches
510b57cec5SDimitry Andric   /// is taken.
520b57cec5SDimitry Andric   SmallVector<Branch, 2> UninitBranches;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric public:
UninitUse(const Expr * User,bool AlwaysUninit)550b57cec5SDimitry Andric   UninitUse(const Expr *User, bool AlwaysUninit)
560b57cec5SDimitry Andric       : User(User), AlwaysUninit(AlwaysUninit) {}
570b57cec5SDimitry Andric 
addUninitBranch(Branch B)580b57cec5SDimitry Andric   void addUninitBranch(Branch B) {
590b57cec5SDimitry Andric     UninitBranches.push_back(B);
600b57cec5SDimitry Andric   }
610b57cec5SDimitry Andric 
setUninitAfterCall()620b57cec5SDimitry Andric   void setUninitAfterCall() { UninitAfterCall = true; }
setUninitAfterDecl()630b57cec5SDimitry Andric   void setUninitAfterDecl() { UninitAfterDecl = true; }
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric   /// Get the expression containing the uninitialized use.
getUser()660b57cec5SDimitry Andric   const Expr *getUser() const { return User; }
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   /// The kind of uninitialized use.
690b57cec5SDimitry Andric   enum Kind {
700b57cec5SDimitry Andric     /// The use might be uninitialized.
710b57cec5SDimitry Andric     Maybe,
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric     /// The use is uninitialized whenever a certain branch is taken.
740b57cec5SDimitry Andric     Sometimes,
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric     /// The use is uninitialized the first time it is reached after we reach
770b57cec5SDimitry Andric     /// the variable's declaration.
780b57cec5SDimitry Andric     AfterDecl,
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric     /// The use is uninitialized the first time it is reached after the function
810b57cec5SDimitry Andric     /// is called.
820b57cec5SDimitry Andric     AfterCall,
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric     /// The use is always uninitialized.
850b57cec5SDimitry Andric     Always
860b57cec5SDimitry Andric   };
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   /// Get the kind of uninitialized use.
getKind()890b57cec5SDimitry Andric   Kind getKind() const {
900b57cec5SDimitry Andric     return AlwaysUninit ? Always :
910b57cec5SDimitry Andric            UninitAfterCall ? AfterCall :
920b57cec5SDimitry Andric            UninitAfterDecl ? AfterDecl :
930b57cec5SDimitry Andric            !branch_empty() ? Sometimes : Maybe;
940b57cec5SDimitry Andric   }
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric   using branch_iterator = SmallVectorImpl<Branch>::const_iterator;
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   /// Branches which inevitably result in the variable being used uninitialized.
branch_begin()990b57cec5SDimitry Andric   branch_iterator branch_begin() const { return UninitBranches.begin(); }
branch_end()1000b57cec5SDimitry Andric   branch_iterator branch_end() const { return UninitBranches.end(); }
branch_empty()1010b57cec5SDimitry Andric   bool branch_empty() const { return UninitBranches.empty(); }
1020b57cec5SDimitry Andric };
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric class UninitVariablesHandler {
1050b57cec5SDimitry Andric public:
1060b57cec5SDimitry Andric   UninitVariablesHandler() = default;
1070b57cec5SDimitry Andric   virtual ~UninitVariablesHandler();
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   /// Called when the uninitialized variable is used at the given expression.
handleUseOfUninitVariable(const VarDecl * vd,const UninitUse & use)1100b57cec5SDimitry Andric   virtual void handleUseOfUninitVariable(const VarDecl *vd,
1110b57cec5SDimitry Andric                                          const UninitUse &use) {}
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   /// Called when the uninitialized variable is used as const refernce argument.
handleConstRefUseOfUninitVariable(const VarDecl * vd,const UninitUse & use)1140b57cec5SDimitry Andric   virtual void handleConstRefUseOfUninitVariable(const VarDecl *vd,
1150b57cec5SDimitry Andric                                                  const UninitUse &use) {}
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   /// Called when the uninitialized variable analysis detects the
1180b57cec5SDimitry Andric   /// idiom 'int x = x'.  All other uses of 'x' within the initializer
1190b57cec5SDimitry Andric   /// are handled by handleUseOfUninitVariable.
handleSelfInit(const VarDecl * vd)1200b57cec5SDimitry Andric   virtual void handleSelfInit(const VarDecl *vd) {}
1210b57cec5SDimitry Andric };
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric struct UninitVariablesAnalysisStats {
1240b57cec5SDimitry Andric   unsigned NumVariablesAnalyzed;
1250b57cec5SDimitry Andric   unsigned NumBlockVisits;
1260b57cec5SDimitry Andric };
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg,
1290b57cec5SDimitry Andric                                        AnalysisDeclContext &ac,
1300b57cec5SDimitry Andric                                        UninitVariablesHandler &handler,
1310b57cec5SDimitry Andric                                        UninitVariablesAnalysisStats &stats);
132 
133 } // namespace clang
134 
135 #endif // LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H
136