[clang-tidy] Add a new check 'replace-with-string-view'
Looks for functions returning std::[w|u8|u16|u32]string and suggests to change it to std::[...]string_view if possible and profitable.
Example:
std::string foo(int i) { // <---- can be replaced to `std::string_view foo(...) {`
switch(i) {
case 1:
return "case1";
case 2:
return "case2";
default:
return {};
}
}
@llvm/pr-subscribers-clang-tidy
@llvm/pr-subscribers-clang-tools-extra
Author: Zinovy Nis (irishrover)
Changes
Looks for functions returning std::[w|u8|u16|u32]string and suggests to change it to std::[...]string_view if possible and profitable.
Example:
std::string foo(int i) { // <---- can be replaced to std::string_view f(...) {
switch(i) {
case 1:
return "case1";
case 2:
return "case2";
default:
return {};
}
}
Full diff: https://github.com/llvm/llvm-project/pull/172170.diff
8 Files Affected:
- (modified) clang-tools-extra/clang-tidy/performance/CMakeLists.txt (+1)
- (modified) clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp (+3)
- (added) clang-tools-extra/clang-tidy/performance/ReplaceWithStringViewCheck.cpp (+74)
- (added) clang-tools-extra/clang-tidy/performance/ReplaceWithStringViewCheck.h (+47)
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+6)
- (modified) clang-tools-extra/docs/clang-tidy/checks/list.rst (+1)
- (added) clang-tools-extra/docs/clang-tidy/checks/performance/replace-with-string-view.rst (+60)
- (added) clang-tools-extra/test/clang-tidy/checkers/performance/replace-with-string-view.cpp (+142)
diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
index 9a2f90069edbf..21a9442be69c0 100644
--- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
@@ -21,6 +21,7 @@ add_clang_library(clangTidyPerformanceModule STATIC
NoexceptMoveConstructorCheck.cpp
NoexceptSwapCheck.cpp
PerformanceTidyModule.cpp
+ ReplaceWithStringViewCheck.cpp
TriviallyDestructibleCheck.cpp
TypePromotionInMathFnCheck.cpp
UnnecessaryCopyInitializationCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
index 3497ea7316c6b..e17bfc42be58f 100644
--- a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
@@ -24,6 +24,7 @@
#include "NoexceptDestructorCheck.h"
#include "NoexceptMoveConstructorCheck.h"
#include "NoexceptSwapCheck.h"
+#include "ReplaceWithStringViewCheck.h"
#include "TriviallyDestructibleCheck.h"
#include "TypePromotionInMathFnCheck.h"
#include "UnnecessaryCopyInitializationCheck.h"
@@ -62,6 +63,8 @@ class PerformanceModule : public ClangTidyModule {
"performance-noexcept-move-constructor");
CheckFactories.registerCheck<NoexceptSwapCheck>(
"performance-noexcept-swap");
+ CheckFactories.registerCheck<ReplaceWithStringViewCheck>(
+ "performance-replace-with-string-view");
CheckFactories.registerCheck<TriviallyDestructibleCheck>(
"performance-trivially-destructible");
CheckFactories.registerCheck<TypePromotionInMathFnCheck>(
diff --git a/clang-tools-extra/clang-tidy/performance/ReplaceWithStringViewCheck.cpp b/clang-tools-extra/clang-tidy/performance/ReplaceWithStringViewCheck.cpp
new file mode 100644
index 0000000000000..0cb11cda8e1aa
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/performance/ReplaceWithStringViewCheck.cpp
@@ -0,0 +1,74 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReplaceWithStringViewCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::performance {
+
+namespace {
+llvm::StringLiteral toStringViewTypeStr(StringRef Type) {
+ if (Type.contains("wchar_t"))
+ return "std::wstring_view";
+ if (Type.contains("wchar_t"))
+ return "std::wstring_view";
+ if (Type.contains("char8_t"))
+ return "std::u8string_view";
+ if (Type.contains("char16_t"))
+ return "std::u16string_view";
+ if (Type.contains("char32_t"))
+ return "std::u32string_view";
+ return "std::string_view";
+}
+} // namespace
+
+void ReplaceWithStringViewCheck::registerMatchers(MatchFinder *Finder) {
+ const auto IsStdString = hasCanonicalType(
+ hasDeclaration(cxxRecordDecl(hasName("::std::basic_string"))));
+ const auto IsStdStringView = expr(hasType(hasCanonicalType(
+ hasDeclaration(cxxRecordDecl(hasName("::std::basic_string_view"))))));
+
+ Finder->addMatcher(
+ functionDecl(
+ isDefinition(), returns(IsStdString), hasDescendant(returnStmt()),
+ unless(hasDescendant(
+ returnStmt(hasReturnValue(unless(ignoringImplicit(anyOf(
+ stringLiteral(), IsStdStringView,
+ cxxConstructExpr(
+ hasType(IsStdString),
+ anyOf(argumentCountIs(0),
+ hasArgument(0, ignoringParenImpCasts(anyOf(
+ stringLiteral(),
+ IsStdStringView)))))))))))))
+ .bind("func"),
+ this);
+}
+
+void ReplaceWithStringViewCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>("func")) {
+ const llvm::StringLiteral DestReturnTypeStr =
+ toStringViewTypeStr(MatchedDecl->getReturnType()
+ .getDesugaredType(*Result.Context)
+ .getAsString());
+
+ auto Diag = diag(MatchedDecl->getReturnTypeSourceRange().getBegin(),
+ "consider using `%0' to avoid unnecessary "
+ "copying and allocations")
+ << DestReturnTypeStr << MatchedDecl;
+
+ for (const auto *FuncDecl = MatchedDecl; FuncDecl != nullptr;
+ FuncDecl = FuncDecl->getPreviousDecl()) {
+ Diag << FixItHint::CreateReplacement(FuncDecl->getReturnTypeSourceRange(),
+ DestReturnTypeStr);
+ }
+ }
+}
+
+} // namespace clang::tidy::performance
diff --git a/clang-tools-extra/clang-tidy/performance/ReplaceWithStringViewCheck.h b/clang-tools-extra/clang-tidy/performance/ReplaceWithStringViewCheck.h
new file mode 100644
index 0000000000000..a9635939e850d
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/performance/ReplaceWithStringViewCheck.h
@@ -0,0 +1,47 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_REPLACEWITHSTRINGVIEWCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_REPLACEWITHSTRINGVIEWCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::performance {
+
+/// Looks for functions returning `std::[w|u8|u16|u32]string` and suggests to
+/// change it to `std::[...]string_view` if possible and profitable.
+///
+/// Example:
+///
+/// std::string foo(int i) { // <---- can be replaced to std::string_view f(...)
+/// switch(i) {
+/// case 1:
+/// return "case1";
+/// case 2:
+/// return "case2";
+/// default:
+/// return {};
+/// }
+/// }
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/performance/replace-with-string-view.html
+class ReplaceWithStringViewCheck : public ClangTidyCheck {
+public:
+ ReplaceWithStringViewCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus17;
+ }
+};
+
+} // namespace clang::tidy::performance
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_REPLACEWITHSTRINGVIEWCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 27467d082ea1e..03470b8c78489 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -244,6 +244,12 @@ New checks
Finds virtual function overrides with different visibility than the function
in the base class.
+- New :doc:`performance-replace-with-string-view
+ <clang-tidy/checks/performance/replace-with-string-view>` check.
+
+ Detects functions returning std::[w|u8|u16|u32]string where
+ return type can be changed to std::[...]string_view.
+
- New :doc:`readability-redundant-parentheses
<clang-tidy/checks/readability/redundant-parentheses>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index e5e77b5cc418b..a45293b1f7823 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -362,6 +362,7 @@ Clang-Tidy Checks
:doc:`performance-noexcept-destructor <performance/noexcept-destructor>`, "Yes"
:doc:`performance-noexcept-move-constructor <performance/noexcept-move-constructor>`, "Yes"
:doc:`performance-noexcept-swap <performance/noexcept-swap>`, "Yes"
+ :doc:`performance-replace-with-string-view <performance/replace-with-string-view>`, "Yes"
:doc:`performance-trivially-destructible <performance/trivially-destructible>`, "Yes"
:doc:`performance-type-promotion-in-math-fn <performance/type-promotion-in-math-fn>`, "Yes"
:doc:`performance-unnecessary-copy-initialization <performance/unnecessary-copy-initialization>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance/replace-with-string-view.rst b/clang-tools-extra/docs/clang-tidy/checks/performance/replace-with-string-view.rst
new file mode 100644
index 0000000000000..a5dc48b450c40
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/performance/replace-with-string-view.rst
@@ -0,0 +1,60 @@
+.. title:: clang-tidy - performance-replace-with-string-view
+
+performance-replace-with-string-view
+====================================
+
+Looks for functions returning `std::[w|u8|u16|u32]string` and suggests to
+change it to `std::[...]string_view` for performance reasons.
+
+Rationale:
+
+Each time a new ``std::string`` is created from a literal, a copy of that
+literal is allocated either in ``std::string``'s internal buffer
+(for short literals) or in a heap.
+
+For the cases where ``std::string`` is returned from a function,
+such allocations can be eliminated sometimes by using std::string_view
+as a return type.
+
+This check looks for such functions returning ``std::string``
+baked from the literals and suggests replacing the return type to ``std::string_view``.
+
+It handles std::string,std::wstring, std::u8string, std::u16string and
+std::u16string and properly selects the kind of std::string_view to return.
+Typedefs for these string type also supported.
+
+Example:
+
+Consider the following code:
+
+.. code-block:: c++
+
+ std::string foo(int i) {
+ switch(i)
+ {
+ case 1: return "case 1";
+ case 2: return "case 2";
+ case 3: return "case 3";
+ default: return "default";
+ }
+ }
+
+In the code above a new ``std::string`` object is created on each
+function invocation, making a copy of a string literal and possibly
+allocating a memory in a heap.
+
+The check gets this code transformed into:
+
+.. code-block:: c++
+
+ std::string_view foo(int i) {
+ switch(i)
+ {
+ case 1: return "case 1";
+ case 2: return "case 2";
+ case 3: return "case 3";
+ default: return "default";
+ }
+ }
+
+New version re-uses statically allocated literals without additional overhead.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/replace-with-string-view.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/replace-with-string-view.cpp
new file mode 100644
index 0000000000000..625d729a6e4c9
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/performance/replace-with-string-view.cpp
@@ -0,0 +1,142 @@
+// RUN: %check_clang_tidy -std=c++17-or-later %s performance-replace-with-string-view %t -- -- -I %S/Inputs
+
+namespace std {
+ template <typename CharT>
+ class basic_string_view {
+ public:
+ basic_string_view(const CharT *);
+ basic_string_view();
+ };
+ using string_view = basic_string_view<char>;
+ using wstring_view = basic_string_view<wchar_t>;
+ using u16string_view = basic_string_view<char16_t>;
+
+ template <typename CharT>
+ class basic_string {
+ public:
+ basic_string();
+ basic_string(const CharT *);
+ basic_string(basic_string_view<CharT>);
+
+ basic_string operator+(const basic_string &) const;
+ };
+ using string = basic_string<char>;
+ using wstring = basic_string<wchar_t>;
+ using u16string = basic_string<char16_t>;
+}
+
+// ==========================================================
+// Positive tests
+// ==========================================================
+
+std::string simpleLiteral() {
+// CHECK-MESSAGES:[[@LINE-1]]:1: {{.*}}[performance-replace-with-string-view]{{.*}}
+// CHECK-FIXES: std::string_view{{.*}}
+ return "simpleLiteral";
+}
+
+std::string implicitView(std::string_view sv) {
+// CHECK-MESSAGES:[[@LINE-1]]:1: {{.*}}[performance-replace-with-string-view]{{.*}}
+// CHECK-FIXES: std::string_view{{.*}}
+ return sv;
+}
+
+std::string emptyReturn() {
+// CHECK-MESSAGES:[[@LINE-1]]:1: {{.*}}[performance-replace-with-string-view]{{.*}}
+// CHECK-FIXES: std::string_view{{.*}}
+ return {};
+}
+
+std::string switchCaseTest(int i) {
+// CHECK-MESSAGES:[[@LINE-1]]:1: {{.*}}[performance-replace-with-string-view]{{.*}}
+// CHECK-FIXES: std::string_view{{.*}}
+ switch (i) {
+ case 1:
+ return "case1";
+ case 2:
+ return "case2";
+ case 3:
+ return {};
+ default:
+ return "default";
+ }
+}
+
+std::string ifElseTest(bool flag) {
+// CHECK-MESSAGES:[[@LINE-1]]:1: {{.*}}[performance-replace-with-string-view]{{.*}}
+// CHECK-FIXES: std::string_view{{.*}}
+ if (flag)
+ return "true";
+ return "false";
+}
+
+std::wstring wideStringTest() {
+// CHECK-MESSAGES:[[@LINE-1]]:1: {{.*}}[performance-replace-with-string-view]{{.*}}
+// CHECK-FIXES: std::wstring_view{{.*}}
+ return L"wide literal";
+}
+
+std::u16string u16StringTest() {
+// CHECK-MESSAGES:[[@LINE-1]]:1: {{.*}}[performance-replace-with-string-view]{{.*}}
+// CHECK-FIXES: std::u16string_view{{.*}}
+ return u"u16 literal";
+}
+
+class A {
+ std::string classMethodInt() { return "internal"; }
+// CHECK-MESSAGES:[[@LINE-1]]:3: {{.*}}[performance-replace-with-string-view]{{.*}}
+// CHECK-FIXES: std::string_view{{.*}}
+
+ std::string classMethodExt();
+// CHECK-MESSAGES:[[@LINE+4]]:1: {{.*}}[performance-replace-with-string-view]{{.*}}
+// CHECK-FIXES: std::string_view{{.*}}
+};
+
+std::string A::classMethodExt() { return "external"; }
+// CHECK-FIXES: std::string_view{{.*}}
+
+// ==========================================================
+// Negative tests
+// ==========================================================
+
+std::string localVariable() {
+ std::string s = "local variable";
+ return s;
+}
+
+std::string dynamicCalculation() {
+ std::string s1 = "hello ";
+ return s1 + "world";
+}
+
+std::string mixedReturns(bool flag) {
+ if (flag) {
+ return "safe static literal";
+ }
+ std::string s = "unsafe dynamic";
+ return s;
+}
+
+std::string_view alreadyGood() {
+ return "alreadyGood";
+}
+
+std::string returnArgCopy(std::string s) {
+ return s;
+}
+
+std::string returnIndirection(const char* ptr) {
+ // TODO: should be convertible to std::string_view
+ return ptr;
+}
+
+std::string passStringView(std::string_view sv) {
+ // TODO: should be convertible to std::string_view
+ return std::string(sv);
+}
+
+std::string explicitConstruction() {
+ // Cannot be std::string_view: returning address of local temporary object
+ return std::string("explicitConstruction");
+}
+
:white_check_mark: With the latest revision this PR passed the C/C++ code linter.
How about custom classes like
StringRefin LLVM?
Maybe add an option for a destination type and set the default to std::string_view?
In the last commit I added checks for virtual/override methods - seems they should be ignored.
How about custom classes like
StringRefin LLVM?
Yes, we should add option ReplacementStringViewClass (with std:: by default) for users to specify a custom pre C++-17 class for string_view. It could be boost::string_view also, which could be used extensively in pre C++-17 codebases.
:white_check_mark: With the latest revision this PR passed the C/C++ code formatter.
:window: Windows x64 Test Results
- 3003 tests passed
- 30 tests skipped
:white_check_mark: The build succeeded and all tests passed.
How about custom classes like
StringRefin LLVM?Yes, we should add option
ReplacementStringViewClass(with std:: by default) for users to specify a custom pre C++-17 class for string_view. It could beboost::string_viewalso, which could be used extensively in pre C++-17 codebases.
I think one option is not enough, as there can be std::u16string-like custom classes. So it looks more like a map.
Maybe it worth to merge the PR in the current state and then I'll add options support and other optimizations as separate commits not to overcomplicate this PR?
Maybe it worth to merge the PR in the current state and then I'll add options support and other optimizations as separate commits not to overcomplicate this PR?
Sure, we can go like this. I'll try to re-review it soon.
For now, could we change check name to modernize-use-string-view, WDYT?
We have this issue https://github.com/llvm/llvm-project/issues/29059 to covert string to string_veiw. And I think modernize-use-string-view check can be easily extended to convert global string a = "text" to string_view a = "text".
So it's better to give a generic name to cover more cases in the future rather than having multiple smaller checks.
Maybe it worth to merge the PR in the current state and then I'll add options support and other optimizations as separate commits not to overcomplicate this PR?
Sure, we can go like this. I'll try to re-review it soon.
For now, could we change check name to
modernize-use-string-view, WDYT?We have this issue #29059 to covert string to string_veiw. And I think
modernize-use-string-viewcheck can be easily extended to convert globalstring a = "text"tostring_view a = "text".So it's better to give a generic name to cover more cases in the future rather than having multiple smaller checks.
Yes> sure. So I move the check to modernize-* family (ironically it lived there initially before I submitted it here) and wait for the approvals.
I prefer "misc-use-string-view" because there is not only one reason to use it.
- Doesn't copy underlying string.
- Cheap to copy.
- Can take both
std::stringand string literals ("str").
FYI someone suggested "modernize-use-span". #156058
I prefer "misc-use-string-view" because there is not only one reason to use it.
Doesn't copy underlying string. Cheap to copy. Can take both std::string and string literals ("str").
I'm fine with misc-use-string-view since we already have misc-use-internal-linkage. But I have a gut feeling that modernize-use-string-view would be better because it brings "modernization" to the project (improvement in speed, readability, reusability).
In clang-tidy docs we have description of misc as "Checks that we didn’t have a better category for", so use-string-view feels like a modernization check to me (same as modernize-use-span).
So I'm in favor of modernize-use-string-view
So I have 2 things to be done:
- rename the check
- add options for custom string types (most probably in the next PR)
What's done:
- renamed to
modernize-use-string-view - added a lot of tests and some code had been fixed due to that
- simplified some conditions
- minor cleanups.
Thanks a lot for your remarks and suggested test samples!
Here's what I've got on the LLVM project trunk use-string-view.patch
getArcana
Thanks. Looks like overloaded functions? So let's ignore overloaded functions as I do for virtual/override?
getArcanaThanks. Looks like overloaded functions? So let's ignore overloaded functions as I do for virtual/override?
Not always overloaded functions; another case is:
// Literals are just printed
- std::string VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
+ std::string_view VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
return "nullptr";
}
std::string VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
return E->getValue() ? "true" : "false";
}
std::string VisitIntegerLiteral(const IntegerLiteral *E) {
return llvm::to_string(E->getValue());
}
std::string VisitFloatingLiteral(const FloatingLiteral *E) {
std::string Result;
llvm::raw_string_ostream OS(Result);
E->getValue().print(OS);
// Printer adds newlines?!
Result.resize(llvm::StringRef(Result).rtrim().size());
return Result;
}
So I'd want a generic mechanism to suppress diagnostics without nolint
std::string getArcana(const TemplateName &NNS) { return std::string{""}; // no warning, explicit ctor call return std::string(""); // no warning }
It works even w/o options. Just wrap literal with std::string(...) or std::string{}. Pls, see the tests:
std::string explicitConstructionEmpty() {
return std::string("");
}
std::string explicitConstructionWithInitListEmpty() {
return std::string{""};
}
std::string getArcana(const TemplateName &NNS) { return std::string{""}; // no warning, explicit ctor call return std::string(""); // no warning }It works even w/o options. Just wrap literal with
std::string(...)orstd::string{}. Pls, see the tests:std::string explicitConstructionEmpty() { return std::string(""); } std::string explicitConstructionWithInitListEmpty() { return std::string{""}; }
In tests they are marked as "todo" for now,
std::string explicitConstruction() {
// Cannot be std::string_view: returning address of local temporary object
// TODO: extract and return literal
return std::string("explicitConstruction");
}
std::string explicitConstructionWithInitList() {
// Cannot be std::string_view: returning address of local temporary object
// TODO: extract and return literal
return std::string{"explicitConstruction"};
}
When eventually have this is implemented, should become an option. Please state in docs that diagnostic could be suppressed by manually constructing string from literal.
Also, please state in docs what are current limitations of this check (ternary op, literals inside strings) so that user don't report them as FN.
std::string getArcana(const TemplateName &NNS) { return std::string{""}; // no warning, explicit ctor call return std::string(""); // no warning }It works even w/o options. Just wrap literal with
std::string(...)orstd::string{}. Pls, see the tests:std::string explicitConstructionEmpty() { return std::string(""); } std::string explicitConstructionWithInitListEmpty() { return std::string{""}; }In tests they are marked as "todo" for now,
std::string explicitConstruction() { // Cannot be std::string_view: returning address of local temporary object // TODO: extract and return literal return std::string("explicitConstruction"); } std::string explicitConstructionWithInitList() { // Cannot be std::string_view: returning address of local temporary object // TODO: extract and return literal return std::string{"explicitConstruction"}; }When eventually have this is implemented, should become an option. Please state in docs that diagnostic could be suppressed by manually constructing string from literal.
Also, please state in docs what are current limitations of this check (ternary op, literals inside strings) so that user don't report them as FN.
Done!
Any other comments? If no, I'd like to merge it tomorrow.