Skip to content

[clangd] Store documentation when indexing standard library #133681

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions clang-tools-extra/clangd/index/FileIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,12 @@ SlabTuple indexSymbols(ASTContext &AST, Preprocessor &PP,
const MainFileMacros *MacroRefsToIndex,
const include_cleaner::PragmaIncludes &PI,
bool IsIndexMainAST, llvm::StringRef Version,
bool CollectMainFileRefs) {
bool CollectMainFileRefs, SymbolOrigin Origin) {
SymbolCollector::Options CollectorOpts;
CollectorOpts.CollectIncludePath = true;
CollectorOpts.PragmaIncludes = Π
CollectorOpts.CountReferences = false;
CollectorOpts.Origin =
IsIndexMainAST ? SymbolOrigin::Open : SymbolOrigin::Preamble;
CollectorOpts.Origin = Origin;
CollectorOpts.CollectMainFileRefs = CollectMainFileRefs;
// We want stdlib implementation details in the index only if we've opened the
// file in question. This does means xrefs won't work, though.
Expand Down Expand Up @@ -221,22 +220,24 @@ FileShardedIndex::getShard(llvm::StringRef Uri) const {
}

SlabTuple indexMainDecls(ParsedAST &AST) {
return indexSymbols(
AST.getASTContext(), AST.getPreprocessor(), AST.getLocalTopLevelDecls(),
&AST.getMacros(), AST.getPragmaIncludes(),
/*IsIndexMainAST=*/true, AST.version(), /*CollectMainFileRefs=*/true);
return indexSymbols(AST.getASTContext(), AST.getPreprocessor(),
AST.getLocalTopLevelDecls(), &AST.getMacros(),
AST.getPragmaIncludes(),
/*IsIndexMainAST=*/true, AST.version(),
/*CollectMainFileRefs=*/true, SymbolOrigin::Open);
}

SlabTuple indexHeaderSymbols(llvm::StringRef Version, ASTContext &AST,
Preprocessor &PP,
const include_cleaner::PragmaIncludes &PI) {
const include_cleaner::PragmaIncludes &PI,
SymbolOrigin Origin) {
std::vector<Decl *> DeclsToIndex(
AST.getTranslationUnitDecl()->decls().begin(),
AST.getTranslationUnitDecl()->decls().end());
return indexSymbols(AST, PP, DeclsToIndex,
/*MainFileMacros=*/nullptr, PI,
/*IsIndexMainAST=*/false, Version,
/*CollectMainFileRefs=*/false);
/*CollectMainFileRefs=*/false, Origin);
}

FileSymbols::FileSymbols(IndexContents IdxContents, bool SupportContainedRefs)
Expand Down Expand Up @@ -463,7 +464,7 @@ void FileIndex::updatePreamble(PathRef Path, llvm::StringRef Version,
const include_cleaner::PragmaIncludes &PI) {
IndexFileIn IF;
std::tie(IF.Symbols, std::ignore, IF.Relations) =
indexHeaderSymbols(Version, AST, PP, PI);
indexHeaderSymbols(Version, AST, PP, PI, SymbolOrigin::Preamble);
updatePreamble(std::move(IF));
}

Expand Down
3 changes: 2 additions & 1 deletion clang-tools-extra/clangd/index/FileIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ SlabTuple indexMainDecls(ParsedAST &AST);
/// included headers.
SlabTuple indexHeaderSymbols(llvm::StringRef Version, ASTContext &AST,
Preprocessor &PP,
const include_cleaner::PragmaIncludes &PI);
const include_cleaner::PragmaIncludes &PI,
SymbolOrigin Origin);

/// Takes slabs coming from a TU (multiple files) and shards them per
/// declaration location.
Expand Down
37 changes: 18 additions & 19 deletions clang-tools-extra/clangd/index/StdLib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@
#include "Compiler.h"
#include "Config.h"
#include "SymbolCollector.h"
#include "clang-include-cleaner/Record.h"
#include "index/FileIndex.h"
#include "index/IndexAction.h"
#include "support/Logger.h"
#include "support/ThreadsafeFS.h"
#include "support/Trace.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Tooling/Inclusions/StandardLibrary.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
Expand Down Expand Up @@ -223,33 +226,29 @@ SymbolSlab indexStandardLibrary(llvm::StringRef HeaderSources,
return Symbols;
}

