brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.3 KiB · a14a559 Raw
105 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "UnconventionalAssignOperatorCheck.h"10#include "clang/ASTMatchers/ASTMatchFinder.h"11#include "clang/ASTMatchers/ASTMatchers.h"12 13using namespace clang::ast_matchers;14 15namespace clang::tidy::misc {16 17namespace {18 19AST_MATCHER_P(CXXMethodDecl, firstParameter,20              ast_matchers::internal::Matcher<ParmVarDecl>, InnerMatcher) {21  const unsigned N = Node.isExplicitObjectMemberFunction() ? 1 : 0;22  return (N < Node.parameters().size() &&23          InnerMatcher.matches(*Node.parameters()[N], Finder, Builder));24}25} // namespace26 27void UnconventionalAssignOperatorCheck::registerMatchers(28    ast_matchers::MatchFinder *Finder) {29  const auto HasGoodReturnType =30      cxxMethodDecl(returns(hasCanonicalType(lValueReferenceType(pointee(31          unless(isConstQualified()),32          anyOf(autoType(),33                hasDeclaration(declaresSameEntityAsBoundNode("class"))))))));34 35  const auto IsSelf = qualType(hasCanonicalType(36      anyOf(hasDeclaration(declaresSameEntityAsBoundNode("class")),37            referenceType(pointee(38                hasDeclaration(declaresSameEntityAsBoundNode("class")))))));39  const auto IsAssign =40      cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())),41                    hasName("operator="), ofClass(recordDecl().bind("class")))42          .bind("method");43  const auto IsSelfAssign =44      cxxMethodDecl(IsAssign, firstParameter(parmVarDecl(hasType(IsSelf))))45          .bind("method");46 47  Finder->addMatcher(48      cxxMethodDecl(IsAssign, unless(HasGoodReturnType)).bind("ReturnType"),49      this);50 51  const auto BadSelf = qualType(hasCanonicalType(referenceType(52      anyOf(lValueReferenceType(pointee(unless(isConstQualified()))),53            rValueReferenceType(pointee(isConstQualified()))))));54 55  Finder->addMatcher(56      cxxMethodDecl(IsSelfAssign, firstParameter(parmVarDecl(hasType(BadSelf))))57          .bind("ArgumentType"),58      this);59 60  Finder->addMatcher(61      cxxMethodDecl(IsSelfAssign, anyOf(isConst(), isVirtual())).bind("cv"),62      this);63 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())),69            cxxOperatorCallExpr(70                hasOverloadedOperatorName("="),71                hasArgument(0, unaryOperator(hasOperatorName("*"),72                                             hasUnaryOperand(cxxThisExpr())))),73            binaryOperator(74                hasOperatorName("="),75                hasLHS(unaryOperator(hasOperatorName("*"),76                                     hasUnaryOperand(cxxThisExpr())))))))));77  const auto IsGoodAssign = cxxMethodDecl(IsAssign, HasGoodReturnType);78 79  Finder->addMatcher(returnStmt(IsBadReturnStatement, forFunction(IsGoodAssign))80                         .bind("returnStmt"),81                     this);82}83 84void UnconventionalAssignOperatorCheck::check(85    const MatchFinder::MatchResult &Result) {86  if (const auto *RetStmt = Result.Nodes.getNodeAs<ReturnStmt>("returnStmt")) {87    diag(RetStmt->getBeginLoc(), "operator=() should always return '*this'");88  } else {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();101  }102}103 104} // namespace clang::tidy::misc105