[clang-tidy]fix incorrect fix-it for the string contains a user-defined suffix (#122901)

Fixed: #97243
This commit is contained in:
Congcong Cai 2025-01-17 21:41:48 +08:00 committed by GitHub
parent 6dcb2a0902
commit 361f363c11
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 39 additions and 8 deletions

View File

@ -10,6 +10,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/StringRef.h"
using namespace clang::ast_matchers;
@ -136,13 +137,26 @@ void RawStringLiteralCheck::check(const MatchFinder::MatchResult &Result) {
void RawStringLiteralCheck::replaceWithRawStringLiteral(
const MatchFinder::MatchResult &Result, const StringLiteral *Literal,
StringRef Replacement) {
CharSourceRange CharRange = Lexer::makeFileCharRange(
CharSourceRange::getTokenRange(Literal->getSourceRange()),
*Result.SourceManager, getLangOpts());
diag(Literal->getBeginLoc(),
"escaped string literal can be written as a raw string literal")
<< FixItHint::CreateReplacement(CharRange, Replacement);
std::string Replacement) {
DiagnosticBuilder Builder =
diag(Literal->getBeginLoc(),
"escaped string literal can be written as a raw string literal");
const SourceManager &SM = *Result.SourceManager;
const CharSourceRange TokenRange =
CharSourceRange::getTokenRange(Literal->getSourceRange());
Token T;
if (Lexer::getRawToken(Literal->getBeginLoc(), T, SM, getLangOpts()))
return;
const CharSourceRange CharRange =
Lexer::makeFileCharRange(TokenRange, SM, getLangOpts());
if (T.hasUDSuffix()) {
const StringRef Text = Lexer::getSourceText(CharRange, SM, getLangOpts());
const size_t UDSuffixPos = Text.find_last_of('"');
if (UDSuffixPos == StringRef::npos)
return;
Replacement += Text.slice(UDSuffixPos + 1, Text.size());
}
Builder << FixItHint::CreateReplacement(CharRange, Replacement);
}
} // namespace clang::tidy::modernize

View File

@ -35,7 +35,7 @@ public:
private:
void replaceWithRawStringLiteral(
const ast_matchers::MatchFinder::MatchResult &Result,
const StringLiteral *Literal, StringRef Replacement);
const StringLiteral *Literal, std::string Replacement);
std::string DelimiterStem;
CharsBitSet DisallowedChars;

View File

@ -321,6 +321,10 @@ Changes in existing checks
a false positive when only an implicit conversion happened inside an
initializer list.
- Improved :doc:`modernize-raw-string-literal
<clang-tidy/checks/modernize/raw-string-literal>` check to fix incorrect
fix-it when the string contains a user-defined suffix.
- Improved :doc:`modernize-use-designated-initializers
<clang-tidy/checks/modernize/use-designated-initializers>` check to fix a
crash when a class is declared but not defined.

View File

@ -129,3 +129,16 @@ void callFn() {
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} can be written as a raw string literal
// CHECK-FIXES: {{^}} fn<double>(R"(foo\bar)");{{$}}
}
namespace std {
using size_t = decltype(sizeof(0));
namespace ud {
int operator""_abc(const char *str, std::size_t len);
} // namespace ud
} // namespace std
namespace gh97243 {
using namespace std::ud;
auto UserDefinedLiteral = "foo\\bar"_abc;
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: {{.*}} can be written as a raw string literal
// CHECK-FIXES: {{^}}auto UserDefinedLiteral = R"(foo\bar)"_abc;
} // namespace gh97243