diff --git a/clang-tools-extra/clang-tidy/utils/Matchers.h b/clang-tools-extra/clang-tidy/utils/Matchers.h --- a/clang-tools-extra/clang-tidy/utils/Matchers.h +++ b/clang-tools-extra/clang-tidy/utils/Matchers.h @@ -49,11 +49,46 @@ return pointerType(pointee(qualType(isConstQualified()))); } -AST_MATCHER_P(NamedDecl, matchesAnyListedName, std::vector, - NameList) { - return llvm::any_of(NameList, [&Node](const std::string &Name) { - return llvm::Regex(Name).match(Node.getName()); +class MatchesAnyListedNameMatcher + : public ast_matchers::internal::MatcherInterface { +public: + explicit MatchesAnyListedNameMatcher(llvm::ArrayRef NameList) { + std::transform(NameList.begin(), NameList.end(), + std::back_inserter(RegexAndScopes), + [](const llvm::StringRef Name) { + return RegexAndScope{ + .Regex = llvm::Regex(Name), + .MatchQualifiedName = Name.contains("::"), + }; + }); + } + bool matches( + const NamedDecl &Node, ast_matchers::internal::ASTMatchFinder *Finder, + ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override { + return llvm::any_of(RegexAndScopes, [&Node](const RegexAndScope &RAS) { + if (RAS.MatchQualifiedName) { + return RAS.Regex.match(Node.getQualifiedNameAsString()); + } + return RAS.Regex.match(Node.getName()); }); + } + +private: + struct RegexAndScope { + llvm::Regex Regex; + bool MatchQualifiedName = false; + }; + + std::vector RegexAndScopes; +}; + +// Returns a matcher that matches NamedDecls against a list of provided regular +// expressions. If a regular expression contains '::' the NamedDecls qualified +// name will be used for matching, otherwise its name will be used. +inline ::clang::ast_matchers::internal::Matcher +matchesAnyListedName(llvm::ArrayRef 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 --- 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 @@ 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 --- 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 @@ 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 --- 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 @@ 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 --- 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)?$;fully::Qualified'}]}" \ // RUN: -- -fno-delayed-template-parsing template @@ -63,6 +63,14 @@ typedef SomeComplexTemplate NotTooComplexRef; +namespace fully { + +struct Qualified { + ~Qualified(); +}; + +} // namespace fully + void negativeSmartPointer() { for (auto P : View>()) { auto P2 = P; @@ -124,3 +132,13 @@ auto R2 = R; } } + +void negativeFullyQualified() { + for (auto Q : View>()) { + auto Q2 = Q; + } + using fully::Qualified; + for (auto Q : View>()) { + auto Q2 = Q; + } +}