flx updated this revision to Diff 335267.
flx marked an inline comment as done.
flx added a comment.

Create a NameMatcher class that handles matching against the best name variant
(unqualified, qualified, fully qualified) of the NamedDecl.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D98738/new/

https://reviews.llvm.org/D98738

Files:
  clang-tools-extra/clang-tidy/utils/Matchers.h
  clang-tools-extra/docs/clang-tidy/checks/performance-for-range-copy.rst
  
clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
  
clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-value-param.rst
  
clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy-allowed-types.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy-allowed-types.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy-allowed-types.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy-allowed-types.cpp
@@ -1,5 +1,5 @@
 // RUN: %check_clang_tidy %s performance-for-range-copy %t -- \
-// RUN:     -config="{CheckOptions: [{key: performance-for-range-copy.AllowedTypes, value: '[Pp]ointer$;[Pp]tr$;[Rr]ef(erence)?$'}]}" \
+// RUN:     -config="{CheckOptions: [{key: performance-for-range-copy.AllowedTypes, value: '[Pp]ointer$;[Pp]tr$;[Rr]ef(erence)?$;qualified::Type;::fully::QualifiedType'}]}" \
 // RUN:     -- -fno-delayed-template-parsing
 
 template <typename T>
@@ -63,6 +63,18 @@
 
 typedef SomeComplexTemplate<int> NotTooComplexRef;
 
+namespace qualified {
+struct Type {
+  ~Type();
+};
+} // namespace qualified
+
+namespace fully {
+struct QualifiedType {
+  ~QualifiedType();
+};
+} // namespace fully
+
 void negativeSmartPointer() {
   for (auto P : View<Iterator<SmartPointer>>()) {
     auto P2 = P;
@@ -124,3 +136,23 @@
     auto R2 = R;
   }
 }
+
+void negativeQualified() {
+  for (auto Q : View<Iterator<qualified::Type>>()) {
+    auto Q2 = Q;
+  }
+  using qualified::Type;
+  for (auto Q : View<Iterator<Type>>()) {
+    auto Q2 = Q;
+  }
+}
+
+void negativeFullyQualified() {
+  for (auto Q : View<Iterator<fully::QualifiedType>>()) {
+    auto Q2 = Q;
+  }
+  using fully::QualifiedType;
+  for (auto Q : View<Iterator<QualifiedType>>()) {
+    auto Q2 = Q;
+  }
+}
Index: clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-value-param.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-value-param.rst
+++ clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-value-param.rst
@@ -66,4 +66,7 @@
 
    A semicolon-separated list of names of types allowed to be passed by value.
    Regular expressions are accepted, e.g. `[Rr]ef(erence)?$` matches every type
