Skip to content

Commit

Permalink
[clang-tidy] New: checker misc-unconventional-assign-operator replaci…
Browse files Browse the repository at this point in the history
…ng misc-assign-operator-signature

Summary: Finds return statements in assign operator bodies where the return value is different from '*this'. Only assignment operators with correct return value Class& are checked.

Reviewers: aaron.ballman, alexfh, sbenza

Subscribers: o.gyorgy, baloghadamsoftware, LegalizeAdulthood, aaron.ballman, Eugene.Zelenko, xazax.hun, cfe-commits

Differential Revision: http://reviews.llvm.org/D18265

llvm-svn: 268492
  • Loading branch information
Xazax-hun committed May 4, 2016
1 parent 4807f82 commit 112d1e8
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 49 deletions.
Expand Up @@ -10,7 +10,7 @@
#include "../ClangTidy.h"
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
#include "../misc/AssignOperatorSignatureCheck.h"
#include "../misc/UnconventionalAssignOperatorCheck.h"
#include "InterfacesGlobalInitCheck.h"
#include "ProBoundsArrayToPointerDecayCheck.h"
#include "ProBoundsConstantArrayIndexCheck.h"
Expand Down Expand Up @@ -53,7 +53,7 @@ class CppCoreGuidelinesModule : public ClangTidyModule {
"cppcoreguidelines-pro-type-union-access");
CheckFactories.registerCheck<ProTypeVarargCheck>(
"cppcoreguidelines-pro-type-vararg");
CheckFactories.registerCheck<misc::AssignOperatorSignatureCheck>(
CheckFactories.registerCheck<misc::UnconventionalAssignOperatorCheck>(
"cppcoreguidelines-c-copy-assignment-signature");
}
};
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clang-tidy/misc/CMakeLists.txt
Expand Up @@ -3,7 +3,7 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTidyMiscModule
ArgumentCommentCheck.cpp
AssertSideEffectCheck.cpp
AssignOperatorSignatureCheck.cpp
UnconventionalAssignOperatorCheck.cpp
BoolPointerImplicitConversionCheck.cpp
DanglingHandleCheck.cpp
DefinitionsInHeadersCheck.cpp
Expand Down
6 changes: 3 additions & 3 deletions clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
Expand Up @@ -12,7 +12,7 @@
#include "../ClangTidyModuleRegistry.h"
#include "ArgumentCommentCheck.h"
#include "AssertSideEffectCheck.h"
#include "AssignOperatorSignatureCheck.h"
#include "UnconventionalAssignOperatorCheck.h"
#include "BoolPointerImplicitConversionCheck.h"
#include "DanglingHandleCheck.h"
#include "DefinitionsInHeadersCheck.h"
Expand Down Expand Up @@ -61,8 +61,8 @@ class MiscModule : public ClangTidyModule {
CheckFactories.registerCheck<ArgumentCommentCheck>("misc-argument-comment");
CheckFactories.registerCheck<AssertSideEffectCheck>(
"misc-assert-side-effect");
CheckFactories.registerCheck<AssignOperatorSignatureCheck>(
"misc-assign-operator-signature");
CheckFactories.registerCheck<UnconventionalAssignOperatorCheck>(
"misc-unconventional-assign-operator");
CheckFactories.registerCheck<BoolPointerImplicitConversionCheck>(
"misc-bool-pointer-implicit-conversion");
CheckFactories.registerCheck<DanglingHandleCheck>(
Expand Down
@@ -1,4 +1,4 @@
//===--- AssignOperatorSignatureCheck.cpp - clang-tidy ----------*- C++ -*-===//
//===--- UnconventionalUnconventionalAssignOperatorCheck.cpp - clang-tidy -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
Expand All @@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//

#include "AssignOperatorSignatureCheck.h"
#include "UnconventionalAssignOperatorCheck.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"

Expand All @@ -17,8 +17,7 @@ namespace clang {
namespace tidy {
namespace misc {

void AssignOperatorSignatureCheck::registerMatchers(
ast_matchers::MatchFinder *Finder) {
void UnconventionalAssignOperatorCheck::registerMatchers(ast_matchers::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)
Expand Down Expand Up @@ -56,22 +55,32 @@ void AssignOperatorSignatureCheck::registerMatchers(
Finder->addMatcher(
cxxMethodDecl(IsSelfAssign, anyOf(isConst(), isVirtual())).bind("cv"),
this);
}

void AssignOperatorSignatureCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *Method = Result.Nodes.getNodeAs<CXXMethodDecl>("method");
std::string Name = Method->getParent()->getName();
const auto IsBadReturnStatement = returnStmt(unless(has(
unaryOperator(hasOperatorName("*"), hasUnaryOperand(cxxThisExpr())))));
const auto IsGoodAssign = cxxMethodDecl(IsAssign, HasGoodReturnType);

Finder->addMatcher(returnStmt(IsBadReturnStatement, forFunction(IsGoodAssign))
.bind("returnStmt"),
this);
}

static const char *const Messages[][2] = {
{"ReturnType", "operator=() should return '%0&'"},
{"ArgumentType", "operator=() should take '%0 const&', '%0&&' or '%0'"},
{"cv", "operator=() should not be marked '%1'"}};
void UnconventionalAssignOperatorCheck::check(const MatchFinder::MatchResult &Result) {
if (const auto *RetStmt = Result.Nodes.getNodeAs<ReturnStmt>("returnStmt")) {
diag(RetStmt->getLocStart(), "operator=() should always return '*this'");
} else {
static const char *const Messages[][2] = {
{"ReturnType", "operator=() should return '%0&'"},
{"ArgumentType", "operator=() should take '%0 const&', '%0&&' or '%0'"},
{"cv", "operator=() should not be marked '%1'"}};

for (const auto &Message : Messages) {
if (Result.Nodes.getNodeAs<Decl>(Message[0]))
diag(Method->getLocStart(), Message[1])
<< Name << (Method->isConst() ? "const" : "virtual");
const auto *Method = Result.Nodes.getNodeAs<CXXMethodDecl>("method");
for (const auto &Message : Messages) {
if (Result.Nodes.getNodeAs<Decl>(Message[0]))
diag(Method->getLocStart(), Message[1])
<< Method->getParent()->getName()
<< (Method->isConst() ? "const" : "virtual");
}
}
}

Expand Down
@@ -1,4 +1,4 @@
//===--- AssignOperatorSignatureCheck.h - clang-tidy ------------*- C++ -*-===//
//===--- UnconventionalUnconventionalAssignOperatorCheck.h - clang-tidy -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
Expand All @@ -16,15 +16,20 @@ namespace clang {
namespace tidy {
namespace misc {

/// Finds declarations of assign operators with the wrong return and/or argument
/// types.
/// Finds declarations of assignment operators with the wrong return and/or
/// argument types and definitions with good return type but wrong return
/// statements.
///
/// * The return type must be `Class&`.
/// * Works with move-assign and assign by value.
/// * Private and deleted operators are ignored.
class AssignOperatorSignatureCheck : public ClangTidyCheck {
/// * The operator must always return ``*this``.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/misc-unconventional-assign-operator.html
class UnconventionalAssignOperatorCheck : public ClangTidyCheck {
public:
AssignOperatorSignatureCheck(StringRef Name, ClangTidyContext *Context)
UnconventionalAssignOperatorCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
Expand Down
6 changes: 6 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Expand Up @@ -236,6 +236,12 @@ identified. The improvements since the 3.8 release include:

Finds static function and variable definitions in anonymous namespace.

- New `misc-unconventional-assign-operator
<http://clang.llvm.org/extra/clang-tidy/checks/misc-unconventional-assign-operator.html>`_ check replacing old `misc-assign-operator-signature` check

Does not only checks for correct signature but also for correct ``return``
statements (returning ``*this``)

Fixed bugs:

- Crash when running on compile database with relative source files paths.
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/docs/clang-tidy/checks/list.rst
Expand Up @@ -52,7 +52,7 @@ Clang-Tidy Checks
llvm-twine-local
misc-argument-comment
misc-assert-side-effect
misc-assign-operator-signature
misc-unconventional-assign-operator
misc-bool-pointer-implicit-conversion
misc-dangling-handle
misc-definitions-in-headers
Expand Down

This file was deleted.

@@ -0,0 +1,13 @@
.. title:: clang-tidy - misc-unconventional-assign-operator

misc-unconventional-assign-operator
====================


Finds declarations of assign operators with the wrong return and/or argument
types and definitions with good return type but wrong return statements.

* The return type must be ``Class&``.
* Works with move-assign and assign by value.
* Private and deleted operators are ignored.
* The operator must always return ``*this``.
@@ -1,4 +1,6 @@
// RUN: %check_clang_tidy %s misc-assign-operator-signature %t
// RUN: %check_clang_tidy %s misc-unconventional-assign-operator %t -- -- -std=c++11 -isystem %S/Inputs/Headers

#include <utility>

struct Good {
Good& operator=(const Good&);
Expand All @@ -13,18 +15,19 @@ struct AlsoGood {
AlsoGood& operator=(AlsoGood);
};

struct BadReturn {
void operator=(const BadReturn&);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'BadReturn&' [misc-assign-operator-signature]
const BadReturn& operator=(BadReturn&&);
struct BadReturnType {
void operator=(const BadReturnType&);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'BadReturnType&' [misc-unconventional-assign-operator]
const BadReturnType& operator=(BadReturnType&&);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
void operator=(int);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
};
struct BadReturn2 {
BadReturn2&& operator=(const BadReturn2&);

struct BadReturnType2 {
BadReturnType2&& operator=(const BadReturnType2&);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
int operator=(BadReturn2&&);
int operator=(BadReturnType2&&);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
};

Expand Down Expand Up @@ -56,3 +59,21 @@ struct Virtual {
virtual Virtual& operator=(const Virtual &);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'virtual'
};

class BadReturnStatement {
int n;

public:
BadReturnStatement& operator=(BadReturnStatement&& rhs) {
n = std::move(rhs.n);
return rhs;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should always return '*this'
}

// Do not check if return type is different from '&BadReturnStatement'
int operator=(int i) {
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
n = i;
return n;
}
};

0 comments on commit 112d1e8

Please sign in to comment.