1//===--- ObjcLocalizeStringLiteral.cpp ---------------------------*- C++-*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ParsedAST.h"
10#include "refactor/Tweak.h"
11#include "support/Logger.h"
12#include "clang/AST/ExprObjC.h"
13#include "clang/Basic/SourceLocation.h"
14#include "clang/Basic/SourceManager.h"
15#include "clang/Tooling/Core/Replacement.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/Support/Casting.h"
18#include "llvm/Support/Error.h"
19
20namespace clang {
21namespace clangd {
22namespace {
23
24/// Wraps an Objective-C string literal with the NSLocalizedString macro.
25/// Before:
26/// @"description"
27/// ^^^
28/// After:
29/// NSLocalizedString(@"description", @"")
30class ObjCLocalizeStringLiteral : public Tweak {
31public:
32 const char *id() const final;
33 llvm::StringLiteral kind() const override {
34 return CodeAction::REFACTOR_KIND;
35 }
36
37 bool prepare(const Selection &Inputs) override;
38 Expected<Tweak::Effect> apply(const Selection &Inputs) override;
39 std::string title() const override;
40
41private:
42 const clang::ObjCStringLiteral *Str = nullptr;
43};
44
45REGISTER_TWEAK(ObjCLocalizeStringLiteral)
46
47bool ObjCLocalizeStringLiteral::prepare(const Selection &Inputs) {
48 const SelectionTree::Node *N = Inputs.ASTSelection.commonAncestor();
49 if (!N)
50 return false;
51 // Allow the refactoring even if the user selected only the C string part
52 // of the expression.
53 if (N->ASTNode.get<StringLiteral>()) {
54 if (N->Parent)
55 N = N->Parent;
56 }
57 Str = dyn_cast_or_null<ObjCStringLiteral>(N->ASTNode.get<Stmt>());
58 return Str;
59}
60
61Expected<Tweak::Effect>
62ObjCLocalizeStringLiteral::apply(const Selection &Inputs) {
63 auto *AST = Inputs.AST;
64 auto &SM = AST->getSourceManager();
65 const auto &TB = AST->getTokens();
66 auto Toks = TB.spelledForExpanded(Expanded: TB.expandedTokens(Str->getSourceRange()));
67 if (!Toks || Toks->empty())
68 return error(Fmt: "Failed to find tokens to replace.");
69 // Insert `NSLocalizedString(` before the literal.
70 auto Reps = tooling::Replacements(tooling::Replacement(
71 SM, Toks->front().location(), 0, "NSLocalizedString("));
72 // Insert `, @"")` after the literal.
73 if (auto Err = Reps.add(
74 tooling::Replacement(SM, Toks->back().endLocation(), 0, ", @\"\")")))
75 return std::move(Err);
76 return Effect::mainFileEdit(SM, Replacements: std::move(Reps));
77}
78
79std::string ObjCLocalizeStringLiteral::title() const {
80 return "Wrap in NSLocalizedString";
81}
82
83} // namespace
84} // namespace clangd
85} // namespace clang
86

source code of clang-tools-extra/clangd/refactor/tweaks/ObjCLocalizeStringLiteral.cpp