[clang-tidy] add default error message for performance-avoid-endl (#107867)

use std::endl as default message when matched expr does not have valid
source text

Fixes: #107859
This commit is contained in:
Congcong Cai 2024-09-14 07:33:06 +08:00 committed by GitHub
parent c6c3803b72
commit b7914dffd6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 33 additions and 15 deletions

View File

@ -46,38 +46,41 @@ void AvoidEndlCheck::check(const MatchFinder::MatchResult &Result) {
// Handle the more common streaming '... << std::endl' case
const CharSourceRange TokenRange =
CharSourceRange::getTokenRange(Expression->getSourceRange());
const StringRef SourceText = Lexer::getSourceText(
StringRef SourceText = Lexer::getSourceText(
TokenRange, *Result.SourceManager, Result.Context->getLangOpts());
if (SourceText.empty())
SourceText = "std::endl";
auto Diag = diag(Expression->getBeginLoc(),
"do not use '%0' with streams; use '\\n' instead")
<< SourceText;
Diag << FixItHint::CreateReplacement(TokenRange, "'\\n'");
if (TokenRange.isValid())
Diag << FixItHint::CreateReplacement(TokenRange, "'\\n'");
} else {
// Handle the less common function call 'std::endl(...)' case
const auto *CallExpression = llvm::cast<CallExpr>(Expression);
assert(CallExpression->getNumArgs() == 1);
const StringRef SourceText = Lexer::getSourceText(
StringRef SourceText = Lexer::getSourceText(
CharSourceRange::getTokenRange(
CallExpression->getCallee()->getSourceRange()),
*Result.SourceManager, Result.Context->getLangOpts());
if (SourceText.empty())
SourceText = "std::endl";
auto Diag = diag(CallExpression->getBeginLoc(),
"do not use '%0' with streams; use '\\n' instead")
<< SourceText;
const CharSourceRange ArgTokenRange = CharSourceRange::getTokenRange(
CallExpression->getArg(0)->getSourceRange());
const StringRef ArgSourceText = Lexer::getSourceText(
ArgTokenRange, *Result.SourceManager, Result.Context->getLangOpts());
const std::string ReplacementString =
std::string(ArgSourceText) + " << '\\n'";
diag(CallExpression->getBeginLoc(),
"do not use '%0' with streams; use '\\n' instead")
<< SourceText
<< FixItHint::CreateReplacement(
CharSourceRange::getTokenRange(CallExpression->getSourceRange()),
ReplacementString);
const CharSourceRange ReplacementRange =
CharSourceRange::getTokenRange(CallExpression->getSourceRange());
if (!ArgSourceText.empty() && ReplacementRange.isValid()) {
const std::string ReplacementString =
std::string(ArgSourceText) + " << '\\n'";
Diag << FixItHint::CreateReplacement(ReplacementRange, ReplacementString);
}
}
}

View File

@ -123,6 +123,10 @@ Changes in existing checks
<clang-tidy/checks/modernize/use-std-print>` check to support replacing
member function calls too.
- Improved :doc:`performance-avoid-endl
<clang-tidy/checks/performance/avoid-endl>` check to use ``std::endl`` as
placeholder when lexer cannot get source text.
- Improved :doc:`readability-implicit-bool-conversion
<clang-tidy/checks/readability/implicit-bool-conversion>` check
by adding the option `UseUpperCaseLiteralSuffix` to select the

View File

@ -225,3 +225,14 @@ void bad_custom_stream() {
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl]
// CHECK-FIXES: logger << '\n';
}
namespace gh107859 {
#define ENDL std::endl;
void bad_macro() {
std::cout << ENDL;
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl]
}
} // namespace gh107859