[clang-tools-extra] r361252 - [clangd] Add tweak to convert normal to raw string literal, when it contains escapes.
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Tue May 21 06:04:25 PDT 2019
Author: sammccall
Date: Tue May 21 06:04:24 2019
New Revision: 361252
URL: http://llvm.org/viewvc/llvm-project?rev=361252&view=rev
Log:
[clangd] Add tweak to convert normal to raw string literal, when it contains escapes.
Reviewers: ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D62151
Added:
clang-tools-extra/trunk/clangd/refactor/tweaks/RawStringLiteral.cpp
Modified:
clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt
clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp
Modified: clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt?rev=361252&r1=361251&r2=361252&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt Tue May 21 06:04:24 2019
@@ -12,6 +12,7 @@ set(LLVM_LINK_COMPONENTS
# $<TARGET_OBJECTS:obj.clangDaemonTweaks> to a list of sources, see
# clangd/tool/CMakeLists.txt for an example.
add_clang_library(clangDaemonTweaks OBJECT
+ RawStringLiteral.cpp
SwapIfBranches.cpp
LINK_LIBS
Added: clang-tools-extra/trunk/clangd/refactor/tweaks/RawStringLiteral.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/refactor/tweaks/RawStringLiteral.cpp?rev=361252&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/refactor/tweaks/RawStringLiteral.cpp (added)
+++ clang-tools-extra/trunk/clangd/refactor/tweaks/RawStringLiteral.cpp Tue May 21 06:04:24 2019
@@ -0,0 +1,103 @@
+//===--- RawStringLiteral.cpp ------------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "ClangdUnit.h"
+#include "Logger.h"
+#include "SourceCode.h"
+#include "refactor/Tweak.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+/// Converts a string literal to a raw string.
+/// Before:
+/// printf("\"a\"\nb");
+/// ^^^^^^^^^
+/// After:
+/// printf(R"("a"
+/// b)");
+class RawStringLiteral : public Tweak {
+public:
+ const char *id() const override final;
+
+ bool prepare(const Selection &Inputs) override;
+ Expected<tooling::Replacements> apply(const Selection &Inputs) override;
+ std::string title() const override;
+
+private:
+ const clang::StringLiteral *Str = nullptr;
+};
+
+REGISTER_TWEAK(RawStringLiteral)
+
+static bool isNormalString(const StringLiteral &Str, SourceLocation Cursor,
+ SourceManager &SM) {
+ // All chunks must be normal ASCII strings, not u8"..." etc.
+ if (!Str.isAscii())
+ return false;
+ SourceLocation LastTokenBeforeCursor;
+ for (auto I = Str.tokloc_begin(), E = Str.tokloc_end(); I != E; ++I) {
+ if (I->isMacroID()) // No tokens in the string may be macro expansions.
+ return false;
+ if (SM.isBeforeInTranslationUnit(*I, Cursor) || *I == Cursor)
+ LastTokenBeforeCursor = *I;
+ }
+ // Token we care about must be a normal "string": not raw, u8, etc.
+ const char* Data = SM.getCharacterData(LastTokenBeforeCursor);
+ return Data && *Data == '"';
+}
+
+static bool needsRaw(llvm::StringRef Content) {
+ return Content.find_first_of("\"\n\t") != StringRef::npos;
+}
+
+static bool canBeRaw(llvm::StringRef Content) {
+ for (char C : Content)
+ if (!llvm::isPrint(C) && C != '\n' && C != '\t')
+ return false;
+ return !Content.contains(")\"");
+}
+
+bool RawStringLiteral::prepare(const Selection &Inputs) {
+ const SelectionTree::Node *N = Inputs.ASTSelection.commonAncestor();
+ if (!N)
+ return false;
+ Str = dyn_cast_or_null<StringLiteral>(N->ASTNode.get<Stmt>());
+ return Str &&
+ isNormalString(*Str, Inputs.Cursor,
+ Inputs.AST.getASTContext().getSourceManager()) &&
+ needsRaw(Str->getBytes()) && canBeRaw(Str->getBytes());
+}
+
+Expected<tooling::Replacements>
+RawStringLiteral::apply(const Selection &Inputs) {
+ return tooling::Replacements(
+ tooling::Replacement(Inputs.AST.getASTContext().getSourceManager(), Str,
+ ("R\"(" + Str->getBytes() + ")\"").str(),
+ Inputs.AST.getASTContext().getLangOpts()));
+}
+
+std::string RawStringLiteral::title() const { return "Convert to raw string"; }
+
+} // namespace
+} // namespace clangd
+} // namespace clang
+
Modified: clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp?rev=361252&r1=361251&r2=361252&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp (original)
+++ clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp Tue May 21 06:04:24 2019
@@ -105,9 +105,10 @@ llvm::Expected<std::string> apply(String
}
void checkTransform(llvm::StringRef ID, llvm::StringRef Input,
- llvm::StringRef Output) {
- EXPECT_THAT_EXPECTED(apply(ID, Input), HasValue(Output))
- << "action id is" << ID;
+ std::string Output) {
+ auto Result = apply(ID, Input);
+ ASSERT_TRUE(bool(Result)) << llvm::toString(Result.takeError()) << Input;
+ EXPECT_EQ(Output, std::string(*Result)) << Input;
}
TEST(TweakTest, SwapIfBranches) {
@@ -185,6 +186,37 @@ TEST(TweakTest, SwapIfBranches) {
)cpp");
}
+TEST(TweakTest, RawStringLiteral) {
+ llvm::StringLiteral ID = "RawStringLiteral";
+
+ checkAvailable(ID, R"cpp(
+ const char *A = ^"^f^o^o^\^n^";
+ const char *B = R"(multi )" ^"token " "str\ning";
+ )cpp");
+
+ checkNotAvailable(ID, R"cpp(
+ const char *A = ^"f^o^o^o^"; // no chars need escaping
+ const char *B = R"(multi )" ^"token " u8"str\ning"; // not all ascii
+ const char *C = ^R^"^(^multi )" "token " "str\ning"; // chunk is raw
+ const char *D = ^"token\n" __FILE__; // chunk is macro expansion
+ const char *E = ^"a\r\n"; // contains forbidden escape character
+ )cpp");
+
+ const char *Input = R"cpp(
+ const char *X = R"(multi
+token)" "\nst^ring\n" "literal";
+ }
+ )cpp";
+ const char *Output = R"cpp(
+ const char *X = R"(multi
+token
+string
+literal)";
+ }
+ )cpp";
+ checkTransform(ID, Input, Output);
+}
+
} // namespace
} // namespace clangd
} // namespace clang
More information about the cfe-commits
mailing list