xref: /freebsd/contrib/llvm-project/clang/include/clang/Analysis/Analyses/UninitializedValues.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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   /// Is this use a const reference to this variable?
51   bool ConstRefUse = false;
52 
53   /// Is this use a const pointer to this variable?
54   bool ConstPtrUse = false;
55 
56   /// This use is always uninitialized if it occurs after any of these branches
57   /// is taken.
58   SmallVector<Branch, 2> UninitBranches;
59 
60 public:
UninitUse(const Expr * User,bool AlwaysUninit)61   UninitUse(const Expr *User, bool AlwaysUninit)
62       : User(User), AlwaysUninit(AlwaysUninit) {}
63 
addUninitBranch(Branch B)64   void addUninitBranch(Branch B) {
65     UninitBranches.push_back(B);
66   }
67 
setUninitAfterCall()68   void setUninitAfterCall() { UninitAfterCall = true; }
setUninitAfterDecl()69   void setUninitAfterDecl() { UninitAfterDecl = true; }
setConstRefUse()70   void setConstRefUse() { ConstRefUse = true; }
setConstPtrUse()71   void setConstPtrUse() { ConstPtrUse = true; }
72 
73   /// Get the expression containing the uninitialized use.
getUser()74   const Expr *getUser() const { return User; }
75 
isConstRefUse()76   bool isConstRefUse() const { return ConstRefUse; }
isConstPtrUse()77   bool isConstPtrUse() const { return ConstPtrUse; }
isConstRefOrPtrUse()78   bool isConstRefOrPtrUse() const { return ConstRefUse || ConstPtrUse; }
79 
80   /// The kind of uninitialized use.
81   enum Kind {
82     /// The use might be uninitialized.
83     Maybe,
84 
85     /// The use is uninitialized whenever a certain branch is taken.
86     Sometimes,
87 
88     /// The use is uninitialized the first time it is reached after we reach
89     /// the variable's declaration.
90     AfterDecl,
91 
92     /// The use is uninitialized the first time it is reached after the function
93     /// is called.
94     AfterCall,
95 
96     /// The use is always uninitialized.
97     Always
98   };
99 
100   /// Get the kind of uninitialized use.
getKind()101   Kind getKind() const {
102     return AlwaysUninit ? Always :
103            UninitAfterCall ? AfterCall :
104            UninitAfterDecl ? AfterDecl :
105            !branch_empty() ? Sometimes : Maybe;
106   }
107 
108   using branch_iterator = SmallVectorImpl<Branch>::const_iterator;
109 
110   /// Branches which inevitably result in the variable being used uninitialized.
branch_begin()111   branch_iterator branch_begin() const { return UninitBranches.begin(); }
branch_end()112   branch_iterator branch_end() const { return UninitBranches.end(); }
branch_empty()113   bool branch_empty() const { return UninitBranches.empty(); }
114 };
115 
116 class UninitVariablesHandler {
117 public:
118   UninitVariablesHandler() = default;
119   virtual ~UninitVariablesHandler();
120 
121   /// Called when the uninitialized variable is used at the given expression.
handleUseOfUninitVariable(const VarDecl * vd,const UninitUse & use)122   virtual void handleUseOfUninitVariable(const VarDecl *vd,
123                                          const UninitUse &use) {}
124 
125   /// Called when the uninitialized variable analysis detects the
126   /// idiom 'int x = x'.  All other uses of 'x' within the initializer
127   /// are handled by handleUseOfUninitVariable.
handleSelfInit(const VarDecl * vd)128   virtual void handleSelfInit(const VarDecl *vd) {}
129 };
130 
131 struct UninitVariablesAnalysisStats {
132   unsigned NumVariablesAnalyzed;
133   unsigned NumBlockVisits;
134 };
135 
136 void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg,
137                                        AnalysisDeclContext &ac,
138                                        UninitVariablesHandler &handler,
139                                        UninitVariablesAnalysisStats &stats);
140 
141 } // namespace clang
142 
143 #endif // LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H
144