Skip to content

Commit 34dc94b

Browse files
committed
Only include SCIP SymbolInformation for first inherent impl
1 parent 3a93fe1 commit 34dc94b

File tree

2 files changed

+52
-33
lines changed

2 files changed

+52
-33
lines changed

crates/ide/src/moniker.rs

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -249,29 +249,20 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati
249249

250250
/// Computes a `MonikerResult` for a definition. Result cases:
251251
///
252-
/// `Some(MonikerResult::Moniker(_))` provides a unique `Moniker` which refers to a definition.
252+
/// * `Some(MonikerResult::Moniker(_))` provides a unique `Moniker` which refers to a definition.
253253
///
254-
/// `Some(MonikerResult::Local { .. })` provides a `Moniker` for the definition enclosing a local.
254+
/// * `Some(MonikerResult::Local { .. })` provides a `Moniker` for the definition enclosing a local.
255255
///
256-
/// `None` is returned in the following cases:
257-
///
258-
/// * Inherent impl definitions, as they cannot be uniquely identified (multiple are allowed for the
259-
/// same type).
260-
///
261-
/// * Definitions which are not in a module: `BuiltinAttr`, `BuiltinType`, `BuiltinLifetime`,
262-
/// `TupleField`, `ToolModule`, and `InlineAsmRegOrRegClass`. TODO: it might be sensible to
263-
/// provide monikers that refer to some non-existent crate of compiler builtin definitions.
256+
/// * `None` is returned for definitions which are not in a module: `BuiltinAttr`, `BuiltinType`,
257+
/// `BuiltinLifetime`, `TupleField`, `ToolModule`, and `InlineAsmRegOrRegClass`. TODO: it might be
258+
/// sensible to provide monikers that refer to some non-existent crate of compiler builtin
259+
/// definitions.
264260
pub(crate) fn def_to_moniker(
265261
db: &RootDatabase,
266262
definition: Definition,
267263
from_crate: Crate,
268264
) -> Option<MonikerResult> {
269265
match definition {
270-
// Not possible to give sensible unique symbols for inherent impls, as multiple can be
271-
// defined for the same type.
272-
Definition::SelfType(impl_) if impl_.trait_(db).is_none() => {
273-
return None;
274-
}
275266
Definition::Local(_) | Definition::Label(_) | Definition::GenericParam(_) => {
276267
return Some(MonikerResult::Local {
277268
enclosing_moniker: enclosing_def_to_moniker(db, definition, from_crate),
@@ -352,9 +343,7 @@ fn def_to_non_local_moniker(
352343
match def {
353344
Definition::Module(module) if module.is_crate_root() => {}
354345
_ => {
355-
tracing::error!(
356-
?def, "Encountered enclosing definition with no name"
357-
);
346+
tracing::error!(?def, "Encountered enclosing definition with no name");
358347
}
359348
}
360349
}

crates/rust-analyzer/src/cli/scip.rs

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,26 @@ impl flags::Scip {
102102
// This is called after definitions have been deduplicated by token_ids_emitted. The purpose
103103
// is to detect reuse of symbol names because this causes ambiguity about their meaning.
104104
let mut record_error_if_symbol_already_used =
105-
|symbol: String, relative_path: &str, line_index: &LineIndex, text_range: TextRange| {
105+
|symbol: String,
106+
is_inherent_impl: bool,
107+
relative_path: &str,
108+
line_index: &LineIndex,
109+
text_range: TextRange| {
106110
let is_local = symbol.starts_with("local ");
107111
if !is_local && !nonlocal_symbols_emitted.insert(symbol.clone()) {
108-
let source_location =
109-
text_range_to_string(relative_path, line_index, text_range);
110-
duplicate_symbol_errors.push((source_location, symbol));
112+
// See #18772. Duplicate SymbolInformation for inherent impls is omitted.
113+
if is_inherent_impl {
114+
false
115+
} else {
116+
let source_location =
117+
text_range_to_string(relative_path, line_index, text_range);
118+
duplicate_symbol_errors.push((source_location, symbol));
119+
// Keep duplicate SymbolInformation. This behavior is preferred over
120+
// omitting so that the issue might be visible within downstream tools.
121+
true
122+
}
123+
} else {
124+
true
111125
}
112126
};
113127

@@ -126,13 +140,13 @@ impl flags::Scip {
126140
tokens.into_iter().for_each(|(text_range, id)| {
127141
let token = si.tokens.get(id).unwrap();
128142

129-
let (symbol, enclosing_symbol) =
130-
if let Some(TokenSymbols { symbol, enclosing_symbol }) =
143+
let (symbol, enclosing_symbol, is_inherent_impl) =
144+
if let Some(TokenSymbols { symbol, enclosing_symbol, is_inherent_impl }) =
131145
symbol_generator.token_symbols(id, token)
132146
{
133-
(symbol, enclosing_symbol)
147+
(symbol, enclosing_symbol, is_inherent_impl)
134148
} else {
135-
("".to_owned(), None)
149+
("".to_owned(), None, false)
136150
};
137151

138152
if !symbol.is_empty() {
@@ -144,17 +158,20 @@ impl flags::Scip {
144158
if token_ids_emitted.insert(id) {
145159
// token_ids_emitted does deduplication. This checks that this results
146160
// in unique emitted symbols, as otherwise references are ambiguous.
147-
record_error_if_symbol_already_used(
161+
let should_emit = record_error_if_symbol_already_used(
148162
symbol.clone(),
163+
is_inherent_impl,
149164
relative_path.as_str(),
150165
&line_index,
151166
text_range,
152167
);
153-
symbols.push(compute_symbol_info(
154-
symbol.clone(),
155-
enclosing_symbol,
156-
token,
157-
));
168+
if should_emit {
169+
symbols.push(compute_symbol_info(
170+
symbol.clone(),
171+
enclosing_symbol,
172+
token,
173+
));
174+
}
158175
}
159176
} else {
160177
token_ids_referenced.insert(id);
@@ -227,12 +244,13 @@ impl flags::Scip {
227244
continue;
228245
}
229246

230-
let TokenSymbols { symbol, enclosing_symbol } = symbol_generator
247+
let TokenSymbols { symbol, enclosing_symbol, .. } = symbol_generator
231248
.token_symbols(id, token)
232249
.expect("To have been referenced, the symbol must be in the cache.");
233250

234251
record_error_if_symbol_already_used(
235252
symbol.clone(),
253+
false,
236254
relative_path.as_str(),
237255
&line_index,
238256
text_range,
@@ -395,6 +413,9 @@ struct TokenSymbols {
395413
symbol: String,
396414
/// Definition that contains this one. Only set when `symbol` is local.
397415
enclosing_symbol: Option<String>,
416+
/// True if this symbol is for an inherent impl. This is used to only emit `SymbolInformation`
417+
/// for a struct's first inherent impl, since their symbol names are not disambiguated.
418+
is_inherent_impl: bool,
398419
}
399420

400421
struct SymbolGenerator {
@@ -421,6 +442,14 @@ impl SymbolGenerator {
421442
MonikerResult::Moniker(moniker) => TokenSymbols {
422443
symbol: scip::symbol::format_symbol(moniker_to_symbol(moniker)),
423444
enclosing_symbol: None,
445+
is_inherent_impl: moniker
446+
.identifier
447+
.description
448+
.get(moniker.identifier.description.len() - 2)
449+
.map_or(false, |descriptor| {
450+
descriptor.desc == MonikerDescriptorKind::Type
451+
&& descriptor.name == "impl"
452+
}),
424453
},
425454
MonikerResult::Local { enclosing_moniker } => {
426455
let local_symbol = scip::types::Symbol::new_local(local_count);
@@ -431,6 +460,7 @@ impl SymbolGenerator {
431460
.as_ref()
432461
.map(moniker_to_symbol)
433462
.map(scip::symbol::format_symbol),
463+
is_inherent_impl: false,
434464
}
435465
}
436466
})

0 commit comments

Comments
 (0)