Tweak.h
5.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//===--- Tweak.h -------------------------------------------------*- 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
//
//===----------------------------------------------------------------------===//
// Tweaks are small actions that run over the AST and produce edits, messages
// etc as a result. They are local, i.e. they should take the current editor
// context, e.g. the cursor position and selection into account.
// The actions are executed in two stages:
// - Stage 1 should check whether the action is available in a current
// context. It should be cheap and fast to compute as it is executed for all
// available actions on every client request, which happen quite frequently.
// - Stage 2 is performed after stage 1 and can be more expensive to compute.
// It is performed when the user actually chooses the action.
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_REFACTOR_ACTIONS_TWEAK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_REFACTOR_ACTIONS_TWEAK_H
#include "ParsedAST.h"
#include "Path.h"
#include "Protocol.h"
#include "Selection.h"
#include "SourceCode.h"
#include "index/Index.h"
#include "clang/Tooling/Core/Replacement.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include <string>
namespace clang {
namespace clangd {
/// An interface base for small context-sensitive refactoring actions.
/// To implement a new tweak use the following pattern in a .cpp file:
/// class MyTweak : public Tweak {
/// public:
/// const char* id() const override final; // defined by REGISTER_TWEAK.
/// // implement other methods here.
/// };
/// REGISTER_TWEAK(MyTweak);
class Tweak {
public:
/// Input to prepare and apply tweaks.
struct Selection {
Selection(const SymbolIndex *Index, ParsedAST &AST, unsigned RangeBegin,
unsigned RangeEnd);
/// The text of the active document.
llvm::StringRef Code;
/// The Index for handling codebase related queries.
const SymbolIndex *Index = nullptr;
/// The parsed active file. Never null. (Pointer so Selection is movable).
ParsedAST *AST;
/// A location of the cursor in the editor.
// FIXME: Cursor is redundant and should be removed
SourceLocation Cursor;
/// The begin offset of the selection
unsigned SelectionBegin;
/// The end offset of the selection
unsigned SelectionEnd;
/// The AST nodes that were selected.
SelectionTree ASTSelection;
// FIXME: provide a way to get sources and ASTs for other files.
};
/// Output of a tweak.
enum Intent {
/// Apply changes that preserve the behavior of the code.
Refactor,
/// Provide information to the user.
Info,
};
struct Effect {
/// A message to be displayed to the user.
llvm::Optional<std::string> ShowMessage;
FileEdits ApplyEdits;
static Effect showMessage(StringRef S) {
Effect E;
E.ShowMessage = S;
return E;
}
/// Path is the absolute, symlink-resolved path for the file pointed by FID
/// in SM. Edit is generated from Replacements.
/// Fails if cannot figure out absolute path for FID.
static llvm::Expected<std::pair<Path, Edit>>
fileEdit(const SourceManager &SM, FileID FID,
tooling::Replacements Replacements);
/// Creates an effect with an Edit for the main file.
/// Fails if cannot figure out absolute path for main file.
static llvm::Expected<Tweak::Effect>
mainFileEdit(const SourceManager &SM, tooling::Replacements Replacements);
};
virtual ~Tweak() = default;
/// A unique id of the action, it is always equal to the name of the class
/// defining the Tweak. Definition is provided automatically by
/// REGISTER_TWEAK.
virtual const char *id() const = 0;
/// Run the first stage of the action. Returns true indicating that the
/// action is available and should be shown to the user. Returns false if the
/// action is not available.
/// This function should be fast, if the action requires non-trivial work it
/// should be moved into 'apply'.
/// Returns true iff the action is available and apply() can be called on it.
virtual bool prepare(const Selection &Sel) = 0;
/// Run the second stage of the action that would produce the actual effect.
/// EXPECTS: prepare() was called and returned true.
virtual Expected<Effect> apply(const Selection &Sel) = 0;
/// A one-line title of the action that should be shown to the users in the
/// UI.
/// EXPECTS: prepare() was called and returned true.
virtual std::string title() const = 0;
/// Describes what kind of action this is.
/// EXPECTS: prepare() was called and returned true.
virtual Intent intent() const = 0;
/// Is this a 'hidden' tweak, which are off by default.
virtual bool hidden() const { return false; }
};
// All tweaks must be registered in the .cpp file next to their definition.
#define REGISTER_TWEAK(Subclass) \
::llvm::Registry<::clang::clangd::Tweak>::Add<Subclass> \
TweakRegistrationFor##Subclass(#Subclass, /*Description=*/""); \
const char *Subclass::id() const { return #Subclass; }
/// Calls prepare() on all tweaks that satisfy the filter, returning those that
/// can run on the selection.
std::vector<std::unique_ptr<Tweak>>
prepareTweaks(const Tweak::Selection &S,
llvm::function_ref<bool(const Tweak &)> Filter);
// Calls prepare() on the tweak with a given ID.
// If prepare() returns false, returns an error.
// If prepare() returns true, returns the corresponding tweak.
llvm::Expected<std::unique_ptr<Tweak>> prepareTweak(StringRef TweakID,
const Tweak::Selection &S);
} // namespace clangd
} // namespace clang
#endif