From: Chandler Carruth Date: Tue, 5 Apr 2011 18:18:05 +0000 (+0000) Subject: Begin refactoring the uninitialized warning code that I uglied up. This X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4c4983bbd2904670a25c840b07600f14efbafd7f;p=clang Begin refactoring the uninitialized warning code that I uglied up. This extracts a function to handle the emission of the diagnostic separately from the walking over the set of uninitialized uses. Also updates the naming used within this extracted function to be a bit more consistent with the rest of Clang's naming patterns. The next step will be breaking this apart so that we can go through different functions rather than tracking so many boolean variables. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@128898 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index df73fc6da3..bd5416f5f7 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -410,6 +410,98 @@ public: }; } +static void DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, + const Expr *E, bool &fixitIssued, + bool isAlwaysUninit) { + bool isSelfInit = false; + + if (const DeclRefExpr *DRE = dyn_cast(E)) { + if (isAlwaysUninit) { + // Inspect the initializer of the variable declaration which is + // being referenced prior to its initialization. We emit + // specialized diagnostics for self-initialization, and we + // specifically avoid warning about self references which take the + // form of: + // + // int x = x; + // + // This is used to indicate to GCC that 'x' is intentionally left + // uninitialized. Proven code paths which access 'x' in + // an uninitialized state after this will still warn. + // + // TODO: Should we suppress maybe-uninitialized warnings for + // variables initialized in this way? + if (const Expr *Initializer = VD->getInit()) { + if (DRE == Initializer->IgnoreParenImpCasts()) + return; + + ContainsReference CR(S.Context, DRE); + CR.Visit(const_cast(Initializer)); + isSelfInit = CR.doesContainReference(); + } + if (isSelfInit) { + S.Diag(DRE->getLocStart(), + diag::warn_uninit_self_reference_in_init) + << VD->getDeclName() << VD->getLocation() << DRE->getSourceRange(); + } else { + S.Diag(DRE->getLocStart(), diag::warn_uninit_var) + << VD->getDeclName() << DRE->getSourceRange(); + } + } else { + S.Diag(DRE->getLocStart(), diag::warn_maybe_uninit_var) + << VD->getDeclName() << DRE->getSourceRange(); + } + } else { + const BlockExpr *BE = cast(E); + S.Diag(BE->getLocStart(), + isAlwaysUninit ? diag::warn_uninit_var_captured_by_block + : diag::warn_maybe_uninit_var_captured_by_block) + << VD->getDeclName(); + } + + // Report where the variable was declared when the use wasn't within + // the initializer of that declaration. + if (!isSelfInit) + S.Diag(VD->getLocStart(), diag::note_uninit_var_def) + << VD->getDeclName(); + + // Only report the fixit once. + if (fixitIssued) + return; + + fixitIssued = true; + + // Don't issue a fixit if there is already an initializer. + if (VD->getInit()) + return; + + // Suggest possible initialization (if any). + const char *initialization = 0; + QualType VariableTy = VD->getType().getCanonicalType(); + + if (VariableTy->getAs()) { + // Check if 'nil' is defined. + if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) + initialization = " = nil"; + else + initialization = " = 0"; + } + else if (VariableTy->isRealFloatingType()) + initialization = " = 0.0"; + else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) + initialization = " = false"; + else if (VariableTy->isEnumeralType()) + return; + else if (VariableTy->isScalarType()) + initialization = " = 0"; + + if (initialization) { + SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd()); + S.Diag(loc, diag::note_var_fixit_add_initialization) + << FixItHint::CreateInsertion(loc, initialization); + } +} + typedef std::pair UninitUse; namespace { @@ -461,98 +553,9 @@ public: std::sort(vec->begin(), vec->end(), SLocSort()); for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; ++vi) - { - const bool isAlwaysUninit = vi->second; - bool isSelfInit = false; - - if (const DeclRefExpr *dr = dyn_cast(vi->first)) { - if (isAlwaysUninit) { - // Inspect the initializer of the variable declaration which is - // being referenced prior to its initialization. We emit - // specialized diagnostics for self-initialization, and we - // specifically avoid warning about self references which take the - // form of: - // - // int x = x; - // - // This is used to indicate to GCC that 'x' is intentionally left - // uninitialized. Proven code paths which access 'x' in - // an uninitialized state after this will still warn. - // - // TODO: Should we suppress maybe-uninitialized warnings for - // variables initialized in this way? - if (const Expr *E = vd->getInit()) { - if (dr == E->IgnoreParenImpCasts()) - continue; - - ContainsReference CR(S.Context, dr); - CR.Visit(const_cast(E)); - isSelfInit = CR.doesContainReference(); - } - if (isSelfInit) { - S.Diag(dr->getLocStart(), - diag::warn_uninit_self_reference_in_init) - << vd->getDeclName() << vd->getLocation() << dr->getSourceRange(); - } else { - S.Diag(dr->getLocStart(), diag::warn_uninit_var) - << vd->getDeclName() << dr->getSourceRange(); - } - } - else { - S.Diag(dr->getLocStart(), diag::warn_maybe_uninit_var) - << vd->getDeclName() << dr->getSourceRange(); - } - } - else { - const BlockExpr *be = cast(vi->first); - S.Diag(be->getLocStart(), - isAlwaysUninit ? diag::warn_uninit_var_captured_by_block - : diag::warn_maybe_uninit_var_captured_by_block) - << vd->getDeclName(); - } - - // Report where the variable was declared when the use wasn't within - // the initializer of that declaration. - if (!isSelfInit) - S.Diag(vd->getLocStart(), diag::note_uninit_var_def) - << vd->getDeclName(); - - // Only report the fixit once. - if (fixitIssued) - continue; - - fixitIssued = true; - - // Don't issue a fixit if there is already an initializer. - if (vd->getInit()) - continue; + DiagnoseUninitializedUse(S, vd, vi->first, fixitIssued, + /*isAlwaysUninit=*/vi->second); - // Suggest possible initialization (if any). - const char *initialization = 0; - QualType vdTy = vd->getType().getCanonicalType(); - - if (vdTy->getAs()) { - // Check if 'nil' is defined. - if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) - initialization = " = nil"; - else - initialization = " = 0"; - } - else if (vdTy->isRealFloatingType()) - initialization = " = 0.0"; - else if (vdTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) - initialization = " = false"; - else if (vdTy->isEnumeralType()) - continue; - else if (vdTy->isScalarType()) - initialization = " = 0"; - - if (initialization) { - SourceLocation loc = S.PP.getLocForEndOfToken(vd->getLocEnd()); - S.Diag(loc, diag::note_var_fixit_add_initialization) - << FixItHint::CreateInsertion(loc, initialization); - } - } delete vec; } delete uses;