dodohand created this revision. Herald added subscribers: carlosgalvezp, mgorny. Herald added a project: All. dodohand requested review of this revision. Herald added a project: clang-tools-extra. Herald added a subscriber: cfe-commits.
new clang-tidy checker for assignments with the condition clause of an 'if' statement. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D127114 Files: clang-tools-extra/clang-tidy/misc/AssignmentInIfClauseCheck.cpp clang-tools-extra/clang-tidy/misc/AssignmentInIfClauseCheck.h clang-tools-extra/clang-tidy/misc/CMakeLists.txt clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/list.rst clang-tools-extra/docs/clang-tidy/checks/misc-assignment-in-if-clause.rst clang-tools-extra/test/clang-tidy/checkers/misc-assignment-in-if-clause.cpp
Index: clang-tools-extra/test/clang-tidy/checkers/misc-assignment-in-if-clause.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/misc-assignment-in-if-clause.cpp @@ -0,0 +1,122 @@ +// RUN: %check_clang_tidy %s misc-assignment-in-if-clause %t + +// Add something that triggers the check here. +void f(int arg) +{ + int f = 3; + if(( f = arg ) || ( f == (arg + 1))) +// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Assignment detected within if statement. Fix to equality check if this was accidental. Consider moving out of if statement if intentional. [misc-assignment-in-if-clause] + { + f = 5; + } +} + +void f1(int arg) +{ + int f = 3; + if(( f == arg ) || ( f = (arg + 1))) +// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: Assignment detected within if statement. Fix to equality check if this was accidental. Consider moving out of if statement if intentional. [misc-assignment-in-if-clause] + { + f = 5; + } +} + +void f2(int arg) +{ + int f = 3; + if( f = arg ) +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: Assignment detected within if statement. Fix to equality check if this was accidental. Consider moving out of if statement if intentional. [misc-assignment-in-if-clause] + { + f = 5; + } +} + +volatile int v = 32; + +void f3(int arg) +{ + int f = 3; + if(( f == arg ) || (( arg + 6 < f ) && ( f = v ))) +// CHECK-MESSAGES: :[[@LINE-1]]:44: warning: Assignment detected within if statement. Fix to equality check if this was accidental. Consider moving out of if statement if intentional. [misc-assignment-in-if-clause] + { + f = 5; + } +} + +void f4(int arg) +{ + int f = 3; + if(( f == arg ) || (( arg + 6 < f ) && (( f = v ) || (f < 8)))) +// CHECK-MESSAGES: :[[@LINE-1]]:45: warning: Assignment detected within if statement. Fix to equality check if this was accidental. Consider moving out of if statement if intentional. [misc-assignment-in-if-clause] + { + f = 5; + } + else if(( arg + 8 < f ) && ((f = v) || (f < 8))) +// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: Assignment detected within if statement. Fix to equality check if this was accidental. Consider moving out of if statement if intentional. [misc-assignment-in-if-clause] + { + f = 6; + } +} + +class BrokenOperator +{ +public: + int d = 0; + int operator = (const int &val) + { + d = val + 1; + return d; + } +}; + +void f5(int arg) +{ + BrokenOperator bo; + int f = 3; + bo = f; + if(bo.d == 3) + { + f = 6; + } + if(bo = 3) +// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Assignment detected within if statement. Fix to equality check if this was accidental. Consider moving out of if statement if intentional. [misc-assignment-in-if-clause] + { + f = 7; + } + if((arg == 3) || (bo = 6)) +// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: Assignment detected within if statement. Fix to equality check if this was accidental. Consider moving out of if statement if intentional. [misc-assignment-in-if-clause] + { + f = 8; + } + v = f; +} + +// Add something that doesn't trigger the check here. +void awesome_f2(int arg) +{ + int f = 3; + if(( f == arg ) || ( f == (arg + 1))) + { + f = 5; + } +} + +void awesome_f3(int arg) +{ + int f = 3; + if( f == arg ) + { + f = 5; + } +} + +void awesome_f4(int arg) +{ + int f = 3; + if(( f == arg ) || (( arg + 6 < f ) && (( f == v ) || (f < 8)))) + { + f = 5; + } +} + + Index: clang-tools-extra/docs/clang-tidy/checks/misc-assignment-in-if-clause.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/misc-assignment-in-if-clause.rst @@ -0,0 +1,27 @@ +.. title:: clang-tidy - misc-assignment-in-if-clause + +misc-assignment-in-if-clause +============================ + +Finds assignments within the condition of `if` statements. +Allows automatic identification of assignments which may have been intended as equality tests. +Finds these assignments even within multiple sets of parentheses which is often appropriate to structure multi-part condition statements. +Finds these assignments even within multiple sets of paretheses which disables the compiler -Wparentheses check which one would otherwise like to rely on to find accidental assignment. +The identified assignments violate BARR group "Rule 8.2.c". See: https://barrgroup.com/embedded-systems/books/embedded-c-coding-standard/statement-rules/if-else-statements + +Also finds these assignments when they're actually calling an overridden `=` operator rather than a plain-old assign. + + +.. code-block:: c++ + + static volatile int f = 3; + if( f = 4 ) // This is identified - should it have been: `if ( f == 4 )` ? + { + f = f + 1; + } + + if(( f == 5 ) || ( f = 6 )) // the assignment here `( f = 6 )` is identified - should it have been `( f == 6 )' ? + { + f = f + 2; + } + Index: clang-tools-extra/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -213,6 +213,7 @@ `llvmlibc-callee-namespace <llvmlibc-callee-namespace.html>`_, `llvmlibc-implementation-in-namespace <llvmlibc-implementation-in-namespace.html>`_, `llvmlibc-restrict-system-libc-headers <llvmlibc-restrict-system-libc-headers.html>`_, "Yes" + `misc-assignment-in-if-clause <misc-assignment-in-if-clause.html>`_, "Yes" `misc-definitions-in-headers <misc-definitions-in-headers.html>`_, "Yes" `misc-misleading-bidirectional <misc-misleading-bidirectional.html>`_, `misc-misleading-identifier <misc-misleading-identifier.html>`_, Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -123,6 +123,11 @@ Warns when the code is unwrapping a `std::optional<T>`, `absl::optional<T>`, or `base::Optional<T>` object without assuring that it contains a value. +- New :doc:`misc-assignment-in-if-clause + <clang-tidy/checks/misc-assignment-in-if-clause>` check. + + Warns when there is an assignment within an if statement condition expression. + - New :doc:`modernize-macro-to-enum <clang-tidy/checks/modernize-macro-to-enum>` check. Index: clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -9,6 +9,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "AssignmentInIfClauseCheck.h" #include "DefinitionsInHeadersCheck.h" #include "MisleadingBidirectional.h" #include "MisleadingIdentifier.h" @@ -33,6 +34,8 @@ class MiscModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck<AssignmentInIfClauseCheck>( + "misc-assignment-in-if-clause"); CheckFactories.registerCheck<DefinitionsInHeadersCheck>( "misc-definitions-in-headers"); CheckFactories.registerCheck<MisleadingBidirectionalCheck>( Index: clang-tools-extra/clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -4,6 +4,7 @@ ) add_clang_library(clangTidyMiscModule + AssignmentInIfClauseCheck.cpp DefinitionsInHeadersCheck.cpp MiscTidyModule.cpp MisleadingBidirectional.cpp Index: clang-tools-extra/clang-tidy/misc/AssignmentInIfClauseCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/misc/AssignmentInIfClauseCheck.h @@ -0,0 +1,34 @@ +//===--- AssignmentInIfClauseCheck.h - clang-tidy ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSIGNMENTINIFCLAUSECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSIGNMENTINIFCLAUSECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace misc { + +/// Catches assignments within the condition clause of an if statement. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc-assignment-in-if-clause.html +class AssignmentInIfClauseCheck : public ClangTidyCheck { +public: + AssignmentInIfClauseCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSIGNMENTINIFCLAUSECHECK_H Index: clang-tools-extra/clang-tidy/misc/AssignmentInIfClauseCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/misc/AssignmentInIfClauseCheck.cpp @@ -0,0 +1,45 @@ +//===--- AssignmentInIfClauseCheck.cpp - clang-tidy -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "AssignmentInIfClauseCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +void AssignmentInIfClauseCheck::registerMatchers(MatchFinder *Finder) { + // Scott Added this one + Finder->addMatcher(ifStmt(hasCondition(forEachDescendant( + binaryOperator(isAssignmentOperator()) + .bind("assignment_in_if_statement")))), + this); + Finder->addMatcher(ifStmt(hasCondition(forEachDescendant( + cxxOperatorCallExpr(isAssignmentOperator()) + .bind("assignment_in_if_statement")))), + this); +} + +void AssignmentInIfClauseCheck::check(const MatchFinder::MatchResult &Result) { + // Add callback implementation. + const auto *MatchedDecl = + Result.Nodes.getNodeAs<clang::Stmt>("assignment_in_if_statement"); + if (!MatchedDecl) { + return; + } + diag(MatchedDecl->getBeginLoc(), + "Assignment detected within if statement. Fix to equality check if this " + "was accidental. Consider moving out of if statement if intentional."); +} + +} // namespace misc +} // namespace tidy +} // namespace clang
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits