77 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 "ShrinkToFitCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/ASTMatchers/ASTMatchFinder.h"12#include "clang/Lex/Lexer.h"13#include "llvm/ADT/StringRef.h"14 15using namespace clang::ast_matchers;16 17namespace clang::tidy::modernize {18 19void ShrinkToFitCheck::registerMatchers(MatchFinder *Finder) {20 // Swap as a function need not to be considered, because rvalue can not21 // be bound to a non-const reference.22 const auto ShrinkableExpr = mapAnyOf(memberExpr, declRefExpr);23 const auto Shrinkable =24 ShrinkableExpr.with(hasDeclaration(valueDecl().bind("ContainerDecl")));25 const auto BoundShrinkable = ShrinkableExpr.with(26 hasDeclaration(valueDecl(equalsBoundNode("ContainerDecl"))));27 28 Finder->addMatcher(29 cxxMemberCallExpr(30 callee(cxxMethodDecl(hasName("swap"))),31 hasArgument(32 0, anyOf(Shrinkable, unaryOperator(hasUnaryOperand(Shrinkable)))),33 on(cxxConstructExpr(hasArgument(34 0,35 expr(anyOf(BoundShrinkable,36 unaryOperator(hasUnaryOperand(BoundShrinkable))),37 hasType(hasCanonicalType(hasDeclaration(namedDecl(hasAnyName(38 "std::basic_string", "std::deque", "std::vector"))))))39 .bind("ContainerToShrink")))))40 .bind("CopyAndSwapTrick"),41 this);42}43 44void ShrinkToFitCheck::check(const MatchFinder::MatchResult &Result) {45 const auto *MemberCall =46 Result.Nodes.getNodeAs<CXXMemberCallExpr>("CopyAndSwapTrick");47 const auto *Container = Result.Nodes.getNodeAs<Expr>("ContainerToShrink");48 FixItHint Hint;49 50 if (!MemberCall->getBeginLoc().isMacroID()) {51 const LangOptions &Opts = getLangOpts();52 std::string ReplacementText;53 if (const auto *UnaryOp = llvm::dyn_cast<UnaryOperator>(Container)) {54 ReplacementText = std::string(55 Lexer::getSourceText(CharSourceRange::getTokenRange(56 UnaryOp->getSubExpr()->getSourceRange()),57 *Result.SourceManager, Opts));58 ReplacementText += "->shrink_to_fit()";59 } else {60 ReplacementText = std::string(Lexer::getSourceText(61 CharSourceRange::getTokenRange(Container->getSourceRange()),62 *Result.SourceManager, Opts));63 ReplacementText += ".shrink_to_fit()";64 }65 66 Hint = FixItHint::CreateReplacement(MemberCall->getSourceRange(),67 ReplacementText);68 }69 70 diag(MemberCall->getBeginLoc(), "the shrink_to_fit method should be used "71 "to reduce the capacity of a shrinkable "72 "container")73 << Hint;74}75 76} // namespace clang::tidy::modernize77