12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/RecursiveASTVisitor.h"
14 #include "clang/AST/Stmt.h"
15 #include "clang/Basic/LangOptions.h"
16 #include "clang/Basic/SourceLocation.h"
17 #include "clang/Basic/SourceManager.h"
18 #include "clang/Lex/Lexer.h"
19 #include "clang/Tooling/Core/Replacement.h"
20 #include "llvm/ADT/None.h"
21 #include "llvm/ADT/Optional.h"
22 #include "llvm/ADT/StringRef.h"
23 #include "llvm/ADT/iterator_range.h"
24 #include "llvm/Support/Casting.h"
25 #include "llvm/Support/Error.h"
37 class RawStringLiteral :
public Tweak {
39 const char *id() const override final;
41 bool prepare(const Selection &
Inputs) override;
43 std::
string title()
const override {
return "Convert to raw string"; }
44 Intent intent()
const override {
return Refactor; }
47 const clang::StringLiteral *Str =
nullptr;
52 static bool isNormalString(
const StringLiteral &Str, SourceLocation Cursor,
57 SourceLocation LastTokenBeforeCursor;
58 for (
auto I = Str.tokloc_begin(),
E = Str.tokloc_end(); I !=
E; ++I) {
61 if (SM.isBeforeInTranslationUnit(*I, Cursor) || *I == Cursor)
62 LastTokenBeforeCursor = *I;
65 const char* Data = SM.getCharacterData(LastTokenBeforeCursor);
66 return Data && *Data ==
'"';
69 static bool needsRaw(llvm::StringRef Content) {
70 return Content.find_first_of(
"\"\n\t") != StringRef::npos;
73 static bool canBeRaw(llvm::StringRef Content) {
74 for (
char C : Content)
75 if (!llvm::isPrint(C) && C !=
'\n' && C !=
'\t')
77 return !Content.contains(
")\"");
80 bool RawStringLiteral::prepare(
const Selection &
Inputs) {
81 const SelectionTree::Node *N =
Inputs.ASTSelection.commonAncestor();
84 Str = dyn_cast_or_null<StringLiteral>(N->ASTNode.get<Stmt>());
86 isNormalString(*Str,
Inputs.Cursor,
Inputs.AST->getSourceManager()) &&
87 needsRaw(Str->getBytes()) && canBeRaw(Str->getBytes());
90 Expected<Tweak::Effect> RawStringLiteral::apply(
const Selection &
Inputs) {
91 auto &SM =
Inputs.AST->getSourceManager();
92 auto Reps = tooling::Replacements(
93 tooling::Replacement(SM, Str, (
"R\"(" + Str->getBytes() +
")\"").str(),
94 Inputs.AST->getLangOpts()));
95 return Effect::mainFileEdit(SM, std::move(Reps));