Index: clang-tidy/misc/AssignOperatorReturnCheck.h =================================================================== --- /dev/null +++ clang-tidy/misc/AssignOperatorReturnCheck.h @@ -0,0 +1,33 @@ +//===--- AssignOperatorReturnCheck.h - clang-tidy----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSIGN_OPERATOR_RETURN_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSIGN_OPERATOR_RETURN_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace misc { + +/// Finds return statements in assign operator bodies where the return value is +/// different from '*this'. +class AssignOperatorReturnCheck : public ClangTidyCheck { +public: + AssignOperatorReturnCheck(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_ASSIGN_OPERATOR_RETURN_H Index: clang-tidy/misc/AssignOperatorReturnCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/misc/AssignOperatorReturnCheck.cpp @@ -0,0 +1,47 @@ +//===--- AssignOperatorReturnCheck.cpp - clang-tidy------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AssignOperatorReturnCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +void AssignOperatorReturnCheck::registerMatchers(MatchFinder *Finder) { + // Only register the matchers for C++; the functionality currently does not + // provide any benefit to other languages, despite being benign. + if (!getLangOpts().CPlusPlus) + return; + + const auto IsAssign = + cxxMethodDecl(hasName("operator="), ofClass(recordDecl().bind("class"))); + const auto HasGoodReturnType = cxxMethodDecl(returns( + lValueReferenceType(pointee(hasDeclaration(equalsBoundNode("class")))))); + const auto IsGoodAssign = cxxMethodDecl(IsAssign, HasGoodReturnType); + const auto IsBadReturn = + returnStmt(unless(has(unaryOperator(hasOperatorName("*"), + hasUnaryOperand(cxxThisExpr()))))); + Finder->addMatcher( + returnStmt(IsBadReturn, hasAncestor(IsGoodAssign)).bind("returnStmt"), + this); +} + +void AssignOperatorReturnCheck::check(const MatchFinder::MatchResult &Result) { + // FIXME: Add callback implementation. + const auto *RetStmt = Result.Nodes.getNodeAs("returnStmt"); + diag(RetStmt->getLocStart(), "operator=() should always return '*this'"); +} + +} // namespace misc +} // namespace tidy +} // namespace clang Index: clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tidy/misc/CMakeLists.txt +++ clang-tidy/misc/CMakeLists.txt @@ -3,6 +3,7 @@ add_clang_library(clangTidyMiscModule ArgumentCommentCheck.cpp AssertSideEffectCheck.cpp + AssignOperatorReturnCheck.cpp AssignOperatorSignatureCheck.cpp BoolPointerImplicitConversionCheck.cpp DefinitionsInHeadersCheck.cpp Index: clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tidy/misc/MiscTidyModule.cpp +++ clang-tidy/misc/MiscTidyModule.cpp @@ -12,6 +12,7 @@ #include "../ClangTidyModuleRegistry.h" #include "ArgumentCommentCheck.h" #include "AssertSideEffectCheck.h" +#include "AssignOperatorReturnCheck.h" #include "AssignOperatorSignatureCheck.h" #include "BoolPointerImplicitConversionCheck.h" #include "DefinitionsInHeadersCheck.h" @@ -50,6 +51,8 @@ CheckFactories.registerCheck("misc-argument-comment"); CheckFactories.registerCheck( "misc-assert-side-effect"); + CheckFactories.registerCheck( + "misc-assign-operator-return"); CheckFactories.registerCheck( "misc-assign-operator-signature"); CheckFactories.registerCheck( Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -48,6 +48,7 @@ llvm-twine-local misc-argument-comment misc-assert-side-effect + misc-assign-operator-return misc-assign-operator-signature misc-bool-pointer-implicit-conversion misc-definitions-in-headers Index: docs/clang-tidy/checks/misc-assign-operator-return.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/misc-assign-operator-return.rst @@ -0,0 +1,7 @@ +.. title:: clang-tidy - misc-assign-operator-return + +misc-assign-operator-return +=========================== + +Finds return statements in assign operator bodies where the return value is +different from '*this'. Index: test/clang-tidy/misc-assign-operator-return.cpp =================================================================== --- /dev/null +++ test/clang-tidy/misc-assign-operator-return.cpp @@ -0,0 +1,23 @@ +// RUN: %check_clang_tidy %s misc-assign-operator-return %t -- -- -std=c++11 =isystem %S/Inputs/Headers + +#include + +struct S { + int n; + + S& operator=(const S& rhs) { + n = rhs.n; + return *this; + } + + S& operator=(S&& rhs) { + n = std::move(rhs.n); + return rhs; +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should always return '*this' + } + + int operator=(int i) { + n = i; + return n; + } +};