kadircet added inline comments.
================ Comment at: clang-tools-extra/clangd/ClangdServer.cpp:85 auto Task = [FIndex(FIndex), Path(Path.str()), Version(Version.str()), - ASTCtx(std::move(ASTCtx)), - CanonIncludes(CanonIncludes)]() mutable { + ASTCtx(std::move(ASTCtx)), PI]() mutable { trace::Span Tracer("PreambleIndexing"); ---------------- nit: `PI(std::move(PI))` ================ Comment at: clang-tools-extra/clangd/TUScheduler.cpp:1086 Callbacks.onPreambleAST(FileName, Inputs.Version, std::move(ASTCtx), - CanonIncludes); + PI); }, ---------------- nit: s/PI/std::move(PI) ================ Comment at: clang-tools-extra/clangd/index/CanonicalIncludes.cpp:672 llvm::StringRef CanonicalIncludes::mapHeader(FileEntryRef Header) const { if (!StdSuffixHeaderMapping) ---------------- we're no longer using any `FileEntry` pieces of this parameter you can take in just a `llvm::StringRef HeaderPath` instead. ================ Comment at: clang-tools-extra/clangd/index/CanonicalIncludes.h:40 /// Adds a file-to-string mapping from \p ID to \p CanonicalPath. void addMapping(FileEntryRef Header, llvm::StringRef CanonicalPath); ---------------- VitaNuo wrote: > kadircet wrote: > > AFAICT, only users of this endpoint were in `IWYUCommentHandler` (and some > > tests). we can also get rid of this one now. > > > > More importantly now this turns into a mapper used only by symbolcollector, > > that can be cheaply created at use time (we just copy around a pointer > > every time we want to create it). so you can drop `CanonicalIncludes` from > > all of the interfaces, including `SymbolCollector::Options` and create one > > on demand in `HeaderFileURICache`. all we need is langopts, and it's > > available through preprocessor (not necessarily on construction, but at the > > time when we want to do the mappings). > > > > As you're already touching all of the interfaces that propagate > > `CanonicalIncludes` around, hopefully this change should only make things > > simpler (and you already need to touch them when you rebase), but if that > > feels like too much churn in this patch feel free to do that in a follow up > > as well. > > ... and create one on demand in HeaderFileURICache. all we need is > > langopts, and it's available through preprocessor (not necessarily on > > construction, but at the time when we want to do the mappings > > This time sounds a little late, since we don't want to rebuild the system > header mapping every time we request a mapping for a particular header. > Cache construction time doesn't work, since it happens before the > preprocessor is set in the symbol collector (and we need the preprocessor to > retrieve language options). > So far the safe place I've found is right after the preprocessor is set in > the symbol collector. Another option is to collect the system header options > in the finish() method, but I can't see why we would need to delay until > then. > This time sounds a little late, since we don't want to rebuild the system > header mapping every time we request a mapping for a particular header. System header mapping is a singleton, we build it statically once on first request throughout the whole process and just use that for the rest of the execution. ================ Comment at: clang-tools-extra/clangd/index/FileIndex.cpp:49 + const MainFileMacros *MacroRefsToIndex, + std::shared_ptr<const include_cleaner::PragmaIncludes> PI, + bool IsIndexMainAST, llvm::StringRef Version, bool CollectMainFileRefs) { ---------------- again you can have a `const include_cleaner::PragmaIncludes &` without `shared_ptr` here. ================ Comment at: clang-tools-extra/clangd/index/FileIndex.h:118 + Preprocessor &PP, + std::shared_ptr<const include_cleaner::PragmaIncludes> PI); void updatePreamble(IndexFileIn); ---------------- you can have a `const include_cleaner::PragmaIncludes& PI` directly both in here and in `indexHeaderSymbols`. after building a preamble we always have a non-null PragmaIncludes and these functions are always executed synchronously, so no need to extend ownership and make the code indirect. ================ Comment at: clang-tools-extra/clangd/index/IndexAction.cpp:230 } - auto Includes = std::make_unique<CanonicalIncludes>(); - Opts.Includes = Includes.get(); - return std::make_unique<IndexAction>( - std::make_shared<SymbolCollector>(std::move(Opts)), std::move(Includes), - IndexOpts, SymbolsCallback, RefsCallback, RelationsCallback, - IncludeGraphCallback); + auto PragmaIncludes = std::make_shared<include_cleaner::PragmaIncludes>(); + Opts.PragmaIncludes = PragmaIncludes; ---------------- you can have a unique_ptr here instead (once we store a non-owning pointer in `Opts.PragmaIncludes`) ================ Comment at: clang-tools-extra/clangd/index/SymbolCollector.cpp:407 + + if (auto Verbatim = PI->getPublic(SM.getFileEntryForID(FID)); + !Verbatim.empty()) ---------------- s/SM.getFileEntryForID(FID)/FE ================ Comment at: clang-tools-extra/clangd/index/SymbolCollector.cpp:793 + S, DefLoc, + include_cleaner::Macro{const_cast<IdentifierInfo *>(Name), DefLoc}); Symbols.insert(S); ---------------- you can actually change `include_cleaner::Macro` to have a `const IdentifierInfo*` instead of the `const_cast` here. it's mostly an oversight to store a non-const `IdentifierInfo` in the first place. ================ Comment at: clang-tools-extra/clangd/index/SymbolCollector.cpp:839 + if (!Headers.empty()) + SymbolProviders.insert({S.ID, Headers[0]}); } ---------------- once we have the optional<Header> as the value type you can also rewrite this as: ``` auto [It, Inserted] = SymbolProviders.try_emplace(S.ID); if (Inserted) { auto Providers = include_cleaner::headersForSymbol(Sym, SM, Opts.PragmaIncludes.get()); if(!Providers.empty()) It->second = Providers.front(); } ``` that way we can get rid of some redundant calls to `headersForSymbol` ================ Comment at: clang-tools-extra/clangd/index/SymbolCollector.cpp:895 + !IncludeHeader.empty()) { + NewSym.IncludeHeaders.push_back({IncludeHeader, 1, Directives}); + Symbols.insert(NewSym); ---------------- you can move the copy into this branch to make sure we're only doing that when necessary, e.g: ``` if(auto IncludeHeader = ...) { Symbol NewSym = *S; NewSym.IncludeHeaders...; Symbols.insert(NewSym); } ``` ================ Comment at: clang-tools-extra/clangd/index/SymbolCollector.cpp:907 + auto It = SymbolProviders.find(SID); + if (It == SymbolProviders.end()) + continue; ---------------- FWIW, i think we should `assert(It != SymbolProviders.end())` (or `IncludeFiles.end()` when you change the outer loop). as we're inserting into these maps simultaneously. ================ Comment at: clang-tools-extra/clangd/index/SymbolCollector.cpp:910 + const auto &H = It->second; + llvm::DenseMap<include_cleaner::Header, std::string> HeaderSpelling; + const auto [SpellingIt, Inserted] = HeaderSpelling.try_emplace(H); ---------------- we're not really getting any caching benefits as this map is inside the loop. can you put it outside the loop body? ================ Comment at: clang-tools-extra/clangd/index/SymbolCollector.cpp:913 + if (!Inserted) + continue; + switch (H.kind()) { ---------------- we shouldn't `continue` here, it just means we can directly use `SpellingIt` to figure out what to put into `NewSym.IncludeHeaders`. maybe something like: ``` auto [SpellingIt, Inserted] = HeaderSpelling.try_emplace(H); if (Inserted) SpellingIt-> second = getSpelling(H, *PP); if(!SpellingIt->second.empty()) { Symbol NewSym = *S; NewSym.IncludeHeaders.push_back({SpellingIt->second, 1, Directives}); Symbols.insert(NewSym); } ``` ``` std::string getSpelling(const include_cleaner::Header &H, const Preprocessor &PP) { if(H.kind() == Physical) { // Check if we have a mapping for the header in system includes. // FIXME: get rid of this once stdlib mapping covers these system headers too. CanonicalIncludes CI; CI.addSystemHeadersMapping(PP.getLangOpts()); if (auto Canonical = CI.mapHeader(H.physical()->getLastRef()); !Canonical.empty()) return Canonical; if (!tooling::isSelfContainedHeader(...)) return ""; } // Otherwise use default spelling strategies in include_cleaner. return include_cleaner::spellHeader(H); } ``` ================ Comment at: clang-tools-extra/clangd/index/SymbolCollector.cpp:250 + // of whether it's an otherwise-good header (header guards etc). + llvm::StringRef mapCanonical(FileID FID) { + if (SysHeaderMapping) { ---------------- VitaNuo wrote: > kadircet wrote: > > let's change the interface here to take in a `FileEntry` instead. > I believe it has to be `FileEntryRef` instead. This is what the > `CanonicalIncludes::mapHeader` expects, and this is also seems right > (somewhere in the Clang docs I've read "everything that needs a name should > use `FileEntryRef`", and name is exactly what `CanonicalIncludes::mapHeader` > needs). > > For the case of a physical header (i.e., `FileEntry` instance) I've switched > to using `getLastRef` now. There's also another API `FileManager::getFileRef` > where I could try passing the result of `tryGetRealPathName`. I am not sure I > have enough information to judge if any of these options is distinctly better. yeah `getLastRef` is fine, i was mostly trying to avoid dodgy call to `getOrCreateFileID`. you can also pass in just a `llvm::StringRef HeaderPath` now, as we're not using anything but file path. which you can retreive with `getName` from both FileEntry and FileEntryRef ================ Comment at: clang-tools-extra/clangd/index/SymbolCollector.cpp:849 + shouldCollectIncludePath(S.SymInfo.Kind) != Symbol::Invalid) + SymbolProviders[S.ID] = std::move(Headers); +} ---------------- VitaNuo wrote: > kadircet wrote: > > because you're taking in `Headers` as `const`, this move is not actually > > moving. > Ok, this is not relevant anymore, but I am not sure I understand why. Am I > not allowed to say that I don't need this variable/memory anymore, even > though it's `const`? `std::move` is unfortunately a little bit misleading at times. it is just a `cast` that returns an rvalue reference. hence on its own it doesn't actually `move` anything. but it enables picking rvalue versions of constructors/assignment operators. (e.g. `Foo(Foo&&)` or `operator=(Foo&&)`) which can be implemented efficiently with the assumption that RHS object is being "moved from" and will no longer be used. that way certain types implement a move semantics by just consuming the RHS object. unfortunately that is not possbile when RHS is `const`, and expressions use regular copy semantics instead. ================ Comment at: clang-tools-extra/clangd/index/SymbolCollector.cpp:877 // We delay this until end of TU so header guards are all resolved. for (const auto &[SID, FID] : IncludeFiles) { if (const Symbol *S = Symbols.find(SID)) { ---------------- VitaNuo wrote: > kadircet wrote: > > let's iterate over `SymbolProviders` instead, as `IncludeFiles` is a legacy > > struct now. > Not sure I'm following. Iterating over `SymbolProviders` means retrieving > `include_cleaner::Header`s. How would I handle the entire Obj-C part then, > without the FID of the include header? we're joining `IncludeFiles` and `SymbolProviders`, as they have the same keys. right now you're iterating over the keys in `IncludeFiles` and doing a lookup into `SymbolProviders` using that key to get providers. we can also do the iteration over `SymbolProviders` and do the lookup into `IncludeFiles` instead to find associated `FID`. ================ Comment at: clang-tools-extra/clangd/index/SymbolCollector.h:64 + /// different #include path specified by IWYU pragmas. + std::shared_ptr<const include_cleaner::PragmaIncludes> PragmaIncludes = + nullptr; ---------------- no need to have ownership here, we can have just a `const include_cleaner::PragmaIncludes* PI`. SymbolCollector shouldn't need to extend lifetimes ================ Comment at: clang-tools-extra/clangd/index/SymbolCollector.h:130 this->PP = PP.get(); + SysHeaderMapping.addSystemHeadersMapping(PP->getLangOpts()); + } ---------------- as mentioned above `addSystemHeadersMapping` is cheap after the first call in the process, we initialize the mappings only once. so you can just have it as a member in `HeaderFileURICache`, and drop it completely from the public interface of `SymbolCollector` ================ Comment at: clang-tools-extra/clangd/index/SymbolCollector.h:186 + // The final spelling is calculated in finish(). + llvm::DenseMap<SymbolID, include_cleaner::Header> SymbolProviders; + ---------------- can we have a `llvm::DenseMap<SymbolID, std::optional<include_cleaner::Header>>`, to indicate there are no providers for a symbol, rather than missing the symbol completely from the mapping? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D152900/new/ https://reviews.llvm.org/D152900 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits