Skip to content

Commit ae825cb

Browse files
authored
[clang-tidy] Skip overloaded functions in modernize-use-string-view (llvm#183921)
1 parent 2033dc4 commit ae825cb

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed

clang-tools-extra/clang-tidy/modernize/UseStringViewCheck.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,38 @@ using namespace clang::ast_matchers;
2121

2222
namespace clang::tidy::modernize {
2323

24+
namespace {
25+
AST_MATCHER(FunctionDecl, isOverloaded) {
26+
const DeclarationName Name = Node.getDeclName();
27+
// Sanity check
28+
if (Name.isEmpty())
29+
return false;
30+
const DeclContext *DC = Node.getDeclContext();
31+
auto LookupResult = DC->lookup(Name);
32+
size_t UniqueSignatures = 0;
33+
llvm::SmallPtrSet<const FunctionDecl *, 2> SeenFunctions;
34+
for (NamedDecl *ND : LookupResult) {
35+
const FunctionDecl *FD = nullptr;
36+
if (const auto *Func = dyn_cast<FunctionDecl>(ND)) {
37+
// Regular functions
38+
FD = Func;
39+
} else if (const auto *USD = dyn_cast<UsingShadowDecl>(ND)) {
40+
// Overloads via "using ns::func_name"
41+
FD = dyn_cast<FunctionDecl>(USD->getTargetDecl());
42+
} else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(ND)) {
43+
// Templated functions
44+
FD = FTD->getTemplatedDecl();
45+
}
46+
if (FD && SeenFunctions.insert(FD->getCanonicalDecl()).second) {
47+
UniqueSignatures++;
48+
if (UniqueSignatures > 1)
49+
return true;
50+
}
51+
}
52+
return false;
53+
}
54+
} // namespace
55+
2456
static constexpr StringRef StringViewClassKey = "string";
2557
static constexpr StringRef WStringViewClassKey = "wstring";
2658
static constexpr StringRef U8StringViewClassKey = "u8string";
@@ -81,6 +113,7 @@ void UseStringViewCheck::registerMatchers(MatchFinder *Finder) {
81113
functionDecl(
82114
isDefinition(),
83115
unless(anyOf(VirtualOrOperator, IgnoredFunctionsMatcher,
116+
isOverloaded(),
84117
ast_matchers::isExplicitTemplateSpecialization())),
85118
returns(IsStdString), hasDescendant(returnStmt()),
86119
unless(hasDescendant(returnStmt(hasReturnValue(unless(

clang-tools-extra/docs/clang-tidy/checks/modernize/use-string-view.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ Limitations
8383
* ``auto Trailing() -> std::string { return "Trailing"; }`` warns, doesn't fix
8484
* returnings from lambda
8585
* complicated macro and templated code
86+
* overloaded functions and methods
8687

8788
In some cases the fixed code will not compile due to lack of conversion from
8889
``std::string_view`` to ``std::string``. It can be fixed (preferably) by

clang-tools-extra/test/clang-tidy/checkers/modernize/use-string-view.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,44 @@ MyString<wchar_t> aliasedWChar() {
203203
return L"aliasedWChar";
204204
}
205205

206+
namespace overload_funcs_redeclared {
207+
std::basic_string<char> overload(int);
208+
std::string overload(int);
209+
std::string overload(int) { return "int"; }
210+
// CHECK-MESSAGES:[[@LINE-1]]:1: warning: consider using 'std::string_view' to avoid unnecessary copying and allocations [modernize-use-string-view]
211+
// CHECK-FIXES: std::string_view overload(int) { return "int"; }
212+
}
213+
214+
namespace overload_non_func {
215+
struct overload {};
216+
std::string overload(int) { return "int"; }
217+
// CHECK-MESSAGES:[[@LINE-1]]:1: warning: consider using 'std::string_view' to avoid unnecessary copying and allocations [modernize-use-string-view]
218+
// CHECK-FIXES: std::string_view overload(int) { return "int"; }
219+
}
220+
221+
namespace overload_with_inline {
222+
inline namespace inline_namespace {
223+
std::string overload(int) { return "int"; }
224+
// CHECK-MESSAGES:[[@LINE-1]]:5: warning: consider using 'std::string_view' to avoid unnecessary copying and allocations [modernize-use-string-view]
225+
// CHECK-FIXES: std::string_view overload(int) { return "int"; }
226+
}
227+
inline namespace regular_namespace {
228+
std::string overload(int) { return "int"; }
229+
// CHECK-MESSAGES:[[@LINE-1]]:5: warning: consider using 'std::string_view' to avoid unnecessary copying and allocations [modernize-use-string-view]
230+
// CHECK-FIXES: std::string_view overload(int) { return "int"; }
231+
}
232+
}
233+
234+
namespace overload_with_outer {
235+
namespace overload_with_templates {
236+
template <typename T>
237+
std::string overload(T) { return "T"; }
238+
std::string overload(std::string) { return "string"; }
239+
}
240+
using overload_with_templates::overload;
241+
std::string overload(char*) { return "char*"; }
242+
}
243+
206244
// ==========================================================
207245
// Negative tests
208246
// ==========================================================
@@ -357,6 +395,59 @@ std::string lambda() {
357395
}();
358396
}
359397

398+
namespace overload_funcs {
399+
std::string dbl2str(double f);
400+
// Skip overloaded functions
401+
std::string overload(int) { return "int"; }
402+
// Because of this overload (non-literal return) the fix should not be applied
403+
std::string overload(double f) { return "f=" + dbl2str(f); }
404+
std::string overload(std::string) { return "string"; }
405+
}
406+
407+
namespace overload_methods {
408+
struct Foo {
409+
// Skip overloaded methods
410+
std::string overload(int) { return "int"; }
411+
std::string overload(double f) { return "double"; }
412+
std::string overload(std::string) { return "string"; }
413+
};
414+
}
415+
416+
namespace overload_methods_nested_classes {
417+
struct Bar {
418+
std::string overload(int) { return "int"; }
419+
std::string overload(std::string) { return "string"; }
420+
421+
struct FooBar {
422+
std::string overload(char*) { return "char*"; }
423+
std::string overload(double f) { return "double"; }
424+
};
425+
};
426+
}
427+
428+
namespace overload_methods_nested_namespaces {
429+
namespace foo {
430+
std::string overload(int) { return "int"; }
431+
std::string overload(std::string) { return "string"; }
432+
}
433+
using foo::overload;
434+
std::string overload(char*) { return "char*"; }
435+
}
436+
437+
namespace overload_methods_templated {
438+
template <typename T>
439+
std::string overload(T value) { return "T";}
440+
std::string overload(int value) { return "int"; }
441+
}
442+
443+
namespace two_overloads_with_inline {
444+
inline namespace inline_namespace {
445+
std::string overload(int) { return "int"; }
446+
std::string overload(double) { return "double"; }
447+
}
448+
std::string overload(int) { return "int"; }
449+
}
450+
360451
struct TemplateString {
361452
static constexpr char* val = "TEMPLATE";
362453
template<typename T>

0 commit comments

Comments
 (0)