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