summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/readability/ShrinkToFitCheck.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-tidy/readability/ShrinkToFitCheck.cpp')
-rw-r--r--clang-tools-extra/clang-tidy/readability/ShrinkToFitCheck.cpp109
1 files changed, 109 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/readability/ShrinkToFitCheck.cpp b/clang-tools-extra/clang-tidy/readability/ShrinkToFitCheck.cpp
new file mode 100644
index 00000000000..1c9e0a8117a
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/ShrinkToFitCheck.cpp
@@ -0,0 +1,109 @@
+//===--- ShrinkToFitCheck.cpp - clang-tidy---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ShrinkToFitCheck.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace {
+bool isShrinkableContainer(llvm::StringRef ClassName) {
+ static const llvm::StringSet<> Shrinkables = [] {
+ llvm::StringSet<> RetVal;
+ RetVal.insert("std::deque");
+ RetVal.insert("std::basic_string");
+ RetVal.insert("std::vector");
+ return RetVal;
+ }();
+ return Shrinkables.find(ClassName) != Shrinkables.end();
+}
+}
+
+namespace clang {
+namespace ast_matchers {
+AST_MATCHER(NamedDecl, stlShrinkableContainer) {
+ return isShrinkableContainer(Node.getQualifiedNameAsString());
+}
+} // namespace ast_matchesr
+} // namespace clang
+
+namespace clang {
+namespace tidy {
+
+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 ShrinkableAsMember =
+ memberExpr(member(valueDecl().bind("ContainerDecl")));
+ const auto ShrinkableAsDecl =
+ declRefExpr(hasDeclaration(valueDecl().bind("ContainerDecl")));
+ const auto CopyCtorCall = constructExpr(
+ hasArgument(0, anyOf(ShrinkableAsMember, ShrinkableAsDecl,
+ unaryOperator(has(ShrinkableAsMember)),
+ unaryOperator(has(ShrinkableAsDecl)))));
+ const auto SwapParam = expr(anyOf(
+ memberExpr(member(equalsBoundNode("ContainerDecl"))),
+ declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl"))),
+ unaryOperator(has(memberExpr(member(equalsBoundNode("ContainerDecl"))))),
+ unaryOperator(
+ has(declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl")))))));
+
+ Finder->addMatcher(
+ memberCallExpr(on(hasType(namedDecl(stlShrinkableContainer()))),
+ callee(methodDecl(hasName("swap"))),
+ has(memberExpr(hasDescendant(CopyCtorCall))),
+ hasArgument(0, SwapParam.bind("ContainerToShrink")),
+ unless(isInTemplateInstantiation()))
+ .bind("CopyAndSwapTrick"),
+ this);
+}
+
+void ShrinkToFitCheck::check(const MatchFinder::MatchResult &Result) {
+ const LangOptions &Opts = Result.Context->getLangOpts();
+
+ if (!Opts.CPlusPlus11)
+ return;
+
+ const auto *MemberCall =
+ Result.Nodes.getNodeAs<CXXMemberCallExpr>("CopyAndSwapTrick");
+ const auto *Container = Result.Nodes.getNodeAs<Expr>("ContainerToShrink");
+ FixItHint Hint;
+
+ if (!MemberCall->getLocStart().isMacroID()) {
+ std::string ReplacementText;
+ if (const auto *UnaryOp = llvm::dyn_cast<UnaryOperator>(Container)) {
+ ReplacementText =
+ Lexer::getSourceText(CharSourceRange::getTokenRange(
+ UnaryOp->getSubExpr()->getSourceRange()),
+ *Result.SourceManager, Opts);
+ ReplacementText += "->shrink_to_fit()";
+ } else {
+ ReplacementText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(Container->getSourceRange()),
+ *Result.SourceManager, Opts);
+ ReplacementText += ".shrink_to_fit()";
+ }
+
+ Hint = FixItHint::CreateReplacement(MemberCall->getSourceRange(),
+ ReplacementText);
+ }
+
+ diag(MemberCall->getLocStart(), "the shrink_to_fit method should be used "
+ "to reduce the capacity of a shrinkable "
+ "container")
+ << Hint;
+}
+
+} // namespace tidy
+} // namespace clang
OpenPOWER on IntegriCloud