[cfe-commits] r113447 - in /cfe/trunk: include/clang/AST/Stmt.h lib/Sema/SemaStmt.cpp lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp
Ted Kremenek
kremenek at apple.com
Wed Sep 8 17:05:53 PDT 2010
Author: kremenek
Date: Wed Sep 8 19:05:53 2010
New Revision: 113447
URL: http://llvm.org/viewvc/llvm-project?rev=113447&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/Stmt.h
cfe/trunk/lib/Sema/SemaStmt.cpp
cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
Modified: cfe/trunk/include/clang/AST/Stmt.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=113447&r1=113446&r2=113447&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Stmt.h (original)
+++ cfe/trunk/include/clang/AST/Stmt.h Wed Sep 8 19:05:53 2010
@@ -662,6 +662,11 @@
SwitchCase *FirstCase;
SourceLocation SwitchLoc;
+ /// If the SwitchStmt is a switch on an enum value, this records whether
+ /// all the enum values were covered by CaseStmts. This value is meant to
+ /// be a hint for possible clients.
+ unsigned AllEnumCasesCovered : 1;
+
public:
SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond);
@@ -709,6 +714,19 @@
SC->setNextSwitchCase(FirstCase);
FirstCase = SC;
}
+
+ /// Set a flag in the SwitchStmt indicating that if the 'switch (X)' is a
+ /// switch over an enum value then all cases have been explicitly covered.
+ void setAllEnumCasesCovered() {
+ AllEnumCasesCovered = 1;
+ }
+
+ /// Returns true if the SwitchStmt is a switch of an enum value and all cases
+ /// have been explicitly covered.
+ bool isAllEnumCasesCovered() const {
+ return (bool) AllEnumCasesCovered;
+ }
+
virtual SourceRange getSourceRange() const {
return SourceRange(SwitchLoc, SubExprs[BODY]->getLocEnd());
}
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=113447&r1=113446&r2=113447&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Wed Sep 8 19:05:53 2010
@@ -696,14 +696,14 @@
}
// 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 @@
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 @@
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();
}
}
Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=113447&r1=113446&r2=113447&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Wed Sep 8 19:05:53 2010
@@ -239,6 +239,9 @@
S->setCond(Reader.ReadSubExpr());
S->setBody(Reader.ReadSubStmt());
S->setSwitchLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ if (Record[Idx++])
+ S->setAllEnumCasesCovered();
+
SwitchCase *PrevSC = 0;
for (unsigned N = Record.size(); Idx != N; ++Idx) {
SwitchCase *SC = Reader.getSwitchCaseWithID(Record[Idx]);
Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=113447&r1=113446&r2=113447&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Wed Sep 8 19:05:53 2010
@@ -233,6 +233,7 @@
Writer.AddStmt(S->getCond());
Writer.AddStmt(S->getBody());
Writer.AddSourceLocation(S->getSwitchLoc(), Record);
+ Record.push_back(S->isAllEnumCasesCovered());
for (SwitchCase *SC = S->getSwitchCaseList(); SC;
SC = SC->getNextSwitchCase())
Record.push_back(Writer.RecordSwitchCaseID(SC));
More information about the cfe-commits
mailing list