10 #include "clang/ASTMatchers/ASTMatchFinder.h"
11 #include "clang/ASTMatchers/ASTMatchers.h"
19 void UnconventionalAssignOperatorCheck::registerMatchers(
20 ast_matchers::MatchFinder *Finder) {
21 const auto HasGoodReturnType =
22 cxxMethodDecl(returns(hasCanonicalType(lValueReferenceType(pointee(
23 unless(isConstQualified()),
24 anyOf(autoType(), hasDeclaration(equalsBoundNode(
"class"))))))));
26 const auto IsSelf = qualType(hasCanonicalType(
27 anyOf(hasDeclaration(equalsBoundNode(
"class")),
28 referenceType(pointee(hasDeclaration(equalsBoundNode(
"class")))))));
30 cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())),
31 hasName(
"operator="), ofClass(recordDecl().bind(
"class")))
33 const auto IsSelfAssign =
34 cxxMethodDecl(IsAssign, hasParameter(0, parmVarDecl(hasType(IsSelf))))
38 cxxMethodDecl(IsAssign, unless(HasGoodReturnType)).bind(
"ReturnType"),
41 const auto BadSelf = qualType(hasCanonicalType(referenceType(
42 anyOf(lValueReferenceType(pointee(unless(isConstQualified()))),
43 rValueReferenceType(pointee(isConstQualified()))))));
46 cxxMethodDecl(IsSelfAssign,
47 hasParameter(0, parmVarDecl(hasType(BadSelf))))
48 .bind(
"ArgumentType"),
52 cxxMethodDecl(IsSelfAssign, anyOf(isConst(), isVirtual())).bind(
"cv"),
55 const auto IsBadReturnStatement = returnStmt(unless(has(ignoringParenImpCasts(
56 anyOf(unaryOperator(hasOperatorName(
"*"), hasUnaryOperand(cxxThisExpr())),
57 cxxOperatorCallExpr(argumentCountIs(1),
58 callee(unresolvedLookupExpr()),
59 hasArgument(0, cxxThisExpr())),
61 hasOverloadedOperatorName(
"="),
63 0, unaryOperator(hasOperatorName(
"*"),
64 hasUnaryOperand(cxxThisExpr())))))))));
65 const auto IsGoodAssign = cxxMethodDecl(IsAssign, HasGoodReturnType);
67 Finder->addMatcher(returnStmt(IsBadReturnStatement, forFunction(IsGoodAssign))
73 const MatchFinder::MatchResult &Result) {
74 if (
const auto *RetStmt = Result.Nodes.getNodeAs<ReturnStmt>(
"returnStmt")) {
75 diag(RetStmt->getBeginLoc(),
"operator=() should always return '*this'");
77 const auto *Method = Result.Nodes.getNodeAs<CXXMethodDecl>(
"method");
78 if (Result.Nodes.getNodeAs<CXXMethodDecl>(
"ReturnType"))
79 diag(Method->getBeginLoc(),
"operator=() should return '%0&'")
80 << Method->getParent()->getName();
81 if (Result.Nodes.getNodeAs<CXXMethodDecl>(
"ArgumentType"))
82 diag(Method->getBeginLoc(),
83 "operator=() should take '%0 const&'%select{|, '%0&&'}1 or '%0'")
84 << Method->getParent()->getName() << getLangOpts().CPlusPlus11;
85 if (Result.Nodes.getNodeAs<CXXMethodDecl>(
"cv"))
86 diag(Method->getBeginLoc(),
87 "operator=() should not be marked '%select{const|virtual}0'")
88 << !Method->isConst();