diff --git a/clang-tools-extra/clangd/ASTSignals.cpp b/clang-tools-extra/clangd/ASTSignals.cpp index cffadb091d557..21647994d259e 100644 --- a/clang-tools-extra/clangd/ASTSignals.cpp +++ b/clang-tools-extra/clangd/ASTSignals.cpp @@ -19,7 +19,7 @@ ASTSignals ASTSignals::derive(const ParsedAST &AST) { trace::Span Span("ASTSignals::derive"); ASTSignals Signals; Signals.InsertionDirective = preferredIncludeDirective( - AST.tuPath(), AST.getLangOpts(), + AST.tuPath().raw(), AST.getLangOpts(), AST.getIncludeStructure().MainFileIncludes, AST.getLocalTopLevelDecls()); const SourceManager &SM = AST.getSourceManager(); findExplicitReferences( diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp index 1e981825c7c15..35ada432cd5dd 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -926,11 +926,11 @@ void ClangdLSPServer::onDocumentDidClose( { std::lock_guard Lock(DiagRefMutex); - DiagRefMap.erase(File); + DiagRefMap.erase(File.raw()); } { std::lock_guard HLock(SemanticTokensMutex); - LastSemanticTokens.erase(File); + LastSemanticTokens.erase(File.raw()); } // clangd will not send updates for this file anymore, so we empty out the // list of diagnostics shown on the client (e.g. in the "Problems" pane of @@ -1816,7 +1816,7 @@ void ClangdLSPServer::onDiagnosticsReady(PathRef File, llvm::StringRef Version, // Cache DiagRefMap { std::lock_guard Lock(DiagRefMutex); - DiagRefMap[File] = LocalDiagMap; + DiagRefMap[File.raw()] = LocalDiagMap; } // Send a notification to the LSP client. diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index 52844129834c3..8ae5aa79674f2 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -88,15 +88,15 @@ struct UpdateIndexCallbacks : public ParsingCallbacks { indexStdlib(CI, std::move(*Loc)); // FIndex outlives the UpdateIndexCallbacks. - auto Task = [FIndex(FIndex), Path(Path.str()), Version(Version.str()), + auto Task = [FIndex(FIndex), Path(Path.owned()), Version(Version.str()), ASTCtx(std::move(ASTCtx)), PI(std::move(PI))]() mutable { trace::Span Tracer("PreambleIndexing"); - FIndex->updatePreamble(Path, Version, ASTCtx.getASTContext(), + FIndex->updatePreamble(Path.raw(), Version, ASTCtx.getASTContext(), ASTCtx.getPreprocessor(), *PI); }; if (Tasks) { - Tasks->runAsync("Preamble indexing for:" + Path + Version, + Tasks->runAsync("Preamble indexing for:" + Path.raw() + Version, std::move(Task)); } else Task(); @@ -262,7 +262,7 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB, BackgroundIdx = std::make_unique( TFS, CDB, BackgroundIndexStorage::createDiskBackedStorageFactory( - [&CDB](llvm::StringRef File) { return CDB.getProjectInfo(File); }), + [&CDB](PathRef File) { return CDB.getProjectInfo(File); }), std::move(BGOpts)); AddIndex(BackgroundIdx.get()); } @@ -316,14 +316,14 @@ void ClangdServer::addDocument(PathRef File, llvm::StringRef Contents, bool NewFile = WorkScheduler->update(File, Inputs, WantDiags); // If we loaded Foo.h, we want to make sure Foo.cpp is indexed. if (NewFile && BackgroundIdx) - BackgroundIdx->boostRelated(File); + BackgroundIdx->boostRelated(File.raw()); } void ClangdServer::reparseOpenFilesIfNeeded( llvm::function_ref Filter) { // Reparse only opened files that were modified. for (const Path &FilePath : DraftMgr.getActiveFiles()) - if (Filter(FilePath)) + if (Filter(FilePath.raw())) if (auto Draft = DraftMgr.getDraft(FilePath)) // else disappeared in race? addDocument(FilePath, *Draft->Contents, Draft->Version, WantDiagnostics::Auto); @@ -340,7 +340,7 @@ std::function ClangdServer::createConfiguredContextProvider(const config::Provider *Provider, Callbacks *Publish) { if (!Provider) - return [](llvm::StringRef) { return Context::current().clone(); }; + return [](PathRef) { return Context::current().clone(); }; struct Impl { const config::Provider *Provider; @@ -408,8 +408,8 @@ ClangdServer::createConfiguredContextProvider(const config::Provider *Provider, }; // Copyable wrapper. - return [I(std::make_shared(Provider, Publish))](llvm::StringRef Path) { - return (*I)(Path); + return [I(std::make_shared(Provider, Publish))](PathRef Path) { + return (*I)(Path.raw()); }; } @@ -426,7 +426,7 @@ void ClangdServer::codeComplete(PathRef File, Position Pos, if (!CodeCompleteOpts.Index) // Respect overridden index. CodeCompleteOpts.Index = Index; - auto Task = [Pos, CodeCompleteOpts, File = File.str(), CB = std::move(CB), + auto Task = [Pos, CodeCompleteOpts, File = File.owned(), CB = std::move(CB), this](llvm::Expected IP) mutable { if (!IP) return CB(IP.takeError()); @@ -442,7 +442,8 @@ void ClangdServer::codeComplete(PathRef File, Position Pos, SpecFuzzyFind.emplace(); { std::lock_guard Lock(CachedCompletionFuzzyFindRequestMutex); - SpecFuzzyFind->CachedReq = CachedCompletionFuzzyFindRequestByFile[File]; + SpecFuzzyFind->CachedReq = + CachedCompletionFuzzyFindRequestByFile[File.raw()]; } } ParseInputs ParseInput{IP->Command, &getHeaderFS(), IP->Contents.str()}; @@ -473,7 +474,8 @@ void ClangdServer::codeComplete(PathRef File, Position Pos, return; if (SpecFuzzyFind->NewReq) { std::lock_guard Lock(CachedCompletionFuzzyFindRequestMutex); - CachedCompletionFuzzyFindRequestByFile[File] = *SpecFuzzyFind->NewReq; + CachedCompletionFuzzyFindRequestByFile[File.raw()] = + *SpecFuzzyFind->NewReq; } // Explicitly block until async task completes, this is fine as we've // already provided reply to the client and running as a preamble task @@ -495,7 +497,7 @@ void ClangdServer::signatureHelp(PathRef File, Position Pos, MarkupKind DocumentationFormat, Callback CB) { - auto Action = [Pos, File = File.str(), CB = std::move(CB), + auto Action = [Pos, File = File.owned(), CB = std::move(CB), DocumentationFormat, this](llvm::Expected IP) mutable { if (!IP) @@ -540,12 +542,13 @@ void ClangdServer::formatFile(PathRef File, std::optional Rng, } // Call clang-format. - auto Action = [File = File.str(), Code = std::move(*Code), + auto Action = [File = File.owned(), Code = std::move(*Code), Ranges = std::vector{RequestedRange}, CB = std::move(CB), this]() mutable { - format::FormatStyle Style = getFormatStyleForFile(File, Code, TFS, true); + format::FormatStyle Style = + getFormatStyleForFile(File.raw(), Code, TFS, true); tooling::Replacements IncludeReplaces = - format::sortIncludes(Style, Code, Ranges, File); + format::sortIncludes(Style, Code, Ranges, File.raw()); auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces); if (!Changed) return CB(Changed.takeError()); @@ -553,9 +556,9 @@ void ClangdServer::formatFile(PathRef File, std::optional Rng, CB(IncludeReplaces.merge(format::reformat( Style, *Changed, tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges), - File))); + File.raw()))); }; - WorkScheduler->runQuick("Format", File, std::move(Action)); + WorkScheduler->runQuick("Format", File.raw(), std::move(Action)); } void ClangdServer::formatOnType(PathRef File, Position Pos, @@ -568,24 +571,24 @@ void ClangdServer::formatOnType(PathRef File, Position Pos, llvm::Expected CursorPos = positionToOffset(*Code, Pos); if (!CursorPos) return CB(CursorPos.takeError()); - auto Action = [File = File.str(), Code = std::move(*Code), + auto Action = [File = File.owned(), Code = std::move(*Code), TriggerText = TriggerText.str(), CursorPos = *CursorPos, CB = std::move(CB), this]() mutable { - auto Style = getFormatStyleForFile(File, Code, TFS, false); + auto Style = getFormatStyleForFile(File.raw(), Code, TFS, false); std::vector Result; for (const tooling::Replacement &R : formatIncremental(Code, CursorPos, TriggerText, Style)) Result.push_back(replacementToEdit(Code, R)); return CB(Result); }; - WorkScheduler->runQuick("FormatOnType", File, std::move(Action)); + WorkScheduler->runQuick("FormatOnType", File.raw(), std::move(Action)); } void ClangdServer::prepareRename(PathRef File, Position Pos, std::optional NewName, const RenameOptions &RenameOpts, Callback CB) { - auto Action = [Pos, File = File.str(), CB = std::move(CB), + auto Action = [Pos, File = File.owned(), CB = std::move(CB), NewName = std::move(NewName), RenameOpts](llvm::Expected InpAST) mutable { if (!InpAST) @@ -594,7 +597,7 @@ void ClangdServer::prepareRename(PathRef File, Position Pos, // only need main-file references auto Results = clangd::rename({Pos, NewName.value_or("__clangd_rename_placeholder"), - InpAST->AST, File, /*FS=*/nullptr, + InpAST->AST, File.raw(), /*FS=*/nullptr, /*Index=*/nullptr, RenameOpts}); if (!Results) { // LSP says to return null on failure, but that will result in a generic @@ -610,7 +613,7 @@ void ClangdServer::prepareRename(PathRef File, Position Pos, void ClangdServer::rename(PathRef File, Position Pos, llvm::StringRef NewName, const RenameOptions &Opts, Callback CB) { - auto Action = [File = File.str(), NewName = NewName.str(), Pos, Opts, + auto Action = [File = File.owned(), NewName = NewName.str(), Pos, Opts, CB = std::move(CB), this](llvm::Expected InpAST) mutable { // Tracks number of files edited per invocation. @@ -618,13 +621,13 @@ void ClangdServer::rename(PathRef File, Position Pos, llvm::StringRef NewName, trace::Metric::Distribution); if (!InpAST) return CB(InpAST.takeError()); - auto R = clangd::rename({Pos, NewName, InpAST->AST, File, + auto R = clangd::rename({Pos, NewName, InpAST->AST, File.raw(), DirtyFS->view(std::nullopt), Index, Opts}); if (!R) return CB(R.takeError()); if (Opts.WantFormat) { - auto Style = getFormatStyleForFile(File, InpAST->Inputs.Contents, + auto Style = getFormatStyleForFile(File.raw(), InpAST->Inputs.Contents, *InpAST->Inputs.TFS, false); llvm::Error Err = llvm::Error::success(); for (auto &E : R->GlobalChanges) @@ -756,7 +759,7 @@ void ClangdServer::applyTweak(PathRef File, Range Sel, StringRef TweakID, static constexpr trace::Metric TweakFailed( "tweak_failed", trace::Metric::Counter, "tweak_id"); TweakAttempt.record(1, TweakID); - auto Action = [File = File.str(), Sel, TweakID = TweakID.str(), + auto Action = [File = File.owned(), Sel, TweakID = TweakID.str(), CB = std::move(CB), this](Expected InpAST) mutable { if (!InpAST) @@ -782,7 +785,7 @@ void ClangdServer::applyTweak(PathRef File, Range Sel, StringRef TweakID, for (auto &It : (*Effect)->ApplyEdits) { Edit &E = It.second; format::FormatStyle Style = - getFormatStyleForFile(File, E.InitialCode, TFS, false); + getFormatStyleForFile(File.raw(), E.InitialCode, TFS, false); if (llvm::Error Err = reformatEdit(E, Style)) elog("Failed to format {0}: {1}", It.first(), std::move(Err)); } @@ -817,7 +820,7 @@ void ClangdServer::switchSourceHeader( if (auto CorrespondingFile = getCorrespondingHeaderOrSource(Path, TFS.view(std::nullopt))) return CB(std::move(CorrespondingFile)); - auto Action = [Path = Path.str(), CB = std::move(CB), + auto Action = [Path = Path.owned(), CB = std::move(CB), this](llvm::Expected InpAST) mutable { if (!InpAST) return CB(InpAST.takeError()); @@ -840,12 +843,12 @@ void ClangdServer::findDocumentHighlights( void ClangdServer::findHover(PathRef File, Position Pos, Callback> CB) { - auto Action = [File = File.str(), Pos, CB = std::move(CB), + auto Action = [File = File.owned(), Pos, CB = std::move(CB), this](llvm::Expected InpAST) mutable { if (!InpAST) return CB(InpAST.takeError()); format::FormatStyle Style = getFormatStyleForFile( - File, InpAST->Inputs.Contents, *InpAST->Inputs.TFS, false); + File.raw(), InpAST->Inputs.Contents, *InpAST->Inputs.TFS, false); CB(clangd::getHover(InpAST->AST, Pos, std::move(Style), Index)); }; @@ -855,7 +858,8 @@ void ClangdServer::findHover(PathRef File, Position Pos, void ClangdServer::typeHierarchy(PathRef File, Position Pos, int Resolve, TypeHierarchyDirection Direction, Callback> CB) { - auto Action = [File = File.str(), Pos, Resolve, Direction, CB = std::move(CB), + auto Action = [File = File.owned(), Pos, Resolve, Direction, + CB = std::move(CB), this](Expected InpAST) mutable { if (!InpAST) return CB(InpAST.takeError()); @@ -894,7 +898,7 @@ void ClangdServer::resolveTypeHierarchy( void ClangdServer::prepareCallHierarchy( PathRef File, Position Pos, Callback> CB) { - auto Action = [File = File.str(), Pos, + auto Action = [File = File.owned(), Pos, CB = std::move(CB)](Expected InpAST) mutable { if (!InpAST) return CB(InpAST.takeError()); @@ -976,7 +980,7 @@ void ClangdServer::foldingRanges(llvm::StringRef File, WorkScheduler->runQuick("FoldingRanges", File, std::move(Action)); } -void ClangdServer::findType(llvm::StringRef File, Position Pos, +void ClangdServer::findType(PathRef File, Position Pos, Callback> CB) { auto Action = [Pos, CB = std::move(CB), this](llvm::Expected InpAST) mutable { diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 0eb196fbad46a..ebbcea5f67bbf 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1384,14 +1384,14 @@ bool semaCodeComplete(std::unique_ptr Consumer, CI->getLangOpts().DelayedTemplateParsing = false; // Setup code completion. FrontendOpts.CodeCompleteOpts = Options; - FrontendOpts.CodeCompletionAt.FileName = std::string(Input.FileName); + FrontendOpts.CodeCompletionAt.FileName = Input.FileName.owned().raw(); std::tie(FrontendOpts.CodeCompletionAt.Line, FrontendOpts.CodeCompletionAt.Column) = offsetToClangLineColumn(Input.ParseInput.Contents, Input.Offset); std::unique_ptr ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(Input.ParseInput.Contents, - Input.FileName); + Input.FileName.raw()); // The diagnostic options must be set before creating a CompilerInstance. CI->getDiagnosticOpts().IgnoreWarnings = true; // We reuse the preamble whether it's valid or not. This is a @@ -1649,7 +1649,7 @@ class CodeCompleteFlow { assert(Recorder && "Recorder is not set"); CCContextKind = Recorder->CCContext.getKind(); IsUsingDeclaration = Recorder->CCContext.isUsingDeclaration(); - auto Style = getFormatStyleForFile(SemaCCInput.FileName, + auto Style = getFormatStyleForFile(SemaCCInput.FileName.raw(), SemaCCInput.ParseInput.Contents, *SemaCCInput.ParseInput.TFS, false); const auto NextToken = findTokenAfterCompletionPoint( @@ -1660,7 +1660,7 @@ class CodeCompleteFlow { // If preprocessor was run, inclusions from preprocessor callback should // already be added to Includes. Inserter.emplace( - SemaCCInput.FileName, SemaCCInput.ParseInput.Contents, Style, + SemaCCInput.FileName.raw(), SemaCCInput.ParseInput.Contents, Style, SemaCCInput.ParseInput.CompileCommand.Directory, &Recorder->CCSema->getPreprocessor().getHeaderSearchInfo(), Config::current().Style.QuotedHeaders, @@ -1741,12 +1741,12 @@ class CodeCompleteFlow { ReplacedRange.start.character -= HeuristicPrefix.Name.size(); llvm::StringMap ProxSources; - ProxSources[FileName].Cost = 0; + ProxSources[FileName.raw()].Cost = 0; FileProximity.emplace(ProxSources); - auto Style = getFormatStyleForFile(FileName, Content, TFS, false); + auto Style = getFormatStyleForFile(FileName.raw(), Content, TFS, false); // This will only insert verbatim headers. - Inserter.emplace(FileName, Content, Style, + Inserter.emplace(FileName.raw(), Content, Style, /*BuildDir=*/"", /*HeaderSearchInfo=*/nullptr, Config::current().Style.QuotedHeaders, Config::current().Style.AngledHeaders); @@ -1917,7 +1917,7 @@ class CodeCompleteFlow { Req.Scopes = QueryScopes; Req.AnyScope = AllScopes; // FIXME: we should send multiple weighted paths here. - Req.ProximityPaths.push_back(std::string(FileName)); + Req.ProximityPaths.push_back(FileName.owned().raw()); if (PreferredType) Req.PreferredTypes.push_back(std::string(PreferredType->raw())); vlog("Code complete: fuzzyFind({0:2})", toJSON(Req)); @@ -1972,8 +1972,9 @@ class CodeCompleteFlow { assert(IdentifierResult); C.Name = IdentifierResult->Name; } - if (auto OverloadSet = C.overloadSet( - Opts, FileName, Inserter ? &*Inserter : nullptr, CCContextKind)) { + if (auto OverloadSet = + C.overloadSet(Opts, FileName.raw(), + Inserter ? &*Inserter : nullptr, CCContextKind)) { auto Ret = BundleLookup.try_emplace(OverloadSet, Bundles.size()); if (Ret.second) Bundles.emplace_back(); @@ -2140,8 +2141,9 @@ class CodeCompleteFlow { : nullptr; if (!Builder) Builder.emplace(Recorder ? &Recorder->CCSema->getASTContext() : nullptr, - Item, SemaCCS, AccessibleScopes, *Inserter, FileName, - CCContextKind, Opts, IsUsingDeclaration, NextTokenKind); + Item, SemaCCS, AccessibleScopes, *Inserter, + FileName.raw(), CCContextKind, Opts, IsUsingDeclaration, + NextTokenKind); else Builder->add(Item, SemaCCS, CCContextKind); } @@ -2214,7 +2216,7 @@ CodeCompleteResult codeCompleteComment(PathRef FileName, unsigned Offset, semaCodeComplete( std::make_unique(Options, ParamNames), Options, {FileName, Offset, *Preamble, - PreamblePatch::createFullPatch(FileName, ParseInput, *Preamble), + PreamblePatch::createFullPatch(FileName.raw(), ParseInput, *Preamble), ParseInput}); if (ParamNames.empty()) return CodeCompleteResult(); @@ -2288,7 +2290,7 @@ CodeCompleteResult codeComplete(PathRef FileName, Position Pos, : std::move(Flow).run({FileName, *Offset, *Preamble, /*PreamblePatch=*/ PreamblePatch::createMacroPatch( - FileName, ParseInput, *Preamble), + FileName.raw(), ParseInput, *Preamble), ParseInput}); } @@ -2312,7 +2314,7 @@ SignatureHelp signatureHelp(PathRef FileName, Position Pos, ParseInput.Index, Result), Options, {FileName, *Offset, Preamble, - PreamblePatch::createFullPatch(FileName, ParseInput, Preamble), + PreamblePatch::createFullPatch(FileName.raw(), ParseInput, Preamble), ParseInput}); return Result; } diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index 13c2405e76df7..a2487c957a230 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -411,8 +411,9 @@ struct FragmentCompiler { C.Index.External = Spec; return; } - if (P.Path.empty() || !pathStartsWith(Spec.MountPoint, P.Path, - llvm::sys::path::Style::posix)) + if (P.Path.empty() || + !PathRef(Spec.MountPoint) + .startsWith(P.Path, llvm::sys::path::Style::posix)) return; C.Index.External = Spec; // Disable background indexing for the files under the mountpoint. diff --git a/clang-tools-extra/clangd/ConfigProvider.cpp b/clang-tools-extra/clangd/ConfigProvider.cpp index ac437ee8b6eb1..24dacabd82b2a 100644 --- a/clang-tools-extra/clangd/ConfigProvider.cpp +++ b/clang-tools-extra/clangd/ConfigProvider.cpp @@ -43,7 +43,8 @@ class FileConfigCache : public FileCache { [&](std::optional Data) { CachedValue.clear(); if (Data) - for (auto &Fragment : Fragment::parseYAML(*Data, path(), DC)) { + for (auto &Fragment : + Fragment::parseYAML(*Data, path().raw(), DC)) { Fragment.Source.Directory = Directory; Fragment.Source.Trusted = Trusted; CachedValue.push_back(std::move(Fragment).compile(DC)); @@ -103,9 +104,9 @@ Provider::fromAncestorRelativeYAMLFiles(llvm::StringRef RelPath, // Compute absolute paths to all ancestors (substrings of P.Path). llvm::SmallVector Ancestors; - for (auto Ancestor = absoluteParent(P.Path); !Ancestor.empty(); - Ancestor = absoluteParent(Ancestor)) { - Ancestors.emplace_back(Ancestor); + for (auto Ancestor = PathRef(P.Path).absoluteParent(); !Ancestor.empty(); + Ancestor = Ancestor.absoluteParent()) { + Ancestors.emplace_back(Ancestor.raw()); } // Ensure corresponding cache entries exist in the map. llvm::SmallVector Caches; diff --git a/clang-tools-extra/clangd/DraftStore.cpp b/clang-tools-extra/clangd/DraftStore.cpp index 66e45b0c04ce3..de84b693f449b 100644 --- a/clang-tools-extra/clangd/DraftStore.cpp +++ b/clang-tools-extra/clangd/DraftStore.cpp @@ -19,7 +19,7 @@ namespace clangd { std::optional DraftStore::getDraft(PathRef File) const { std::lock_guard Lock(Mutex); - auto It = Drafts.find(File); + auto It = Drafts.find(File.raw()); if (It == Drafts.end()) return std::nullopt; @@ -76,7 +76,7 @@ std::string DraftStore::addDraft(PathRef File, llvm::StringRef Version, llvm::StringRef Contents) { std::lock_guard Lock(Mutex); - auto &D = Drafts[File]; + auto &D = Drafts[File.raw()]; updateVersion(D.D, Version); std::time(&D.MTime); D.D.Contents = std::make_shared(Contents); @@ -86,7 +86,7 @@ std::string DraftStore::addDraft(PathRef File, llvm::StringRef Version, void DraftStore::removeDraft(PathRef File) { std::lock_guard Lock(Mutex); - Drafts.erase(File); + Drafts.erase(File.raw()); } namespace { diff --git a/clang-tools-extra/clangd/FS.cpp b/clang-tools-extra/clangd/FS.cpp index 5729b9341d9d4..cdf5fc6aceae0 100644 --- a/clang-tools-extra/clangd/FS.cpp +++ b/clang-tools-extra/clangd/FS.cpp @@ -113,11 +113,5 @@ PreambleFileStatusCache::getConsumingFS( return llvm::IntrusiveRefCntPtr(new CacheVFS(std::move(FS), *this)); } -Path removeDots(PathRef File) { - llvm::SmallString<128> CanonPath(File); - llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true); - return CanonPath.str().str(); -} - } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/FS.h b/clang-tools-extra/clangd/FS.h index 827b465aed983..4f9845bdf9111 100644 --- a/clang-tools-extra/clangd/FS.h +++ b/clang-tools-extra/clangd/FS.h @@ -9,7 +9,6 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FS_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FS_H -#include "support/Path.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/VirtualFileSystem.h" @@ -68,13 +67,6 @@ class PreambleFileStatusCache { llvm::StringMap StatCache; }; -/// Returns a version of \p File that doesn't contain dots and dot dots. -/// e.g /a/b/../c -> /a/c -/// /a/b/./c -> /a/b/c -/// FIXME: We should avoid encountering such paths in clangd internals by -/// filtering everything we get over LSP, CDB, etc. -Path removeDots(PathRef File); - } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp index 7c0eb9651feaa..8743344845125 100644 --- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp +++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp @@ -47,8 +47,8 @@ namespace { // deepest directory and going up to root. Stops whenever action succeeds. void actOnAllParentDirectories(PathRef FileName, llvm::function_ref Action) { - for (auto Path = absoluteParent(FileName); !Path.empty() && !Action(Path); - Path = absoluteParent(Path)) + for (auto Path = FileName.absoluteParent(); !Path.empty() && !Action(Path); + Path = Path.absoluteParent()) ; } @@ -60,12 +60,12 @@ GlobalCompilationDatabase::getFallbackCommand(PathRef File) const { // Clang treats .h files as C by default and files without extension as linker // input, resulting in unhelpful diagnostics. // Parsing as Objective C++ is friendly to more cases. - auto FileExtension = llvm::sys::path::extension(File); + auto FileExtension = File.extension(); if (FileExtension.empty() || FileExtension == ".h") Argv.push_back("-xobjective-c++-header"); - Argv.push_back(std::string(File)); - tooling::CompileCommand Cmd(llvm::sys::path::parent_path(File), - llvm::sys::path::filename(File), std::move(Argv), + Argv.push_back(File.owned().raw()); + tooling::CompileCommand Cmd(File.parentPath().raw(), File.filename(), + std::move(Argv), /*Output=*/""); Cmd.Heuristic = "clangd fallback"; return Cmd; @@ -265,7 +265,7 @@ parseJSON(PathRef Path, llvm::StringRef Data, std::string &Error) { static std::unique_ptr parseFixed(PathRef Path, llvm::StringRef Data, std::string &Error) { return tooling::FixedCompilationDatabase::loadFromBuffer( - llvm::sys::path::parent_path(Path), Data, Error); + Path.parentPath().raw(), Data, Error); } bool DirectoryBasedGlobalCompilationDatabase::DirectoryCache::load( @@ -374,7 +374,7 @@ DirectoryBasedGlobalCompilationDatabase::getCompileCommand(PathRef File) const { return std::nullopt; } - auto Candidates = Res->CDB->getCompileCommands(File); + auto Candidates = Res->CDB->getCompileCommands(File.raw()); if (!Candidates.empty()) return std::move(Candidates.front()); @@ -388,10 +388,10 @@ DirectoryBasedGlobalCompilationDatabase::getDirectoryCaches( FoldedDirs.reserve(Dirs.size()); for (const auto &Dir : Dirs) { #ifndef NDEBUG - if (!llvm::sys::path::is_absolute(Dir)) + if (!PathRef(Dir).isAbsolute()) elog("Trying to cache CDB for relative {0}"); #endif - FoldedDirs.push_back(maybeCaseFoldPath(Dir)); + FoldedDirs.push_back(PathRef(Dir).caseFolded().raw()); } std::vector Ret; @@ -406,15 +406,15 @@ DirectoryBasedGlobalCompilationDatabase::getDirectoryCaches( std::optional DirectoryBasedGlobalCompilationDatabase::lookupCDB( CDBLookupRequest Request) const { - assert(llvm::sys::path::is_absolute(Request.FileName) && - "path must be absolute"); + assert(Request.FileName.isAbsolute() && "path must be absolute"); std::string Storage; std::vector SearchDirs; if (Opts.CompileCommandsDir) // FIXME: unify this case with config. - SearchDirs = {*Opts.CompileCommandsDir}; + SearchDirs = {Opts.CompileCommandsDir->raw()}; else { - WithContext WithProvidedContext(Opts.ContextProvider(Request.FileName)); + WithContext WithProvidedContext( + Opts.ContextProvider(Request.FileName.raw())); const auto &Spec = Config::current().CompileFlags.CDBSearch; switch (Spec.Policy) { case Config::CDBSearchSpec::NoCDBSearch: @@ -427,9 +427,9 @@ DirectoryBasedGlobalCompilationDatabase::lookupCDB( // Traverse the canonical version to prevent false positives. i.e.: // src/build/../a.cc can detect a CDB in /src/build if not // canonicalized. - Storage = removeDots(Request.FileName); - actOnAllParentDirectories(Storage, [&](llvm::StringRef Dir) { - SearchDirs.push_back(Dir); + Storage = Request.FileName.removeDots().raw(); + actOnAllParentDirectories(Storage, [&](PathRef Dir) { + SearchDirs.push_back(Dir.raw()); return false; }); } @@ -581,8 +581,8 @@ class DirectoryBasedGlobalCompilationDatabase::BroadcastThread::Filter { DirInfo *addParents(llvm::StringRef FilePath) { DirInfo *Leaf = nullptr; DirInfo *Child = nullptr; - actOnAllParentDirectories(FilePath, [&](llvm::StringRef Dir) { - auto &Info = Dirs[Dir]; + actOnAllParentDirectories(FilePath, [&](PathRef Dir) { + auto &Info = Dirs[Dir.raw()]; // If this is the first iteration, then this node is the overall result. if (!Leaf) Leaf = &Info; @@ -677,7 +677,7 @@ class DirectoryBasedGlobalCompilationDatabase::BroadcastThread::Filter { std::vector SearchPaths(AllFiles.size()); for (unsigned I = 0; I < AllFiles.size(); ++I) { if (Parent.Opts.CompileCommandsDir) { // FIXME: unify with config - SearchPaths[I].setPointer(&Dirs[*Parent.Opts.CompileCommandsDir]); + SearchPaths[I].setPointer(&Dirs[Parent.Opts.CompileCommandsDir->raw()]); continue; } if (ExitEarly()) // loading config may be slow @@ -768,7 +768,7 @@ OverlayCDB::getCompileCommand(PathRef File) const { std::optional Cmd; { std::lock_guard Lock(Mutex); - auto It = Commands.find(removeDots(File)); + auto It = Commands.find(File.removeDots().raw()); if (It != Commands.end()) Cmd = It->second; } @@ -793,7 +793,7 @@ OverlayCDB::getCompileCommand(PathRef File) const { if (!Cmd) return std::nullopt; if (Mangler) - Mangler(*Cmd, File); + Mangler(*Cmd, File.raw()); return Cmd; } @@ -803,7 +803,7 @@ tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File) const { Cmd.CommandLine.insert(Cmd.CommandLine.end(), FallbackFlags.begin(), FallbackFlags.end()); if (Mangler) - Mangler(Cmd, File); + Mangler(Cmd, File.raw()); return Cmd; } @@ -812,7 +812,7 @@ bool OverlayCDB::setCompileCommand(PathRef File, // We store a canonical version internally to prevent mismatches between set // and get compile commands. Also it assures clients listening to broadcasts // doesn't receive different names for the same file. - std::string CanonPath = removeDots(File); + std::string CanonPath = File.removeDots().raw(); { std::unique_lock Lock(Mutex); if (Cmd) { @@ -835,7 +835,7 @@ OverlayCDB::getProjectModules(PathRef File) const { auto MDB = DelegatingCDB::getProjectModules(File); MDB->setCommandMangler([&Mangler = Mangler](tooling::CompileCommand &Command, PathRef CommandPath) { - Mangler(Command, CommandPath); + Mangler(Command, CommandPath.raw()); }); return MDB; } diff --git a/clang-tools-extra/clangd/HeaderSourceSwitch.cpp b/clang-tools-extra/clangd/HeaderSourceSwitch.cpp index d54c3668570eb..4ea2fccda464e 100644 --- a/clang-tools-extra/clangd/HeaderSourceSwitch.cpp +++ b/clang-tools-extra/clangd/HeaderSourceSwitch.cpp @@ -26,16 +26,18 @@ std::optional getCorrespondingHeaderOrSource( ".inc", ".cppm", ".ccm", ".cxxm", ".c++m", ".ixx"}; - llvm::StringRef PathExt = llvm::sys::path::extension(OriginalFile); + llvm::StringRef PathExt = OriginalFile.extension(); // Lookup in a list of known extensions. - bool IsSource = llvm::any_of(SourceExtensions, [&PathExt](PathRef SourceExt) { - return SourceExt.equals_insensitive(PathExt); - }); + bool IsSource = + llvm::any_of(SourceExtensions, [&PathExt](llvm::StringRef SourceExt) { + return SourceExt.equals_insensitive(PathExt); + }); - bool IsHeader = llvm::any_of(HeaderExtensions, [&PathExt](PathRef HeaderExt) { - return HeaderExt.equals_insensitive(PathExt); - }); + bool IsHeader = + llvm::any_of(HeaderExtensions, [&PathExt](llvm::StringRef HeaderExt) { + return HeaderExt.equals_insensitive(PathExt); + }); // We can only switch between the known extensions. if (!IsSource && !IsHeader) @@ -50,7 +52,7 @@ std::optional getCorrespondingHeaderOrSource( NewExts = SourceExtensions; // Storage for the new path. - llvm::SmallString<128> NewPath = OriginalFile; + llvm::SmallString<128> NewPath = OriginalFile.raw(); // Loop through switched extension candidates. for (llvm::StringRef NewExt : NewExts) { @@ -81,8 +83,8 @@ std::optional getCorrespondingHeaderOrSource(PathRef OriginalFile, } llvm::StringMap Candidates; // Target path => score. auto AwardTarget = [&](const char *TargetURI) { - if (auto TargetPath = URI::resolve(TargetURI, OriginalFile)) { - if (!pathEqual(*TargetPath, OriginalFile)) // exclude the original file. + if (auto TargetPath = URI::resolve(TargetURI, OriginalFile.raw())) { + if (PathRef(*TargetPath) != OriginalFile) // exclude the original file. ++Candidates[*TargetPath]; } else { elog("Failed to resolve URI {0}: {1}", TargetURI, TargetPath.takeError()); @@ -94,7 +96,7 @@ std::optional getCorrespondingHeaderOrSource(PathRef OriginalFile, // // For each symbol in the original file, we get its target location (decl or // def) from the index, then award that target file. - bool IsHeader = isHeaderFile(OriginalFile, AST.getLangOpts()); + bool IsHeader = isHeaderFile(OriginalFile.raw(), AST.getLangOpts()); Index->lookup(Request, [&](const Symbol &Sym) { if (IsHeader) AwardTarget(Sym.Definition.FileURI); diff --git a/clang-tools-extra/clangd/Headers.cpp b/clang-tools-extra/clangd/Headers.cpp index 87fd261b906e6..58bf77a1c9285 100644 --- a/clang-tools-extra/clangd/Headers.cpp +++ b/clang-tools-extra/clangd/Headers.cpp @@ -263,7 +263,7 @@ IncludeStructure::mainFileIncludesWithSpelling(llvm::StringRef Spelling) const { void IncludeInserter::addExisting(const Inclusion &Inc) { IncludedHeaders.insert(Inc.Written); if (!Inc.Resolved.empty()) - IncludedHeaders.insert(Inc.Resolved); + IncludedHeaders.insert(Inc.Resolved.raw()); } /// FIXME(ioeric): we might not want to insert an absolute include path if the @@ -278,7 +278,7 @@ bool IncludeInserter::shouldInsertInclude( auto Included = [&](llvm::StringRef Header) { return IncludedHeaders.contains(Header); }; - return !Included(DeclaringHeader) && !Included(InsertedHeader.File); + return !Included(DeclaringHeader.raw()) && !Included(InsertedHeader.File); } std::optional @@ -348,7 +348,7 @@ IncludeInserter::insert(llvm::StringRef VerbatimHeader, llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Inclusion &Inc) { return OS << Inc.Written << " = " - << (!Inc.Resolved.empty() ? Inc.Resolved : "[unresolved]") + << (!Inc.Resolved.empty() ? Inc.Resolved.raw() : "[unresolved]") << " at line" << Inc.HashLine; } diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index 3ab3d89030520..c5957afbdc4de 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -1302,7 +1302,7 @@ std::optional getHover(ParsedAST &AST, Position Pos, continue; HoverCountMetric.record(1, "include"); HoverInfo HI; - HI.Name = std::string(llvm::sys::path::filename(Inc.Resolved)); + HI.Name = Inc.Resolved.ref().filename().str(); // FIXME: We don't have a fitting value for Kind. HI.Definition = URIForFile::canonicalize(Inc.Resolved, AST.tuPath()).file().str(); diff --git a/clang-tools-extra/clangd/IncludeCleaner.cpp b/clang-tools-extra/clangd/IncludeCleaner.cpp index e34706172f0bf..c37adc1f58593 100644 --- a/clang-tools-extra/clangd/IncludeCleaner.cpp +++ b/clang-tools-extra/clangd/IncludeCleaner.cpp @@ -100,7 +100,7 @@ bool mayConsiderUnused(const Inclusion &Inc, ParsedAST &AST, // Since most private -> public mappings happen in a verbatim way, we // check textually here. This might go wrong in presence of symlinks or // header mappings. But that's not different than rest of the places. - if (AST.tuPath().ends_with(PHeader)) + if (AST.tuPath().raw().ends_with(PHeader)) return false; } } @@ -122,9 +122,9 @@ std::vector generateMissingIncludeDiagnostics( const SourceManager &SM = AST.getSourceManager(); const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID()); - auto FileStyle = getFormatStyleForFile(AST.tuPath(), Code, TFS, false); + auto FileStyle = getFormatStyleForFile(AST.tuPath().raw(), Code, TFS, false); - tooling::HeaderIncludes HeaderIncludes(AST.tuPath(), Code, + tooling::HeaderIncludes HeaderIncludes(AST.tuPath().raw(), Code, FileStyle.IncludeStyle); for (const auto &SymbolWithMissingInclude : MissingIncludes) { llvm::StringRef ResolvedPath = @@ -157,7 +157,7 @@ std::vector generateMissingIncludeDiagnostics( SymbolWithMissingInclude.Symbol.name()); D.Name = "missing-includes"; D.Source = Diag::DiagSource::Clangd; - D.File = AST.tuPath(); + D.File = AST.tuPath().raw(); D.InsideMainFile = true; // We avoid the "warning" severity here in favor of LSP's "information". // @@ -194,7 +194,7 @@ std::vector generateUnusedIncludeDiagnostics( llvm::StringRef Code, HeaderFilter IgnoreHeaders) { std::vector Result; for (const auto *Inc : UnusedIncludes) { - if (isIgnored(Inc->Resolved, IgnoreHeaders)) + if (isIgnored(Inc->Resolved.raw(), IgnoreHeaders)) continue; Diag &D = Result.emplace_back(); D.Message = @@ -204,7 +204,7 @@ std::vector generateUnusedIncludeDiagnostics( llvm::sys::path::Style::posix)); D.Name = "unused-includes"; D.Source = Diag::DiagSource::Clangd; - D.File = FileName; + D.File = FileName.raw(); D.InsideMainFile = true; D.Severity = DiagnosticsEngine::Warning; D.Tags.push_back(Unnecessary); @@ -343,7 +343,7 @@ include_cleaner::Includes convertIncludes(const ParsedAST &AST) { TransformedInc.Angled = WrittenRef.starts_with("<"); // Inc.Resolved is canonicalized with clangd::getCanonicalPath(), // which is based on FileManager::getCanonicalName(ParentDir). - auto FE = SM.getFileManager().getFileRef(Inc.Resolved); + auto FE = SM.getFileManager().getFileRef(Inc.Resolved.raw()); if (!FE) { elog("IncludeCleaner: Failed to get an entry for resolved path {0}: {1}", Inc.Resolved, FE.takeError()); @@ -363,7 +363,7 @@ computeIncludeCleanerFindings(ParsedAST &AST, bool AnalyzeAngledIncludes) { const auto &SM = AST.getSourceManager(); include_cleaner::Includes ConvertedIncludes = convertIncludes(AST); const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID()); - auto PreamblePatch = PreamblePatch::getPatchEntry(AST.tuPath(), SM); + auto PreamblePatch = PreamblePatch::getPatchEntry(AST.tuPath().raw(), SM); std::vector Macros = collectMacroReferences(AST); diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp index c1878f91b5e16..72d5f6568ce51 100644 --- a/clang-tools-extra/clangd/ModulesBuilder.cpp +++ b/clang-tools-extra/clangd/ModulesBuilder.cpp @@ -36,10 +36,10 @@ namespace { // TODO: Move these module fils out of the temporary directory if the module // files are persistent. llvm::SmallString<256> getUniqueModuleFilesPath(PathRef MainFile) { - llvm::SmallString<128> HashedPrefix = llvm::sys::path::filename(MainFile); + llvm::SmallString<128> HashedPrefix = MainFile.filename(); // There might be multiple files with the same name in a project. So appending // the hash value of the full path to make sure they won't conflict. - HashedPrefix += std::to_string(llvm::hash_value(MainFile)); + HashedPrefix += std::to_string(hash_value(MainFile)); llvm::SmallString<256> ResultPattern; @@ -64,7 +64,7 @@ llvm::SmallString<256> getUniqueModuleFilesPath(PathRef MainFile) { // Get a unique module file path under \param ModuleFilesPrefix. std::string getModuleFilePath(llvm::StringRef ModuleName, PathRef ModuleFilesPrefix) { - llvm::SmallString<256> ModuleFilePath(ModuleFilesPrefix); + llvm::SmallString<256> ModuleFilePath(ModuleFilesPrefix.raw()); auto [PrimaryModuleName, PartitionName] = ModuleName.split(':'); llvm::sys::path::append(ModuleFilePath, PrimaryModuleName); if (!PartitionName.empty()) { @@ -97,7 +97,7 @@ class FailedPrerequisiteModules : public PrerequisiteModules { struct ModuleFile { ModuleFile(StringRef ModuleName, PathRef ModuleFilePath) - : ModuleName(ModuleName.str()), ModuleFilePath(ModuleFilePath.str()) {} + : ModuleName(ModuleName.str()), ModuleFilePath(ModuleFilePath.raw()) {} ModuleFile() = delete; @@ -216,7 +216,7 @@ bool IsModuleFileUpToDate(PathRef ModuleFilePath, // listener. Reader.setListener(nullptr); - if (Reader.ReadAST(ModuleFilePath, serialization::MK_MainFile, + if (Reader.ReadAST(ModuleFilePath.raw(), serialization::MK_MainFile, SourceLocation(), ASTReader::ARR_None) != ASTReader::Success) return false; @@ -308,7 +308,7 @@ bool ReusablePrerequisiteModules::canReuse( if (RequiredModules.empty()) return true; - llvm::SmallVector BMIPaths; + llvm::SmallVector BMIPaths; for (auto &MF : RequiredModules) BMIPaths.push_back(MF->getModuleFilePath()); return IsModuleFilesUpToDate(BMIPaths, *this, VFS); @@ -370,7 +370,7 @@ class ModuleNameToSourceCache { void addEntry(llvm::StringRef ModuleName, PathRef Source) { std::lock_guard Lock(CacheMutex); - ModuleNameToSourceCache[ModuleName] = Source.str(); + ModuleNameToSourceCache[ModuleName] = Source.raw(); } void eraseEntry(llvm::StringRef ModuleName) { diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp index 3f63daaf400db..2874b2c245bbd 100644 --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -196,8 +196,9 @@ class ReplayPreamble : private PPCallbacks { void replay() { for (const auto &Inc : Includes) { OptionalFileEntryRef File; - if (Inc.Resolved != "") - File = expectedToOptional(SM.getFileManager().getFileRef(Inc.Resolved)); + if (!Inc.Resolved.empty()) + File = expectedToOptional( + SM.getFileManager().getFileRef(Inc.Resolved.ref().raw())); // Re-lex the #include directive to find its interesting parts. auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset); diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp index 6fab3e2191426..1e2fcccf78c71 100644 --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -595,11 +595,11 @@ buildPreamble(PathRef FileName, CompilerInvocation CI, // Note that we don't need to copy the input contents, preamble can live // without those. auto ContentsBuffer = - llvm::MemoryBuffer::getMemBuffer(Inputs.Contents, FileName); + llvm::MemoryBuffer::getMemBuffer(Inputs.Contents, FileName.raw()); auto Bounds = ComputePreambleBounds(CI.getLangOpts(), *ContentsBuffer, 0); trace::Span Tracer("BuildPreamble"); - SPAN_ATTACH(Tracer, "File", FileName); + SPAN_ATTACH(Tracer, "File", FileName.raw()); std::vector> ASTListeners; if (Inputs.FeatureModules) { for (auto &M : *Inputs.FeatureModules) { @@ -650,7 +650,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI, for (const auto &L : ASTListeners) L->beforeExecute(CI); }); - llvm::SmallString<32> AbsFileName(FileName); + llvm::SmallString<32> AbsFileName(FileName.raw()); VFS->makeAbsolute(AbsFileName); auto StatCache = std::make_shared(AbsFileName); auto StatCacheFS = StatCache->getProducingFS(VFS); @@ -743,7 +743,7 @@ bool isPreambleCompatible(const PreambleData &Preamble, const ParseInputs &Inputs, PathRef FileName, const CompilerInvocation &CI) { auto ContentsBuffer = - llvm::MemoryBuffer::getMemBuffer(Inputs.Contents, FileName); + llvm::MemoryBuffer::getMemBuffer(Inputs.Contents, FileName.raw()); auto Bounds = ComputePreambleBounds(CI.getLangOpts(), *ContentsBuffer, 0); auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory); return compileCommandsAreEqual(Inputs.CompileCommand, diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp index 05c8041df7de7..dc220daba1c82 100644 --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -13,6 +13,7 @@ #include "Protocol.h" #include "URI.h" #include "support/Logger.h" +#include "support/Path.h" #include "clang/Basic/LLVM.h" #include "clang/Index/IndexSymbol.h" #include "llvm/ADT/StringExtras.h" @@ -43,15 +44,14 @@ bool mapOptOrNull(const llvm::json::Value &Params, llvm::StringLiteral Prop, char LSPError::ID; -URIForFile URIForFile::canonicalize(llvm::StringRef AbsPath, - llvm::StringRef TUPath) { - assert(llvm::sys::path::is_absolute(AbsPath) && "the path is relative"); - auto Resolved = URI::resolvePath(AbsPath, TUPath); +URIForFile URIForFile::canonicalize(PathRef AbsPath, PathRef TUPath) { + assert(AbsPath.isAbsolute() && "the path is relative"); + auto Resolved = URI::resolvePath(AbsPath.raw(), TUPath.raw()); if (!Resolved) { elog("URIForFile: failed to resolve path {0} with TU path {1}: " "{2}.\nUsing unresolved path.", AbsPath, TUPath, Resolved.takeError()); - return URIForFile(std::string(AbsPath)); + return URIForFile(AbsPath.owned().raw()); } return URIForFile(std::move(*Resolved)); } diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index c7ef1a13e6e39..e89880527ca1c 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -26,6 +26,7 @@ #include "URI.h" #include "index/SymbolID.h" #include "support/MemoryTree.h" +#include "support/Path.h" #include "clang/Index/IndexSymbol.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/JSON.h" @@ -94,8 +95,7 @@ struct URIForFile { /// Files can be referred to by several paths (e.g. in the presence of links). /// Which one we prefer may depend on where we're coming from. \p TUPath is a /// hint, and should usually be the main entrypoint file we're processing. - static URIForFile canonicalize(llvm::StringRef AbsPath, - llvm::StringRef TUPath); + static URIForFile canonicalize(PathRef AbsPath, PathRef TUPath); static llvm::Expected fromURI(const URI &U, llvm::StringRef HintPath); diff --git a/clang-tools-extra/clangd/ScanningProjectModules.cpp b/clang-tools-extra/clangd/ScanningProjectModules.cpp index e561513fe687f..b509d7cee838d 100644 --- a/clang-tools-extra/clangd/ScanningProjectModules.cpp +++ b/clang-tools-extra/clangd/ScanningProjectModules.cpp @@ -92,7 +92,7 @@ class ModuleDependencyScanner { std::optional ModuleDependencyScanner::scan(PathRef FilePath, const ProjectModules::CommandMangler &Mangler) { - auto Candidates = CDB->getCompileCommands(FilePath); + auto Candidates = CDB->getCompileCommands(FilePath.raw()); if (Candidates.empty()) return std::nullopt; @@ -106,7 +106,7 @@ ModuleDependencyScanner::scan(PathRef FilePath, using namespace clang::tooling::dependencies; - llvm::SmallString<128> FilePathDir(FilePath); + llvm::SmallString<128> FilePathDir(FilePath.raw()); llvm::sys::path::remove_filename(FilePathDir); DependencyScanningTool ScanningTool(Service, TFS.view(FilePathDir)); @@ -122,7 +122,7 @@ ModuleDependencyScanner::scan(PathRef FilePath, ModuleDependencyInfo Result; if (ScanningResult->Provides) { - ModuleNameToSource[ScanningResult->Provides->ModuleName] = FilePath; + ModuleNameToSource[ScanningResult->Provides->ModuleName] = FilePath.raw(); Result.ModuleName = ScanningResult->Provides->ModuleName; } @@ -195,7 +195,7 @@ class ScanningAllProjectModules : public ProjectModules { std::string getSourceForModuleName(llvm::StringRef ModuleName, PathRef RequiredSourceFile) override { Scanner.globalScan(Mangler); - return Scanner.getSourceForModuleName(ModuleName).str(); + return Scanner.getSourceForModuleName(ModuleName).owned().raw(); } std::string getModuleNameForSource(PathRef File) override { diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp index 035e5e63d8fbb..c7e76d9d70e96 100644 --- a/clang-tools-extra/clangd/TUScheduler.cpp +++ b/clang-tools-extra/clangd/TUScheduler.cpp @@ -310,7 +310,7 @@ class TUScheduler::HeaderIncluderCache { // Headers not in the list will have their associations removed. void update(PathRef MainFile, llvm::ArrayRef Headers) { std::lock_guard Lock(Mu); - auto It = MainToFirst.try_emplace(MainFile, nullptr); + auto It = MainToFirst.try_emplace(MainFile.raw(), nullptr); Association *&First = It.first->second; if (First) invalidate(First); @@ -323,7 +323,7 @@ class TUScheduler::HeaderIncluderCache { // will be eligible for association with other files that get update()d. void remove(PathRef MainFile) { std::lock_guard Lock(Mu); - Association *&First = MainToFirst[MainFile]; + Association *&First = MainToFirst[MainFile.raw()]; if (First) { invalidate(First); First = nullptr; @@ -335,7 +335,7 @@ class TUScheduler::HeaderIncluderCache { /// Get the mainfile associated with Header, or the empty string if none. std::string get(PathRef Header) const { std::lock_guard Lock(Mu); - return HeaderToMain.lookup(Header).MainFile.str(); + return HeaderToMain.lookup(Header.raw()).MainFile.str(); } size_t getUsedBytes() const { @@ -483,7 +483,7 @@ class PreambleThread { break; { - Throttle.emplace(FileName, Throttler, ReqCV); + Throttle.emplace(FileName.raw(), Throttler, ReqCV); std::optional Tracer; // If acquire succeeded synchronously, avoid status jitter. if (!Throttle->satisfied()) { @@ -822,9 +822,9 @@ ASTWorker::create(PathRef FileName, const GlobalCompilationDatabase &CDB, new ASTWorker(FileName, CDB, IdleASTs, HeaderIncluders, Barrier, /*RunSync=*/!Tasks, Opts, Callbacks)); if (Tasks) { - Tasks->runAsync("ASTWorker:" + llvm::sys::path::filename(FileName), + Tasks->runAsync("ASTWorker:" + FileName.filename(), [Worker]() { Worker->run(); }); - Tasks->runAsync("PreambleWorker:" + llvm::sys::path::filename(FileName), + Tasks->runAsync("PreambleWorker:" + FileName.filename(), [Worker]() { Worker->PreamblePeer.run(); }); } @@ -841,8 +841,9 @@ ASTWorker::ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB, UpdateDebounce(Opts.UpdateDebounce), FileName(FileName), ContextProvider(Opts.ContextProvider), CDB(CDB), Callbacks(Callbacks), Barrier(Barrier), Done(false), Status(FileName, Callbacks), - PreamblePeer(FileName, Callbacks, Opts.StorePreamblesInMemory, RunSync, - Opts.PreambleThrottler, Status, HeaderIncluders, *this) { + PreamblePeer(FileName.raw(), Callbacks, Opts.StorePreamblesInMemory, + RunSync, Opts.PreambleThrottler, Status, HeaderIncluders, + *this) { // Set a fallback command because compile command can be accessed before // `Inputs` is initialized. Other fields are only used after initialization // from client inputs. @@ -881,7 +882,8 @@ void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags, HeaderIncluders.remove(ProxyFile); } else { // We have a reliable command for an including file, use it. - Cmd = tooling::transferCompileCommand(std::move(*ProxyCmd), FileName); + Cmd = tooling::transferCompileCommand(std::move(*ProxyCmd), + FileName.raw()); } } } @@ -995,9 +997,9 @@ void ASTWorker::runWithAST( // return a compatible preamble as ASTWorker::update blocks. std::optional NewAST; if (Invocation) { - NewAST = ParsedAST::build(FileName, FileInputs, std::move(Invocation), - CompilerInvocationDiagConsumer.take(), - getPossiblyStalePreamble()); + NewAST = ParsedAST::build( + FileName.raw(), FileInputs, std::move(Invocation), + CompilerInvocationDiagConsumer.take(), getPossiblyStalePreamble()); ++ASTBuildCount; } AST = NewAST ? std::make_unique(std::move(*NewAST)) : nullptr; @@ -1211,8 +1213,9 @@ void ASTWorker::generateDiagnostics( IdleASTs.take(this, &ASTAccessForDiag); if (!AST || !InputsAreLatest) { auto RebuildStartTime = DebouncePolicy::clock::now(); - std::optional NewAST = ParsedAST::build( - FileName, Inputs, std::move(Invocation), CIDiags, *LatestPreamble); + std::optional NewAST = + ParsedAST::build(FileName.raw(), Inputs, std::move(Invocation), CIDiags, + *LatestPreamble); auto RebuildDuration = DebouncePolicy::clock::now() - RebuildStartTime; ++ASTBuildCount; // Try to record the AST-build time, to inform future update debouncing. @@ -1324,7 +1327,7 @@ void ASTWorker::runTask(llvm::StringRef Name, llvm::function_ref Task) { crashDumpParseInputs(llvm::errs(), FileInputs); }); trace::Span Tracer(Name); - WithContext WithProvidedContext(ContextProvider(FileName)); + WithContext WithProvidedContext(ContextProvider(FileName.raw())); Task(); } @@ -1352,7 +1355,7 @@ void ASTWorker::startTask(llvm::StringRef Name, } // Allow this request to be cancelled if invalidated. - Context Ctx = Context::current().derive(FileBeingProcessed, FileName); + Context Ctx = Context::current().derive(FileBeingProcessed, FileName.raw()); Canceler Invalidate = nullptr; if (Invalidation) { WithContext WC(std::move(Ctx)); @@ -1640,7 +1643,7 @@ TUScheduler::TUScheduler(const GlobalCompilationDatabase &CDB, HeaderIncluders(std::make_unique()) { // Avoid null checks everywhere. if (!Opts.ContextProvider) { - this->Opts.ContextProvider = [](llvm::StringRef) { + this->Opts.ContextProvider = [](PathRef) { return Context::current().clone(); }; } @@ -1673,7 +1676,7 @@ bool TUScheduler::blockUntilIdle(Deadline D) const { bool TUScheduler::update(PathRef File, ParseInputs Inputs, WantDiagnostics WantDiags) { - std::unique_ptr &FD = Files[File]; + std::unique_ptr &FD = Files[File.raw()]; bool NewFile = FD == nullptr; bool ContentChanged = false; if (!FD) { @@ -1692,12 +1695,12 @@ bool TUScheduler::update(PathRef File, ParseInputs Inputs, // There might be synthetic update requests, don't change the LastActiveFile // in such cases. if (ContentChanged) - LastActiveFile = File.str(); + LastActiveFile = File.owned().raw(); return NewFile; } void TUScheduler::remove(PathRef File) { - bool Removed = Files.erase(File); + bool Removed = Files.erase(File.raw()); if (!Removed) elog("Trying to remove file from TUScheduler that is not tracked: {0}", File); @@ -1744,13 +1747,13 @@ void TUScheduler::runWithAST( llvm::StringRef Name, PathRef File, llvm::unique_function)> Action, TUScheduler::ASTActionInvalidation Invalidation) { - auto It = Files.find(File); + auto It = Files.find(File.raw()); if (It == Files.end()) { Action(llvm::make_error( "trying to get AST for non-added document", ErrorCode::InvalidParams)); return; } - LastActiveFile = File.str(); + LastActiveFile = File.owned().raw(); It->second->Worker->runWithAST(Name, std::move(Action), Invalidation); } @@ -1758,18 +1761,18 @@ void TUScheduler::runWithAST( void TUScheduler::runWithPreamble(llvm::StringRef Name, PathRef File, PreambleConsistency Consistency, Callback Action) { - auto It = Files.find(File); + auto It = Files.find(File.raw()); if (It == Files.end()) { Action(llvm::make_error( "trying to get preamble for non-added document", ErrorCode::InvalidParams)); return; } - LastActiveFile = File.str(); + LastActiveFile = File.owned().raw(); if (!PreambleTasks) { trace::Span Tracer(Name); - SPAN_ATTACH(Tracer, "file", File); + SPAN_ATTACH(Tracer, "file", File.raw()); std::shared_ptr Signals; std::shared_ptr Preamble = It->second->Worker->getPossiblyStalePreamble(&Signals); @@ -1781,11 +1784,11 @@ void TUScheduler::runWithPreamble(llvm::StringRef Name, PathRef File, } std::shared_ptr Worker = It->second->Worker.lock(); - auto Task = [Worker, Consistency, Name = Name.str(), File = File.str(), + auto Task = [Worker, Consistency, Name = Name.str(), File = File.owned(), Contents = It->second->Contents, Command = Worker->getCurrentCompileCommand(), Ctx = Context::current().derive(FileBeingProcessed, - std::string(File)), + File.owned().raw()), Action = std::move(Action), this]() mutable { clang::noteBottomOfStack(); ThreadCrashReporter ScopedReporter([&Name, &Contents, &Command]() { @@ -1811,8 +1814,7 @@ void TUScheduler::runWithPreamble(llvm::StringRef Name, PathRef File, Action(InputsAndPreamble{Contents, Command, Preamble.get(), Signals.get()}); }; - PreambleTasks->runAsync("task:" + llvm::sys::path::filename(File), - std::move(Task)); + PreambleTasks->runAsync("task:" + File.filename(), std::move(Task)); } llvm::StringMap TUScheduler::fileStats() const { diff --git a/clang-tools-extra/clangd/TidyProvider.cpp b/clang-tools-extra/clangd/TidyProvider.cpp index 1d79a7a7399ec..d2be8fa03b057 100644 --- a/clang-tools-extra/clangd/TidyProvider.cpp +++ b/clang-tools-extra/clangd/TidyProvider.cpp @@ -64,7 +64,7 @@ class DotClangTidyCache : private FileCache { } }; if (auto Parsed = tidy::parseConfigurationWithDiags( - llvm::MemoryBufferRef(*Data, path()), Diagnostics)) + llvm::MemoryBufferRef(*Data, path().raw()), Diagnostics)) Value = std::make_shared( std::move(*Parsed)); else @@ -99,21 +99,21 @@ class DotClangTidyTree { void apply(tidy::ClangTidyOptions &Result, PathRef AbsPath) { namespace path = llvm::sys::path; - assert(path::is_absolute(AbsPath)); + assert(AbsPath.isAbsolute()); // Compute absolute paths to all ancestors (substrings of P.Path). // Ensure cache entries for each ancestor exist in the map. llvm::SmallVector Caches; { std::lock_guard Lock(Mu); - for (auto Ancestor = absoluteParent(AbsPath); !Ancestor.empty(); - Ancestor = absoluteParent(Ancestor)) { - auto It = Cache.find(Ancestor); + for (auto Ancestor = AbsPath.absoluteParent(); !Ancestor.empty(); + Ancestor = Ancestor.absoluteParent()) { + auto It = Cache.find(Ancestor.raw()); // Assemble the actual config file path only if needed. if (It == Cache.end()) { - llvm::SmallString<256> ConfigPath = Ancestor; + llvm::SmallString<256> ConfigPath = Ancestor.raw(); path::append(ConfigPath, RelPath); - It = Cache.try_emplace(Ancestor, ConfigPath.str()).first; + It = Cache.try_emplace(Ancestor.raw(), ConfigPath.str()).first; } Caches.push_back(&It->second); } diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp index 8b9fffa3f64cd..af63e15bcea14 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -226,7 +226,7 @@ std::optional locateFileReferent(const Position &Pos, for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) { if (!Inc.Resolved.empty() && Inc.HashLine == Pos.line) { LocatedSymbol File; - File.Name = std::string(llvm::sys::path::filename(Inc.Resolved)); + File.Name = Inc.Resolved.ref().filename().str(); File.PreferredDeclaration = { URIForFile::canonicalize(Inc.Resolved, MainFilePath), Range{}}; File.Definition = File.PreferredDeclaration; @@ -514,7 +514,7 @@ std::vector locateSymbolForType(const ParsedAST &AST, const QualType &Type, const SymbolIndex *Index) { const auto &SM = AST.getSourceManager(); - auto MainFilePath = AST.tuPath(); + auto MainFilePath = AST.tuPath().raw(); // FIXME: this sends unique_ptr to unique_ptr. // Likely it would be better to send it to Foo (heuristically) or to both. @@ -776,7 +776,7 @@ const syntax::Token *findNearbyIdentifier(const SpelledWord &Word, std::vector locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index) { const auto &SM = AST.getSourceManager(); - auto MainFilePath = AST.tuPath(); + auto MainFilePath = AST.tuPath().raw(); if (auto File = locateFileReferent(Pos, AST, MainFilePath)) return {std::move(*File)}; @@ -1320,7 +1320,7 @@ std::vector findImplementations(ParsedAST &AST, Position Pos, QueryKind = RelationKind::BaseOf; } } - return findImplementors(std::move(IDs), QueryKind, Index, AST.tuPath()); + return findImplementors(std::move(IDs), QueryKind, Index, AST.tuPath().raw()); } namespace { @@ -1538,8 +1538,9 @@ ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, return; } const auto LSPLocDecl = - toLSPLocation(Object.CanonicalDeclaration, MainFilePath); - const auto LSPLocDef = toLSPLocation(Object.Definition, MainFilePath); + toLSPLocation(Object.CanonicalDeclaration, MainFilePath.raw()); + const auto LSPLocDef = + toLSPLocation(Object.Definition, MainFilePath.raw()); if (LSPLocDecl && LSPLocDecl != LSPLocDef) { ReferencesResult::Reference Result; Result.Loc = {std::move(*LSPLocDecl), std::nullopt}; @@ -1590,7 +1591,7 @@ ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, LookupRequest ContainerLookup; llvm::DenseMap> RefIndicesForContainer; Results.HasMore |= Index->refs(Req, [&](const Ref &R) { - auto LSPLoc = toLSPLocation(R.Location, MainFilePath); + auto LSPLoc = toLSPLocation(R.Location, MainFilePath.raw()); // Avoid indexed results for the main file - the AST is authoritative. if (!LSPLoc || (!AllowMainFileSymbols && LSPLoc->uri.file() == MainFilePath)) @@ -1668,9 +1669,9 @@ std::vector getSymbolInfo(ParsedAST &AST, Position Pos) { } if (const NamedDecl *Def = getDefinition(D)) NewSymbol.definitionRange = makeLocation( - AST.getASTContext(), nameLocation(*Def, SM), MainFilePath); - NewSymbol.declarationRange = - makeLocation(AST.getASTContext(), nameLocation(*D, SM), MainFilePath); + AST.getASTContext(), nameLocation(*Def, SM), MainFilePath.raw()); + NewSymbol.declarationRange = makeLocation( + AST.getASTContext(), nameLocation(*D, SM), MainFilePath.raw()); Results.push_back(std::move(NewSymbol)); } @@ -1789,7 +1790,7 @@ declToCallHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) { template static std::optional symbolToHierarchyItem(const Symbol &S, PathRef TUPath) { - auto Loc = symbolToLocation(S, TUPath); + auto Loc = symbolToLocation(S, TUPath.raw()); if (!Loc) { elog("Failed to convert symbol to hierarchy item: {0}", Loc.takeError()); return std::nullopt; @@ -2204,12 +2205,12 @@ getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels, } std::optional Result = - declToTypeHierarchyItem(*CXXRD, AST.tuPath()); + declToTypeHierarchyItem(*CXXRD, AST.tuPath().raw()); if (!Result) continue; RecursionProtectionSet RPSet; - fillSuperTypes(*CXXRD, AST.tuPath(), *Result, RPSet); + fillSuperTypes(*CXXRD, AST.tuPath().raw(), *Result, RPSet); if (WantChildren && ResolveLevels > 0) { Result->children.emplace(); @@ -2289,7 +2290,7 @@ prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath) { !cast(Decl)->isLocalVarDecl()) && Decl->getKind() != Decl::Kind::Field) continue; - if (auto CHI = declToCallHierarchyItem(*Decl, AST.tuPath())) + if (auto CHI = declToCallHierarchyItem(*Decl, AST.tuPath().raw())) Result.emplace_back(std::move(*CHI)); } return Result; diff --git a/clang-tools-extra/clangd/index/Background.cpp b/clang-tools-extra/clangd/index/Background.cpp index 496d1455def4b..fad6e3cbe3e46 100644 --- a/clang-tools-extra/clangd/index/Background.cpp +++ b/clang-tools-extra/clangd/index/Background.cpp @@ -78,7 +78,7 @@ llvm::SmallString<128> getAbsolutePath(const tooling::CompileCommand &Cmd) { } bool shardIsStale(const LoadedShard &LS, llvm::vfs::FileSystem *FS) { - auto Buf = FS->getBufferForFile(LS.AbsolutePath); + auto Buf = FS->getBufferForFile(LS.AbsolutePath.raw()); if (!Buf) { vlog("Background-index: Couldn't read {0} to validate stored index: {1}", LS.AbsolutePath, Buf.getError().message()); @@ -224,14 +224,14 @@ void BackgroundIndex::update( // We need to store shards before updating the index, since the latter // consumes slabs. // FIXME: Also skip serializing the shard if it is already up-to-date. - if (auto Error = IndexStorageFactory(Path)->storeShard(Path, *IF)) + if (auto Error = IndexStorageFactory(Path)->storeShard(Path.raw(), *IF)) elog("Failed to write background-index shard for file {0}: {1}", Path, std::move(Error)); { std::lock_guard Lock(ShardVersionsMu); const auto &Hash = FileIt.getValue().second; - auto DigestIt = ShardVersions.try_emplace(Path); + auto DigestIt = ShardVersions.try_emplace(Path.raw()); ShardVersion &SV = DigestIt.first->second; // Skip if file is already up to date, unless previous index was broken // and this one is not. @@ -386,12 +386,12 @@ BackgroundIndex::loadProject(std::vector MainFiles) { LS.Shard->Relations ? std::make_unique(std::move(*LS.Shard->Relations)) : nullptr; - ShardVersion &SV = ShardVersions[LS.AbsolutePath]; + ShardVersion &SV = ShardVersions[LS.AbsolutePath.raw()]; SV.Digest = LS.Digest; SV.HadErrors = LS.HadErrors; ++LoadedShards; - IndexedSymbols.update(URI::create(LS.AbsolutePath).toString(), + IndexedSymbols.update(URI::create(LS.AbsolutePath.raw()).toString(), std::move(SS), std::move(RS), std::move(RelS), LS.CountReferences); } @@ -417,7 +417,9 @@ BackgroundIndex::loadProject(std::vector MainFiles) { TUsToIndex.insert(TUForFile); } - return {TUsToIndex.begin(), TUsToIndex.end()}; + auto ToRaw = [](PathRef R) { return R.raw(); }; + return {llvm::map_iterator(TUsToIndex.begin(), ToRaw), + llvm::map_iterator(TUsToIndex.end(), ToRaw)}; } void BackgroundIndex::profile(MemoryTree &MT) const { diff --git a/clang-tools-extra/clangd/index/Background.h b/clang-tools-extra/clangd/index/Background.h index 448e911201575..1babc3f85edbb 100644 --- a/clang-tools-extra/clangd/index/Background.h +++ b/clang-tools-extra/clangd/index/Background.h @@ -211,6 +211,7 @@ class BackgroundIndex : public SwapIndex { std::mutex ShardVersionsMu; BackgroundIndexStorage::Factory IndexStorageFactory; + // XXX: `MainFiles` should be a vector of `Path`s // Tries to load shards for the MainFiles and their dependencies. std::vector loadProject(std::vector MainFiles); diff --git a/clang-tools-extra/clangd/index/BackgroundIndexLoader.cpp b/clang-tools-extra/clangd/index/BackgroundIndexLoader.cpp index c09a5c3a3aeb8..4abe594e50e6f 100644 --- a/clang-tools-extra/clangd/index/BackgroundIndexLoader.cpp +++ b/clang-tools-extra/clangd/index/BackgroundIndexLoader.cpp @@ -48,17 +48,17 @@ class BackgroundIndexLoader { std::pair> BackgroundIndexLoader::loadShard(PathRef StartSourceFile, PathRef DependentTU) { - auto It = LoadedShards.try_emplace(StartSourceFile); + auto It = LoadedShards.try_emplace(StartSourceFile.raw()); LoadedShard &LS = It.first->getValue(); std::vector Edges = {}; // Return the cached shard. if (!It.second) return {LS, Edges}; - LS.AbsolutePath = StartSourceFile.str(); - LS.DependentTU = std::string(DependentTU); + LS.AbsolutePath = StartSourceFile.owned(); + LS.DependentTU = DependentTU.owned(); BackgroundIndexStorage *Storage = IndexStorageFactory(LS.AbsolutePath); - auto Shard = Storage->loadShard(StartSourceFile); + auto Shard = Storage->loadShard(StartSourceFile.raw()); if (!Shard || !Shard->Sources) { vlog("Failed to load shard: {0}", StartSourceFile); return {LS, Edges}; @@ -66,7 +66,7 @@ BackgroundIndexLoader::loadShard(PathRef StartSourceFile, PathRef DependentTU) { LS.Shard = std::move(Shard); for (const auto &It : *LS.Shard->Sources) { - auto AbsPath = URI::resolve(It.getKey(), StartSourceFile); + auto AbsPath = URI::resolve(It.getKey(), StartSourceFile.raw()); if (!AbsPath) { elog("Failed to resolve URI: {0}", AbsPath.takeError()); continue; @@ -91,7 +91,7 @@ void BackgroundIndexLoader::load(PathRef MainFile) { llvm::StringSet<> InQueue; // Following containers points to strings inside InQueue. std::queue ToVisit; - InQueue.insert(MainFile); + InQueue.insert(MainFile.raw()); ToVisit.push(MainFile); while (!ToVisit.empty()) { @@ -100,7 +100,7 @@ void BackgroundIndexLoader::load(PathRef MainFile) { auto ShardAndEdges = loadShard(SourceFile, MainFile); for (PathRef Edge : ShardAndEdges.second) { - auto It = InQueue.insert(Edge); + auto It = InQueue.insert(Edge.raw()); if (It.second) ToVisit.push(It.first->getKey()); } @@ -117,7 +117,7 @@ std::vector BackgroundIndexLoader::takeResult() && { } // namespace std::vector -loadIndexShards(llvm::ArrayRef MainFiles, +loadIndexShards(llvm::ArrayRef MainFiles, BackgroundIndexStorage::Factory &IndexStorageFactory, const GlobalCompilationDatabase &CDB) { BackgroundIndexLoader Loader(IndexStorageFactory); diff --git a/clang-tools-extra/clangd/index/BackgroundIndexLoader.h b/clang-tools-extra/clangd/index/BackgroundIndexLoader.h index 81033646b6a4e..bee5ce6c6974b 100644 --- a/clang-tools-extra/clangd/index/BackgroundIndexLoader.h +++ b/clang-tools-extra/clangd/index/BackgroundIndexLoader.h @@ -39,7 +39,7 @@ struct LoadedShard { /// Loads all shards for the TU \p MainFile from \p Storage. std::vector -loadIndexShards(llvm::ArrayRef MainFiles, +loadIndexShards(llvm::ArrayRef MainFiles, BackgroundIndexStorage::Factory &IndexStorageFactory, const GlobalCompilationDatabase &CDB); diff --git a/clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp b/clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp index d887b09482a95..5c077c4ed9471 100644 --- a/clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp +++ b/clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp @@ -109,7 +109,7 @@ class DiskBackedIndexStorageManager { // Creates or fetches to storage from cache for the specified project. BackgroundIndexStorage *operator()(PathRef File) { std::lock_guard Lock(*IndexStorageMapMu); - llvm::SmallString<128> StorageDir(FallbackDir); + llvm::SmallString<128> StorageDir(FallbackDir.raw()); if (auto PI = GetProjectInfo(File)) { StorageDir = PI->SourceRoot; llvm::sys::path::append(StorageDir, ".cache", "clangd", "index"); @@ -126,7 +126,7 @@ class DiskBackedIndexStorageManager { elog("Tried to create storage for empty directory!"); return std::make_unique(); } - return std::make_unique(CDBDirectory); + return std::make_unique(CDBDirectory.raw()); } Path FallbackDir; diff --git a/clang-tools-extra/clangd/index/FileIndex.cpp b/clang-tools-extra/clangd/index/FileIndex.cpp index aa573e312a756..7714fdbdebe65 100644 --- a/clang-tools-extra/clangd/index/FileIndex.cpp +++ b/clang-tools-extra/clangd/index/FileIndex.cpp @@ -182,7 +182,7 @@ FileShardedIndex::FileShardedIndex(IndexFileIn Input) std::vector FileShardedIndex::getAllSources() const { // It should be enough to construct a vector with {Shards.keys().begin(), // Shards.keys().end()} but MSVC fails to compile that. - std::vector Result; + std::vector Result; Result.reserve(Shards.size()); for (auto Key : Shards.keys()) Result.push_back(Key); @@ -470,7 +470,7 @@ void FileIndex::updatePreamble(PathRef Path, llvm::StringRef Version, void FileIndex::updateMain(PathRef Path, ParsedAST &AST) { auto Contents = indexMainDecls(AST); MainFileSymbols.update( - URI::create(Path).toString(), + URI::create(Path.raw()).toString(), std::make_unique(std::move(std::get<0>(Contents))), std::make_unique(std::move(std::get<1>(Contents))), std::make_unique(std::move(std::get<2>(Contents))), diff --git a/clang-tools-extra/clangd/refactor/Rename.cpp b/clang-tools-extra/clangd/refactor/Rename.cpp index 26059167208aa..436b6be40dbf6 100644 --- a/clang-tools-extra/clangd/refactor/Rename.cpp +++ b/clang-tools-extra/clangd/refactor/Rename.cpp @@ -784,7 +784,8 @@ renameObjCMethodWithinFile(ParsedAST &AST, const ObjCMethodDecl *MD, auto FilePath = AST.tuPath(); auto RenameRanges = collectRenameIdentifierRanges( RenameSymbolName(MD->getDeclName()), Code, LangOpts); - auto RenameEdit = buildRenameEdit(FilePath, Code, RenameRanges, NewNames); + auto RenameEdit = + buildRenameEdit(FilePath.raw(), Code, RenameRanges, NewNames); if (!RenameEdit) return error("failed to rename in file {0}: {1}", FilePath, RenameEdit.takeError()); @@ -891,7 +892,7 @@ findOccurrencesOutsideFile(const NamedDecl &RenameDecl, if ((R.Kind & RefKind::Spelled) == RefKind::Unknown) return; if (auto RefFilePath = filePath(R.Location, /*HintFilePath=*/MainFile)) { - if (!pathEqual(*RefFilePath, MainFile)) + if (PathRef(*RefFilePath) != MainFile) AffectedFiles[*RefFilePath].push_back(toRange(R.Location)); } }); diff --git a/clang-tools-extra/clangd/refactor/Tweak.cpp b/clang-tools-extra/clangd/refactor/Tweak.cpp index 840843d1bfc4b..683b8c5710448 100644 --- a/clang-tools-extra/clangd/refactor/Tweak.cpp +++ b/clang-tools-extra/clangd/refactor/Tweak.cpp @@ -100,7 +100,7 @@ prepareTweak(StringRef ID, const Tweak::Selection &S, return error("tweak ID {0} is invalid", ID); } -llvm::Expected> +llvm::Expected> Tweak::Effect::fileEdit(const SourceManager &SM, FileID FID, tooling::Replacements Replacements) { Edit Ed(SM.getBufferData(FID), std::move(Replacements)); diff --git a/clang-tools-extra/clangd/refactor/Tweak.h b/clang-tools-extra/clangd/refactor/Tweak.h index 257f44a285f88..4e8269138eda9 100644 --- a/clang-tools-extra/clangd/refactor/Tweak.h +++ b/clang-tools-extra/clangd/refactor/Tweak.h @@ -85,10 +85,11 @@ class Tweak { return E; } + /// XXX: This should return Path instead of std::string /// Path is the absolute, symlink-resolved path for the file pointed by FID /// in SM. Edit is generated from Replacements. /// Fails if cannot figure out absolute path for FID. - static llvm::Expected> + static llvm::Expected> fileEdit(const SourceManager &SM, FileID FID, tooling::Replacements Replacements); diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp index d6556bba14725..52e8c9315de73 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp @@ -474,7 +474,7 @@ class DefineInline : public Tweak { const tooling::Replacement DeleteFuncBody(SM, DefRange->getBegin(), SourceLen, ""); - llvm::SmallVector> Edits; + llvm::SmallVector> Edits; // Edit for Target. auto FE = Effect::fileEdit(SM, SM.getFileID(*Semicolon), std::move(TargetFileReplacements)); @@ -499,7 +499,8 @@ class DefineInline : public Tweak { Effect E; for (auto &Pair : Edits) - E.ApplyEdits.try_emplace(std::move(Pair.first), std::move(Pair.second)); + E.ApplyEdits.try_emplace(std::move(Pair.first).raw(), + std::move(Pair.second)); return E; } diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp index e4eef228b6b99..6e87cc3ecfab1 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp @@ -428,7 +428,7 @@ class DefineOutline : public Tweak { } bool prepare(const Selection &Sel) override { - SameFile = !isHeaderFile(Sel.AST->tuPath(), Sel.AST->getLangOpts()); + SameFile = !isHeaderFile(Sel.AST->tuPath().raw(), Sel.AST->getLangOpts()); Source = getSelectedFunction(Sel.ASTSelection.commonAncestor()); // Bail out if the selection is not a in-line function definition. @@ -489,12 +489,12 @@ class DefineOutline : public Tweak { Expected apply(const Selection &Sel) override { const SourceManager &SM = Sel.AST->getSourceManager(); - auto CCFile = SameFile ? Sel.AST->tuPath().str() - : getSourceFile(Sel.AST->tuPath(), Sel); + auto CCFile = SameFile ? Sel.AST->tuPath().owned() + : getSourceFile(Sel.AST->tuPath().raw(), Sel); if (!CCFile) return error("Couldn't find a suitable implementation file."); assert(Sel.FS && "FS Must be set in apply"); - auto Buffer = Sel.FS->getBufferForFile(*CCFile); + auto Buffer = Sel.FS->getBufferForFile(CCFile->raw()); // FIXME: Maybe we should consider creating the implementation file if it // doesn't exist? if (!Buffer) @@ -507,13 +507,14 @@ class DefineOutline : public Tweak { auto FuncDef = getFunctionSourceCode( Source, InsertionPoint->EnclosingNamespace, Sel.AST->getTokens(), Sel.AST->getHeuristicResolver(), - SameFile && isHeaderFile(Sel.AST->tuPath(), Sel.AST->getLangOpts())); + SameFile && + isHeaderFile(Sel.AST->tuPath().raw(), Sel.AST->getLangOpts())); if (!FuncDef) return FuncDef.takeError(); - SourceManagerForFile SMFF(*CCFile, Contents); + SourceManagerForFile SMFF(CCFile->raw(), Contents); const tooling::Replacement InsertFunctionDef( - *CCFile, InsertionPoint->Offset, 0, *FuncDef); + CCFile->raw(), InsertionPoint->Offset, 0, *FuncDef); auto Effect = Effect::mainFileEdit( SMFF.get(), tooling::Replacements(InsertFunctionDef)); if (!Effect) @@ -536,7 +537,7 @@ class DefineOutline : public Tweak { } if (SameFile) { - tooling::Replacements &R = Effect->ApplyEdits[*CCFile].Replacements; + tooling::Replacements &R = Effect->ApplyEdits[CCFile->raw()].Replacements; R = R.merge(HeaderUpdates); } else { auto HeaderFE = Effect::fileEdit(SM, SM.getMainFileID(), HeaderUpdates); diff --git a/clang-tools-extra/clangd/support/FileCache.cpp b/clang-tools-extra/clangd/support/FileCache.cpp index cc59c648b062a..9c55c0499f427 100644 --- a/clang-tools-extra/clangd/support/FileCache.cpp +++ b/clang-tools-extra/clangd/support/FileCache.cpp @@ -22,10 +22,10 @@ static constexpr uint64_t CacheDiskMismatch = // The cached value reflects that the file doesn't exist. static constexpr uint64_t FileNotFound = CacheDiskMismatch - 1; -FileCache::FileCache(llvm::StringRef Path) - : Path(Path), ValidTime(std::chrono::steady_clock::time_point::min()), +FileCache::FileCache(PathRef Path) + : Path(Path.raw()), ValidTime(std::chrono::steady_clock::time_point::min()), ModifiedTime(), Size(CacheDiskMismatch) { - assert(llvm::sys::path::is_absolute(Path)); + assert(Path.isAbsolute()); } void FileCache::read( diff --git a/clang-tools-extra/clangd/support/Path.cpp b/clang-tools-extra/clangd/support/Path.cpp index 1dd107cc6abef..9e9a1c308e36c 100644 --- a/clang-tools-extra/clangd/support/Path.cpp +++ b/clang-tools-extra/clangd/support/Path.cpp @@ -7,47 +7,151 @@ //===----------------------------------------------------------------------===// #include "support/Path.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" + +#include + namespace clang { namespace clangd { -#ifdef CLANGD_PATH_CASE_INSENSITIVE -std::string maybeCaseFoldPath(PathRef Path) { return Path.lower(); } -bool pathEqual(PathRef A, PathRef B) { return A.equals_insensitive(B); } -#else // NOT CLANGD_PATH_CASE_INSENSITIVE -std::string maybeCaseFoldPath(PathRef Path) { return Path.str(); } -bool pathEqual(PathRef A, PathRef B) { return A == B; } -#endif // CLANGD_PATH_CASE_INSENSITIVE - -PathRef absoluteParent(PathRef Path) { - assert(llvm::sys::path::is_absolute(Path)); +PathRef PathRef::absoluteParent() const { + assert(llvm::sys::path::is_absolute(Data)); #if defined(_WIN32) // llvm::sys says "C:\" is absolute, and its parent is "C:" which is relative. // This unhelpful behavior seems to have been inherited from boost. - if (llvm::sys::path::relative_path(Path).empty()) { + if (llvm::sys::path::relative_path(Data).empty()) { return PathRef(); } #endif - PathRef Result = llvm::sys::path::parent_path(Path); + llvm::StringRef Result = llvm::sys::path::parent_path(Data); assert(Result.empty() || llvm::sys::path::is_absolute(Result)); return Result; } -bool pathStartsWith(PathRef Ancestor, PathRef Path, - llvm::sys::path::Style Style) { - assert(llvm::sys::path::is_absolute(Ancestor) && - llvm::sys::path::is_absolute(Path)); +PathRef PathRef::parentPath(Style Style) const { + return llvm::sys::path::parent_path(Data, Style); +} + +bool PathRef::startsWith(PathRef Path, Style Style) const { + assert(isAbsolute() && Path.isAbsolute()); // XXX: this doesn't pass the Style + // If ancestor ends with a separator drop that, so that we can match /foo/ as // a parent of /foo. - if (llvm::sys::path::is_separator(Ancestor.back(), Style)) - Ancestor = Ancestor.drop_back(); + PathRef Ancestor = withoutTrailingSeparator(Style); // Ensure Path starts with Ancestor. - if (!pathEqual(Ancestor, Path.take_front(Ancestor.size()))) + if (Ancestor != PathRef(Path.raw().take_front(Ancestor.size()))) return false; - Path = Path.drop_front(Ancestor.size()); + Path = Path.Data.drop_front(Ancestor.size()); // Then make sure either two paths are equal or Path has a separator // afterwards. - return Path.empty() || llvm::sys::path::is_separator(Path.front(), Style); + return Path.empty() || + llvm::sys::path::is_separator(Path.raw().front(), Style); +} + +llvm::StringRef PathRef::filename(Style Style) const { + return llvm::sys::path::filename(raw(), Style); +} + +llvm::StringRef PathRef::extension(Style Style) const { + return llvm::sys::path::extension(raw(), Style); +} + +PathRef PathRef::stem(Style Style) const { + return llvm::sys::path::stem(raw(), Style); +} + +PathRef PathRef::withoutTrailingSeparator(Style Style) const { + if (llvm::sys::path::is_separator(Data.back(), Style)) + return Data.drop_back(); + return Data; +} + +Path PathRef::removeDots() const { + llvm::SmallString<128> CanonPath(Data); + llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true); + return CanonPath.str().str(); +} + +Path PathRef::caseFolded() const { +#ifdef CLANGD_PATH_CASE_INSENSITIVE + return Data.lower(); +#else + return Data.str(); +#endif +} + +bool PathRef::isAbsolute(Style Style) const { + return llvm::sys::path::is_absolute(Data, Style); +} + +bool PathRef::isRelative(Style Style) const { + return llvm::sys::path::is_relative(Data, Style); +} + +bool PathRef::exists() const { return llvm::sys::fs::exists(Data); } + +std::ostream &operator<<(std::ostream &OS, PathRef Path) { + OS << std::string_view(Path.raw()); + return OS; +} + +bool operator==(PathRef LHS, PathRef RHS) { +#ifdef CLANGD_PATH_CASE_INSENSITIVE + return LHS.raw().equals_insensitive(RHS.raw()); +#else + return LHS.raw() == RHS.raw(); +#endif +} + +llvm::hash_code hash_value(PathRef P) { +#ifdef CLANGD_PATH_CASE_INSENSITIVE + return hash_combine_range(llvm::map_iterator(P.raw().begin(), llvm::toLower), + llvm::map_iterator(P.raw().end(), llvm::toLower)); +#else + return hash_value(P.raw()); +#endif } + } // namespace clangd } // namespace clang + +namespace llvm { + +unsigned DenseMapInfo::getHashValue( + clang::clangd::PathRef Val) { + assert(Val.Data.data() != getEmptyKey().Data.data() && + "Cannot hash the empty key!"); + assert(Val.Data.data() != getTombstoneKey().Data.data() && + "Cannot hash the tombstone key!"); + return (unsigned)(hash_value(Val)); +} + +namespace cl { + +void parser::printOptionDiff(const Option &O, + clang::clangd::PathRef V, + const OptVal &Default, + size_t GlobalWidth) const { + constexpr static const size_t MaxOptWidth = 8; + + printOptionName(O, GlobalWidth); + outs() << "= " << V.raw(); + size_t NumSpaces = MaxOptWidth > V.size() ? MaxOptWidth - V.size() : 0; + outs().indent(NumSpaces) << " (default: "; + if (Default.hasValue()) + outs() << Default.getValue().raw(); + else + outs() << "*no default*"; + outs() << ")\n"; +} + +void parser::anchor() {} + +} // namespace cl + +} // namespace llvm diff --git a/clang-tools-extra/clangd/support/Path.h b/clang-tools-extra/clangd/support/Path.h index ff45a436e5f08..a6c3a8e345434 100644 --- a/clang-tools-extra/clangd/support/Path.h +++ b/clang-tools-extra/clangd/support/Path.h @@ -9,8 +9,15 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_PATH_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_PATH_H +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormatProviders.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/Path.h" + #include /// Whether current platform treats paths case insensitively. @@ -21,30 +28,179 @@ namespace clang { namespace clangd { -/// A typedef to represent a file path. Used solely for more descriptive -/// signatures. -using Path = std::string; -/// A typedef to represent a ref to file path. Used solely for more descriptive -/// signatures. -using PathRef = llvm::StringRef; - -// For platforms where paths are case-insensitive (but case-preserving), -// we need to do case-insensitive comparisons and use lowercase keys. -// FIXME: Make Path a real class with desired semantics instead. -std::string maybeCaseFoldPath(PathRef Path); -bool pathEqual(PathRef, PathRef); - -/// Checks if \p Ancestor is a proper ancestor of \p Path. This is just a -/// smarter lexical prefix match, e.g: foo/bar/baz doesn't start with foo/./bar. -/// Both \p Ancestor and \p Path must be absolute. -bool pathStartsWith( - PathRef Ancestor, PathRef Path, - llvm::sys::path::Style Style = llvm::sys::path::Style::native); - -/// Variant of parent_path that operates only on absolute paths. -/// Unlike parent_path doesn't consider C: a parent of C:\. -PathRef absoluteParent(PathRef Path); +class PathRef; +class Path { +public: + Path() = default; + Path(std::string Data) : Data(std::move(Data)) {} + Path(const char *Data) : Data(Data) {} + + explicit Path(PathRef Ref); + + operator PathRef() const; + PathRef ref() const; + + [[nodiscard]] const std::string &raw() const & { return Data; } + [[nodiscard]] std::string &&raw() && { return std::move(Data); } + + [[nodiscard]] size_t size() const { return Data.size(); } + [[nodiscard]] bool empty() const { return Data.empty(); } + +private: + std::string Data; + + friend llvm::json::Value toJSON(const Path &Path) { return Path.Data; } + + friend bool fromJSON(const llvm::json::Value &Value, Path &Path, + llvm::json::Path Cursor) { + return fromJSON(Value, Path.Data, Cursor); + } +}; + +class LLVM_GSL_POINTER PathRef { +public: + using Style = llvm::sys::path::Style; + + PathRef() = default; + PathRef(llvm::StringRef Ref) : Data(Ref) {} + PathRef(const std::string &Str) : Data(Str) {} + PathRef(const char *Str) : Data(Str) {} + template + PathRef(const llvm::SmallString &Str) : Data(Str) {} + + /// Variant of parent_path that operates only on absolute paths. + /// Unlike parent_path doesn't consider C: a parent of C:\. + [[nodiscard]] PathRef absoluteParent() const; + + [[nodiscard]] PathRef parentPath(Style Style = Style::native) const; + + /// Checks if \p this is a proper ancestor of \p Path. This is just a + /// smarter lexical prefix match, e.g: foo/bar/baz doesn't start with + /// foo/./bar. Both \p this and \p Path must be absolute. + [[nodiscard]] bool startsWith(PathRef Path, + Style Style = Style::native) const; + + [[nodiscard]] llvm::StringRef filename(Style Style = Style::native) const; + + [[nodiscard]] llvm::StringRef extension(Style Style = Style::native) const; + + [[nodiscard]] PathRef stem(Style Style = Style::native) const; + + /// Returns a version of \p File that doesn't contain dots and dot dots. + /// e.g /a/b/../c -> /a/c + /// /a/b/./c -> /a/b/c + /// FIXME: We should avoid encountering such paths in clangd internals by + /// filtering everything we get over LSP, CDB, etc. + [[nodiscard]] Path removeDots() const; + + [[nodiscard]] Path caseFolded() const; + + [[nodiscard]] Path owned() const { return Path(*this); } + [[nodiscard]] llvm::StringRef raw() const { return Data; } + + [[nodiscard]] PathRef + withoutTrailingSeparator(Style Style = Style::native) const; + + [[nodiscard]] size_t size() const { return Data.size(); } + + [[nodiscard]] bool empty() const { return Data.empty(); } + + [[nodiscard]] bool isAbsolute(Style Style = Style::native) const; + [[nodiscard]] bool isRelative(Style Style = Style::native) const; + + [[nodiscard]] bool exists() const; + +private: + llvm::StringRef Data; + + friend llvm::DenseMapInfo; +}; + +inline Path::Path(PathRef Ref) : Data(Ref.raw().str()) {} + +// for gtest +std::ostream &operator<<(std::ostream &OS, PathRef Path); + +inline Path::operator PathRef() const { return PathRef(Data); } +inline PathRef Path::ref() const { return PathRef(Data); } + +bool operator==(PathRef LHS, PathRef RHS); +inline bool operator!=(PathRef LHS, PathRef RHS) { return !(LHS == RHS); } + +inline bool operator==(Path LHS, Path RHS) { + return clang::clangd::PathRef(LHS) == clang::clangd::PathRef(RHS); +} +inline bool operator!=(Path LHS, Path RHS) { return !(LHS == RHS); } + +[[nodiscard]] llvm::hash_code hash_value(PathRef P); +[[nodiscard]] inline llvm::hash_code hash_value(const Path &P) { + return hash_value(PathRef(P)); +} + +inline llvm::json::Value toJson(PathRef Path) { return Path.raw(); } + } // namespace clangd } // namespace clang +namespace llvm { + +template <> struct format_provider { + static void format(const clang::clangd::PathRef &V, llvm::raw_ostream &Stream, + StringRef Style) { + format_provider::format(V.raw(), Stream, Style); + } +}; + +template <> struct format_provider { + static void format(const clang::clangd::Path &V, llvm::raw_ostream &Stream, + StringRef Style) { + format_provider::format(V, Stream, Style); + } +}; + +template <> struct DenseMapInfo { + static inline clang::clangd::PathRef getEmptyKey() { + return DenseMapInfo::getEmptyKey(); + } + + static inline clang::clangd::PathRef getTombstoneKey() { + return DenseMapInfo::getTombstoneKey(); + } + + static unsigned getHashValue(clang::clangd::PathRef Val); + + static bool isEqual(clang::clangd::PathRef LHS, clang::clangd::PathRef RHS) { + if (RHS.Data.data() == getEmptyKey().Data.data()) + return LHS.Data.data() == getEmptyKey().Data.data(); + if (RHS.Data.data() == getTombstoneKey().Data.data()) + return LHS.Data.data() == getTombstoneKey().Data.data(); + return LHS == RHS; + } +}; + +namespace cl { + +template <> +struct parser : public basic_parser { +public: + parser(Option &O) : basic_parser(O) {} + + bool parse(cl::Option &O, StringRef ArgName, StringRef ArgValue, + clang::clangd::Path &Val) { + Val = ArgValue.str(); + return false; + } + + StringRef getValueName() const override { return "path"; } + + void printOptionDiff(const Option &O, clang::clangd::PathRef V, + const OptVal &Default, size_t GlobalWidth) const; + + void anchor() override; +}; + +} // namespace cl + +} // namespace llvm + #endif diff --git a/clang-tools-extra/clangd/support/ThreadsafeFS.cpp b/clang-tools-extra/clangd/support/ThreadsafeFS.cpp index 7398e4258527b..8c78ad0fe088e 100644 --- a/clang-tools-extra/clangd/support/ThreadsafeFS.cpp +++ b/clang-tools-extra/clangd/support/ThreadsafeFS.cpp @@ -74,7 +74,7 @@ class VolatileFileSystem : public llvm::vfs::ProxyFileSystem { llvm::IntrusiveRefCntPtr ThreadsafeFS::view(PathRef CWD) const { auto FS = view(std::nullopt); - if (auto EC = FS->setCurrentWorkingDirectory(CWD)) + if (auto EC = FS->setCurrentWorkingDirectory(CWD.raw())) elog("VFS: failed to set CWD to {0}: {1}", CWD, EC.message()); return FS; } diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index 4bd256d6be22b..26b34e8dee3fc 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -673,12 +673,12 @@ class FlagsConfigProvider : public config::Provider { // If --compile-commands-dir arg was invoked, check value and override // default path. if (!CompileCommandsDir.empty()) { - if (llvm::sys::fs::exists(CompileCommandsDir)) { + if (CompileCommandsDir.ref().exists()) { // We support passing both relative and absolute paths to the // --compile-commands-dir argument, but we assume the path is absolute // in the rest of clangd so we make sure the path is absolute before // continuing. - llvm::SmallString<128> Path(CompileCommandsDir); + llvm::SmallString<128> Path(CompileCommandsDir.raw()); if (std::error_code EC = llvm::sys::fs::make_absolute(Path)) { elog("Error while converting the relative path specified by " "--compile-commands-dir to an absolute path: {0}. The argument " @@ -695,7 +695,7 @@ class FlagsConfigProvider : public config::Provider { if (!IndexFile.empty()) { Config::ExternalIndexSpec Spec; Spec.Kind = Spec.File; - Spec.Location = IndexFile; + Spec.Location = IndexFile.raw(); IndexSpec = std::move(Spec); } #if CLANGD_ENABLE_REMOTE @@ -826,7 +826,7 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var std::optional InputMirrorStream; if (!InputMirrorFile.empty()) { std::error_code EC; - InputMirrorStream.emplace(InputMirrorFile, /*ref*/ EC, + InputMirrorStream.emplace(InputMirrorFile.raw(), /*ref*/ EC, llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write); if (EC) { InputMirrorStream.reset(); @@ -911,7 +911,7 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var break; } if (!ResourceDir.empty()) - Opts.ResourceDir = ResourceDir; + Opts.ResourceDir = ResourceDir.raw(); Opts.BuildDynamicSymbolIndex = true; std::vector> IdxStack; #if CLANGD_ENABLE_REMOTE @@ -1013,9 +1013,9 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var if (CheckFile.getNumOccurrences()) { llvm::SmallString<256> Path; - if (auto Error = - llvm::sys::fs::real_path(CheckFile, Path, /*expand_tilde=*/true)) { - elog("Failed to resolve path {0}: {1}", CheckFile, Error.message()); + if (auto Error = llvm::sys::fs::real_path(CheckFile.raw(), Path, + /*expand_tilde=*/true)) { + elog("Failed to resolve path {0}: {1}", CheckFile.raw(), Error.message()); return 1; } log("Entering check mode (no LSP server)"); diff --git a/clang-tools-extra/clangd/unittests/ASTTests.cpp b/clang-tools-extra/clangd/unittests/ASTTests.cpp index d0bc3c4d7db98..3eee66c02b851 100644 --- a/clang-tools-extra/clangd/unittests/ASTTests.cpp +++ b/clang-tools-extra/clangd/unittests/ASTTests.cpp @@ -622,7 +622,7 @@ TEST(ClangdAST, HasReservedName) { TEST(ClangdAST, PreferredIncludeDirective) { auto ComputePreferredDirective = [](TestTU &TU) { auto AST = TU.build(); - return preferredIncludeDirective(AST.tuPath(), AST.getLangOpts(), + return preferredIncludeDirective(AST.tuPath().raw(), AST.getLangOpts(), AST.getIncludeStructure().MainFileIncludes, AST.getLocalTopLevelDecls()); }; diff --git a/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp b/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp index ada14c9939318..2d26e1ac5656c 100644 --- a/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp +++ b/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp @@ -98,7 +98,7 @@ TEST_F(BackgroundIndexTest, NoCrashOnErrorFile) { size_t CacheHits = 0; MemoryShardStorage MSS(Storage, CacheHits); OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; }, + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, /*Opts=*/{}); tooling::CompileCommand Cmd; @@ -132,11 +132,11 @@ TEST_F(BackgroundIndexTest, Config) { BackgroundIndex::Options Opts; Opts.ContextProvider = [](PathRef P) { Config C; - if (P.ends_with("foo.cpp")) + if (P.raw().ends_with("foo.cpp")) C.CompileFlags.Edits.push_back([](std::vector &Argv) { Argv = tooling::getInsertArgumentAdjuster("-Done=two")(Argv, ""); }); - if (P.ends_with("baz.cpp")) + if (P.raw().ends_with("baz.cpp")) C.Index.Background = Config::BackgroundPolicy::Skip; return Context::current().derive(Config::Key, std::move(C)); }; @@ -148,8 +148,7 @@ TEST_F(BackgroundIndexTest, Config) { OverlayCDB CDB(/*Base=*/nullptr, /*FallbackFlags=*/{}, CommandMangler::forTests()); - BackgroundIndex Idx( - FS, CDB, [&](llvm::StringRef) { return &MSS; }, std::move(Opts)); + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, std::move(Opts)); // Index the two files. for (auto &Cmd : Cmds) { std::string FullPath = testPath(Cmd.Filename); @@ -191,8 +190,7 @@ TEST_F(BackgroundIndexTest, IndexTwoFiles) { MemoryShardStorage MSS(Storage, CacheHits); OverlayCDB CDB(/*Base=*/nullptr); BackgroundIndex::Options Opts; - BackgroundIndex Idx( - FS, CDB, [&](llvm::StringRef) { return &MSS; }, Opts); + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, Opts); tooling::CompileCommand Cmd; Cmd.Filename = testPath("root/A.cc"); @@ -246,8 +244,7 @@ TEST_F(BackgroundIndexTest, MainFileRefs) { MemoryShardStorage MSS(Storage, CacheHits); OverlayCDB CDB(/*Base=*/nullptr); BackgroundIndex::Options Opts; - BackgroundIndex Idx( - FS, CDB, [&](llvm::StringRef) { return &MSS; }, Opts); + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, Opts); tooling::CompileCommand Cmd; Cmd.Filename = testPath("root/A.cc"); @@ -286,7 +283,7 @@ TEST_F(BackgroundIndexTest, ShardStorageTest) { // Check nothing is loaded from Storage, but A.cc and A.h has been stored. { OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; }, + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, /*Opts=*/{}); CDB.setCompileCommand(testPath("root/A.cc"), Cmd); ASSERT_TRUE(Idx.blockUntilIdleForTest()); @@ -296,7 +293,7 @@ TEST_F(BackgroundIndexTest, ShardStorageTest) { { OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; }, + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, /*Opts=*/{}); CDB.setCompileCommand(testPath("root/A.cc"), Cmd); ASSERT_TRUE(Idx.blockUntilIdleForTest()); @@ -355,7 +352,7 @@ TEST_F(BackgroundIndexTest, DirectIncludesTest) { Cmd.CommandLine = {"clang++", testPath("root/A.cc")}; { OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; }, + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, /*Opts=*/{}); CDB.setCompileCommand(testPath("root/A.cc"), Cmd); ASSERT_TRUE(Idx.blockUntilIdleForTest()); @@ -405,7 +402,7 @@ TEST_F(BackgroundIndexTest, ShardStorageLoad) { // Check nothing is loaded from Storage, but A.cc and A.h has been stored. { OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; }, + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, /*Opts=*/{}); CDB.setCompileCommand(testPath("root/A.cc"), Cmd); ASSERT_TRUE(Idx.blockUntilIdleForTest()); @@ -420,7 +417,7 @@ TEST_F(BackgroundIndexTest, ShardStorageLoad) { )cpp"; { OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; }, + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, /*Opts=*/{}); CDB.setCompileCommand(testPath("root/A.cc"), Cmd); ASSERT_TRUE(Idx.blockUntilIdleForTest()); @@ -438,7 +435,7 @@ TEST_F(BackgroundIndexTest, ShardStorageLoad) { { CacheHits = 0; OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; }, + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, /*Opts=*/{}); CDB.setCompileCommand(testPath("root/A.cc"), Cmd); ASSERT_TRUE(Idx.blockUntilIdleForTest()); @@ -479,7 +476,7 @@ TEST_F(BackgroundIndexTest, ShardStorageEmptyFile) { // Check that A.cc, A.h and B.h has been stored. { OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; }, + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, /*Opts=*/{}); CDB.setCompileCommand(testPath("root/A.cc"), Cmd); ASSERT_TRUE(Idx.blockUntilIdleForTest()); @@ -495,7 +492,7 @@ TEST_F(BackgroundIndexTest, ShardStorageEmptyFile) { { CacheHits = 0; OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; }, + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, /*Opts=*/{}); CDB.setCompileCommand(testPath("root/A.cc"), Cmd); ASSERT_TRUE(Idx.blockUntilIdleForTest()); @@ -511,7 +508,7 @@ TEST_F(BackgroundIndexTest, ShardStorageEmptyFile) { { CacheHits = 0; OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; }, + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, /*Opts=*/{}); CDB.setCompileCommand(testPath("root/A.cc"), Cmd); ASSERT_TRUE(Idx.blockUntilIdleForTest()); @@ -529,7 +526,7 @@ TEST_F(BackgroundIndexTest, NoDotsInAbsPath) { size_t CacheHits = 0; MemoryShardStorage MSS(Storage, CacheHits); OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; }, + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, /*Opts=*/{}); ASSERT_TRUE(Idx.blockUntilIdleForTest()); @@ -560,7 +557,7 @@ TEST_F(BackgroundIndexTest, UncompilableFiles) { size_t CacheHits = 0; MemoryShardStorage MSS(Storage, CacheHits); OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; }, + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, /*Opts=*/{}); tooling::CompileCommand Cmd; @@ -624,7 +621,7 @@ TEST_F(BackgroundIndexTest, CmdLineHash) { size_t CacheHits = 0; MemoryShardStorage MSS(Storage, CacheHits); OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; }, + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, /*Opts=*/{}); tooling::CompileCommand Cmd; @@ -652,7 +649,7 @@ TEST_F(BackgroundIndexTest, Reindex) { size_t CacheHits = 0; MemoryShardStorage MSS(Storage, CacheHits); OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Idx(FS, CDB, [&](llvm::StringRef) { return &MSS; }, + BackgroundIndex Idx(FS, CDB, [&](PathRef) { return &MSS; }, /*Opts=*/{}); // Index a file. @@ -901,7 +898,7 @@ TEST(BackgroundQueueTest, Progress) { TEST(BackgroundIndex, Profile) { MockFS FS; MockCompilationDatabase CDB; - BackgroundIndex Idx(FS, CDB, [](llvm::StringRef) { return nullptr; }, + BackgroundIndex Idx(FS, CDB, [](PathRef) { return nullptr; }, /*Opts=*/{}); llvm::BumpPtrAllocator Alloc; diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp b/clang-tools-extra/clangd/unittests/ClangdTests.cpp index 643b8e9f12d75..fce04fe711680 100644 --- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp +++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp @@ -102,7 +102,7 @@ class MultipleErrorCheckingCallbacks : public ClangdServer::Callbacks { bool HadError = diagsContainErrors(Diagnostics); std::lock_guard Lock(Mutex); - LastDiagsHadError[File] = HadError; + LastDiagsHadError[File.raw()] = HadError; } /// Exposes all files consumed by onDiagnosticsReady in an unspecified order. @@ -591,8 +591,8 @@ struct Something { )cpp"; Path BarCpp = testPath("bar.cpp"); - FS.Files[FooCpp] = ""; - FS.Files[BarCpp] = ""; + FS.Files[FooCpp.raw()] = ""; + FS.Files[BarCpp.raw()] = ""; EXPECT_THAT(Server.fileStats(), IsEmpty()); @@ -691,7 +691,7 @@ int d; void onDiagnosticsReady(PathRef File, llvm::StringRef Version, llvm::ArrayRef Diagnostics) override { - StringRef FileIndexStr = llvm::sys::path::stem(File); + StringRef FileIndexStr = File.stem().raw(); ASSERT_TRUE(FileIndexStr.consume_front("Foo")); unsigned long FileIndex = std::stoul(FileIndexStr.str()); @@ -1117,11 +1117,11 @@ TEST(ClangdServerTest, FallbackWhenWaitingForCompileCommand) { // FIXME: make this timeout and fail instead of waiting forever in case // something goes wrong. CanReturnCommand.wait(); - auto FileName = llvm::sys::path::filename(File); + auto FileName = File.filename(); std::vector CommandLine = {"clangd", "-ffreestanding", - std::string(File)}; - return {tooling::CompileCommand(llvm::sys::path::parent_path(File), - FileName, std::move(CommandLine), "")}; + File.owned().raw()}; + return {tooling::CompileCommand(File.parentPath().raw(), FileName, + std::move(CommandLine), "")}; } std::vector ExtraClangFlags; diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 718bee2e40b11..c197c288a0f3d 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -147,7 +147,7 @@ CodeCompleteResult completions(llvm::StringRef Text, Annotations Test(Text); auto TU = TestTU::withCode(Test.code()); // To make sure our tests for completiopns inside templates work on Windows. - TU.Filename = FilePath.str(); + TU.Filename = FilePath.owned().raw(); return completions(TU, Test.point(), std::move(IndexSymbols), std::move(Opts)); } diff --git a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp index c9e01e52dac1f..1fc72fb36a9ee 100644 --- a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp +++ b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp @@ -55,23 +55,23 @@ TEST(GlobalCompilationDatabaseTest, FallbackCommand) { testPath("foo/bar"))); } -static tooling::CompileCommand cmd(llvm::StringRef File, llvm::StringRef Arg) { +static tooling::CompileCommand cmd(PathRef File, llvm::StringRef Arg) { return tooling::CompileCommand( - testRoot(), File, {"clang", std::string(Arg), std::string(File)}, ""); + testRoot(), File.owned().raw(), + {"clang", std::string(Arg), File.owned().raw()}, ""); } class OverlayCDBTest : public ::testing::Test { class BaseCDB : public GlobalCompilationDatabase { public: std::optional - getCompileCommand(llvm::StringRef File) const override { + getCompileCommand(PathRef File) const override { if (File == testPath("foo.cc")) return cmd(File, "-DA=1"); return std::nullopt; } - tooling::CompileCommand - getFallbackCommand(llvm::StringRef File) const override { + tooling::CompileCommand getFallbackCommand(PathRef File) const override { return cmd(File, "-DA=2"); } diff --git a/clang-tools-extra/clangd/unittests/HeaderSourceSwitchTests.cpp b/clang-tools-extra/clangd/unittests/HeaderSourceSwitchTests.cpp index e600207de458a..c9f95db7c923c 100644 --- a/clang-tools-extra/clangd/unittests/HeaderSourceSwitchTests.cpp +++ b/clang-tools-extra/clangd/unittests/HeaderSourceSwitchTests.cpp @@ -334,17 +334,17 @@ TEST(HeaderSourceSwitchTest, CaseSensitivity) { // index, check if we can still find the source file, which defines less // symbols than the header. auto HeaderAbsPath = testPath("HEADER.H"); - // We expect the heuristics to pick: - // - header on case sensitive file systems, because the HeaderAbsPath doesn't - // match what we've seen through index. - // - source on case insensitive file systems, as the HeaderAbsPath would match - // the filename in index. +// We expect the heuristics to pick: +// - header on case sensitive file systems, because the HeaderAbsPath doesn't +// match what we've seen through index. +// - source on case insensitive file systems, as the HeaderAbsPath would match +// the filename in index. #ifdef CLANGD_PATH_CASE_INSENSITIVE EXPECT_THAT(getCorrespondingHeaderOrSource(HeaderAbsPath, AST, Index.get()), - llvm::ValueIs(testing::StrCaseEq(testPath(TU.Filename)))); + llvm::ValueIs(Path(testPath(TU.Filename)))); #else EXPECT_THAT(getCorrespondingHeaderOrSource(HeaderAbsPath, AST, Index.get()), - llvm::ValueIs(testing::StrCaseEq(testPath(TU.HeaderFilename)))); + llvm::ValueIs(Path(testPath(TU.HeaderFilename)))); #endif } diff --git a/clang-tools-extra/clangd/unittests/HeadersTests.cpp b/clang-tools-extra/clangd/unittests/HeadersTests.cpp index 751383e3b4650..fd62c72b9340b 100644 --- a/clang-tools-extra/clangd/unittests/HeadersTests.cpp +++ b/clang-tools-extra/clangd/unittests/HeadersTests.cpp @@ -111,7 +111,7 @@ class HeadersTest : public ::testing::Test { QuotedHeaders, AngledHeaders); for (const auto &Inc : Inclusions) Inserter.addExisting(Inc); - auto Inserted = ToHeaderFile(Preferred); + auto Inserted = ToHeaderFile(Preferred.raw()); if (!Inserter.shouldInsertInclude(Original, Inserted)) return ""; auto Path = Inserter.calculateIncludePath(Inserted, MainFile); diff --git a/clang-tools-extra/clangd/unittests/PreambleTests.cpp b/clang-tools-extra/clangd/unittests/PreambleTests.cpp index 16a2f9448b1ec..330bed8d08a5c 100644 --- a/clang-tools-extra/clangd/unittests/PreambleTests.cpp +++ b/clang-tools-extra/clangd/unittests/PreambleTests.cpp @@ -883,14 +883,14 @@ TEST(PreamblePatch, PatchFileEntry) { #define FOO)cpp"); { auto AST = createPatchedAST(Code.code(), Code.code()); - EXPECT_EQ( - PreamblePatch::getPatchEntry(AST->tuPath(), AST->getSourceManager()), - nullptr); + EXPECT_EQ(PreamblePatch::getPatchEntry(AST->tuPath().raw(), + AST->getSourceManager()), + nullptr); } { auto AST = createPatchedAST(Code.code(), NewCode.code()); - auto FE = - PreamblePatch::getPatchEntry(AST->tuPath(), AST->getSourceManager()); + auto FE = PreamblePatch::getPatchEntry(AST->tuPath().raw(), + AST->getSourceManager()); ASSERT_NE(FE, std::nullopt); EXPECT_THAT(FE->getName().str(), testing::EndsWith(PreamblePatch::HeaderName.str())); diff --git a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp index 43f38e39c8952..27c39955035b4 100644 --- a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp +++ b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp @@ -79,7 +79,7 @@ MATCHER_P2(TUState, PreambleActivity, ASTActivity, "") { // Simple ContextProvider to verify the provider is invoked & contexts are used. static Key BoundPath; Context bindPath(PathRef F) { - return Context::current().derive(BoundPath, F.str()); + return Context::current().derive(BoundPath, F.owned().raw()); } llvm::StringRef boundPath() { const std::string *V = Context::current().get(BoundPath); @@ -155,7 +155,7 @@ class TUSchedulerTests : public ::testing::Test { void updateWithDiags(TUScheduler &S, PathRef File, ParseInputs Inputs, WantDiagnostics WD, llvm::unique_function)> CB) { - Path OrigFile = File.str(); + Path OrigFile = File.owned(); WithContextValue Ctx(DiagsCallbackKey, [OrigFile, CB = std::move(CB)]( PathRef File, std::vector Diags) mutable { @@ -1569,7 +1569,7 @@ TEST_F(TUSchedulerTests, PreambleThrottle) { // Deliberately no synchronization. // The PreambleThrottler should serialize these calls, if not then tsan // will find a bug here. - Filenames.emplace_back(Path); + Filenames.emplace_back(Path.owned().raw()); } }; diff --git a/clang-tools-extra/clangd/unittests/TestFS.cpp b/clang-tools-extra/clangd/unittests/TestFS.cpp index bb309609eda20..816d5e364d99b 100644 --- a/clang-tools-extra/clangd/unittests/TestFS.cpp +++ b/clang-tools-extra/clangd/unittests/TestFS.cpp @@ -21,8 +21,8 @@ namespace { // Tries to strip \p Prefix from beginning of \p Path. Returns true on success. // If \p Prefix doesn't match, leaves \p Path untouched and returns false. -bool pathConsumeFront(PathRef &Path, PathRef Prefix) { - if (!pathStartsWith(Prefix, Path)) +bool pathConsumeFront(llvm::StringRef &Path, PathRef Prefix) { + if (!Prefix.startsWith(Path)) return false; Path = Path.drop_front(Prefix.size()); return true; @@ -61,14 +61,14 @@ MockCompilationDatabase::getCompileCommand(PathRef File) const { if (ExtraClangFlags.empty()) return std::nullopt; - auto FileName = llvm::sys::path::filename(File); + auto FileName = File.filename(); // Build the compile command. auto CommandLine = ExtraClangFlags; CommandLine.insert(CommandLine.begin(), "clang"); if (RelPathPrefix.empty()) { // Use the absolute path in the compile command. - CommandLine.push_back(std::string(File)); + CommandLine.push_back(File.owned().raw()); } else { // Build a relative path using RelPathPrefix. llvm::SmallString<32> RelativeFilePath(RelPathPrefix); @@ -76,10 +76,9 @@ MockCompilationDatabase::getCompileCommand(PathRef File) const { CommandLine.push_back(std::string(RelativeFilePath.str())); } - return {tooling::CompileCommand(Directory != llvm::StringRef() - ? Directory - : llvm::sys::path::parent_path(File), - FileName, std::move(CommandLine), "")}; + return {tooling::CompileCommand( + Directory != llvm::StringRef() ? Directory : File.parentPath().raw(), + FileName, std::move(CommandLine), "")}; } const char *testRoot() { @@ -91,9 +90,9 @@ const char *testRoot() { } std::string testPath(PathRef File, llvm::sys::path::Style Style) { - assert(llvm::sys::path::is_relative(File) && "FileName should be relative"); + assert(File.isRelative() && "FileName should be relative"); - llvm::SmallString<32> NativeFile = File; + llvm::SmallString<32> NativeFile = File.raw(); llvm::sys::path::native(NativeFile, Style); llvm::SmallString<32> Path; llvm::sys::path::append(Path, Style, testRoot(), NativeFile); @@ -110,7 +109,7 @@ class TestScheme : public URIScheme { llvm::Expected getAbsolutePath(llvm::StringRef /*Authority*/, llvm::StringRef Body, llvm::StringRef HintPath) const override { - if (!HintPath.empty() && !pathStartsWith(testRoot(), HintPath)) + if (!HintPath.empty() && !PathRef(testRoot()).startsWith(HintPath)) return error("Hint path is not empty and doesn't start with {0}: {1}", testRoot(), HintPath); if (!Body.consume_front("/")) diff --git a/clang-tools-extra/clangd/unittests/support/PathTests.cpp b/clang-tools-extra/clangd/unittests/support/PathTests.cpp index 599c76926d30d..98f3d6a2cc6d7 100644 --- a/clang-tools-extra/clangd/unittests/support/PathTests.cpp +++ b/clang-tools-extra/clangd/unittests/support/PathTests.cpp @@ -15,21 +15,21 @@ namespace clang { namespace clangd { namespace { TEST(PathTests, IsAncestor) { - EXPECT_TRUE(pathStartsWith(testPath("foo"), testPath("foo"))); - EXPECT_TRUE(pathStartsWith(testPath("foo/"), testPath("foo"))); + EXPECT_TRUE(PathRef(testPath("foo")).startsWith(testPath("foo"))); + EXPECT_TRUE(PathRef(testPath("foo/")).startsWith(testPath("foo"))); - EXPECT_FALSE(pathStartsWith(testPath("foo"), testPath("fooz"))); - EXPECT_FALSE(pathStartsWith(testPath("foo/"), testPath("fooz"))); + EXPECT_FALSE(PathRef(testPath("foo")).startsWith(testPath("fooz"))); + EXPECT_FALSE(PathRef(testPath("foo/")).startsWith(testPath("fooz"))); - EXPECT_TRUE(pathStartsWith(testPath("foo"), testPath("foo/bar"))); - EXPECT_TRUE(pathStartsWith(testPath("foo/"), testPath("foo/bar"))); + EXPECT_TRUE(PathRef(testPath("foo")).startsWith(testPath("foo/bar"))); + EXPECT_TRUE(PathRef(testPath("foo/")).startsWith(testPath("foo/bar"))); #ifdef CLANGD_PATH_CASE_INSENSITIVE - EXPECT_TRUE(pathStartsWith(testPath("fOo"), testPath("foo/bar"))); - EXPECT_TRUE(pathStartsWith(testPath("foo"), testPath("fOo/bar"))); + EXPECT_TRUE(PathRef(testPath("fOo")).startsWith(testPath("foo/bar"))); + EXPECT_TRUE(PathRef(testPath("foo")).startsWith(testPath("fOo/bar"))); #else - EXPECT_FALSE(pathStartsWith(testPath("fOo"), testPath("foo/bar"))); - EXPECT_FALSE(pathStartsWith(testPath("foo"), testPath("fOo/bar"))); + EXPECT_FALSE(PathRef(testPath("fOo")).startsWith(testPath("foo/bar"))); + EXPECT_FALSE(PathRef(testPath("foo")).startsWith(testPath("fOo/bar"))); #endif } } // namespace