36#include "clang/AST/Decl.h"
37#include "clang/AST/Stmt.h"
38#include "clang/AST/Type.h"
39#include "clang/Basic/SourceLocation.h"
40#include "clang/Basic/SourceManager.h"
41#include "clang/Tooling/Core/Replacement.h"
42#include "llvm/ADT/MapVector.h"
43#include "llvm/ADT/STLExtras.h"
50class PopulateSwitch :
public Tweak {
51 const char *id()
const override;
52 bool prepare(
const Selection &Sel)
override;
53 Expected<Effect> apply(
const Selection &Sel)
override;
54 std::string title()
const override {
return "Populate switch"; }
55 llvm::StringLiteral kind()
const override {
62 ExpectedCase(
const EnumConstantDecl *
Decl) : Data(
Decl, false) {}
63 bool isCovered()
const {
return Data.getInt(); }
64 void setCovered(
bool Val =
true) { Data.setInt(Val); }
65 const EnumConstantDecl *getEnumConstant()
const {
66 return Data.getPointer();
70 llvm::PointerIntPair<const EnumConstantDecl *, 1, bool> Data;
73 const DeclContext *DeclCtx =
nullptr;
74 const SwitchStmt *Switch =
nullptr;
75 const CompoundStmt *Body =
nullptr;
76 const EnumType *EnumT =
nullptr;
77 const EnumDecl *EnumD =
nullptr;
80 llvm::MapVector<llvm::APSInt, ExpectedCase> ExpectedCases;
85bool PopulateSwitch::prepare(
const Selection &Sel) {
86 const SelectionTree::Node *CA = Sel.ASTSelection.commonAncestor();
96 Switch = CA->ASTNode.get<SwitchStmt>();
98 if (
const SelectionTree::Node *
Parent = CA->outerImplicit().Parent)
99 Switch =
Parent->ASTNode.get<SwitchStmt>();
104 Body = llvm::dyn_cast_or_null<CompoundStmt>(Switch->getBody());
107 DeclCtx = &CA->getDeclContext();
110 const Expr *Cond = Switch->getCond();
114 Cond = Cond->IgnoreParenImpCasts();
116 EnumT = Cond->getType().getCanonicalType()->getAsAdjusted<EnumType>();
119 EnumD = EnumT->getDecl();
120 if (!EnumD || EnumD->isDependentType())
127 ASTContext &Ctx = Sel.AST->getASTContext();
129 unsigned EnumIntWidth = Ctx.getIntWidth(QualType(EnumT, 0));
130 bool EnumIsSigned = EnumT->isSignedIntegerOrEnumerationType();
132 auto Normalize = [&](llvm::APSInt Val) {
133 Val = Val.extOrTrunc(EnumIntWidth);
134 Val.setIsSigned(EnumIsSigned);
139 ExpectedCases.insert(
143 for (
const SwitchCase *CaseList = Switch->getSwitchCaseList(); CaseList;
144 CaseList = CaseList->getNextSwitchCase()) {
146 if (isa<DefaultStmt>(CaseList))
149 const CaseStmt *CS = cast<CaseStmt>(CaseList);
152 if (CS->caseStmtIsGNURange())
159 if (
auto *DRE = dyn_cast<DeclRefExpr>(CS->getLHS()->IgnoreParenCasts())) {
160 if (
auto *Enumerator = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
161 auto Iter = ExpectedCases.find(Normalize(Enumerator->getInitVal()));
162 if (Iter != ExpectedCases.end())
163 Iter->second.setCovered();
173 const ConstantExpr *
CE = dyn_cast<ConstantExpr>(CS->getLHS());
174 if (!
CE ||
CE->isValueDependent())
179 if (
CE->getResultStorageKind() == ConstantResultStorageKind::None)
181 auto Iter = ExpectedCases.find(Normalize(
CE->getResultAsAPSInt()));
182 if (Iter != ExpectedCases.end())
183 Iter->second.setCovered();
186 return !llvm::all_of(ExpectedCases,
187 [](
auto &Pair) {
return Pair.second.isCovered(); });
190Expected<Tweak::Effect> PopulateSwitch::apply(
const Selection &Sel) {
191 ASTContext &Ctx = Sel.AST->getASTContext();
193 SourceLocation
Loc = Body->getRBracLoc();
194 ASTContext &DeclASTCtx = DeclCtx->getParentASTContext();
196 llvm::SmallString<256>
Text;
203 if (EnumD->isScoped())
204 Text.append({EnumD->getName(),
"::"});
208 assert(!
Text.empty() &&
"No enumerators to insert!");
211 const SourceManager &SM = Ctx.getSourceManager();
212 return Effect::mainFileEdit(
213 SM, tooling::Replacements(tooling::Replacement(SM,
Loc, 0,
Text)));
const FunctionDecl * Decl
#define REGISTER_TWEAK(Subclass)
std::string getQualification(ASTContext &Context, const DeclContext *DestContext, SourceLocation InsertionPoint, const NamedDecl *ND)
Gets the nested name specifier necessary for spelling ND in DestContext, at InsertionPoint.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static const llvm::StringLiteral QUICKFIX_KIND