30 const SourceManager &SM,
31 const LangOptions &LangOpts) {
32 if (If->getLParenLoc().isMacroID() || If->getRParenLoc().isMacroID())
35 const SourceRange HeaderRange(If->getLParenLoc(), If->getRParenLoc());
38 if (Lexer::makeFileCharRange(CharSourceRange::getTokenRange(HeaderRange), SM,
46getBraceFix(
const Stmt *S,
const LangOptions &LangOpts,
const SourceManager &SM,
47 SourceLocation StartLoc,
48 SourceLocation EndLocHint = SourceLocation()) {
49 if (!S || isa<CompoundStmt>(S))
51 if (isa<AttributedStmt, LabelStmt, SwitchCase>(S))
56 if (!Hints || !Hints.offersFixIts())
59 return BraceFix{
true, Hints};
70 const auto IsConstantEvaluatedCall =
71 callExpr(callee(functionDecl(hasName(
"is_constant_evaluated"),
74 const auto IsNegatedConstantEvaluatedExpr =
75 unaryOperator(hasOperatorName(
"!"),
76 hasUnaryOperand(ignoringParens(IsConstantEvaluatedCall)))
78 const auto IsConstantEvaluatedExpr = ignoringParenImpCasts(
79 anyOf(IsConstantEvaluatedCall, IsNegatedConstantEvaluatedExpr));
82 ifStmt(unless(isConstexpr()),
83 anyOf(hasCondition(IsConstantEvaluatedExpr),
84 hasConditionVariableStatement(declStmt(hasSingleDecl(
85 varDecl(hasInitializer(IsConstantEvaluatedExpr)))))))
91 const auto *If = Result.Nodes.getNodeAs<IfStmt>(
"if");
92 const auto *Call = Result.Nodes.getNodeAs<CallExpr>(
"call");
93 assert(If && Call &&
"expected to match an if statement and its call");
95 const bool IsNegated = Result.Nodes.getNodeAs<UnaryOperator>(
"negation");
96 const llvm::StringRef ConstevalClause =
97 IsNegated ?
"!consteval" :
"consteval";
98 const SourceLocation DiagLoc =
99 Result.SourceManager->getExpansionLoc(Call->getExprLoc());
101 const auto Diag = diag(DiagLoc,
"use 'if %0' instead of checking "
102 "'std::is_constant_evaluated()'")
105 if (If->hasInitStorage() || If->hasVarStorage())
108 std::optional<SourceRange> HeaderRange =
113 std::optional<BraceFix> ThenBraceFix =
114 getBraceFix(If->getThen(), getLangOpts(), *Result.SourceManager,
115 If->getRParenLoc(), If->getElseLoc());
119 std::optional<BraceFix> ElseBraceFix = BraceFix();
121 ElseBraceFix =
getBraceFix(If->getElse(), getLangOpts(),
122 *Result.SourceManager, If->getElseLoc());
128 If->getLParenLoc(), *Result.SourceManager);
129 const std::string HeaderReplacement = [&] {
130 std::string Replacement = ConstevalClause.str();
131 if (NeedsLeadingSpace)
132 Replacement.insert(0, 1,
' ');
133 if (ThenBraceFix->NeedsBraces)
137 Diag << FixItHint::CreateReplacement(*HeaderRange, HeaderReplacement);
139 if (ThenBraceFix->NeedsBraces)
140 Diag << ThenBraceFix->Hints.closingBraceFixIt();
142 if (ElseBraceFix && ElseBraceFix->NeedsBraces)
143 Diag << ElseBraceFix->Hints.openingBraceFixIt()
144 << ElseBraceFix->Hints.closingBraceFixIt();
BraceInsertionHints getBraceInsertionsHints(const Stmt *const S, const LangOptions &LangOpts, const SourceManager &SM, SourceLocation StartLoc, SourceLocation EndLocHint)
Create fix-it hints for braces that wrap the given statement when applied.