forked from OSchip/llvm-project
[clangd] Improve PopulateSwitch tweak
- Support enums in C and ObjC as their AST representations differ slightly. - Add support for typedef'ed enums. Differential Revision: https://reviews.llvm.org/D110954
This commit is contained in:
parent
bfc8f9e9b0
commit
a90d57b6cc
|
@ -113,7 +113,8 @@ bool PopulateSwitch::prepare(const Selection &Sel) {
|
|||
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 @@ bool PopulateSwitch::prepare(const Selection &Sel) {
|
|||
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()));
|
||||
|
|
|
@ -23,6 +23,7 @@ TEST_F(PopulateSwitchTest, Test) {
|
|||
CodeContext Context;
|
||||
llvm::StringRef TestSource;
|
||||
llvm::StringRef ExpectedSource;
|
||||
llvm::StringRef FileName = "TestTU.cpp";
|
||||
};
|
||||
|
||||
Case Cases[]{
|
||||
|
@ -206,10 +207,43 @@ TEST_F(PopulateSwitchTest, Test) {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue