sbenza created this revision.
sbenza added a reviewer: alexfh.
sbenza added a subscriber: cfe-commits.
Add check performance-faster-string-find.
It replaces single character string literals to character literals in calls to
string::find and friends.
http://reviews.llvm.org/D16152
Files:
clang-tidy/performance/CMakeLists.txt
clang-tidy/performance/FasterStringFindCheck.cpp
clang-tidy/performance/FasterStringFindCheck.h
clang-tidy/performance/PerformanceTidyModule.cpp
docs/clang-tidy/checks/list.rst
docs/clang-tidy/checks/performance-faster-string-find.rst
test/clang-tidy/performance-faster-string-find.cpp
Index: test/clang-tidy/performance-faster-string-find.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/performance-faster-string-find.cpp
@@ -0,0 +1,74 @@
+// RUN: %check_clang_tidy %s performance-faster-string-find %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: performance-faster-string-find.StringLikeClasses, \
+// RUN: value: 'std::basic_string,::llvm::StringRef'}]}" --
+
+namespace std {
+template <typename T>
+struct basic_string {
+ int find(const char *, int = 0) const;
+ int find(const char *, int, int) const;
+ int rfind(const char *) const;
+ int find_first_of(const char *) const;
+ int find_first_not_of(const char *) const;
+ int find_last_of(const char *) const;
+ int find_last_not_of(const char *) const;
+};
+
+typedef basic_string<char> string;
+} // namespace std
+
+namespace llvm {
+struct StringRef {
+ int find(const char *) const;
+};
+} // namespace llvm
+
+struct NotStringRef {
+ int find(const char *);
+};
+
+void StringFind() {
+ std::string Str;
+
+ Str.find("a");
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: char overload is more efficient [performance-faster-string-find]
+ // CHECK-FIXES: Str.find('a');
+
+ // Works with the pos argument.
+ Str.find("a", 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: char overload is more efficient
+ // CHECK-FIXES: Str.find('a', 1);
+
+ // Doens't work with strings smaller or larger than 1 char.
+ Str.find("");
+ Str.find("ab");
+
+ // Doesn't do anything with the 3 argument overload.
+ Str.find("a", 1, 1);
+
+ // Some other overloads
+ Str.rfind("a");
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: char overload is more efficient
+ // CHECK-FIXES: Str.rfind('a');
+ Str.find_first_of("a");
+ // CHECK-MESSAGES: [[@LINE-1]]:21: warning: char overload is more efficient
+ // CHECK-FIXES: Str.find_first_of('a');
+ Str.find_first_not_of("a");
+ // CHECK-MESSAGES: [[@LINE-1]]:25: warning: char overload is more efficient
+ // CHECK-FIXES: Str.find_first_not_of('a');
+ Str.find_last_of("a");
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: char overload is more efficient
+ // CHECK-FIXES: Str.find_last_of('a');
+ Str.find_last_not_of("a");
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: char overload is more efficient
+ // CHECK-FIXES: Str.find_last_not_of('a');
+
+ // Also with other types, but only if it was specified in the options.
+ llvm::StringRef sr;
+ sr.find("x");
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: char overload is more efficient
+ // CHECK-FIXES: sr.find('x');
+ NotStringRef nsr;
+ nsr.find("x");
+}
Index: docs/clang-tidy/checks/performance-faster-string-find.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/performance-faster-string-find.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - performance-faster-string-find
+
+performance-faster-string-find
+==============================
+
+Optimize calls to std::string::find() and friends when the needle passed is
+a single character string literal.
+The character literal overload is more efficient.
+
+Examples:
+
+.. code-block:: c++
+
+ str.find("A");
+
+ // becomes
+
+ str.find('A');
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -75,6 +75,7 @@
modernize-use-default
modernize-use-nullptr
modernize-use-override
+ performance-faster-string-find
readability-braces-around-statements
readability-container-size-empty
readability-else-after-return
Index: clang-tidy/performance/PerformanceTidyModule.cpp
===================================================================
--- clang-tidy/performance/PerformanceTidyModule.cpp
+++ clang-tidy/performance/PerformanceTidyModule.cpp
@@ -10,6 +10,7 @@
#include "../ClangTidy.h"
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
+#include "FasterStringFindCheck.h"
#include "UnnecessaryCopyInitialization.h"
@@ -20,6 +21,8 @@
class PerformanceModule : public ClangTidyModule {
public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<FasterStringFindCheck>(
+ "performance-faster-string-find");
CheckFactories.registerCheck<UnnecessaryCopyInitialization>(
"performance-unnecessary-copy-initialization");
}
Index: clang-tidy/performance/FasterStringFindCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/performance/FasterStringFindCheck.h
@@ -0,0 +1,43 @@
+//===--- FasterStringFindCheck.h - clang-tidy--------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_FASTER_STRING_FIND_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_FASTER_STRING_FIND_H
+
+#include "../ClangTidy.h"
+
+#include <vector>
+#include <string>
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// Optimize calls to std::string::find() and friends when the needle passed is
+/// a single character string literal.
+/// The character literal overload is more efficient.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/performance-faster-string-find.html
+class FasterStringFindCheck : public ClangTidyCheck {
+public:
+ FasterStringFindCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ const std::vector<std::string> StringLikeClasses;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_FASTER_STRING_FIND_H
Index: clang-tidy/performance/FasterStringFindCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/performance/FasterStringFindCheck.cpp
@@ -0,0 +1,84 @@
+//===--- FasterStringFindCheck.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 "FasterStringFindCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/Optional.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+namespace {
+
+std::vector<std::string> ParseClasses(StringRef Option) {
+ SmallVector<StringRef, 4> Classes;
+ Option.split(Classes, ",");
+ return std::vector<std::string>(Classes.begin(), Classes.end());
+}
+
+AST_MATCHER(StringLiteral, lengthIsOne) { return Node.getLength() == 1; }
+
+} // namespace
+
+FasterStringFindCheck::FasterStringFindCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ StringLikeClasses(
+ ParseClasses(Options.get("StringLikeClasses", "std::basic_string"))) {
+}
+
+void FasterStringFindCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(
+ Opts, "StringLikeClasses",
+ llvm::join(StringLikeClasses.begin(), StringLikeClasses.end(), ","));
+}
+
+void FasterStringFindCheck::registerMatchers(MatchFinder *Finder) {
+ const auto SingleChar =
+ expr(ignoringParenCasts(stringLiteral(lengthIsOne()).bind("literal")));
+
+ const auto StringFindFunctions =
+ anyOf(hasName("find"), hasName("rfind"), hasName("find_first_of"),
+ hasName("find_first_not_of"), hasName("find_last_of"),
+ hasName("find_last_not_of"));
+
+ llvm::Optional<ast_matchers::internal::Matcher<NamedDecl>> IsStringClass;
+
+ for (auto &ClassName : StringLikeClasses) {
+ const auto HasName = hasName(ClassName);
+ IsStringClass = IsStringClass ? anyOf(*IsStringClass, HasName) : HasName;
+ }
+
+ if (IsStringClass) {
+ Finder->addMatcher(
+ cxxMemberCallExpr(callee(functionDecl(StringFindFunctions)),
+ anyOf(argumentCountIs(1), argumentCountIs(2)),
+ hasArgument(0, SingleChar),
+ on(expr(hasType(recordDecl(*IsStringClass))))),
+ this);
+ }
+}
+
+void FasterStringFindCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Literal = Result.Nodes.getNodeAs<StringLiteral>("literal");
+
+ diag(Literal->getLocStart(), "char overload is more efficient")
+ << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(Literal->getLocStart(),
+ Literal->getLocEnd()),
+ ("'" + Literal->getString() + "'").str());
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/performance/CMakeLists.txt
===================================================================
--- clang-tidy/performance/CMakeLists.txt
+++ clang-tidy/performance/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTidyPerformanceModule
+ FasterStringFindCheck.cpp
PerformanceTidyModule.cpp
UnnecessaryCopyInitialization.cpp
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits