179 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_REFACTOR_RENAME_H10#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_REFACTOR_RENAME_H11 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 meaningful27 /// 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-C41/// methods can contain multiple argument labels:42///43/// \code44/// - (void) myMethodNamePiece: (int)x anotherNamePieces:(int)y;45/// ^~ string 0 ~~~~~ ^~ string 1 ~~~~~46/// \endcode47class 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 return61 /// `None`.62 ///63 /// Only symbols in Objective-C can consist of multiple pieces, so this64 /// 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-C70 /// selector/method name), the pieces are separated by `:`, otherwise just an71 /// 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 rename83 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, Index90 // 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 multiple111/// 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 for115 /// 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 used131/// in another file (per the index).132llvm::Expected<RenameResult> rename(const RenameInputs &RInputs);133 134/// Generates rename edits that replaces all given occurrences with the135/// 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 locations146/// reported by the index may mangle the code in such cases.147/// This function determines whether the indexed occurrences can be applied to148/// this file, and heuristically repairs the occurrences if necessary.149///150/// The API assumes that Indexed contains only named occurrences (each151/// 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 the170/// same size.171size_t renameRangeAdjustmentCost(ArrayRef<Range> Indexed,172 ArrayRef<SymbolRange> Lexed,173 ArrayRef<size_t> MappedIndex);174 175} // namespace clangd176} // namespace clang177 178#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_REFACTOR_RENAME_H179