This revision was automatically updated to reflect the committed changes.
Closed by commit rGa90d57b6cc5f: [clangd] Improve PopulateSwitch tweak 
(authored by dgoldman).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D110954/new/

https://reviews.llvm.org/D110954

Files:
  clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp
  clang-tools-extra/clangd/unittests/tweaks/PopulateSwitchTests.cpp

Index: clang-tools-extra/clangd/unittests/tweaks/PopulateSwitchTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/tweaks/PopulateSwitchTests.cpp
+++ clang-tools-extra/clangd/unittests/tweaks/PopulateSwitchTests.cpp
@@ -23,6 +23,7 @@
     CodeContext Context;
     llvm::StringRef TestSource;
     llvm::StringRef ExpectedSource;
+    llvm::StringRef FileName = "TestTU.cpp";
   };
 
   Case Cases[]{
@@ -206,10 +207,43 @@
           R""(template<typename T> void f() {enum Enum {A}; ^switch (A) {}})"",
           "unavailable",
       },
+      {// C: Only filling in missing enumerators
+       Function,
+       R""(
+            enum CEnum {A,B,C};
+            enum CEnum val = A;
+            ^switch (val) {case B:break;}
+          )"",
+       R""(
+            enum CEnum {A,B,C};
+            enum CEnum val = A;
+            switch (val) {case B:break;case A:case C:break;}
+          )"",
+       "TestTU.c"},
+      {// C: Only filling in missing enumerators w/ typedefs
+       Function,
+       R""(
+            typedef unsigned long UInteger;
+            enum ControlState : UInteger;
+            typedef enum ControlState ControlState;
+            enum ControlState : UInteger {A,B,C};
+            ControlState controlState = A;
+            switch (^controlState) {case A:break;}
+          )"",
+       R""(
+            typedef unsigned long UInteger;
+            enum ControlState : UInteger;
+            typedef enum ControlState ControlState;
+            enum ControlState : UInteger {A,B,C};
+            ControlState controlState = A;
+            switch (controlState) {case A:break;case B:case C:break;}
+          )"",
+       "TestTU.c"},
   };
 
   for (const auto &Case : Cases) {
     Context = Case.Context;
+    FileName = Case.FileName;
     EXPECT_EQ(apply(Case.TestSource), Case.ExpectedSource);
   }
 }
Index: clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp
===================================================================
--- clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp
+++ clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp
@@ -113,7 +113,8 @@
     return false;
   // Ignore implicit casts, since enums implicitly cast to integer types.
   Cond = Cond->IgnoreParenImpCasts();
-  EnumT = Cond->getType()->getAsAdjusted<EnumType>();
+  // Get the canonical type to handle typedefs.
+  EnumT = Cond->getType().getCanonicalType()->getAsAdjusted<EnumType>();
   if (!EnumT)
     return false;
   EnumD = EnumT->getDecl();
@@ -152,14 +153,30 @@
     if (CS->caseStmtIsGNURange())
       return false;
 
+    // Support for direct references to enum constants. This is required to
+    // support C and ObjC which don't contain values in their ConstantExprs.
+    // The general way to get the value of a case is EvaluateAsRValue, but we'd
+    // rather not deal with that in case the AST is broken.
+    if (auto *DRE = dyn_cast<DeclRefExpr>(CS->getLHS()->IgnoreParenCasts())) {
+      if (auto *Enumerator = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
+        auto Iter = ExpectedCases.find(Normalize(Enumerator->getInitVal()));
+        if (Iter != ExpectedCases.end())
+          Iter->second.setCovered();
+        continue;
+      }
+    }
+
+    // ConstantExprs with values are expected for C++, otherwise the storage
+    // kind will be None.
+
     // Case expression is not a constant expression or is value-dependent,
     // so we may not be able to work out which cases are covered.
     const ConstantExpr *CE = dyn_cast<ConstantExpr>(CS->getLHS());
     if (!CE || CE->isValueDependent())
       return false;
 
-    // Unsure if this case could ever come up, but prevents an unreachable
-    // executing in getResultAsAPSInt.
+    // We need a stored value in order to continue; currently both C and ObjC
+    // enums won't have one.
     if (CE->getResultStorageKind() == ConstantExpr::RSK_None)
       return false;
     auto Iter = ExpectedCases.find(Normalize(CE->getResultAsAPSInt()));
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to