11 #include "clang/AST/RecursiveASTVisitor.h" 12 #include "clang/Lex/Lexer.h" 22 namespace readability {
26 StringRef getText(
const MatchFinder::MatchResult &Result, SourceRange
Range) {
27 return Lexer::getSourceText(CharSourceRange::getTokenRange(Range),
28 *Result.SourceManager,
29 Result.Context->getLangOpts());
33 StringRef getText(
const MatchFinder::MatchResult &Result, T &Node) {
34 return getText(Result, Node.getSourceRange());
37 const char ConditionThenStmtId[] =
"if-bool-yields-then";
38 const char ConditionElseStmtId[] =
"if-bool-yields-else";
39 const char TernaryId[] =
"ternary-bool-yields-condition";
40 const char TernaryNegatedId[] =
"ternary-bool-yields-not-condition";
41 const char IfReturnsBoolId[] =
"if-return";
42 const char IfReturnsNotBoolId[] =
"if-not-return";
43 const char ThenLiteralId[] =
"then-literal";
44 const char IfAssignVariableId[] =
"if-assign-lvalue";
45 const char IfAssignLocId[] =
"if-assign-loc";
46 const char IfAssignBoolId[] =
"if-assign";
47 const char IfAssignNotBoolId[] =
"if-assign-not";
48 const char IfAssignObjId[] =
"if-assign-obj";
49 const char CompoundReturnId[] =
"compound-return";
50 const char CompoundBoolId[] =
"compound-bool";
51 const char CompoundNotBoolId[] =
"compound-bool-not";
53 const char IfStmtId[] =
"if";
55 const char SimplifyOperatorDiagnostic[] =
56 "redundant boolean literal supplied to boolean operator";
57 const char SimplifyConditionDiagnostic[] =
58 "redundant boolean literal in if statement condition";
59 const char SimplifyConditionalReturnDiagnostic[] =
60 "redundant boolean literal in conditional return statement";
62 const CXXBoolLiteralExpr *getBoolLiteral(
const MatchFinder::MatchResult &Result,
64 const auto *Literal = Result.Nodes.getNodeAs<CXXBoolLiteralExpr>(Id);
65 return (Literal && Literal->getLocStart().isMacroID()) ?
nullptr : Literal;
68 internal::Matcher<Stmt> returnsBool(
bool Value, StringRef Id =
"ignored") {
69 auto SimpleReturnsBool =
70 returnStmt(has(cxxBoolLiteral(equals(Value)).bind(Id)))
71 .bind(
"returns-bool");
72 return anyOf(SimpleReturnsBool,
73 compoundStmt(statementCountIs(1), has(SimpleReturnsBool)));
76 bool needsParensAfterUnaryNegation(
const Expr *E) {
77 E = E->IgnoreImpCasts();
78 if (isa<BinaryOperator>(E) || isa<ConditionalOperator>(E))
81 if (
const auto *Op = dyn_cast<CXXOperatorCallExpr>(E))
82 return Op->getNumArgs() == 2 && Op->getOperator() != OO_Call &&
83 Op->getOperator() != OO_Subscript;
88 std::pair<BinaryOperatorKind, BinaryOperatorKind> Opposites[] = {
89 {BO_LT, BO_GE}, {BO_GT, BO_LE}, {BO_EQ, BO_NE}};
91 StringRef negatedOperator(
const BinaryOperator *BinOp) {
92 const BinaryOperatorKind Opcode = BinOp->getOpcode();
93 for (
auto NegatableOp : Opposites) {
94 if (Opcode == NegatableOp.first)
95 return BinOp->getOpcodeStr(NegatableOp.second);
96 if (Opcode == NegatableOp.second)
97 return BinOp->getOpcodeStr(NegatableOp.first);
102 std::pair<OverloadedOperatorKind, StringRef> OperatorNames[] = {
103 {OO_EqualEqual,
"=="}, {OO_ExclaimEqual,
"!="}, {OO_Less,
"<"},
104 {OO_GreaterEqual,
">="}, {OO_Greater,
">"}, {OO_LessEqual,
"<="}};
106 StringRef getOperatorName(OverloadedOperatorKind OpKind) {
107 for (
auto Name : OperatorNames) {
108 if (
Name.first == OpKind)
115 std::pair<OverloadedOperatorKind, OverloadedOperatorKind> OppositeOverloads[] =
116 {{OO_EqualEqual, OO_ExclaimEqual},
117 {OO_Less, OO_GreaterEqual},
118 {OO_Greater, OO_LessEqual}};
120 StringRef negatedOperator(
const CXXOperatorCallExpr *OpCall) {
121 const OverloadedOperatorKind Opcode = OpCall->getOperator();
122 for (
auto NegatableOp : OppositeOverloads) {
123 if (Opcode == NegatableOp.first)
124 return getOperatorName(NegatableOp.second);
125 if (Opcode == NegatableOp.second)
126 return getOperatorName(NegatableOp.first);
131 std::string asBool(StringRef text,
bool NeedsStaticCast) {
133 return (
"static_cast<bool>(" + text +
")").str();
138 bool needsNullPtrComparison(
const Expr *E) {
139 if (
const auto *ImpCast = dyn_cast<ImplicitCastExpr>(E))
140 return ImpCast->getCastKind() == CK_PointerToBoolean ||
141 ImpCast->getCastKind() == CK_MemberPointerToBoolean;
146 bool needsZeroComparison(
const Expr *E) {
147 if (
const auto *ImpCast = dyn_cast<ImplicitCastExpr>(E))
148 return ImpCast->getCastKind() == CK_IntegralToBoolean;
153 bool needsStaticCast(
const Expr *E) {
154 if (
const auto *ImpCast = dyn_cast<ImplicitCastExpr>(E)) {
155 if (ImpCast->getCastKind() == CK_UserDefinedConversion &&
156 ImpCast->getSubExpr()->getType()->isBooleanType()) {
157 if (
const auto *MemCall =
158 dyn_cast<CXXMemberCallExpr>(ImpCast->getSubExpr())) {
159 if (
const auto *MemDecl =
160 dyn_cast<CXXConversionDecl>(MemCall->getMethodDecl())) {
161 if (MemDecl->isExplicit())
168 E = E->IgnoreImpCasts();
169 return !E->getType()->isBooleanType();
172 std::string compareExpressionToConstant(
const MatchFinder::MatchResult &Result,
173 const Expr *E,
bool Negated,
174 const char *Constant) {
175 E = E->IgnoreImpCasts();
176 const std::string ExprText =
177 (isa<BinaryOperator>(E) ? (
"(" + getText(Result, *E) +
")")
178 : getText(Result, *E))
180 return ExprText +
" " + (Negated ?
"!=" :
"==") +
" " + Constant;
183 std::string compareExpressionToNullPtr(
const MatchFinder::MatchResult &Result,
184 const Expr *E,
bool Negated) {
185 const char *NullPtr =
186 Result.Context->getLangOpts().CPlusPlus11 ?
"nullptr" :
"NULL";
187 return compareExpressionToConstant(Result, E, Negated, NullPtr);
190 std::string compareExpressionToZero(
const MatchFinder::MatchResult &Result,
191 const Expr *E,
bool Negated) {
192 return compareExpressionToConstant(Result, E, Negated,
"0");
195 std::string replacementExpression(
const MatchFinder::MatchResult &Result,
196 bool Negated,
const Expr *E) {
197 E = E->ignoreParenBaseCasts();
198 if (
const auto *EC = dyn_cast<ExprWithCleanups>(E))
199 E = EC->getSubExpr();
201 const bool NeedsStaticCast = needsStaticCast(E);
203 if (
const auto *UnOp = dyn_cast<UnaryOperator>(E)) {
204 if (UnOp->getOpcode() == UO_LNot) {
205 if (needsNullPtrComparison(UnOp->getSubExpr()))
206 return compareExpressionToNullPtr(Result, UnOp->getSubExpr(),
true);
208 if (needsZeroComparison(UnOp->getSubExpr()))
209 return compareExpressionToZero(Result, UnOp->getSubExpr(),
true);
211 return replacementExpression(Result,
false, UnOp->getSubExpr());
215 if (needsNullPtrComparison(E))
216 return compareExpressionToNullPtr(Result, E,
false);
218 if (needsZeroComparison(E))
219 return compareExpressionToZero(Result, E,
false);
221 StringRef NegatedOperator;
222 const Expr *LHS =
nullptr;
223 const Expr *RHS =
nullptr;
224 if (
const auto *BinOp = dyn_cast<BinaryOperator>(E)) {
225 NegatedOperator = negatedOperator(BinOp);
226 LHS = BinOp->getLHS();
227 RHS = BinOp->getRHS();
228 }
else if (
const auto *OpExpr = dyn_cast<CXXOperatorCallExpr>(E)) {
229 if (OpExpr->getNumArgs() == 2) {
230 NegatedOperator = negatedOperator(OpExpr);
231 LHS = OpExpr->getArg(0);
232 RHS = OpExpr->getArg(1);
235 if (!NegatedOperator.empty() && LHS && RHS)
236 return (asBool((getText(Result, *LHS) +
" " + NegatedOperator +
" " +
237 getText(Result, *RHS))
241 StringRef
Text = getText(Result, *E);
242 if (!NeedsStaticCast && needsParensAfterUnaryNegation(E))
243 return (
"!(" + Text +
")").str();
245 if (needsNullPtrComparison(E))
246 return compareExpressionToNullPtr(Result, E,
false);
248 if (needsZeroComparison(E))
249 return compareExpressionToZero(Result, E,
false);
251 return (
"!" + asBool(Text, NeedsStaticCast));
254 if (
const auto *UnOp = dyn_cast<UnaryOperator>(E)) {
255 if (UnOp->getOpcode() == UO_LNot) {
256 if (needsNullPtrComparison(UnOp->getSubExpr()))
257 return compareExpressionToNullPtr(Result, UnOp->getSubExpr(),
false);
259 if (needsZeroComparison(UnOp->getSubExpr()))
260 return compareExpressionToZero(Result, UnOp->getSubExpr(),
false);
264 if (needsNullPtrComparison(E))
265 return compareExpressionToNullPtr(Result, E,
true);
267 if (needsZeroComparison(E))
268 return compareExpressionToZero(Result, E,
true);
270 return asBool(getText(Result, *E), NeedsStaticCast);
273 const CXXBoolLiteralExpr *stmtReturnsBool(
const ReturnStmt *Ret,
bool Negated) {
274 if (
const auto *Bool = dyn_cast<CXXBoolLiteralExpr>(Ret->getRetValue())) {
275 if (Bool->getValue() == !Negated)
282 const CXXBoolLiteralExpr *stmtReturnsBool(
const IfStmt *IfRet,
bool Negated) {
283 if (IfRet->getElse() !=
nullptr)
286 if (
const auto *Ret = dyn_cast<ReturnStmt>(IfRet->getThen()))
287 return stmtReturnsBool(Ret, Negated);
289 if (
const auto *Compound = dyn_cast<CompoundStmt>(IfRet->getThen())) {
290 if (Compound->size() == 1) {
291 if (
const auto *CompoundRet = dyn_cast<ReturnStmt>(Compound->body_back()))
292 return stmtReturnsBool(CompoundRet, Negated);
299 bool containsDiscardedTokens(
const MatchFinder::MatchResult &Result,
300 CharSourceRange CharRange) {
301 std::string ReplacementText =
302 Lexer::getSourceText(CharRange, *Result.SourceManager,
303 Result.Context->getLangOpts())
305 Lexer Lex(CharRange.getBegin(), Result.Context->getLangOpts(),
306 ReplacementText.data(), ReplacementText.data(),
307 ReplacementText.data() + ReplacementText.size());
308 Lex.SetCommentRetentionState(
true);
311 while (!Lex.LexFromRawLexer(Tok)) {
312 if (Tok.is(tok::TokenKind::comment) || Tok.is(tok::TokenKind::hash))
322 using Base = RecursiveASTVisitor<Visitor>;
326 const MatchFinder::MatchResult &Result)
327 : Check(Check), Result(Result) {}
330 Check->reportBinOp(Result, Op);
336 const MatchFinder::MatchResult &Result;
340 SimplifyBooleanExprCheck::SimplifyBooleanExprCheck(StringRef
Name,
343 ChainedConditionalReturn(Options.get(
"ChainedConditionalReturn", 0U)),
344 ChainedConditionalAssignment(
345 Options.get(
"ChainedConditionalAssignment", 0U)) {}
350 E = E->IgnoreParenImpCasts();
351 if (isa<CXXBoolLiteralExpr>(E))
353 if (
const auto *BinOp = dyn_cast<BinaryOperator>(E))
356 if (
const auto *UnaryOp = dyn_cast<UnaryOperator>(E))
361 void SimplifyBooleanExprCheck::reportBinOp(
362 const MatchFinder::MatchResult &Result,
const BinaryOperator *Op) {
363 const auto *LHS = Op->getLHS()->IgnoreParenImpCasts();
364 const auto *RHS = Op->getRHS()->IgnoreParenImpCasts();
366 const CXXBoolLiteralExpr *Bool =
nullptr;
367 const Expr *Other =
nullptr;
368 if ((Bool = dyn_cast<CXXBoolLiteralExpr>(LHS)))
370 else if ((Bool = dyn_cast<CXXBoolLiteralExpr>(RHS)))
375 if (Bool->getLocStart().isMacroID())
382 bool BoolValue = Bool->getValue();
384 auto replaceWithExpression = [
this, &Result, LHS, RHS, Bool](
385 const Expr *ReplaceWith,
bool Negated) {
386 std::string Replacement =
387 replacementExpression(Result, Negated, ReplaceWith);
388 SourceRange
Range(LHS->getLocStart(), RHS->getLocEnd());
389 issueDiag(Result, Bool->getLocStart(), SimplifyOperatorDiagnostic,
Range,
393 switch (Op->getOpcode()) {
397 replaceWithExpression(Other,
false);
400 replaceWithExpression(Bool,
false);
406 replaceWithExpression(Bool,
false);
409 replaceWithExpression(Other,
false);
414 replaceWithExpression(Other, !BoolValue);
418 replaceWithExpression(Other, BoolValue);
425 void SimplifyBooleanExprCheck::matchBoolCondition(MatchFinder *Finder,
427 StringRef BooleanId) {
429 ifStmt(isExpansionInMainFile(),
430 hasCondition(cxxBoolLiteral(equals(Value)).bind(BooleanId)))
435 void SimplifyBooleanExprCheck::matchTernaryResult(MatchFinder *Finder,
437 StringRef TernaryId) {
439 conditionalOperator(isExpansionInMainFile(),
440 hasTrueExpression(cxxBoolLiteral(equals(Value))),
441 hasFalseExpression(cxxBoolLiteral(equals(!Value))))
446 void SimplifyBooleanExprCheck::matchIfReturnsBool(MatchFinder *Finder,
447 bool Value, StringRef Id) {
448 if (ChainedConditionalReturn)
449 Finder->addMatcher(ifStmt(isExpansionInMainFile(),
450 hasThen(returnsBool(Value, ThenLiteralId)),
451 hasElse(returnsBool(!Value)))
455 Finder->addMatcher(ifStmt(isExpansionInMainFile(),
456 unless(hasParent(ifStmt())),
457 hasThen(returnsBool(Value, ThenLiteralId)),
458 hasElse(returnsBool(!Value)))
463 void SimplifyBooleanExprCheck::matchIfAssignsBool(MatchFinder *Finder,
464 bool Value, StringRef Id) {
465 auto SimpleThen = binaryOperator(
466 hasOperatorName(
"="),
467 hasLHS(declRefExpr(hasDeclaration(decl().bind(IfAssignObjId)))),
468 hasLHS(expr().bind(IfAssignVariableId)),
469 hasRHS(cxxBoolLiteral(equals(Value)).bind(IfAssignLocId)));
470 auto Then = anyOf(SimpleThen, compoundStmt(statementCountIs(1),
471 hasAnySubstatement(SimpleThen)));
472 auto SimpleElse = binaryOperator(
473 hasOperatorName(
"="),
474 hasLHS(declRefExpr(hasDeclaration(equalsBoundNode(IfAssignObjId)))),
475 hasRHS(cxxBoolLiteral(equals(!Value))));
476 auto Else = anyOf(SimpleElse, compoundStmt(statementCountIs(1),
477 hasAnySubstatement(SimpleElse)));
478 if (ChainedConditionalAssignment)
480 ifStmt(isExpansionInMainFile(), hasThen(Then), hasElse(Else)).bind(Id),
483 Finder->addMatcher(ifStmt(isExpansionInMainFile(),
484 unless(hasParent(ifStmt())), hasThen(Then),
490 void SimplifyBooleanExprCheck::matchCompoundIfReturnsBool(MatchFinder *Finder,
494 compoundStmt(allOf(hasAnySubstatement(ifStmt(hasThen(returnsBool(Value)),
495 unless(hasElse(stmt())))),
497 returnStmt(has(ignoringParenImpCasts(
498 cxxBoolLiteral(equals(!Value)))))
499 .bind(CompoundReturnId))))
505 Options.
store(Opts,
"ChainedConditionalReturn", ChainedConditionalReturn);
507 ChainedConditionalAssignment);
511 Finder->addMatcher(translationUnitDecl().bind(
"top"),
this);
513 matchBoolCondition(Finder,
true, ConditionThenStmtId);
514 matchBoolCondition(Finder,
false, ConditionElseStmtId);
516 matchTernaryResult(Finder,
true, TernaryId);
517 matchTernaryResult(Finder,
false, TernaryNegatedId);
519 matchIfReturnsBool(Finder,
true, IfReturnsBoolId);
520 matchIfReturnsBool(Finder,
false, IfReturnsNotBoolId);
522 matchIfAssignsBool(Finder,
true, IfAssignBoolId);
523 matchIfAssignsBool(Finder,
false, IfAssignNotBoolId);
525 matchCompoundIfReturnsBool(Finder,
true, CompoundBoolId);
526 matchCompoundIfReturnsBool(Finder,
false, CompoundNotBoolId);
530 if (
const CXXBoolLiteralExpr *TrueConditionRemoved =
531 getBoolLiteral(Result, ConditionThenStmtId))
532 replaceWithThenStatement(Result, TrueConditionRemoved);
533 else if (
const CXXBoolLiteralExpr *FalseConditionRemoved =
534 getBoolLiteral(Result, ConditionElseStmtId))
535 replaceWithElseStatement(Result, FalseConditionRemoved);
536 else if (
const auto *Ternary =
537 Result.Nodes.getNodeAs<ConditionalOperator>(TernaryId))
538 replaceWithCondition(Result, Ternary);
539 else if (
const auto *TernaryNegated =
540 Result.Nodes.getNodeAs<ConditionalOperator>(TernaryNegatedId))
541 replaceWithCondition(Result, TernaryNegated,
true);
542 else if (
const auto *If = Result.Nodes.getNodeAs<IfStmt>(IfReturnsBoolId))
543 replaceWithReturnCondition(Result, If);
544 else if (
const auto *IfNot =
545 Result.Nodes.getNodeAs<IfStmt>(IfReturnsNotBoolId))
546 replaceWithReturnCondition(Result, IfNot,
true);
547 else if (
const auto *IfAssign =
548 Result.Nodes.getNodeAs<IfStmt>(IfAssignBoolId))
549 replaceWithAssignment(Result, IfAssign);
550 else if (
const auto *IfAssignNot =
551 Result.Nodes.getNodeAs<IfStmt>(IfAssignNotBoolId))
552 replaceWithAssignment(Result, IfAssignNot,
true);
553 else if (
const auto *Compound =
554 Result.Nodes.getNodeAs<CompoundStmt>(CompoundBoolId))
555 replaceCompoundReturnWithCondition(Result, Compound);
556 else if (
const auto *Compound =
557 Result.Nodes.getNodeAs<CompoundStmt>(CompoundNotBoolId))
558 replaceCompoundReturnWithCondition(Result, Compound,
true);
559 else if (
const auto TU = Result.Nodes.getNodeAs<Decl>(
"top"))
560 Visitor(
this, Result).TraverseDecl(const_cast<Decl*>(TU));
563 void SimplifyBooleanExprCheck::issueDiag(
564 const ast_matchers::MatchFinder::MatchResult &Result, SourceLocation
Loc,
565 StringRef Description, SourceRange ReplacementRange,
566 StringRef Replacement) {
567 CharSourceRange CharRange =
568 Lexer::makeFileCharRange(CharSourceRange::getTokenRange(ReplacementRange),
571 DiagnosticBuilder Diag =
diag(Loc, Description);
572 if (!containsDiscardedTokens(Result, CharRange))
573 Diag << FixItHint::CreateReplacement(CharRange, Replacement);
576 void SimplifyBooleanExprCheck::replaceWithThenStatement(
577 const MatchFinder::MatchResult &Result,
578 const CXXBoolLiteralExpr *TrueConditionRemoved) {
579 const auto *IfStatement = Result.Nodes.getNodeAs<IfStmt>(IfStmtId);
580 issueDiag(Result, TrueConditionRemoved->getLocStart(),
581 SimplifyConditionDiagnostic, IfStatement->getSourceRange(),
582 getText(Result, *IfStatement->getThen()));
585 void SimplifyBooleanExprCheck::replaceWithElseStatement(
586 const MatchFinder::MatchResult &Result,
587 const CXXBoolLiteralExpr *FalseConditionRemoved) {
588 const auto *IfStatement = Result.Nodes.getNodeAs<IfStmt>(IfStmtId);
589 const Stmt *ElseStatement = IfStatement->getElse();
590 issueDiag(Result, FalseConditionRemoved->getLocStart(),
591 SimplifyConditionDiagnostic, IfStatement->getSourceRange(),
592 ElseStatement ? getText(Result, *ElseStatement) :
"");
595 void SimplifyBooleanExprCheck::replaceWithCondition(
596 const MatchFinder::MatchResult &Result,
const ConditionalOperator *Ternary,
598 std::string Replacement =
599 replacementExpression(Result, Negated, Ternary->getCond());
600 issueDiag(Result, Ternary->getTrueExpr()->getLocStart(),
601 "redundant boolean literal in ternary expression result",
602 Ternary->getSourceRange(), Replacement);
605 void SimplifyBooleanExprCheck::replaceWithReturnCondition(
606 const MatchFinder::MatchResult &Result,
const IfStmt *If,
bool Negated) {
607 StringRef Terminator = isa<CompoundStmt>(If->getElse()) ?
";" :
"";
608 std::string Condition = replacementExpression(Result, Negated, If->getCond());
609 std::string Replacement = (
"return " + Condition + Terminator).str();
610 SourceLocation Start =
611 Result.Nodes.getNodeAs<CXXBoolLiteralExpr>(ThenLiteralId)->getLocStart();
612 issueDiag(Result, Start, SimplifyConditionalReturnDiagnostic,
613 If->getSourceRange(), Replacement);
616 void SimplifyBooleanExprCheck::replaceCompoundReturnWithCondition(
617 const MatchFinder::MatchResult &Result,
const CompoundStmt *Compound,
619 const auto *Ret = Result.Nodes.getNodeAs<ReturnStmt>(CompoundReturnId);
627 assert(Compound->size() >= 2);
628 const IfStmt *BeforeIf =
nullptr;
629 CompoundStmt::const_body_iterator Current = Compound->body_begin();
630 CompoundStmt::const_body_iterator After = Compound->body_begin();
631 for (++After; After != Compound->body_end() && *Current != Ret;
632 ++Current, ++After) {
633 if (
const auto *If = dyn_cast<IfStmt>(*Current)) {
634 if (
const CXXBoolLiteralExpr *Lit = stmtReturnsBool(If, Negated)) {
636 if (!ChainedConditionalReturn && BeforeIf)
639 const Expr *Condition = If->getCond();
640 std::string Replacement =
641 "return " + replacementExpression(Result, Negated, Condition);
643 Result, Lit->getLocStart(), SimplifyConditionalReturnDiagnostic,
644 SourceRange(If->getLocStart(), Ret->getLocEnd()), Replacement);
656 void SimplifyBooleanExprCheck::replaceWithAssignment(
657 const MatchFinder::MatchResult &Result,
const IfStmt *IfAssign,
659 SourceRange Range = IfAssign->getSourceRange();
660 StringRef VariableName =
661 getText(Result, *Result.Nodes.getNodeAs<Expr>(IfAssignVariableId));
662 StringRef Terminator = isa<CompoundStmt>(IfAssign->getElse()) ?
";" :
"";
663 std::string Condition =
664 replacementExpression(Result, Negated, IfAssign->getCond());
665 std::string Replacement =
666 (VariableName +
" = " + Condition + Terminator).str();
668 Result.Nodes.getNodeAs<CXXBoolLiteralExpr>(IfAssignLocId)->getLocStart();
669 issueDiag(Result, Location,
670 "redundant boolean literal in conditional assignment", Range,
SourceLocation Loc
'#' location in the include directive
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
bool containsBoolLiteral(const Expr *E)
LangOptions getLangOpts() const
Returns the language options from the context.
Visitor(SimplifyBooleanExprCheck *Check, const MatchFinder::MatchResult &Result)
void storeOptions(ClangTidyOptions::OptionMap &Options) override
Should store all options supported by this check with their current values or default values for opti...
bool VisitBinaryOperator(BinaryOperator *Op)
Looks for boolean expressions involving boolean constants and simplifies them to use the appropriate ...
Base class for all clang-tidy checks.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
std::map< std::string, std::string > OptionMap
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
CharSourceRange Range
SourceRange for the file name.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.