SymbolCollector::Options IndexOpts;
IndexOpts.Origin = SymbolOrigin::StdLib;
IndexOpts.CollectMainFileSymbols = false;
IndexOpts.CollectMainFileRefs = false;
IndexOpts.CollectMacro = true;
IndexOpts.StoreAllDocumentation = true;
// Sadly we can't use IndexOpts.FileFilter to restrict indexing scope.
// Files from outside the StdLibLocation may define true std symbols anyway.
// We end up "blessing" such headers, and can only do that by indexing
// everything first.

// Refs, relations, include graph in the stdlib mostly aren't useful.
auto Action = createStaticIndexingAction(
IndexOpts, [&](SymbolSlab S) { Symbols = std::move(S); }, nullptr,
nullptr, nullptr);

if (!Action->BeginSourceFile(*Clang, Input)) {
SyntaxOnlyAction Action;

if (!Action.BeginSourceFile(*Clang, Input)) {
elog("Standard Library Index: BeginSourceFile() failed");
return Symbols;
}

if (llvm::Error Err = Action->Execute()) {
if (llvm::Error Err = Action.Execute()) {
elog("Standard Library Index: Execute failed: {0}", std::move(Err));
return Symbols;
}

Action->EndSourceFile();
// We don't care about include graph for stdlib headers, so provide a no-op
// PI.
include_cleaner::PragmaIncludes PI;
auto Slabs =
indexHeaderSymbols("", Clang->getASTContext(), Clang->getPreprocessor(),
PI, SymbolOrigin::StdLib);
Symbols = std::move(std::get<0>(Slabs));

// Run EndSourceFile() after indexing completes, so ensure the AST and
// preprocessor state is alive during indexing.
Action.EndSourceFile();

unsigned SymbolsBeforeFilter = Symbols.size();
Symbols = filter(std::move(Symbols), Loc);
Expand Down
48 changes: 48 additions & 0 deletions clang-tools-extra/clangd/unittests/StdLibTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
#include "Config.h"
#include "SyncAPI.h"
#include "TestFS.h"
#include "index/Index.h"
#include "index/StdLib.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Testing/Support/Error.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <memory>
Expand Down Expand Up @@ -158,6 +160,52 @@ TEST(StdLibTests, EndToEnd) {
UnorderedElementsAre(StdlibSymbol("list"), StdlibSymbol("vector")));
}

TEST(StdLibTests, StdLibDocComments) {
Config Cfg;
Cfg.Index.StandardLibrary = true;
WithContextValue Enabled(Config::Key, std::move(Cfg));

MockFS FS;
FS.Files["stdlib/vector"] = R"cpp(
namespace std {
struct vector {
/**doc comment*/
struct inner {};
};
}
)cpp";
MockCompilationDatabase CDB;
CDB.ExtraClangFlags.push_back("-isystem" + testPath("stdlib"));
ClangdServer::Options Opts = ClangdServer::optsForTest();
Opts.BuildDynamicSymbolIndex = true; // also used for stdlib index
ClangdServer Server(CDB, FS, Opts);

// Open an empty file. <vector> will not be part of the preamble index,
// but it will be part of the stdlib index.
Server.addDocument(testPath("foo.cc"), "");

// Wait for the stdlib index to be built.
ASSERT_TRUE(Server.blockUntilIdleForTest());

// Check that the index contains the doc comment.
SymbolSlab Result;
EXPECT_THAT_ERROR(runCustomAction(Server, testPath("foo.cc"),
[&](InputsAndAST Inputs) {
FuzzyFindRequest Req;
Req.Query = "inner";
Req.Scopes = {"std::vector::"};
SymbolSlab::Builder Builder;
Inputs.Inputs.Index->fuzzyFind(
Req, [&](const Symbol &Sym) {
Builder.insert(Sym);
});
Result = std::move(Builder).build();
}),
llvm::Succeeded());
ASSERT_EQ(Result.size(), 1u);
EXPECT_EQ(Result.begin()->Documentation, "doc comment");
}

} // namespace
} // namespace clangd
} // namespace clang
3 changes: 2 additions & 1 deletion clang-tools-extra/clangd/unittests/TestTU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "Diagnostics.h"
#include "TestFS.h"
#include "index/FileIndex.h"
#include "index/SymbolOrigin.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Frontend/CompilerInvocation.h"
Expand Down Expand Up @@ -164,7 +165,7 @@ SymbolSlab TestTU::headerSymbols() const {
auto AST = build();
return std::get<0>(indexHeaderSymbols(
/*Version=*/"null", AST.getASTContext(), AST.getPreprocessor(),
AST.getPragmaIncludes()));
AST.getPragmaIncludes(), SymbolOrigin::Preamble));
}

RefSlab TestTU::headerRefs() const {
Expand Down
Loading