28 ast_matchers::MatchFinder *Finder) {
29 const auto HasGoodReturnType =
30 cxxMethodDecl(returns(hasCanonicalType(lValueReferenceType(pointee(
31 unless(isConstQualified()),
33 hasDeclaration(declaresSameEntityAsBoundNode(
"class"))))))));
35 const auto IsSelf = qualType(hasCanonicalType(
36 anyOf(hasDeclaration(declaresSameEntityAsBoundNode(
"class")),
37 referenceType(pointee(
38 hasDeclaration(declaresSameEntityAsBoundNode(
"class")))))));
40 cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())),
41 hasName(
"operator="), ofClass(recordDecl().bind(
"class")))
43 const auto IsSelfAssign =
44 cxxMethodDecl(IsAssign, firstParameter(parmVarDecl(hasType(IsSelf))))
48 cxxMethodDecl(IsAssign, unless(HasGoodReturnType)).bind(
"ReturnType"),
51 const auto BadSelf = qualType(hasCanonicalType(referenceType(
52 anyOf(lValueReferenceType(pointee(unless(isConstQualified()))),
53 rValueReferenceType(pointee(isConstQualified()))))));
56 cxxMethodDecl(IsSelfAssign, firstParameter(parmVarDecl(hasType(BadSelf))))
57 .bind(
"ArgumentType"),
61 cxxMethodDecl(IsSelfAssign, anyOf(isConst(), isVirtual())).bind(
"cv"),
64 const auto IsBadReturnStatement = returnStmt(unless(has(ignoringParenImpCasts(
65 anyOf(unaryOperator(hasOperatorName(
"*"), hasUnaryOperand(cxxThisExpr())),
66 cxxOperatorCallExpr(argumentCountIs(1),
67 callee(unresolvedLookupExpr()),
68 hasArgument(0, cxxThisExpr())),
70 hasOverloadedOperatorName(
"="),
71 hasArgument(0, unaryOperator(hasOperatorName(
"*"),
72 hasUnaryOperand(cxxThisExpr())))),
75 hasLHS(unaryOperator(hasOperatorName(
"*"),
76 hasUnaryOperand(cxxThisExpr())))))))));
77 const auto IsGoodAssign = cxxMethodDecl(IsAssign, HasGoodReturnType);
79 Finder->addMatcher(returnStmt(IsBadReturnStatement, forFunction(IsGoodAssign))
85 const MatchFinder::MatchResult &Result) {
86 if (
const auto *RetStmt = Result.Nodes.getNodeAs<ReturnStmt>(
"returnStmt")) {
87 diag(RetStmt->getBeginLoc(),
"operator=() should always return '*this'");
89 const auto *Method = Result.Nodes.getNodeAs<CXXMethodDecl>(
"method");
90 if (Result.Nodes.getNodeAs<CXXMethodDecl>(
"ReturnType"))
91 diag(Method->getBeginLoc(),
"operator=() should return '%0&'")
92 << Method->getParent()->getName();
93 if (Result.Nodes.getNodeAs<CXXMethodDecl>(
"ArgumentType"))
94 diag(Method->getBeginLoc(),
95 "operator=() should take '%0 const&'%select{|, '%0&&'}1 or '%0'")
96 << Method->getParent()->getName() << getLangOpts().CPlusPlus11;
97 if (Result.Nodes.getNodeAs<CXXMethodDecl>(
"cv"))
98 diag(Method->getBeginLoc(),
99 "operator=() should not be marked '%select{const|virtual}0'")
100 << !Method->isConst();