1 //===--- ObjcLocalizeStringLiteral.cpp ---------------------------*- C++-*-===//
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
7 //===----------------------------------------------------------------------===//
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/Optional.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/Support/Casting.h"
19 #include "llvm/Support/Error.h"
25 /// Wraps an Objective-C string literal with the NSLocalizedString macro.
30 /// NSLocalizedString(@"description", @"")
31 class ObjCLocalizeStringLiteral
: public Tweak
{
33 const char *id() const final
;
34 llvm::StringLiteral
kind() const override
{
35 return CodeAction::REFACTOR_KIND
;
38 bool prepare(const Selection
&Inputs
) override
;
39 Expected
<Tweak::Effect
> apply(const Selection
&Inputs
) override
;
40 std::string
title() const override
;
43 const clang::ObjCStringLiteral
*Str
= nullptr;
46 REGISTER_TWEAK(ObjCLocalizeStringLiteral
)
48 bool ObjCLocalizeStringLiteral::prepare(const Selection
&Inputs
) {
49 const SelectionTree::Node
*N
= Inputs
.ASTSelection
.commonAncestor();
52 // Allow the refactoring even if the user selected only the C string part
54 if (N
->ASTNode
.get
<StringLiteral
>()) {
58 Str
= dyn_cast_or_null
<ObjCStringLiteral
>(N
->ASTNode
.get
<Stmt
>());
62 Expected
<Tweak::Effect
>
63 ObjCLocalizeStringLiteral::apply(const Selection
&Inputs
) {
64 auto *AST
= Inputs
.AST
;
65 auto &SM
= AST
->getSourceManager();
66 const auto &TB
= AST
->getTokens();
67 auto Toks
= TB
.spelledForExpanded(TB
.expandedTokens(Str
->getSourceRange()));
68 if (!Toks
|| Toks
->empty())
69 return error("Failed to find tokens to replace.");
70 // Insert `NSLocalizedString(` before the literal.
71 auto Reps
= tooling::Replacements(tooling::Replacement(
72 SM
, Toks
->front().location(), 0, "NSLocalizedString("));
73 // Insert `, @"")` after the literal.
74 if (auto Err
= Reps
.add(
75 tooling::Replacement(SM
, Toks
->back().endLocation(), 0, ", @\"\")")))
76 return std::move(Err
);
77 return Effect::mainFileEdit(SM
, std::move(Reps
));
80 std::string
ObjCLocalizeStringLiteral::title() const {
81 return "Wrap in NSLocalizedString";