diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -549,7 +549,8 @@ // May generate several candidate selections, due to SelectionTree ambiguity. // vector of pointers because GCC doesn't like non-copyable Selection. static llvm::Expected>> -tweakSelection(const Range &Sel, const InputsAndAST &AST) { +tweakSelection(const Range &Sel, const InputsAndAST &AST, + llvm::vfs::FileSystem *FS) { auto Begin = positionToOffset(AST.Inputs.Contents, Sel.start); if (!Begin) return Begin.takeError(); @@ -561,7 +562,7 @@ AST.AST.getASTContext(), AST.AST.getTokens(), *Begin, *End, [&](SelectionTree T) { Result.push_back(std::make_unique( - AST.Inputs.Index, AST.AST, *Begin, *End, std::move(T))); + AST.Inputs.Index, AST.AST, *Begin, *End, std::move(T), FS)); return false; }); assert(!Result.empty() && "Expected at least one SelectionTree"); @@ -580,7 +581,7 @@ Expected InpAST) mutable { if (!InpAST) return CB(InpAST.takeError()); - auto Selections = tweakSelection(Sel, *InpAST); + auto Selections = tweakSelection(Sel, *InpAST, /*FS=*/nullptr); if (!Selections) return CB(Selections.takeError()); std::vector Res; @@ -618,7 +619,8 @@ this](Expected InpAST) mutable { if (!InpAST) return CB(InpAST.takeError()); - auto Selections = tweakSelection(Sel, *InpAST); + auto FS = DirtyFS->view(llvm::None); + auto Selections = tweakSelection(Sel, *InpAST, FS.get()); if (!Selections) return CB(Selections.takeError()); llvm::Optional> Effect; diff --git a/clang-tools-extra/clangd/refactor/Tweak.h b/clang-tools-extra/clangd/refactor/Tweak.h --- a/clang-tools-extra/clangd/refactor/Tweak.h +++ b/clang-tools-extra/clangd/refactor/Tweak.h @@ -51,7 +51,8 @@ /// Input to prepare and apply tweaks. struct Selection { Selection(const SymbolIndex *Index, ParsedAST &AST, unsigned RangeBegin, - unsigned RangeEnd, SelectionTree ASTSelection); + unsigned RangeEnd, SelectionTree ASTSelection, + llvm::vfs::FileSystem *VFS); /// The text of the active document. llvm::StringRef Code; /// The Index for handling codebase related queries. @@ -67,6 +68,9 @@ unsigned SelectionEnd; /// The AST nodes that were selected. SelectionTree ASTSelection; + /// File system used to access source code (for cross-file tweaks). + /// This is only populated when applying a tweak, not during prepare. + llvm::vfs::FileSystem *FS = nullptr; // FIXME: provide a way to get sources and ASTs for other files. }; diff --git a/clang-tools-extra/clangd/refactor/Tweak.cpp b/clang-tools-extra/clangd/refactor/Tweak.cpp --- a/clang-tools-extra/clangd/refactor/Tweak.cpp +++ b/clang-tools-extra/clangd/refactor/Tweak.cpp @@ -61,9 +61,10 @@ Tweak::Selection::Selection(const SymbolIndex *Index, ParsedAST &AST, unsigned RangeBegin, unsigned RangeEnd, - SelectionTree ASTSelection) + SelectionTree ASTSelection, + llvm::vfs::FileSystem *FS) : Index(Index), AST(&AST), SelectionBegin(RangeBegin), - SelectionEnd(RangeEnd), ASTSelection(std::move(ASTSelection)) { + SelectionEnd(RangeEnd), ASTSelection(std::move(ASTSelection)), FS(FS) { auto &SM = AST.getSourceManager(); Code = SM.getBufferData(SM.getMainFileID()); Cursor = SM.getComposedLoc(SM.getMainFileID(), RangeBegin); diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp --- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp @@ -64,9 +64,8 @@ llvm::Optional getSourceFile(llvm::StringRef FileName, const Tweak::Selection &Sel) { - if (auto Source = getCorrespondingHeaderOrSource( - FileName, - &Sel.AST->getSourceManager().getFileManager().getVirtualFileSystem())) + assert(Sel.FS); + if (auto Source = getCorrespondingHeaderOrSource(FileName, Sel.FS)) return *Source; return getCorrespondingHeaderOrSource(FileName, *Sel.AST, Sel.Index); } @@ -414,12 +413,11 @@ return error("Couldn't get absolute path for main file."); auto CCFile = getSourceFile(*MainFileName, Sel); + if (!CCFile) return error("Couldn't find a suitable implementation file."); - - auto &FS = - Sel.AST->getSourceManager().getFileManager().getVirtualFileSystem(); - auto Buffer = FS.getBufferForFile(*CCFile); + assert(Sel.FS && "FS Must be set in apply"); + auto Buffer = Sel.FS->getBufferForFile(*CCFile); // FIXME: Maybe we should consider creating the implementation file if it // doesn't exist? if (!Buffer) diff --git a/clang-tools-extra/clangd/tool/Check.cpp b/clang-tools-extra/clangd/tool/Check.cpp --- a/clang-tools-extra/clangd/tool/Check.cpp +++ b/clang-tools-extra/clangd/tool/Check.cpp @@ -210,7 +210,8 @@ vlog(" {0} {1}", Pos, Tok.text(AST->getSourceManager())); auto Tree = SelectionTree::createRight(AST->getASTContext(), AST->getTokens(), Start, End); - Tweak::Selection Selection(&Index, *AST, Start, End, std::move(Tree)); + Tweak::Selection Selection(&Index, *AST, Start, End, std::move(Tree), + nullptr); for (const auto &T : prepareTweaks(Selection, Opts.TweakFilter, Opts.FeatureModules)) { auto Result = T->apply(Selection); diff --git a/clang-tools-extra/clangd/unittests/FeatureModulesTests.cpp b/clang-tools-extra/clangd/unittests/FeatureModulesTests.cpp --- a/clang-tools-extra/clangd/unittests/FeatureModulesTests.cpp +++ b/clang-tools-extra/clangd/unittests/FeatureModulesTests.cpp @@ -47,7 +47,8 @@ auto Tree = SelectionTree::createRight(AST.getASTContext(), AST.getTokens(), 0, 0); auto Actual = prepareTweak( - TweakID, Tweak::Selection(nullptr, AST, 0, 0, std::move(Tree)), &Set); + TweakID, Tweak::Selection(nullptr, AST, 0, 0, std::move(Tree), nullptr), + &Set); ASSERT_TRUE(bool(Actual)); EXPECT_EQ(Actual->get()->id(), TweakID); } diff --git a/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp b/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp --- a/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp @@ -68,13 +68,14 @@ // Returns None if and only if prepare() failed. llvm::Optional> applyTweak(ParsedAST &AST, const Annotations &Input, StringRef TweakID, - const SymbolIndex *Index) { + const SymbolIndex *Index, llvm::vfs::FileSystem *FS) { auto Range = rangeOrPoint(Input); llvm::Optional> Result; SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), Range.first, Range.second, [&](SelectionTree ST) { Tweak::Selection S(Index, AST, Range.first, - Range.second, std::move(ST)); + Range.second, std::move(ST), + FS); if (auto T = prepareTweak(TweakID, S, nullptr)) { Result = (*T)->apply(S); return true; @@ -98,7 +99,9 @@ TU.ExtraArgs = ExtraArgs; TU.AdditionalFiles = std::move(ExtraFiles); ParsedAST AST = TU.build(); - auto Result = applyTweak(AST, Input, TweakID, Index); + auto Result = applyTweak( + AST, Input, TweakID, Index, + &AST.getSourceManager().getFileManager().getVirtualFileSystem()); // We only care if prepare() succeeded, but must handle Errors. if (Result && !*Result) consumeError(Result->takeError()); @@ -119,7 +122,9 @@ TU.ExtraArgs = ExtraArgs; ParsedAST AST = TU.build(); - auto Result = applyTweak(AST, Input, TweakID, Index.get()); + auto Result = applyTweak( + AST, Input, TweakID, Index.get(), + &AST.getSourceManager().getFileManager().getVirtualFileSystem()); if (!Result) return "unavailable"; if (!*Result)