brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.6 KiB · 22ff5ce Raw
127 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 "AmbiguousSmartptrResetCallCheck.h"10#include "../utils/OptionsUtils.h"11#include "clang/AST/ASTContext.h"12#include "clang/ASTMatchers/ASTMatchFinder.h"13#include "clang/ASTMatchers/ASTMatchers.h"14#include "clang/Lex/Lexer.h"15 16using namespace clang::ast_matchers;17 18namespace clang::tidy::readability {19 20namespace {21 22AST_MATCHER(CXXMethodDecl, hasOnlyDefaultParameters) {23  for (const auto *Param : Node.parameters()) {24    if (!Param->hasDefaultArg())25      return false;26  }27 28  return true;29}30 31const auto DefaultSmartPointers = "::std::shared_ptr;::std::unique_ptr;"32                                  "::boost::shared_ptr";33} // namespace34 35AmbiguousSmartptrResetCallCheck::AmbiguousSmartptrResetCallCheck(36    StringRef Name, ClangTidyContext *Context)37    : ClangTidyCheck(Name, Context),38      SmartPointers(utils::options::parseStringList(39          Options.get("SmartPointers", DefaultSmartPointers))) {}40 41void AmbiguousSmartptrResetCallCheck::storeOptions(42    ClangTidyOptions::OptionMap &Opts) {43  Options.store(Opts, "SmartPointers",44                utils::options::serializeStringList(SmartPointers));45}46 47void AmbiguousSmartptrResetCallCheck::registerMatchers(MatchFinder *Finder) {48  const auto IsSmartptr = hasAnyName(SmartPointers);49 50  const auto ResetMethod =51      cxxMethodDecl(hasName("reset"), hasOnlyDefaultParameters());52 53  const auto TypeWithReset =54      anyOf(cxxRecordDecl(55                anyOf(hasMethod(ResetMethod),56                      isDerivedFrom(cxxRecordDecl(hasMethod(ResetMethod))))),57            classTemplateSpecializationDecl(58                hasSpecializedTemplate(classTemplateDecl(has(ResetMethod)))));59 60  const auto SmartptrWithReset = expr(hasType(hasUnqualifiedDesugaredType(61      recordType(hasDeclaration(classTemplateSpecializationDecl(62          IsSmartptr,63          hasTemplateArgument(64              0, templateArgument(refersToType(hasUnqualifiedDesugaredType(65                     recordType(hasDeclaration(TypeWithReset))))))))))));66 67  Finder->addMatcher(68      cxxMemberCallExpr(69          callee(ResetMethod),70          unless(hasAnyArgument(expr(unless(cxxDefaultArgExpr())))),71          anyOf(on(cxxOperatorCallExpr(hasOverloadedOperatorName("->"),72                                       hasArgument(0, SmartptrWithReset))73                       .bind("ArrowOp")),74                on(SmartptrWithReset)))75          .bind("MemberCall"),76      this);77}78 79void AmbiguousSmartptrResetCallCheck::check(80    const MatchFinder::MatchResult &Result) {81  const auto *MemberCall =82      Result.Nodes.getNodeAs<CXXMemberCallExpr>("MemberCall");83  assert(MemberCall);84 85  if (const auto *Arrow =86          Result.Nodes.getNodeAs<CXXOperatorCallExpr>("ArrowOp")) {87    const CharSourceRange SmartptrSourceRange =88        Lexer::getAsCharRange(Arrow->getArg(0)->getSourceRange(),89                              *Result.SourceManager, getLangOpts());90 91    diag(MemberCall->getBeginLoc(),92         "ambiguous call to 'reset()' on a pointee of a smart pointer, prefer "93         "more explicit approach");94 95    diag(MemberCall->getBeginLoc(),96         "consider dereferencing smart pointer to call 'reset' method "97         "of the pointee here",98         DiagnosticIDs::Note)99        << FixItHint::CreateInsertion(SmartptrSourceRange.getBegin(), "(*")100        << FixItHint::CreateInsertion(SmartptrSourceRange.getEnd(), ")")101        << FixItHint::CreateReplacement(102               CharSourceRange::getCharRange(103                   Arrow->getOperatorLoc(),104                   Arrow->getOperatorLoc().getLocWithOffset(2)),105               ".");106  } else {107    const auto *Member = cast<MemberExpr>(MemberCall->getCallee());108    assert(Member);109 110    diag(MemberCall->getBeginLoc(),111         "ambiguous call to 'reset()' on a smart pointer with pointee that "112         "also has a 'reset()' method, prefer more explicit approach");113 114    diag(MemberCall->getBeginLoc(),115         "consider assigning the pointer to 'nullptr' here",116         DiagnosticIDs::Note)117        << FixItHint::CreateReplacement(118               SourceRange(Member->getOperatorLoc(), Member->getOperatorLoc()),119               " =")120        << FixItHint::CreateReplacement(121               SourceRange(Member->getMemberLoc(), MemberCall->getEndLoc()),122               " nullptr");123  }124}125 126} // namespace clang::tidy::readability127