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