-   with suffix `Ref`, `ref`, `Reference` and `reference`. The default is empty.
+   with suffix `Ref`, `ref`, `Reference` and `reference`. The default is
+   empty. If a name in the list contains the sequence `::` it is matched against
+   the qualified typename (i.e. `namespace::Type`, otherwise it is matched
+   against only the type name (i.e. `Type`).
Index: clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
+++ clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
@@ -43,5 +43,7 @@
 
    A semicolon-separated list of names of types allowed to be initialized by
    copying. Regular expressions are accepted, e.g. `[Rr]ef(erence)?$` matches
-   every type with suffix `Ref`, `ref`, `Reference` and `reference`. The
-   default is empty.
+   every type with suffix `Ref`, `ref`, `Reference` and `reference`. The default
+   is empty. If a name in the list contains the sequence `::` it is matched
+   against the qualified typename (i.e. `namespace::Type`, otherwise it is
+   matched against only the type name (i.e. `Type`).
Index: clang-tools-extra/docs/clang-tidy/checks/performance-for-range-copy.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/performance-for-range-copy.rst
+++ clang-tools-extra/docs/clang-tidy/checks/performance-for-range-copy.rst
@@ -31,4 +31,6 @@
    A semicolon-separated list of names of types allowed to be copied in each
    iteration. Regular expressions are accepted, e.g. `[Rr]ef(erence)?$` matches
    every type with suffix `Ref`, `ref`, `Reference` and `reference`. The default
-   is empty.
+   is empty. If a name in the list contains the sequence `::` it is matched
+   against the qualified typename (i.e. `namespace::Type`, otherwise it is
+   matched against only the type name (i.e. `Type`).
Index: clang-tools-extra/clang-tidy/utils/Matchers.h
===================================================================
--- clang-tools-extra/clang-tidy/utils/Matchers.h
+++ clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -49,11 +49,76 @@
   return pointerType(pointee(qualType(isConstQualified())));
 }
 
-AST_MATCHER_P(NamedDecl, matchesAnyListedName, std::vector<std::string>,
-              NameList) {
-  return llvm::any_of(NameList, [&Node](const std::string &Name) {
-      return llvm::Regex(Name).match(Node.getName());
+// A matcher implementation that matches a list of type name regular expressions
+// against a NamedDecl. If a regular expression contains the substring "::"
+// matching will occur against the qualified name, otherwise only the typename.
+class MatchesAnyListedNameMatcher
+    : public ast_matchers::internal::MatcherInterface<NamedDecl> {
+public:
+  explicit MatchesAnyListedNameMatcher(llvm::ArrayRef<std::string> NameList) {
+    std::transform(
+        NameList.begin(), NameList.end(), std::back_inserter(NameMatchers),
+        [](const llvm::StringRef Name) { return NameMatcher(Name); });
+  }
+  bool matches(
+      const NamedDecl &Node, ast_matchers::internal::ASTMatchFinder *Finder,
+      ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
+    return llvm::any_of(NameMatchers, [&Node](const NameMatcher &NM) {
+      return NM.match(Node);
     });
+  }
+
+private:
+  class NameMatcher {
+    llvm::Regex Regex;
+    enum class MatchMode {
+      // Match against the unqualified name because the regular expression
+      // does not contain ":".
+      MatchUnqualified,
+      // Match against the qualified name because the regular expression
+      // contains ":" suggesting name and namespace should be matched.
+      MatchQualified,
+      // Match against the fully qualified name because the regular expression
+      // starts with ":".
+      MatchFullyQualified,
+    };
+    MatchMode Mode;
+
+  public:
+    NameMatcher(const llvm::StringRef Regex)
+        : Regex(Regex), Mode(determineMatchMode(Regex)) {}
+
+    bool match(const NamedDecl &ND) const {
+      switch (Mode) {
+      case MatchMode::MatchUnqualified:
+        return Regex.match(ND.getName());
+      case MatchMode::MatchQualified:
+        return Regex.match(ND.getQualifiedNameAsString());
+      case MatchMode::MatchFullyQualified:
+        return Regex.match("::" + ND.getQualifiedNameAsString());
+      }
+    }
+
+  private:
+    MatchMode determineMatchMode(llvm::StringRef Regex) {
+      if (Regex.startswith(":") || Regex.startswith("^:")) {
+        return MatchMode::MatchFullyQualified;
+      }
+      return Regex.contains(":") ? MatchMode::MatchQualified
+                                 : MatchMode::MatchUnqualified;
+    }
+  };
+
+  std::vector<NameMatcher> NameMatchers;
+};
+
+// Returns a matcher that matches NamedDecl's against a list of provided regular
+// expressions. If a regular expression contains starts ':' the NamedDecl's
+// qualified name will be used for matching, otherwise its name will be used.
+inline ::clang::ast_matchers::internal::Matcher<NamedDecl>
+matchesAnyListedName(llvm::ArrayRef<std::string> NameList) {
+  return ::clang::ast_matchers::internal::makeMatcher(
+      new MatchesAnyListedNameMatcher(NameList));
 }
 
 } // namespace matchers
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to