diff options
author | Ted Kremenek <kremenek@apple.com> | 2010-09-09 00:05:53 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2010-09-09 00:05:53 +0000 |
commit | 559fb554602bedb57dbbf3cc14ac8a38264b4547 (patch) | |
tree | b104938f48e69198ff5051b9ff456497ddd395f8 /lib/Sema/SemaStmt.cpp | |
parent | 1efb6c716397f2c4e3ede3a4853c5efebb375441 (diff) |
When building SwitchStmts in Sema, record whether all the enum values of a switch(enum) where
covered by individual case statements. Flow-based analyses may wish to consult this information,
and recording this in the AST allows us to obviate reconstructing this information later when
we build the CFG.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@113447 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaStmt.cpp')
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 82 |
1 files changed, 47 insertions, 35 deletions
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 083e4dba85..fa23654e0d 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -696,14 +696,14 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, } // Check to see if switch is over an Enum and handles all of its - // values. We don't need to do this if there's a default - // statement or if we have a constant condition. + // values. We only issue a warning if there is not 'default:', but + // we still do the analysis to preserve this information in the AST + // (which can be used by flow-based analyes). // - // TODO: we might want to check whether case values are out of the - // enum even if we don't want to check whether all cases are handled. const EnumType* ET = CondTypeBeforePromotion->getAs<EnumType>(); + // If switch has default case, then ignore it. - if (!CaseListIsErroneous && !TheDefaultStmt && !HasConstantCond && ET) { + if (!CaseListIsErroneous && !HasConstantCond && ET) { const EnumDecl *ED = ET->getDecl(); typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy; EnumValsTy EnumVals; @@ -723,40 +723,46 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals); EnumValsTy::iterator EIend = std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals); - // See which case values aren't in enum - EnumValsTy::const_iterator EI = EnumVals.begin(); - for (CaseValsTy::const_iterator CI = CaseVals.begin(); + + // See which case values aren't in enum. + // TODO: we might want to check whether case values are out of the + // enum even if we don't want to check whether all cases are handled. + if (!TheDefaultStmt) { + EnumValsTy::const_iterator EI = EnumVals.begin(); + for (CaseValsTy::const_iterator CI = CaseVals.begin(); CI != CaseVals.end(); CI++) { - while (EI != EIend && EI->first < CI->first) - EI++; - if (EI == EIend || EI->first > CI->first) + while (EI != EIend && EI->first < CI->first) + EI++; + if (EI == EIend || EI->first > CI->first) Diag(CI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum) << ED->getDeclName(); - } - // See which of case ranges aren't in enum - EI = EnumVals.begin(); - for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); + } + // See which of case ranges aren't in enum + EI = EnumVals.begin(); + for (CaseRangesTy::const_iterator RI = CaseRanges.begin(); RI != CaseRanges.end() && EI != EIend; RI++) { - while (EI != EIend && EI->first < RI->first) - EI++; + while (EI != EIend && EI->first < RI->first) + EI++; - if (EI == EIend || EI->first != RI->first) { - Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum) - << ED->getDeclName(); - } - - llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context); - while (EI != EIend && EI->first < Hi) - EI++; - if (EI == EIend || EI->first != Hi) - Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum) - << ED->getDeclName(); + if (EI == EIend || EI->first != RI->first) { + Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum) + << ED->getDeclName(); + } + + llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context); + while (EI != EIend && EI->first < Hi) + EI++; + if (EI == EIend || EI->first != Hi) + Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum) + << ED->getDeclName(); + } } - //Check which enum vals aren't in switch + // Check which enum vals aren't in switch CaseValsTy::const_iterator CI = CaseVals.begin(); CaseRangesTy::const_iterator RI = CaseRanges.begin(); - EI = EnumVals.begin(); - for (; EI != EIend; EI++) { + bool hasCasesNotInSwitch = false; + + for (EnumValsTy::const_iterator EI = EnumVals.begin(); EI != EIend; EI++){ //Drop unneeded case values llvm::APSInt CIVal; while (CI != CaseVals.end() && CI->first < EI->first) @@ -765,17 +771,23 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, if (CI != CaseVals.end() && CI->first == EI->first) continue; - //Drop unneeded case ranges + // Drop unneeded case ranges for (; RI != CaseRanges.end(); RI++) { llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context); if (EI->first <= Hi) break; } - if (RI == CaseRanges.end() || EI->first < RI->first) - Diag(CondExpr->getExprLoc(), diag::warn_missing_cases) - << EI->second->getDeclName(); + if (RI == CaseRanges.end() || EI->first < RI->first) { + hasCasesNotInSwitch = true; + if (!TheDefaultStmt) + Diag(CondExpr->getExprLoc(), diag::warn_missing_cases) + << EI->second->getDeclName(); + } } + + if (!hasCasesNotInSwitch) + SS->setAllEnumCasesCovered(); } } |