[clang-tools-extra] ddebed8 - [clang-tidy] performance-* checks: Match AllowedTypes against qualified type names when they contain "::".
Felix Berger via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 6 12:42:02 PDT 2021
Author: Felix Berger
Date: 2021-04-06T15:41:35-04:00
New Revision: ddebed8e9742add4372d54021cb55e06b655cfd6
URL: https://github.com/llvm/llvm-project/commit/ddebed8e9742add4372d54021cb55e06b655cfd6
DIFF: https://github.com/llvm/llvm-project/commit/ddebed8e9742add4372d54021cb55e06b655cfd6.diff
LOG: [clang-tidy] performance-* checks: Match AllowedTypes against qualified type names when they contain "::".
This allows users to be more precise and exclude a type in a specific namespace
from triggering the check instead of excluding all types with the same
unqualified name.
This change should not interfere with correctly configured clang-tidy setups
since an AllowedType with "::" would never match.
Differential Revision: https://reviews.llvm.org/D98738
Reviewed-by: ymandel, hokein
Added:
Modified:
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
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/utils/Matchers.h b/clang-tools-extra/clang-tidy/utils/Matchers.h
index 9b765aedd13af..469ce4a9c4a4c 100644
--- a/clang-tools-extra/clang-tidy/utils/Matchers.h
+++ b/clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -49,11 +49,76 @@ AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isPointerToConst) {
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::MatchQualified:
+ return Regex.match(ND.getQualifiedNameAsString());
+ case MatchMode::MatchFullyQualified:
+ return Regex.match("::" + ND.getQualifiedNameAsString());
+ default:
+ return Regex.match(ND.getName());
+ }
+ }
+
+ 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
diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance-for-range-copy.rst b/clang-tools-extra/docs/clang-tidy/checks/performance-for-range-copy.rst
index a48d6d4cb5399..01fde9580e2a0 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/performance-for-range-copy.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/performance-for-range-copy.rst
@@ -31,4 +31,6 @@ Options
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`).
diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst b/clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
index 661c3072e4796..7a8fe8408f422 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
@@ -43,5 +43,7 @@ Options
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`).
diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-value-param.rst b/clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-value-param.rst
index 21a5c65f6d5d4..cc5e1ae73508c 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-value-param.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-value-param.rst
@@ -66,4 +66,7 @@ Options
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`).
diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy-allowed-types.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy-allowed-types.cpp
index c40347c6d3558..3edc68a321293 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy-allowed-types.cpp
+++ b/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 @@ template <typename T> struct SomeComplexTemplate {
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 @@ void negativeNotTooComplexRef() {
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;
+ }
+}
More information about the cfe-commits
mailing list