1 //=- UninitializedValues.h - Finding uses of uninitialized values -*- 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 APIs for invoking and reported uninitialized values
10 // warnings.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H
15 #define LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H
16 
17 #include "clang/Basic/LLVM.h"
18 #include "llvm/ADT/SmallVector.h"
19 
20 namespace clang {
21 
22 class AnalysisDeclContext;
23 class CFG;
24 class DeclContext;
25 class Expr;
26 class Stmt;
27 class VarDecl;
28 
29 /// A use of a variable, which might be uninitialized.
30 class UninitUse {
31 public:
32   struct Branch {
33     const Stmt *Terminator;
34     unsigned Output;
35   };
36 
37 private:
38   /// The expression which uses this variable.
39   const Expr *User;
40 
41   /// Is this use uninitialized whenever the function is called?
42   bool UninitAfterCall = false;
43 
44   /// Is this use uninitialized whenever the variable declaration is reached?
45   bool UninitAfterDecl = false;
46 
47   /// Does this use always see an uninitialized value?
48   bool AlwaysUninit;
49 
50   /// This use is always uninitialized if it occurs after any of these branches
51   /// is taken.
52   SmallVector<Branch, 2> UninitBranches;
53 
54 public:
UninitUse(const Expr * User,bool AlwaysUninit)55   UninitUse(const Expr *User, bool AlwaysUninit)
56       : User(User), AlwaysUninit(AlwaysUninit) {}
57 
addUninitBranch(Branch B)58   void addUninitBranch(Branch B) {
59     UninitBranches.push_back(B);
60   }
61 
setUninitAfterCall()62   void setUninitAfterCall() { UninitAfterCall = true; }
setUninitAfterDecl()63   void setUninitAfterDecl() { UninitAfterDecl = true; }
64 
65   /// Get the expression containing the uninitialized use.
getUser()66   const Expr *getUser() const { return User; }
67 
68   /// The kind of uninitialized use.
69   enum Kind {
70     /// The use might be uninitialized.
71     Maybe,
72 
73     /// The use is uninitialized whenever a certain branch is taken.
74     Sometimes,
75 
76     /// The use is uninitialized the first time it is reached after we reach
77     /// the variable's declaration.
78     AfterDecl,
79 
80     /// The use is uninitialized the first time it is reached after the function
81     /// is called.
82     AfterCall,
83 
84     /// The use is always uninitialized.
85     Always
86   };
87 
88   /// Get the kind of uninitialized use.
getKind()89   Kind getKind() const {
90     return AlwaysUninit ? Always :
91            UninitAfterCall ? AfterCall :
92            UninitAfterDecl ? AfterDecl :
93            !branch_empty() ? Sometimes : Maybe;
94   }
95 
96   using branch_iterator = SmallVectorImpl<Branch>::const_iterator;
97 
98   /// Branches which inevitably result in the variable being used uninitialized.
branch_begin()99   branch_iterator branch_begin() const { return UninitBranches.begin(); }
branch_end()100   branch_iterator branch_end() const { return UninitBranches.end(); }
branch_empty()101   bool branch_empty() const { return UninitBranches.empty(); }
102 };
103 
104 class UninitVariablesHandler {
105 public:
106   UninitVariablesHandler() = default;
107   virtual ~UninitVariablesHandler();
108 
109   /// Called when the uninitialized variable is used at the given expression.
handleUseOfUninitVariable(const VarDecl * vd,const UninitUse & use)110   virtual void handleUseOfUninitVariable(const VarDecl *vd,
111                                          const UninitUse &use) {}
112 
113   /// Called when the uninitialized variable is used as const refernce argument.
handleConstRefUseOfUninitVariable(const VarDecl * vd,const UninitUse & use)114   virtual void handleConstRefUseOfUninitVariable(const VarDecl *vd,
115                                                  const UninitUse &use) {}
116 
117   /// Called when the uninitialized variable analysis detects the
118   /// idiom 'int x = x'.  All other uses of 'x' within the initializer
119   /// are handled by handleUseOfUninitVariable.
handleSelfInit(const VarDecl * vd)120   virtual void handleSelfInit(const VarDecl *vd) {}
121 };
122 
123 struct UninitVariablesAnalysisStats {
124   unsigned NumVariablesAnalyzed;
125   unsigned NumBlockVisits;
126 };
127 
128 void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg,
129                                        AnalysisDeclContext &ac,
130                                        UninitVariablesHandler &handler,
131                                        UninitVariablesAnalysisStats &stats);
132 
133 } // namespace clang
134 
135 #endif // LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H
136