10 #include "clang/AST/Stmt.h"
11 #include "clang/Basic/LangOptions.h"
12 #include "clang/Basic/SourceLocation.h"
13 #include "clang/Basic/SourceManager.h"
14 #include "clang/Tooling/Core/Replacement.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Support/Casting.h"
17 #include "llvm/Support/Error.h"
29 class RawStringLiteral :
public Tweak {
31 const char *id() const final;
33 bool prepare(const Selection &
Inputs) override;
35 std::
string title()
const override {
return "Convert to raw string"; }
36 llvm::StringLiteral kind()
const override {
41 const clang::StringLiteral *Str =
nullptr;
46 static bool isNormalString(
const StringLiteral &Str, SourceLocation Cursor,
49 if (!Str.isOrdinary())
51 SourceLocation LastTokenBeforeCursor;
52 for (
auto I = Str.tokloc_begin(),
E = Str.tokloc_end(); I !=
E; ++I) {
55 if (SM.isBeforeInTranslationUnit(*I, Cursor) || *I == Cursor)
56 LastTokenBeforeCursor = *I;
59 const char* Data = SM.getCharacterData(LastTokenBeforeCursor);
60 return Data && *Data ==
'"';
63 static bool needsRaw(llvm::StringRef Content) {
64 return Content.find_first_of(
"\"\n\t") != StringRef::npos;
67 static bool canBeRaw(llvm::StringRef Content) {
68 for (
char C : Content)
69 if (!llvm::isPrint(
C) &&
C !=
'\n' &&
C !=
'\t')
71 return !Content.contains(
")\"");
74 bool RawStringLiteral::prepare(
const Selection &
Inputs) {
75 const SelectionTree::Node *N =
Inputs.ASTSelection.commonAncestor();
78 Str = dyn_cast_or_null<StringLiteral>(N->ASTNode.get<Stmt>());
80 isNormalString(*Str,
Inputs.Cursor,
Inputs.AST->getSourceManager()) &&
81 needsRaw(Str->getBytes()) && canBeRaw(Str->getBytes());
84 Expected<Tweak::Effect> RawStringLiteral::apply(
const Selection &
Inputs) {
85 auto &SM =
Inputs.AST->getSourceManager();
86 auto Reps = tooling::Replacements(
87 tooling::Replacement(SM, Str, (
"R\"(" + Str->getBytes() +
")\"").str(),
88 Inputs.AST->getLangOpts()));
89 return Effect::mainFileEdit(SM, std::move(Reps));