Skip to content

Commit 460cad6

Browse files
refactor: Plumb original decl location for package info (#342)
1 parent 7242afb commit 460cad6

File tree

2 files changed

+121
-48
lines changed

2 files changed

+121
-48
lines changed

indexer/SymbolFormatter.cc

Lines changed: 97 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -256,28 +256,96 @@ std::optional<SymbolString> SymbolFormatter::getSymbolCached(
256256
}
257257
ENFORCE(!optSymbol.value().empty(),
258258
"forgot to use nullopt to signal failure in computing symbol name");
259-
auto [newIt, inserted] = this->declBasedCache.insert(
260-
{canonicalDecl, std::move(optSymbol.value())});
259+
auto [newIt, inserted] =
260+
this->declBasedCache.insert({canonicalDecl, *optSymbol});
261261
ENFORCE(inserted);
262262
return std::string_view(newIt->second);
263263
}
264264

265-
std::optional<SymbolString>
266-
SymbolFormatter::getContextSymbol(const clang::DeclContext &declContext) {
265+
std::optional<std::string_view> SymbolFormatter::getSymbolCached(
266+
const clang::Decl *decl, clang::SourceLocation loc,
267+
absl::FunctionRef<std::optional<SymbolString>()> getSymbol) {
268+
auto fileId = this->sourceManager.getFileID(loc);
269+
if (decl) {
270+
decl = decl->getCanonicalDecl();
271+
}
272+
using KeyType =
273+
std::pair<const clang::Decl *, llvm_ext::AbslHashAdapter<clang::FileID>>;
274+
auto it = this->namespacePrefixCache.find(KeyType{decl, {fileId}});
275+
if (it != this->namespacePrefixCache.end()) {
276+
return std::string_view(it->second);
277+
}
278+
auto optSymbol = getSymbol();
279+
if (!optSymbol.has_value()) {
280+
return {};
281+
}
282+
ENFORCE(!optSymbol.value().empty(),
283+
"forgot to use nullopt to signal failure in compute symbol name");
284+
auto [newIt, inserted] =
285+
this->namespacePrefixCache.emplace(KeyType{decl, {fileId}}, *optSymbol);
286+
ENFORCE(inserted);
287+
return std::string_view(newIt->second);
288+
}
289+
290+
std::optional<std::string_view> SymbolFormatter::getNamespaceSymbolPrefix(
291+
const clang::NamespaceDecl &namespaceDecl, clang::SourceLocation loc) {
292+
return this->getSymbolCached(
293+
&namespaceDecl, loc, [&]() -> std::optional<SymbolString> {
294+
auto optContextSymbol =
295+
this->getContextSymbol(*namespaceDecl.getDeclContext(), loc);
296+
if (!optContextSymbol.has_value()) {
297+
return {};
298+
}
299+
auto contextSymbol = optContextSymbol.value();
300+
DescriptorBuilder descriptor{.suffix = scip::Descriptor::Namespace};
301+
if (namespaceDecl.isAnonymousNamespace()) {
302+
auto mainFileId = this->sourceManager.getMainFileID();
303+
ENFORCE(mainFileId.isValid());
304+
auto optStableFileId =
305+
this->fileMetadataMap.getStableFileId(mainFileId);
306+
ENFORCE(optStableFileId.has_value(),
307+
"main file always has a valid StableFileId");
308+
auto path = optStableFileId->path;
309+
descriptor.name = this->formatTemporaryName("$anonymous_namespace_{}",
310+
path.asStringView());
311+
} else {
312+
descriptor.name = this->formatTemporaryName(namespaceDecl);
313+
}
314+
return this->formatContextual(contextSymbol, descriptor);
315+
});
316+
}
317+
318+
std::optional<std::string_view>
319+
SymbolFormatter::getLocationBasedSymbolPrefix(clang::SourceLocation loc) {
320+
if (loc.isInvalid()) {
321+
return {};
322+
}
323+
return this->getSymbolCached(
324+
nullptr, loc, [&]() -> std::optional<SymbolString> {
325+
auto fileId = this->sourceManager.getFileID(loc);
326+
auto *fileMetadata = this->fileMetadataMap.getFileMetadata(fileId);
327+
if (!fileMetadata) {
328+
return {};
329+
}
330+
auto packageId = fileMetadata->packageId();
331+
return this->format(SymbolBuilder{packageId, /*descriptors*/ {}});
332+
});
333+
}
334+
335+
std::optional<std::string_view>
336+
SymbolFormatter::getContextSymbol(const clang::DeclContext &declContext,
337+
clang::SourceLocation loc) {
338+
loc = this->sourceManager.getExpansionLoc(loc);
267339
if (auto *namespaceDecl =
268340
llvm::dyn_cast<clang::NamespaceDecl>(&declContext)) {
269-
return this->getNamespaceSymbol(*namespaceDecl);
341+
return this->getNamespaceSymbolPrefix(*namespaceDecl, loc);
270342
}
271343
if (auto *tagDecl = llvm::dyn_cast<clang::TagDecl>(&declContext)) {
272344
return this->getTagSymbol(*tagDecl);
273345
}
274-
if (llvm::isa<clang::TranslationUnitDecl>(declContext)
275-
|| llvm::isa<clang::ExternCContextDecl>(declContext)) {
276-
auto decl = llvm::dyn_cast<clang::Decl>(&declContext);
277-
return this->getSymbolCached(*decl, [&]() -> std::optional<SymbolString> {
278-
// TODO: Retrieve the correct PackageId and use that here
279-
return this->format(SymbolBuilder{{"", ""}, {}});
280-
});
346+
if (llvm::isa<clang::TranslationUnitDecl>(&declContext)
347+
|| llvm::isa<clang::ExternCContextDecl>(&declContext)) {
348+
return this->getLocationBasedSymbolPrefix(loc);
281349
}
282350
if (auto *functionDecl = llvm::dyn_cast<clang::FunctionDecl>(&declContext)) {
283351
// TODO: Strictly speaking, we should return some information marking
@@ -312,7 +380,8 @@ SymbolFormatter::getRecordSymbol(const clang::RecordDecl &recordDecl) {
312380
std::optional<SymbolString>
313381
SymbolFormatter::getTagSymbol(const clang::TagDecl &tagDecl) {
314382
return this->getSymbolCached(tagDecl, [&]() -> std::optional<SymbolString> {
315-
auto optContextSymbol = this->getContextSymbol(*tagDecl.getDeclContext());
383+
auto optContextSymbol = this->getContextSymbol(*tagDecl.getDeclContext(),
384+
tagDecl.getLocation());
316385
if (!optContextSymbol.has_value()) {
317386
return {};
318387
}
@@ -323,6 +392,7 @@ SymbolFormatter::getTagSymbol(const clang::TagDecl &tagDecl) {
323392
DescriptorBuilder{.name = this->formatTemporaryName(tagDecl),
324393
.suffix = scip::Descriptor::Type});
325394
}
395+
326396
auto *definitionTagDecl = tagDecl.getDefinition();
327397
if (!definitionTagDecl) {
328398
// NOTE(def: missing-definition-for-tagdecl)
@@ -412,7 +482,8 @@ std::optional<SymbolString> SymbolFormatter::getEnumConstantSymbol(
412482
std::optional<SymbolString> optContextSymbol =
413483
parentEnumDecl->isScoped()
414484
? this->getEnumSymbol(*parentEnumDecl)
415-
: this->getContextSymbol(*parentEnumDecl->getDeclContext());
485+
: this->getContextSymbol(*parentEnumDecl->getDeclContext(),
486+
enumConstantDecl.getLocation());
416487
if (!optContextSymbol.has_value()) {
417488
return {};
418489
}
@@ -468,8 +539,8 @@ std::optional<SymbolString>
468539
SymbolFormatter::getFunctionSymbol(const clang::FunctionDecl &functionDecl) {
469540
return this->getSymbolCached(
470541
functionDecl, [&]() -> std::optional<SymbolString> {
471-
auto optContextSymbol =
472-
this->getContextSymbol(*functionDecl.getDeclContext());
542+
auto optContextSymbol = this->getContextSymbol(
543+
*functionDecl.getDeclContext(), functionDecl.getLocation());
473544
if (!optContextSymbol.has_value()) {
474545
return {};
475546
}
@@ -496,7 +567,8 @@ SymbolFormatter::getFieldSymbol(const clang::FieldDecl &fieldDecl) {
496567
return {};
497568
}
498569
return this->getSymbolCached(fieldDecl, [&]() -> std::optional<SymbolString> {
499-
auto optContextSymbol = this->getContextSymbol(*fieldDecl.getDeclContext());
570+
auto optContextSymbol = this->getContextSymbol(*fieldDecl.getDeclContext(),
571+
fieldDecl.getLocation());
500572
if (!optContextSymbol.has_value()) {
501573
return {};
502574
}
@@ -523,30 +595,8 @@ SymbolFormatter::getNamedDeclSymbol(const clang::NamedDecl &namedDecl) {
523595
/// getCanonicalPath returns nullopt.
524596
std::optional<SymbolString>
525597
SymbolFormatter::getNamespaceSymbol(const clang::NamespaceDecl &namespaceDecl) {
526-
return this->getSymbolCached(
527-
namespaceDecl, [&]() -> std::optional<SymbolString> {
528-
auto optContextSymbol =
529-
this->getContextSymbol(*namespaceDecl.getDeclContext());
530-
if (!optContextSymbol.has_value()) {
531-
return {};
532-
}
533-
auto contextSymbol = optContextSymbol.value();
534-
DescriptorBuilder descriptor{.suffix = scip::Descriptor::Namespace};
535-
if (namespaceDecl.isAnonymousNamespace()) {
536-
auto mainFileId = this->sourceManager.getMainFileID();
537-
ENFORCE(mainFileId.isValid());
538-
auto optStableFileId =
539-
this->fileMetadataMap.getStableFileId(mainFileId);
540-
ENFORCE(optStableFileId.has_value(),
541-
"main file always has a valid StableFileId");
542-
auto path = optStableFileId->path;
543-
descriptor.name = this->formatTemporaryName("$anonymous_namespace_{}",
544-
path.asStringView());
545-
} else {
546-
descriptor.name = this->formatTemporaryName(namespaceDecl);
547-
}
548-
return this->formatContextual(contextSymbol, descriptor);
549-
});
598+
return this->getNamespaceSymbolPrefix(namespaceDecl,
599+
namespaceDecl.getLocation());
550600
}
551601

552602
std::optional<SymbolString>
@@ -567,8 +617,8 @@ std::optional<SymbolString> SymbolFormatter::getTypedefNameSymbol(
567617
const clang::TypedefNameDecl &typedefNameDecl) {
568618
return this->getSymbolCached(
569619
typedefNameDecl, [&]() -> std::optional<SymbolString> {
570-
auto optContextSymbol =
571-
this->getContextSymbol(*typedefNameDecl.getDeclContext());
620+
auto optContextSymbol = this->getContextSymbol(
621+
*typedefNameDecl.getDeclContext(), typedefNameDecl.getLocation());
572622
if (!optContextSymbol.has_value()) {
573623
return {};
574624
}
@@ -592,8 +642,8 @@ std::optional<SymbolString> SymbolFormatter::getUsingShadowSymbol(
592642
}
593643
return this->getSymbolCached(
594644
usingShadowDecl, [&]() -> std::optional<SymbolString> {
595-
auto optContextSymbol =
596-
this->getContextSymbol(*usingShadowDecl.getDeclContext());
645+
auto optContextSymbol = this->getContextSymbol(
646+
*usingShadowDecl.getDeclContext(), usingShadowDecl.getLocation());
597647
if (!optContextSymbol) {
598648
return {};
599649
}
@@ -669,8 +719,8 @@ SymbolFormatter::getVarSymbol(const clang::VarDecl &varDecl) {
669719
case Kind::VarTemplatePartialSpecialization:
670720
case Kind::VarTemplateSpecialization:
671721
case Kind::Var: {
672-
if (auto optContextSymbol =
673-
this->getContextSymbol(*varDecl.getDeclContext())) {
722+
if (auto optContextSymbol = this->getContextSymbol(
723+
*varDecl.getDeclContext(), varDecl.getLocation())) {
674724
auto descriptor = DescriptorBuilder{
675725
.name = llvm_ext::toStringView(varDecl.getName()),
676726
.suffix = scip::Descriptor::Term,

indexer/SymbolFormatter.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ class SymbolFormatter final {
8787
absl::flat_hash_map<llvm_ext::AbslHashAdapter<clang::SourceLocation>,
8888
SymbolString>
8989
locationBasedCache;
90+
absl::flat_hash_map<
91+
std::pair<const clang::Decl *, llvm_ext::AbslHashAdapter<clang::FileID>>,
92+
SymbolString>
93+
namespacePrefixCache;
9094
absl::flat_hash_map<const clang::Decl *, SymbolString> declBasedCache;
9195
absl::flat_hash_map<StableFileId, SymbolString> fileSymbolCache;
9296
absl::flat_hash_map<llvm_ext::AbslHashAdapter<clang::FileID>, uint32_t>
@@ -124,14 +128,33 @@ class SymbolFormatter final {
124128
std::optional<SymbolString> getTagSymbol(const clang::TagDecl &);
125129

126130
private:
127-
std::optional<SymbolString> getContextSymbol(const clang::DeclContext &);
131+
/// Create a symbol for the context, optionally using \p loc to determine
132+
/// package information.
133+
std::optional<SymbolString> getContextSymbol(const clang::DeclContext &,
134+
clang::SourceLocation loc);
135+
136+
/// Construct a symbol for a namespace using package information based
137+
/// on \p loc rather than the NamespaceDecl's own location. This is because
138+
/// namespaces can cut across packages.
139+
std::optional<SymbolString>
140+
getNamespaceSymbolPrefix(const clang::NamespaceDecl &,
141+
clang::SourceLocation loc);
128142

129143
std::optional<SymbolString> getNextLocalSymbol(const clang::NamedDecl &);
130144

131145
std::optional<SymbolString>
132146
getSymbolCached(const clang::Decl &,
133147
absl::FunctionRef<std::optional<SymbolString>()>);
134148

149+
/// Cache the symbol based on the decl ptr (may be null) + the file containing
150+
/// the location.
151+
std::optional<SymbolString>
152+
getSymbolCached(const clang::Decl *, clang::SourceLocation,
153+
absl::FunctionRef<std::optional<std::string_view>()>);
154+
155+
std::optional<SymbolString>
156+
getLocationBasedSymbolPrefix(clang::SourceLocation loc);
157+
135158
// --- Final step functions for symbol formatting ---
136159

137160
/// Format a symbol for an entity isn't inside a namespace/type/etc. and isn't

0 commit comments

Comments
 (0)