//===--- ShrinkToFitCheck.cpp - clang-tidy---------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "ShrinkToFitCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/StringRef.h" using namespace clang::ast_matchers; namespace clang::tidy::modernize { void ShrinkToFitCheck::registerMatchers(MatchFinder *Finder) { // Swap as a function need not to be considered, because rvalue can not // be bound to a non-const reference. const auto ShrinkableExpr = mapAnyOf(memberExpr, declRefExpr); const auto Shrinkable = ShrinkableExpr.with(hasDeclaration(valueDecl().bind("ContainerDecl"))); const auto BoundShrinkable = ShrinkableExpr.with( hasDeclaration(valueDecl(equalsBoundNode("ContainerDecl")))); Finder->addMatcher( cxxMemberCallExpr( callee(cxxMethodDecl(hasName("swap"))), hasArgument( 0, anyOf(Shrinkable, unaryOperator(hasUnaryOperand(Shrinkable)))), on(cxxConstructExpr(hasArgument( 0, expr(anyOf(BoundShrinkable, unaryOperator(hasUnaryOperand(BoundShrinkable))), hasType(hasCanonicalType(hasDeclaration(namedDecl(hasAnyName( "std::basic_string", "std::deque", "std::vector")))))) .bind("ContainerToShrink"))))) .bind("CopyAndSwapTrick"), this); } void ShrinkToFitCheck::check(const MatchFinder::MatchResult &Result) { const auto *MemberCall = Result.Nodes.getNodeAs("CopyAndSwapTrick"); const auto *Container = Result.Nodes.getNodeAs("ContainerToShrink"); FixItHint Hint; if (!MemberCall->getBeginLoc().isMacroID()) { const LangOptions &Opts = getLangOpts(); std::string ReplacementText; if (const auto *UnaryOp = llvm::dyn_cast(Container)) { ReplacementText = std::string( Lexer::getSourceText(CharSourceRange::getTokenRange( UnaryOp->getSubExpr()->getSourceRange()), *Result.SourceManager, Opts)); ReplacementText += "->shrink_to_fit()"; } else { ReplacementText = std::string(Lexer::getSourceText( CharSourceRange::getTokenRange(Container->getSourceRange()), *Result.SourceManager, Opts)); ReplacementText += ".shrink_to_fit()"; } Hint = FixItHint::CreateReplacement(MemberCall->getSourceRange(), ReplacementText); } diag(MemberCall->getBeginLoc(), "the shrink_to_fit method should be used " "to reduce the capacity of a shrinkable " "container") << Hint; } } // namespace clang::tidy::modernize