13 #include "clang/Tooling/Refactoring/RefactoringResultConsumer.h" 14 #include "clang/Tooling/Refactoring/Rename/RenamingAction.h" 20 class RefactoringResultCollector final
21 :
public tooling::RefactoringResultConsumer {
24 assert(!
Result.hasValue());
29 using tooling::RefactoringResultConsumer::handle;
31 void handle(tooling::AtomicChanges SourceReplacements)
override {
32 assert(!
Result.hasValue());
33 Result = std::move(SourceReplacements);
36 llvm::Optional<llvm::Expected<tooling::AtomicChanges>>
Result;
42 if (
auto Diag = DiagnosticError::take(Err)) {
43 llvm::cantFail(std::move(Err));
44 SmallVector<char, 128> DiagMessage;
45 Diag->second.EmitToString(DE, DiagMessage);
46 return llvm::make_error<llvm::StringError>(DiagMessage,
47 llvm::inconvertibleErrorCode());
52 llvm::Optional<std::string> filePath(
const SymbolLocation &
Loc,
53 llvm::StringRef HintFilePath) {
58 elog(
"Could not parse URI {0}: {1}", Loc.FileURI, Uri.takeError());
63 elog(
"Could not resolve URI {0}: {1}", Loc.FileURI, U.takeError());
66 return U->file().str();
70 llvm::Optional<std::string> getOtherRefFile(
const Decl &
D, StringRef
MainFile,
71 const SymbolIndex &
Index) {
79 llvm::Optional<std::string> OtherFile;
80 Index.refs(Req, [&](
const Ref &R) {
83 if (
auto RefFilePath = filePath(R.Location, MainFile)) {
84 if (*RefFilePath != MainFile)
85 OtherFile = *RefFilePath;
99 llvm::Optional<ReasonToReject> renamableWithinFile(
const Decl &RenameDecl,
102 if (llvm::isa<NamespaceDecl>(&RenameDecl))
103 return ReasonToReject::UnsupportedSymbol;
104 auto &ASTCtx = RenameDecl.getASTContext();
105 const auto &SM = ASTCtx.getSourceManager();
106 bool MainFileIsHeader = ASTCtx.getLangOpts().IsHeaderFile;
107 bool DeclaredInMainFile =
108 SM.isWrittenInMainFile(SM.getExpansionLoc(RenameDecl.getLocation()));
112 if (DeclaredInMainFile && !MainFileIsHeader)
117 if (RenameDecl.getParentFunctionOrMethod())
121 return ReasonToReject::NoIndexProvided;
123 bool IsIndexable = isa<NamedDecl>(RenameDecl) &&
125 cast<NamedDecl>(RenameDecl), ASTCtx, {},
false);
128 return ReasonToReject::NonIndexable;
129 auto OtherFile = getOtherRefFile(RenameDecl, MainFile, *Index);
136 return ReasonToReject::UsedOutsideFile;
142 case NoIndexProvided:
143 return "symbol may be used in other files (no index available)";
144 case UsedOutsideFile:
145 return "the symbol is used outside main file";
147 return "symbol may be used in other files (not eligible for indexing)";
148 case UnsupportedSymbol:
149 return "symbol is not a supported kind (e.g. namespace, macro)";
151 llvm_unreachable(
"unhandled reason kind");
153 return llvm::make_error<llvm::StringError>(
154 llvm::formatv(
"Cannot rename symbol: {0}",
Message(Reason)),
155 llvm::inconvertibleErrorCode());
160 llvm::Expected<tooling::Replacements>
163 RefactoringResultCollector ResultCollector;
173 auto Rename = clang::tooling::RenameOccurrences::initiate(
174 Context, SourceRange(SourceLocationBeg), NewName);
176 return expandDiagnostics(Rename.takeError(), ASTCtx.getDiagnostics());
178 const auto *RenameDecl = Rename->getRenameDecl();
179 assert(RenameDecl &&
"symbol must be found at this point");
181 renamableWithinFile(*RenameDecl->getCanonicalDecl(),
File,
Index))
184 Rename->invoke(ResultCollector,
Context);
186 assert(ResultCollector.Result.hasValue());
187 if (!ResultCollector.Result.getValue())
188 return expandDiagnostics(ResultCollector.Result->takeError(),
189 ASTCtx.getDiagnostics());
191 tooling::Replacements FilteredChanges;
197 for (
const tooling::AtomicChange &Change : ResultCollector.Result->get()) {
198 for (
const auto &Rep : Change.getReplacements()) {
199 if (Rep.getFilePath() ==
File)
200 cantFail(FilteredChanges.add(Rep));
203 return FilteredChanges;
SourceLocation Loc
'#' location in the include directive
llvm::Optional< SymbolID > getSymbolID(const Decl *D)
Gets the symbol ID for a declaration, if possible.
static llvm::Error makeError(const char *Msg)
Preprocessor & getPreprocessor()
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
constexpr llvm::StringLiteral Message
Documents should not be synced at all.
void elog(const char *Fmt, Ts &&... Vals)
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
SourceLocation getBeginningOfIdentifier(const ParsedAST &Unit, const Position &Pos, const FileID FID)
Get the beginning SourceLocation at a specified Pos.
llvm::Expected< tooling::Replacements > renameWithinFile(ParsedAST &AST, llvm::StringRef File, Position Pos, llvm::StringRef NewName, const SymbolIndex *Index)
Renames all occurrences of the symbol at Pos to NewName.
static llvm::Expected< URIForFile > fromURI(const URI &U, llvm::StringRef HintPath)
A context is an immutable container for per-request data that must be propagated through layers that ...
Stores and provides access to parsed AST.
SourceManager & getSourceManager()
static bool shouldCollectSymbol(const NamedDecl &ND, const ASTContext &ASTCtx, const Options &Opts, bool IsMainFileSymbol)
Returns true is ND should be collected.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
llvm::Optional< DefinedMacro > locateMacroAt(SourceLocation Loc, Preprocessor &PP)
const SymbolIndex * Index