arphaman updated this revision to Diff 228548.
arphaman marked 2 inline comments as done.
arphaman retitled this revision from "[WIP][clangd] Add a tweak refactoring to
wrap Objective-C string literals in `NSLocalizedString` macros" to "[clangd]
Add a tweak refactoring to wrap Objective-C string literals in
`NSLocalizedString` macros".
arphaman added a comment.
I figured out what I was doing wrong in the tests, and fixed them. This is no
longer WIP and is ready for review.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D69543/new/
https://reviews.llvm.org/D69543
Files:
clang-tools-extra/clangd/ParsedAST.h
clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
clang-tools-extra/clangd/refactor/tweaks/ObjCLocalizeStringLiteral.cpp
clang-tools-extra/clangd/unittests/TweakTests.cpp
Index: clang-tools-extra/clangd/unittests/TweakTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/TweakTests.cpp
+++ clang-tools-extra/clangd/unittests/TweakTests.cpp
@@ -122,6 +122,29 @@
EXPECT_EQ(apply(Input), Output);
}
+TWEAK_TEST(ObjCLocalizeStringLiteral);
+TEST_F(ObjCLocalizeStringLiteralTest, Test) {
+ ExtraArgs.push_back("-x");
+ ExtraArgs.push_back("objective-c");
+
+ // Ensure the the action can be initiated in the string literal.
+ EXPECT_AVAILABLE(R"(id x = ^@^"^t^est^";)");
+ EXPECT_AVAILABLE(R"(id x = [[@"test"]];)");
+ EXPECT_AVAILABLE(R"(id x = @[["test"]];)");
+
+ // Ensure that the action can't be initiated in other places.
+ EXPECT_UNAVAILABLE(R"(i^d ^x ^= @"test";^)");
+ EXPECT_UNAVAILABLE(R"(id [[x]] = @"test";)");
+ EXPECT_UNAVAILABLE(R"([[id x = @"test";]])");
+
+ // Ensure that the action is not available for regular C strings.
+ EXPECT_UNAVAILABLE(R"(const char * x= "^test";)");
+
+ const char *Input = R"(id x = [[@"test"]];)";
+ const char *Output = R"(id x = NSLocalizedString(@"test", @"");)";
+ EXPECT_EQ(apply(Input), Output);
+}
+
TWEAK_TEST(DumpAST);
TEST_F(DumpASTTest, Test) {
EXPECT_AVAILABLE("^int f^oo() { re^turn 2 ^+ 2; }");
Index: clang-tools-extra/clangd/refactor/tweaks/ObjCLocalizeStringLiteral.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clangd/refactor/tweaks/ObjCLocalizeStringLiteral.cpp
@@ -0,0 +1,86 @@
+//===--- ObjcLocalizeStringLiteral.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 "Logger.h"
+#include "ParsedAST.h"
+#include "SourceCode.h"
+#include "refactor/Tweak.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.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 {
+
+/// Wraps an Objective-C string literal with the NSLocalizedString macro.
+/// Before:
+/// @"description"
+/// ^^^
+/// After:
+/// NSLocalizedString(@"description", "")
+class ObjCLocalizeStringLiteral : public Tweak {
+public:
+ const char *id() const override final;
+ Intent intent() const override { return Intent::Refactor; }
+
+ bool prepare(const Selection &Inputs) override;
+ Expected<Tweak::Effect> apply(const Selection &Inputs) override;
+ std::string title() const override;
+
+private:
+ const clang::ObjCStringLiteral *Str = nullptr;
+};
+
+REGISTER_TWEAK(ObjCLocalizeStringLiteral)
+
+bool ObjCLocalizeStringLiteral::prepare(const Selection &Inputs) {
+ const SelectionTree::Node *N = Inputs.ASTSelection.commonAncestor();
+ if (!N)
+ return false;
+ // Allow the refactoring even if the user selected only the C string part
+ // of the expression.
+ if (N->ASTNode.get<StringLiteral>()) {
+ if (N->Parent)
+ N = N->Parent;
+ }
+ Str = dyn_cast_or_null<ObjCStringLiteral>(N->ASTNode.get<Stmt>());
+ return Str;
+}
+
+Expected<Tweak::Effect>
+ObjCLocalizeStringLiteral::apply(const Selection &Inputs) {
+ auto &SM = Inputs.AST.getSourceManager();
+ auto Reps = tooling::Replacements(tooling::Replacement(
+ SM, CharSourceRange::getCharRange(Str->getBeginLoc()),
+ "NSLocalizedString(", Inputs.AST.getASTContext().getLangOpts()));
+ SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ Str->getEndLoc(), 0, Inputs.AST.getSourceManager(),
+ Inputs.AST.getLangOpts());
+ if (auto Err = Reps.add(tooling::Replacement(
+ SM, CharSourceRange::getCharRange(EndLoc), ", @\"\")",
+ Inputs.AST.getASTContext().getLangOpts())))
+ return std::move(Err);
+ return Effect::mainFileEdit(SM, std::move(Reps));
+}
+
+std::string ObjCLocalizeStringLiteral::title() const {
+ return "Wrap in NSLocalizedString";
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
Index: clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
===================================================================
--- clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
+++ clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
@@ -19,6 +19,7 @@
ExpandMacro.cpp
ExtractFunction.cpp
ExtractVariable.cpp
+ ObjCLocalizeStringLiteral.cpp
RawStringLiteral.cpp
RemoveUsingNamespace.cpp
SwapIfBranches.cpp
Index: clang-tools-extra/clangd/ParsedAST.h
===================================================================
--- clang-tools-extra/clangd/ParsedAST.h
+++ clang-tools-extra/clangd/ParsedAST.h
@@ -77,6 +77,10 @@
return getASTContext().getSourceManager();
}
+ const LangOptions &getLangOpts() const {
+ return getASTContext().getLangOpts();
+ }
+
/// This function returns top-level decls present in the main file of the AST.
/// The result does not include the decls that come from the preamble.
/// (These should be const, but RecursiveASTVisitor requires Decl*).
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits