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