diff --git a/clang-tools-extra/clang-tidy/llvm/StringReferencingCheck.cpp b/clang-tools-extra/clang-tidy/llvm/StringReferencingCheck.cpp --- a/clang-tools-extra/clang-tidy/llvm/StringReferencingCheck.cpp +++ b/clang-tools-extra/clang-tidy/llvm/StringReferencingCheck.cpp @@ -19,39 +19,38 @@ namespace tidy { namespace llvm_check { +static const llvm::StringRef ParamID = "string_reference"; + void StringReferencingCheck::registerMatchers(MatchFinder *Finder) { - // create a matcher looking for const std::string& parameters - auto Matcher = - parmVarDecl(hasType(references(namedDecl( - hasName("string"), isInStdNamespace()))), // std::string& - hasType(references(qualType(isConstQualified()))), // const - hasType(lValueReferenceType()) // don't match std::string&& - ); - // Add matcher to the finder and bound matched nodes - Finder->addMatcher(Matcher.bind(BoundNodeId), this); + // Create a matcher looking for const std::string& parameters. + auto Matcher = parmVarDecl( + hasType(references(namedDecl(hasName("::std::string")))), // std::string& + hasType(references(qualType(isConstQualified()))), // const + hasType(lValueReferenceType()) // don't match std::string&& + ); + // Add matcher to the finder and bound matched nodes. + Finder->addMatcher(Matcher.bind(ParamID), this); } -void StringReferencingCheck::registerPPCallbacks( - const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { +void StringReferencingCheck::registerPPCallbacks(const SourceManager &, + Preprocessor *PP, + Preprocessor *) { Inserter.registerPreprocessor(PP); } void StringReferencingCheck::check(const MatchFinder::MatchResult &Result) { - // Retrieve parameters found by matcher - const auto *ParamDecl = Result.Nodes.getNodeAs(BoundNodeId); - // Extract parameter type location in source + // Retrieve parameters found by matcher. + const auto *ParamDecl = Result.Nodes.getNodeAs(ParamID); + // Extract parameter type location in source. clang::SourceRange TypeRange; auto ParamBegin = ParamDecl->getBeginLoc(); if (!ParamBegin.isValid()) return; TypeRange.setBegin(ParamBegin); TypeRange.setEnd(ParamDecl->getTypeSpecEndLoc()); - // Generate diagnostics and fix - diag(ParamBegin, "Use of const std::string & is discouraged in the LLVM " - "Programmer's Manual"); - diag(ParamBegin, "replace parameter %0 type with llvm::StringRef", - DiagnosticIDs::Note) - << ParamDecl + // Generate diagnostics and fix. + diag(ParamBegin, "parameter of type 'const std::string &' could potentially " + "be replaced with 'llvm::StringRef'") << FixItHint::CreateReplacement(TypeRange, "llvm::StringRef ") << Inserter.createMainFileIncludeInsertion( "llvm/include/llvm/ADT/StringRef.h", diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm-string-referencing.rst b/clang-tools-extra/docs/clang-tidy/checks/llvm-string-referencing.rst --- a/clang-tools-extra/docs/clang-tidy/checks/llvm-string-referencing.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/llvm-string-referencing.rst @@ -3,4 +3,15 @@ llvm-string-referencing ======================= -FIXME: Describe what patterns does the check detect and why. Give examples. +The StringRef data type represents a reference to a constant string (a +character array and a length) and supports the common operations available +on std::string. The LLVM Programmer's Manual recommends the use of StringRef +instead 'const std::string &' +https://llvm.org/docs/ProgrammersManual.html#id14 + +The check warns about uses of 'const std::string &' as a function parameter +type and provides an appropriate fix. + +IMPORTANT NOTE: not all std::string member functions are available from +StringRef so applying the fix should be considered on a case-by-case basis. + diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm-string-referencing.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm-string-referencing.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/llvm-string-referencing.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/llvm-string-referencing.cpp @@ -15,41 +15,41 @@ namespace A { using namespace std; void f(const string &P); -// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Use of const std::string & is discouraged in the LLVM Programmer's Manual [llvm-string-referencing] +// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: parameter of type 'const std::string &' could potentially be replaced with 'llvm::StringRef' [llvm-string-referencing] // CHECK-FIXES: void f(llvm::StringRef P);{{$}} } // namespace A namespace B { using std::string; void f1(const string &P); -// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Use of const std::string & is discouraged in the LLVM Programmer's Manual [llvm-string-referencing] +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter of type 'const std::string &' could potentially be replaced with 'llvm::StringRef' [llvm-string-referencing] // CHECK-FIXES: void f1(llvm::StringRef P);{{$}} } // namespace B void f2(std::string, int, const std::string &); -// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: Use of const std::string & is discouraged in the LLVM Programmer's Manual [llvm-string-referencing] +// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: parameter of type 'const std::string &' could potentially be replaced with 'llvm::StringRef' [llvm-string-referencing] // CHECK-FIXES: void f2(std::string, int, llvm::StringRef );{{$}} void f2(std::string P, int x, const std::string &P2) { - // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: Use of const std::string & is discouraged in the LLVM Programmer's Manual [llvm-string-referencing] + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: parameter of type 'const std::string &' could potentially be replaced with 'llvm::StringRef' [llvm-string-referencing] // CHECK-FIXES: void f2(std::string P, int x, llvm::StringRef P2) {{{$}} return; } void f3(const std::string &P1, const std::string &P2); -// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Use of const std::string & is discouraged in the LLVM Programmer's Manual [llvm-string-referencing] -// CHECK-MESSAGES: :[[@LINE-2]]:32: warning: Use of const std::string & is discouraged in the LLVM Programmer's Manual [llvm-string-referencing] +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter of type 'const std::string &' could potentially be replaced with 'llvm::StringRef' [llvm-string-referencing] +// CHECK-MESSAGES: :[[@LINE-2]]:32: warning: parameter of type 'const std::string &' could potentially be replaced with 'llvm::StringRef' [llvm-string-referencing] // CHECK-FIXES: void f3(llvm::StringRef P1, llvm::StringRef P2);{{$}} struct St { void operator=(const std::string &Val) const { - // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: Use of const std::string & is discouraged in the LLVM Programmer's Manual [llvm-string-referencing] + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: parameter of type 'const std::string &' could potentially be replaced with 'llvm::StringRef' [llvm-string-referencing] // CHECK-FIXES: void operator=(llvm::StringRef Val) const {{{$}} return; } }; void f7(const std::string &); -// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Use of const std::string & is discouraged in the LLVM Programmer's Manual [llvm-string-referencing] +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter of type 'const std::string &' could potentially be replaced with 'llvm::StringRef' [llvm-string-referencing] // CHECK-FIXES: void f7(llvm::StringRef );{{$}} // Functions below this line should not trigger the check