[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