84 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "AssignmentInIfConditionCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/AST/RecursiveASTVisitor.h"12#include "clang/ASTMatchers/ASTMatchFinder.h"13 14using namespace clang::ast_matchers;15 16namespace clang::tidy::bugprone {17 18void AssignmentInIfConditionCheck::registerMatchers(MatchFinder *Finder) {19 Finder->addMatcher(translationUnitDecl(), this);20}21 22void AssignmentInIfConditionCheck::check(23 const ast_matchers::MatchFinder::MatchResult &Result) {24 class Visitor : public RecursiveASTVisitor<Visitor> {25 AssignmentInIfConditionCheck &Check;26 27 public:28 explicit Visitor(AssignmentInIfConditionCheck &Check) : Check(Check) {}29 bool VisitIfStmt(IfStmt *If) {30 class ConditionVisitor : public RecursiveASTVisitor<ConditionVisitor> {31 AssignmentInIfConditionCheck &Check;32 33 public:34 explicit ConditionVisitor(AssignmentInIfConditionCheck &Check)35 : Check(Check) {}36 37 // Dont traverse into any lambda expressions.38 bool TraverseLambdaExpr(LambdaExpr *, DataRecursionQueue * = nullptr) {39 return true;40 }41 42 // Dont traverse into any requires expressions.43 bool TraverseRequiresExpr(RequiresExpr *,44 DataRecursionQueue * = nullptr) {45 return true;46 }47 48 bool VisitBinaryOperator(BinaryOperator *BO) {49 if (BO->isAssignmentOp())50 Check.report(BO);51 return true;52 }53 54 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *OCE) {55 if (OCE->isAssignmentOp())56 Check.report(OCE);57 return true;58 }59 };60 61 ConditionVisitor(Check).TraverseStmt(If->getCond());62 return true;63 }64 };65 Visitor(*this).TraverseAST(*Result.Context);66}67 68void AssignmentInIfConditionCheck::report(const Expr *AssignmentExpr) {69 const SourceLocation OpLoc =70 isa<BinaryOperator>(AssignmentExpr)71 ? cast<BinaryOperator>(AssignmentExpr)->getOperatorLoc()72 : cast<CXXOperatorCallExpr>(AssignmentExpr)->getOperatorLoc();73 74 diag(OpLoc, "an assignment within an 'if' condition is bug-prone")75 << AssignmentExpr->getSourceRange();76 diag(OpLoc,77 "if it should be an assignment, move it out of the 'if' condition",78 DiagnosticIDs::Note);79 diag(OpLoc, "if it is meant to be an equality check, change '=' to '=='",80 DiagnosticIDs::Note);81}82 83} // namespace clang::tidy::bugprone84