[clang-tools-extra] [clang-tidy]fix incorrect auto-fix for the string contains a user-defined suffix (PR #122901)

Congcong Cai via cfe-commits cfe-commits at lists.llvm.org
Tue Jan 14 06:53:46 PST 2025


https://github.com/HerrCai0907 updated https://github.com/llvm/llvm-project/pull/122901

>From 6cec0ebf3b028bdef5c381b0bea1985139d0c916 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Tue, 14 Jan 2025 21:10:57 +0800
Subject: [PATCH] [clang-tidy]fix incorrect auto-fix for the string contains a
 user-defined suffix

Fixed: #97243
---
 .../modernize/RawStringLiteralCheck.cpp       | 28 ++++++++++++++-----
 .../modernize/RawStringLiteralCheck.h         |  2 +-
 clang-tools-extra/docs/ReleaseNotes.rst       |  4 +++
 .../checkers/modernize/raw-string-literal.cpp | 13 +++++++++
 4 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.cpp b/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.cpp
index 7ec62f41aec019..126463ae795eb6 100644
--- a/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.cpp
@@ -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
diff --git a/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.h b/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.h
index aae58ca0e98d9a..6898e0624d1eb8 100644
--- a/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.h
@@ -35,7 +35,7 @@ class RawStringLiteralCheck : public ClangTidyCheck {
 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;
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 6350022ed9a8d3..4f7ab559254899 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -317,6 +317,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.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/raw-string-literal.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/raw-string-literal.cpp
index ad5d450036f2fd..5856b8882574a7 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/raw-string-literal.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/raw-string-literal.cpp
@@ -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



More information about the cfe-commits mailing list