10#include "../utils/Aliasing.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
14#include "clang/Lex/Lexer.h"
32 const VarDecl *Var, ASTContext *Context) {
33 ExprMutationAnalyzer MutAn(*S, *Context);
34 const auto &SM = Context->getSourceManager();
35 const Stmt *MutS = MutAn.findMutation(Var);
37 SM.isBeforeInTranslationUnit(PrevS->getEndLoc(),
38 MutS->getBeginLoc()) &&
39 SM.isBeforeInTranslationUnit(MutS->getEndLoc(), NextS->getBeginLoc());
43 const auto ImmutableVar =
44 varDecl(anyOf(parmVarDecl(), hasLocalStorage()), hasType(isInteger()),
45 unless(hasType(isVolatileQualified())))
52 hasOperatorName(
"&&"),
53 hasEitherOperand(declRefExpr(hasDeclaration(ImmutableVar))
55 hasThen(hasDescendant(
56 ifStmt(hasCondition(anyOf(
57 declRefExpr(hasDeclaration(
61 hasAnyOperatorName(
"&&",
"||"),
63 declRefExpr(hasDeclaration(varDecl(
67 forFunction(functionDecl().bind(
FuncStr)))
74 const auto *OuterIf = Result.Nodes.getNodeAs<IfStmt>(
OuterIfStr);
75 const auto *InnerIf = Result.Nodes.getNodeAs<IfStmt>(
InnerIfStr);
76 const auto *CondVar = Result.Nodes.getNodeAs<VarDecl>(
CondVarStr);
77 const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>(
FuncStr);
79 const DeclRefExpr *OuterIfVar =
nullptr, *InnerIfVar =
nullptr;
84 if (
const auto *Outer = Result.Nodes.getNodeAs<DeclRefExpr>(
OuterIfVar1Str))
89 if (OuterIfVar && InnerIfVar) {
90 if (
isChangedBefore(OuterIf->getThen(), InnerIfVar, OuterIfVar, CondVar,
94 if (
isChangedBefore(OuterIf->getCond(), InnerIfVar, OuterIfVar, CondVar,
102 if (hasPtrOrReferenceInFunc(Func, CondVar))
105 auto Diag =
diag(InnerIf->getBeginLoc(),
"redundant condition %0") << CondVar;
109 const auto *BinOpCond =
110 dyn_cast<BinaryOperator>(InnerIf->getCond()->IgnoreParenImpCasts());
112 if (isa<DeclRefExpr>(InnerIf->getCond()->IgnoreParenImpCasts()) ||
113 (BinOpCond && BinOpCond->getOpcode() == BO_LOr)) {
114 SourceLocation IfBegin = InnerIf->getBeginLoc();
115 const Stmt *Body = InnerIf->getThen();
116 const Expr *OtherSide =
nullptr;
118 const auto *LeftDRE =
119 dyn_cast<DeclRefExpr>(BinOpCond->getLHS()->IgnoreParenImpCasts());
120 if (LeftDRE && LeftDRE->getDecl() == CondVar)
121 OtherSide = BinOpCond->getRHS();
123 OtherSide = BinOpCond->getLHS();
126 SourceLocation IfEnd = Body->getBeginLoc().getLocWithOffset(-1);
129 if (isa<CompoundStmt>(Body))
130 IfEnd = Body->getBeginLoc();
133 if (OtherSide && OtherSide->HasSideEffects(*Result.Context)) {
134 SourceLocation BeforeOtherSide =
135 OtherSide->getBeginLoc().getLocWithOffset(-1);
136 SourceLocation AfterOtherSide =
137 Lexer::findNextToken(OtherSide->getEndLoc(), *Result.SourceManager,
140 Diag << FixItHint::CreateRemoval(
141 CharSourceRange::getTokenRange(IfBegin, BeforeOtherSide))
142 << FixItHint::CreateInsertion(AfterOtherSide,
";")
143 << FixItHint::CreateRemoval(
144 CharSourceRange::getTokenRange(AfterOtherSide, IfEnd));
146 Diag << FixItHint::CreateRemoval(
147 CharSourceRange::getTokenRange(IfBegin, IfEnd));
151 if (isa<CompoundStmt>(Body))
152 Diag << FixItHint::CreateRemoval(
153 CharSourceRange::getTokenRange(Body->getEndLoc(), Body->getEndLoc()));
159 cast<BinaryOperator>(InnerIf->getCond()->IgnoreParenImpCasts());
160 const auto *LeftDRE =
161 dyn_cast<DeclRefExpr>(CondOp->getLHS()->IgnoreParenImpCasts());
162 if (LeftDRE && LeftDRE->getDecl() == CondVar) {
163 SourceLocation BeforeRHS =
164 CondOp->getRHS()->getBeginLoc().getLocWithOffset(-1);
165 Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
166 CondOp->getLHS()->getBeginLoc(), BeforeRHS));
168 SourceLocation AfterLHS =
169 Lexer::findNextToken(CondOp->getLHS()->getEndLoc(),
172 Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
173 AfterLHS, CondOp->getRHS()->getEndLoc()));
std::pair< Context, Canceler > Inner
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
const LangOptions & getLangOpts() const
Returns the language options from the context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
static const char OuterIfStr[]
static const char CondVarStr[]
static const char InnerIfStr[]
static const char InnerIfVar1Str[]
static const char InnerIfVar2Str[]
static const char OuterIfVar2Str[]
static bool isChangedBefore(const Stmt *S, const Stmt *NextS, const Stmt *PrevS, const VarDecl *Var, ASTContext *Context)
Returns whether Var is changed in range (PrevS..NextS).
static const char FuncStr[]
static const char OuterIfVar1Str[]
bool hasPtrOrReferenceInFunc(const Decl *Func, const VarDecl *Var)
Returns whether Var has a pointer or reference in Func.