xref: /llvm-project/clang-tools-extra/clangd/refactor/Rename.h (revision edfc859af89e44207bf499b5d702aa26a7357da4)
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 
20 namespace clang {
21 namespace clangd {
22 class ParsedAST;
23 class SymbolIndex;
24 
25 struct 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 struct RenameInputs {
39   Position Pos; // the position triggering the rename
40   llvm::StringRef NewName;
41 
42   ParsedAST &AST;
43   llvm::StringRef MainFilePath;
44 
45   // The filesystem to query when performing cross file renames.
46   // If this is set, Index must also be set, likewise if this is nullptr, Index
47   // must also be nullptr.
48   llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr;
49 
50   const SymbolIndex *Index = nullptr;
51 
52   RenameOptions Opts = {};
53 };
54 
55 struct RenameResult {
56   // The range of the symbol that the user can attempt to rename.
57   Range Target;
58   // Placeholder text for the rename operation if non-empty.
59   std::string Placeholder;
60   // Rename occurrences for the current main file.
61   std::vector<Range> LocalChanges;
62   // Complete edits for the rename, including LocalChanges.
63   // If the full set of changes is unknown, this field is empty.
64   FileEdits GlobalChanges;
65 };
66 
67 /// Represents a symbol range where the symbol can potentially have multiple
68 /// tokens.
69 struct SymbolRange {
70   /// Ranges for the tokens that make up the symbol's name.
71   /// Usually a single range, but there can be multiple ranges if the tokens for
72   /// the symbol are split, e.g. ObjC selectors.
73   std::vector<Range> Ranges;
74 
75   SymbolRange(Range R);
76   SymbolRange(std::vector<Range> Ranges);
77 
78   /// Returns the first range.
79   Range range() const;
80 
81   friend bool operator==(const SymbolRange &LHS, const SymbolRange &RHS);
82   friend bool operator!=(const SymbolRange &LHS, const SymbolRange &RHS);
83   friend bool operator<(const SymbolRange &LHS, const SymbolRange &RHS);
84 };
85 
86 /// Renames all occurrences of the symbol. The result edits are unformatted.
87 /// If AllowCrossFile is false, returns an error if rename a symbol that's used
88 /// in another file (per the index).
89 llvm::Expected<RenameResult> rename(const RenameInputs &RInputs);
90 
91 /// Generates rename edits that replaces all given occurrences with the
92 /// NewName.
93 /// Exposed for testing only.
94 /// REQUIRED: Occurrences is sorted and doesn't have duplicated ranges.
95 llvm::Expected<Edit> buildRenameEdit(llvm::StringRef AbsFilePath,
96                                      llvm::StringRef InitialCode,
97                                      std::vector<SymbolRange> Occurrences,
98                                      llvm::ArrayRef<llvm::StringRef> NewNames);
99 
100 /// Adjusts indexed occurrences to match the current state of the file.
101 ///
102 /// The Index is not always up to date. Blindly editing at the locations
103 /// reported by the index may mangle the code in such cases.
104 /// This function determines whether the indexed occurrences can be applied to
105 /// this file, and heuristically repairs the occurrences if necessary.
106 ///
107 /// The API assumes that Indexed contains only named occurrences (each
108 /// occurrence has the same length).
109 /// REQUIRED: Indexed is sorted.
110 std::optional<std::vector<SymbolRange>>
111 adjustRenameRanges(llvm::StringRef DraftCode, llvm::StringRef Identifier,
112                    std::vector<Range> Indexed, const LangOptions &LangOpts,
113                    std::optional<Selector> Selector);
114 
115 /// Calculates the lexed occurrences that the given indexed occurrences map to.
116 /// Returns std::nullopt if we don't find a mapping.
117 ///
118 /// Exposed for testing only.
119 ///
120 /// REQUIRED: Indexed and Lexed are sorted.
121 std::optional<std::vector<SymbolRange>>
122 getMappedRanges(ArrayRef<Range> Indexed, ArrayRef<SymbolRange> Lexed);
123 /// Evaluates how good the mapped result is. 0 indicates a perfect match.
124 ///
125 /// Exposed for testing only.
126 ///
127 /// REQUIRED: Indexed and Lexed are sorted, Indexed and MappedIndex have the
128 /// same size.
129 size_t renameRangeAdjustmentCost(ArrayRef<Range> Indexed,
130                                  ArrayRef<SymbolRange> Lexed,
131                                  ArrayRef<size_t> MappedIndex);
132 
133 } // namespace clangd
134 } // namespace clang
135 
136 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_REFACTOR_RENAME_H
137