1//===--- Rename.h - Symbol-rename refactorings -------------------*- 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#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_REFACTOR_RENAME_H
10#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_REFACTOR_RENAME_H
11
12#include "Protocol.h"
13#include "SourceCode.h"
14#include "clang/Basic/IdentifierTable.h"
15#include "clang/Basic/LangOptions.h"
16#include "llvm/ADT/SmallVector.h"
17#include "llvm/Support/Error.h"
18#include <optional>
19
20namespace clang {
21namespace clangd {
22class ParsedAST;
23class SymbolIndex;
24
25struct RenameOptions {
26 /// The maximum number of affected files (0 means no limit), only meaningful
27 /// when AllowCrossFile = true.
28 /// If the actual number exceeds the limit, rename is forbidden.
29 size_t LimitFiles = 50;
30 /// If true, format the rename edits, only meaningful in ClangdServer layer.
31 bool WantFormat = false;
32 /// Allow rename of virtual method hierarchies.
33 /// Disable to support broken index implementations with missing relations.
34 /// FIXME: fix those implementations and remove this option.
35 bool RenameVirtual = true;
36};
37
38/// A name of a symbol that should be renamed.
39///
40/// Symbol's name can be composed of multiple strings. For example, Objective-C
41/// methods can contain multiple argument labels:
42///
43/// \code
44/// - (void) myMethodNamePiece: (int)x anotherNamePieces:(int)y;
45/// ^~ string 0 ~~~~~ ^~ string 1 ~~~~~
46/// \endcode
47class RenameSymbolName {
48 llvm::SmallVector<std::string, 1> NamePieces;
49
50public:
51 RenameSymbolName();
52
53 /// Create a new \c SymbolName with the specified pieces.
54 explicit RenameSymbolName(ArrayRef<std::string> NamePieces);
55
56 explicit RenameSymbolName(const DeclarationName &Name);
57
58 ArrayRef<std::string> getNamePieces() const { return NamePieces; }
59
60 /// If this symbol consists of a single piece return it, otherwise return
61 /// `None`.
62 ///
63 /// Only symbols in Objective-C can consist of multiple pieces, so this
64 /// function always returns a value for non-Objective-C symbols.
65 std::optional<std::string> getSinglePiece() const;
66
67 /// Returns a human-readable version of this symbol name.
68 ///
69 /// If the symbol consists of multiple pieces (aka. it is an Objective-C
70 /// selector/method name), the pieces are separated by `:`, otherwise just an
71 /// identifier name.
72 std::string getAsString() const;
73
74 void print(raw_ostream &OS) const;
75
76 bool operator==(const RenameSymbolName &Other) const {
77 return NamePieces == Other.NamePieces;
78 }
79};
80
81struct RenameInputs {
82 Position Pos; // the position triggering the rename
83 llvm::StringRef NewName;
84
85 ParsedAST &AST;
86 llvm::StringRef MainFilePath;
87
88 // The filesystem to query when performing cross file renames.
89 // If this is set, Index must also be set, likewise if this is nullptr, Index
90 // must also be nullptr.
91 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr;
92
93 const SymbolIndex *Index = nullptr;
94
95 RenameOptions Opts = {};
96};
97
98struct RenameResult {
99 // The range of the symbol that the user can attempt to rename.
100 Range Target;
101 // Placeholder text for the rename operation if non-empty.
102 std::string Placeholder;
103 // Rename occurrences for the current main file.
104 std::vector<Range> LocalChanges;
105 // Complete edits for the rename, including LocalChanges.
106 // If the full set of changes is unknown, this field is empty.
107 FileEdits GlobalChanges;
108};
109
110/// Represents a symbol range where the symbol can potentially have multiple
111/// tokens.
112struct SymbolRange {
113 /// Ranges for the tokens that make up the symbol's name.
114 /// Usually a single range, but there can be multiple ranges if the tokens for
115 /// the symbol are split, e.g. ObjC selectors.
116 std::vector<Range> Ranges;
117
118 SymbolRange(Range R);
119 SymbolRange(std::vector<Range> Ranges);
120
121 /// Returns the first range.
122 Range range() const;
123
124 friend bool operator==(const SymbolRange &LHS, const SymbolRange &RHS);
125 friend bool operator!=(const SymbolRange &LHS, const SymbolRange &RHS);
126 friend bool operator<(const SymbolRange &LHS, const SymbolRange &RHS);
127};
128
129/// Renames all occurrences of the symbol. The result edits are unformatted.
130/// If AllowCrossFile is false, returns an error if rename a symbol that's used
131/// in another file (per the index).
132llvm::Expected<RenameResult> rename(const RenameInputs &RInputs);
133
134/// Generates rename edits that replaces all given occurrences with the
135/// NewName.
136/// Exposed for testing only.
137/// REQUIRED: Occurrences is sorted and doesn't have duplicated ranges.
138llvm::Expected<Edit> buildRenameEdit(llvm::StringRef AbsFilePath,
139 llvm::StringRef InitialCode,
140 std::vector<SymbolRange> Occurrences,
141 llvm::ArrayRef<llvm::StringRef> NewNames);
142
143/// Adjusts indexed occurrences to match the current state of the file.
144///
145/// The Index is not always up to date. Blindly editing at the locations
146/// reported by the index may mangle the code in such cases.
147/// This function determines whether the indexed occurrences can be applied to
148/// this file, and heuristically repairs the occurrences if necessary.
149///
150/// The API assumes that Indexed contains only named occurrences (each
151/// occurrence has the same length).
152/// REQUIRED: Indexed is sorted.
153std::optional<std::vector<SymbolRange>>
154adjustRenameRanges(llvm::StringRef DraftCode, const RenameSymbolName &Name,
155 std::vector<Range> Indexed, const LangOptions &LangOpts);
156
157/// Calculates the lexed occurrences that the given indexed occurrences map to.
158/// Returns std::nullopt if we don't find a mapping.
159///
160/// Exposed for testing only.
161///
162/// REQUIRED: Indexed and Lexed are sorted.
163std::optional<std::vector<SymbolRange>>
164getMappedRanges(ArrayRef<Range> Indexed, ArrayRef<SymbolRange> Lexed);
165/// Evaluates how good the mapped result is. 0 indicates a perfect match.
166///
167/// Exposed for testing only.
168///
169/// REQUIRED: Indexed and Lexed are sorted, Indexed and MappedIndex have the
170/// same size.
171size_t renameRangeAdjustmentCost(ArrayRef<Range> Indexed,
172 ArrayRef<SymbolRange> Lexed,
173 ArrayRef<size_t> MappedIndex);
174
175} // namespace clangd
176} // namespace clang
177
178#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_REFACTOR_RENAME_H
179

source code of clang-tools-extra/clangd/refactor/Rename.h