Skip to content

Commit 7ec2d5d

Browse files
fix: Add disambiguator for using declarations (#304)
1 parent 1d4e2b8 commit 7ec2d5d

File tree

4 files changed

+69
-32
lines changed

4 files changed

+69
-32
lines changed

indexer/SymbolFormatter.cc

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,41 @@ SymbolFormatter::getEnumSymbol(const clang::EnumDecl &enumDecl) {
403403
return this->getTagSymbol(enumDecl);
404404
}
405405

406+
std::string_view SymbolFormatter::getFunctionDisambiguator(
407+
const clang::FunctionDecl &functionDecl, char buf[16]) {
408+
const clang::FunctionDecl *definingDecl = &functionDecl;
409+
// clang-format off
410+
if (functionDecl.isTemplateInstantiation()) {
411+
// Handle non-templated member functions
412+
if (auto *memberFnDecl = functionDecl.getInstantiatedFromMemberFunction()) {
413+
definingDecl = memberFnDecl;
414+
} else if (auto *templateInfo = functionDecl.getTemplateSpecializationInfo()) {
415+
// Consider code like:
416+
// template <typename T> class C { template <typename U> void f() {} };
417+
// void g() { C<int>().f<int>(); }
418+
// ^ Emitting a reference
419+
//
420+
// The dance below gets to the original declaration in 3 steps:
421+
// C<int>.f<int> (FunctionDecl) → C<int>.f<$U> (FunctionTemplateDecl)
422+
//
423+
// C<$T>.f<$U> (FunctionDecl) ← C<$T>.f<$U> (FunctionTemplateDecl)
424+
auto *instantiatedTemplateDecl = templateInfo->getTemplate();
425+
// For some reason, we end up on this code path for overloaded
426+
// literal operators. In that case, uninstantiatedTemplateDecl
427+
// can be null.
428+
if (auto *uninstantiatedTemplateDecl = instantiatedTemplateDecl->getInstantiatedFromMemberTemplate()) {
429+
definingDecl = uninstantiatedTemplateDecl->getTemplatedDecl();
430+
}
431+
}
432+
}
433+
// clang-format on
434+
// 64-bit hash in hex should take 16 characters at most.
435+
auto typeString = definingDecl->getType().getCanonicalType().getAsString();
436+
// char buf[16] = {0};
437+
auto *end = fmt::format_to(buf, "{:x}", HashValue::forText(typeString));
438+
return std::string_view{buf, end};
439+
}
440+
406441
std::optional<std::string_view>
407442
SymbolFormatter::getFunctionSymbol(const clang::FunctionDecl &functionDecl) {
408443
return this->getSymbolCached(
@@ -412,39 +447,9 @@ SymbolFormatter::getFunctionSymbol(const clang::FunctionDecl &functionDecl) {
412447
if (!optContextSymbol.has_value()) {
413448
return {};
414449
}
415-
const clang::FunctionDecl *definingDecl = &functionDecl;
416-
// clang-format off
417-
if (functionDecl.isTemplateInstantiation()) {
418-
// Handle non-templated member functions
419-
if (auto *memberFnDecl = functionDecl.getInstantiatedFromMemberFunction()) {
420-
definingDecl = memberFnDecl;
421-
} else if (auto *templateInfo = functionDecl.getTemplateSpecializationInfo()) {
422-
// Consider code like:
423-
// template <typename T> class C { template <typename U> void f() {} };
424-
// void g() { C<int>().f<int>(); }
425-
// ^ Emitting a reference
426-
//
427-
// The dance below gets to the original declaration in 3 steps:
428-
// C<int>.f<int> (FunctionDecl) → C<int>.f<$U> (FunctionTemplateDecl)
429-
//
430-
// C<$T>.f<$U> (FunctionDecl) ← C<$T>.f<$U> (FunctionTemplateDecl)
431-
auto *instantiatedTemplateDecl = templateInfo->getTemplate();
432-
// For some reason, we end up on this code path for overloaded
433-
// literal operators. In that case, uninstantiatedTemplateDecl
434-
// can be null.
435-
if (auto *uninstantiatedTemplateDecl = instantiatedTemplateDecl->getInstantiatedFromMemberTemplate()) {
436-
definingDecl = uninstantiatedTemplateDecl->getTemplatedDecl();
437-
}
438-
}
439-
}
440-
// clang-format on
441450
auto name = this->formatTemporary(functionDecl);
442-
// 64-bit hash in hex should take 16 characters at most.
443-
auto typeString =
444-
definingDecl->getType().getCanonicalType().getAsString();
445451
char buf[16] = {0};
446-
auto *end = fmt::format_to(buf, "{:x}", HashValue::forText(typeString));
447-
std::string_view disambiguator{buf, end};
452+
auto disambiguator = this->getFunctionDisambiguator(functionDecl, buf);
448453
return SymbolBuilder::formatContextual(
449454
optContextSymbol.value(), DescriptorBuilder{
450455
.name = name,
@@ -566,6 +571,8 @@ std::optional<std::string_view> SymbolFormatter::getUsingShadowSymbol(
566571
return {};
567572
}
568573
scip::Descriptor::Suffix suffix;
574+
char buf[16] = {0};
575+
std::string_view disambiguator = "";
569576
// NOTE: First two branches can't be re-ordered as all
570577
// TemplateTypeParmDecls also TypeDecls
571578
if (llvm::dyn_cast<clang::TemplateTypeParmDecl>(canonicalDecl)) {
@@ -577,13 +584,16 @@ std::optional<std::string_view> SymbolFormatter::getUsingShadowSymbol(
577584
} else if (llvm::dyn_cast<clang::EnumConstantDecl>(canonicalDecl)
578585
|| llvm::dyn_cast<clang::FieldDecl>(canonicalDecl)) {
579586
suffix = scip::Descriptor::Term;
580-
} else if (llvm::dyn_cast<clang::FunctionDecl>(canonicalDecl)) {
587+
} else if (auto *functionDecl =
588+
llvm::dyn_cast<clang::FunctionDecl>(canonicalDecl)) {
589+
disambiguator = this->getFunctionDisambiguator(*functionDecl, buf);
581590
suffix = scip::Descriptor::Method;
582591
} else {
583592
return {};
584593
}
585594
auto descriptor = DescriptorBuilder{
586595
.name = this->formatTemporary(usingShadowDecl),
596+
.disambiguator = disambiguator,
587597
.suffix = suffix,
588598
};
589599
return SymbolBuilder::formatContextual(*optContextSymbol, descriptor);

indexer/SymbolFormatter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ class SymbolFormatter final {
137137
return std::string_view(this->scratchBuffer);
138138
}
139139

140+
std::string_view getFunctionDisambiguator(const clang::FunctionDecl &,
141+
char[16]);
142+
140143
/// Format the string to a buffer stored by `this` and return a view to it.
141144
std::string_view formatTemporary(const clang::NamedDecl &);
142145
};

test/index/aliases/aliases.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,11 @@ namespace z {
7676
T identity(T t) { return v.identity<T>(t); }
7777
};
7878
}
79+
80+
namespace i {
81+
namespace j {
82+
void f() {}
83+
}
84+
using j::f;
85+
void g() { f(); }
86+
}

test/index/aliases/aliases.snapshot.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,19 @@
163163
// ^ reference local 6
164164
};
165165
}
166+
167+
namespace i {
168+
// ^ definition [..] i/
169+
namespace j {
170+
// ^ definition [..] i/j/
171+
void f() {}
172+
// ^ definition [..] i/j/f(49f6e7a06ebc5aa8).
173+
}
174+
using j::f;
175+
// ^ reference [..] i/j/
176+
// ^ definition [..] i/f(49f6e7a06ebc5aa8).
177+
// ^ reference [..] i/j/f(49f6e7a06ebc5aa8).
178+
void g() { f(); }
179+
// ^ definition [..] i/g(49f6e7a06ebc5aa8).
180+
// ^ reference [..] i/f(49f6e7a06ebc5aa8).
181+
}

0 commit comments

Comments
 (0)