Skip to content

Commit 8285fc6

Browse files
authored
refactor(ide): centralize semantic target resolution (#281)
2 parents f65a6f0 + 2020476 commit 8285fc6

16 files changed

Lines changed: 812 additions & 360 deletions

File tree

crates/ide/src/document_highlight.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::{
1111
self, ReferenceCategory, ReferencesConfig,
1212
search::{ReferencesCtx, SearchScope},
1313
},
14+
semantic_target::{SemanticTarget, TargetIntent, resolve_semantic_target},
1415
};
1516

1617
#[derive(Debug, Clone)]
@@ -32,16 +33,11 @@ pub(crate) fn document_highlight(
3233
let sema = Semantics::new(db);
3334
let hir_file_id = file_id.into();
3435
let parsed_file = sema.parse_file(file_id);
35-
let root = parsed_file.root()?;
36-
let tokens = crate::source_targets::source_target_at_offset(
37-
db,
38-
file_id,
39-
root,
40-
offset,
41-
token_precedence,
42-
)?
43-
.resolved()?
44-
.into_tokens();
36+
let target = resolve_semantic_target(db, file_id, offset, parsed_file.root(), token_precedence);
37+
let SemanticTarget::Source(target) = target.unique_for_intent(TargetIntent::Highlight)? else {
38+
return None;
39+
};
40+
let tokens = target.into_tokens();
4541
let highlights = tokens
4642
.into_iter()
4743
.filter_map(|token| highlight_for_token(&sema, file_id, hir_file_id, token, config.clone()))

crates/ide/src/goto_declaration.rs

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
use hir::semantics::Semantics;
1+
use hir::{file::HirFileId, semantics::Semantics};
22
use itertools::Itertools;
3+
use utils::line_index::covering_range;
34

45
use crate::{
56
FilePosition, RangeInfo,
67
db::root_db::RootDb,
78
definitions::DefinitionClass,
89
goto_definition,
910
navigation_target::{NavTarget, ToNav},
11+
semantic_target::{SemanticTarget, TargetIntent, resolve_semantic_target},
12+
source_targets::SourceTarget,
1013
};
1114

1215
pub(crate) fn goto_declaration(
@@ -16,20 +19,53 @@ pub(crate) fn goto_declaration(
1619
let sema = Semantics::new(db);
1720
let hir_file_id = file_id.into();
1821
let parsed_file = sema.parse_file(file_id);
19-
let root = parsed_file.root()?;
20-
let target = crate::source_targets::source_target_at_offset(
22+
let target = resolve_semantic_target(
2123
db,
2224
file_id,
23-
root,
2425
offset,
26+
parsed_file.root(),
2527
goto_definition::token_precedence,
26-
)?
27-
.resolved()?;
28+
);
29+
render_declaration_target(
30+
db,
31+
hir_file_id,
32+
&sema,
33+
target.targets_for_intent(TargetIntent::Navigate),
34+
)
35+
}
36+
37+
fn render_declaration_target(
38+
db: &RootDb,
39+
hir_file_id: HirFileId,
40+
sema: &Semantics<RootDb>,
41+
targets: Vec<SemanticTarget<'_>>,
42+
) -> Option<RangeInfo<Vec<NavTarget>>> {
43+
let mut ranges = Vec::new();
44+
let mut navs = Vec::new();
45+
for target in targets {
46+
let SemanticTarget::Source(target) = target else {
47+
return None;
48+
};
49+
let target = render_source_declaration_target(db, hir_file_id, sema, target)?;
50+
ranges.push(target.range);
51+
navs.extend(target.info);
52+
}
53+
54+
let range = covering_range(&ranges)?;
55+
Some(RangeInfo::new(range, navs.into_iter().unique().collect()))
56+
}
57+
58+
fn render_source_declaration_target(
59+
db: &RootDb,
60+
hir_file_id: HirFileId,
61+
sema: &Semantics<RootDb>,
62+
target: SourceTarget<'_>,
63+
) -> Option<RangeInfo<Vec<NavTarget>>> {
2864
let (range, tokens) = target.into_parts();
2965

3066
let origins = tokens
3167
.into_iter()
32-
.filter_map(|token| match DefinitionClass::resolve(&sema, hir_file_id, token)? {
68+
.filter_map(|token| match DefinitionClass::resolve(sema, hir_file_id, token)? {
3369
DefinitionClass::Definition(definition) => {
3470
Some(definition.declaration_origins().into_iter().collect_vec())
3571
}

crates/ide/src/goto_definition.rs

Lines changed: 33 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2,84 +2,64 @@ use hir::{
22
base_db::source_db::SourceDb,
33
container::InFile,
44
file::HirFileId,
5-
preproc::{
6-
IncludeDirective, IncludeTarget, MacroDefinition, MacroParamDefinition,
7-
MacroParamReferenceDefinitions, MacroReferenceDefinitions, include_directives_at,
8-
macro_definition_at, macro_param_definition_at, macro_param_reference_definitions_at,
9-
macro_reference_definitions_at,
10-
},
5+
preproc::{IncludeDirective, IncludeTarget, MacroDefinition, MacroParamDefinition},
116
semantics::Semantics,
127
};
138
use itertools::Itertools;
149
use syntax::{
15-
SyntaxNode, SyntaxTokenWithParent, TokenKind,
10+
SyntaxTokenWithParent, TokenKind,
1611
token::{TokenKindExt, pair_token},
1712
};
18-
use utils::line_index::{TextRange, TextSize};
13+
use utils::line_index::{TextRange, TextSize, covering_range};
1914
use vfs::FileId;
2015

2116
use crate::{
2217
FilePosition, RangeInfo,
2318
db::root_db::RootDb,
2419
definitions::DefinitionClass,
2520
navigation_target::{NavTarget, ToNav},
26-
source_targets::{SourceTarget, source_target_at_offset},
21+
semantic_target::{
22+
PreprocMacroTarget, SemanticTarget, TargetIntent, TargetResolution, resolve_semantic_target,
23+
},
24+
source_targets::SourceTarget,
2725
};
2826

29-
enum DefinitionTarget<'tree> {
30-
Preproc(Box<PreprocDefinitionTarget>),
31-
Include(Vec<IncludeDirective>),
32-
Source(SourceTarget<'tree>),
33-
}
34-
35-
enum PreprocDefinitionTarget {
36-
ParamDefinition(MacroParamDefinition),
37-
ParamReference(MacroParamReferenceDefinitions),
38-
Definition(MacroDefinition),
39-
Reference(MacroReferenceDefinitions),
40-
}
41-
4227
pub(crate) fn goto_definition(
4328
db: &RootDb,
4429
FilePosition { file_id, offset }: FilePosition,
4530
) -> Option<RangeInfo<Vec<NavTarget>>> {
4631
let sema = Semantics::new(db);
4732
let parsed_file = sema.parse_file(file_id);
48-
let target = dispatch_definition_target(db, file_id, offset, parsed_file.root())?;
33+
let target = resolve_semantic_target(db, file_id, offset, parsed_file.root(), token_precedence);
4934
render_definition_target(db, file_id, &sema, target)
5035
}
5136

52-
fn dispatch_definition_target<'tree>(
53-
db: &RootDb,
54-
file_id: FileId,
55-
offset: TextSize,
56-
root: Option<SyntaxNode<'tree>>,
57-
) -> Option<DefinitionTarget<'tree>> {
58-
if let Some(target) = dispatch_preproc_definition_target(db, file_id, offset) {
59-
return Some(DefinitionTarget::Preproc(Box::new(target)));
60-
}
61-
if let Some(includes) = dispatch_include_definition_target(db, file_id, offset) {
62-
return Some(DefinitionTarget::Include(includes));
63-
}
64-
let root = root?;
65-
let target =
66-
source_target_at_offset(db, file_id, root, offset, token_precedence)?.resolved()?;
67-
Some(DefinitionTarget::Source(target))
68-
}
69-
7037
fn render_definition_target(
7138
db: &RootDb,
7239
file_id: FileId,
7340
sema: &Semantics<RootDb>,
74-
target: DefinitionTarget<'_>,
41+
target: TargetResolution<'_>,
7542
) -> Option<RangeInfo<Vec<NavTarget>>> {
76-
match target {
77-
DefinitionTarget::Preproc(target) => render_preproc_definition_target(*target),
78-
DefinitionTarget::Include(includes) => render_include_definition_target(db, includes),
79-
DefinitionTarget::Source(target) => {
80-
render_source_definition_target(db, file_id, sema, target)
81-
}
43+
let mut ranges = Vec::new();
44+
let mut navs = Vec::new();
45+
for target in target.targets_for_intent(TargetIntent::Navigate) {
46+
let target = match target {
47+
SemanticTarget::PreprocMacro(target) => render_preproc_definition_target(target),
48+
SemanticTarget::Include(includes) => render_include_definition_target(db, includes),
49+
SemanticTarget::Source(target) => {
50+
render_source_definition_target(db, file_id, sema, target)
51+
}
52+
}?;
53+
ranges.push(target.range);
54+
navs.extend(target.info);
55+
}
56+
57+
if navs.is_empty() {
58+
return None;
8259
}
60+
61+
let range = covering_range(&ranges)?;
62+
Some(RangeInfo::new(range, navs.into_iter().unique().collect()))
8363
}
8464

8565
fn render_source_definition_target(
@@ -120,47 +100,23 @@ fn nav_targets_for_token(
120100
})
121101
}
122102

123-
fn dispatch_preproc_definition_target(
124-
db: &RootDb,
125-
file_id: FileId,
126-
offset: TextSize,
127-
) -> Option<PreprocDefinitionTarget> {
128-
if let Ok(Some(definition)) = macro_param_definition_at(db, file_id, offset) {
129-
return Some(PreprocDefinitionTarget::ParamDefinition(definition));
130-
}
131-
132-
if let Ok(Some(resolution)) = macro_param_reference_definitions_at(db, file_id, offset) {
133-
return Some(PreprocDefinitionTarget::ParamReference(resolution));
134-
}
135-
136-
if let Ok(Some(definition)) = macro_definition_at(db, file_id, offset) {
137-
return Some(PreprocDefinitionTarget::Definition(definition));
138-
}
139-
140-
if let Ok(Some(resolution)) = macro_reference_definitions_at(db, file_id, offset) {
141-
return Some(PreprocDefinitionTarget::Reference(resolution));
142-
}
143-
144-
None
145-
}
146-
147103
fn render_preproc_definition_target(
148-
target: PreprocDefinitionTarget,
104+
target: PreprocMacroTarget,
149105
) -> Option<RangeInfo<Vec<NavTarget>>> {
150106
match target {
151-
PreprocDefinitionTarget::ParamDefinition(definition) => {
107+
PreprocMacroTarget::ParamDefinition(definition) => {
152108
Some(RangeInfo::new(definition.range, vec![macro_param_nav_target(definition)]))
153109
}
154-
PreprocDefinitionTarget::ParamReference(resolution) => {
110+
PreprocMacroTarget::ParamReference(resolution) => {
155111
let reference_range = resolution.range;
156112
let targets =
157113
resolution.definitions.into_iter().map(macro_param_nav_target).collect_vec();
158114
(!targets.is_empty()).then_some(RangeInfo::new(reference_range, targets))
159115
}
160-
PreprocDefinitionTarget::Definition(definition) => {
116+
PreprocMacroTarget::Definition(definition) => {
161117
Some(RangeInfo::new(definition.name_range, vec![macro_nav_target(definition)]))
162118
}
163-
PreprocDefinitionTarget::Reference(resolution) => {
119+
PreprocMacroTarget::Reference(resolution) => {
164120
let reference_range = resolution.range;
165121
let targets = resolution.definitions.into_iter().map(macro_nav_target).collect_vec();
166122
(!targets.is_empty()).then_some(RangeInfo::new(reference_range, targets))
@@ -192,15 +148,6 @@ fn macro_nav_target(definition: MacroDefinition) -> NavTarget {
192148
}
193149
}
194150

195-
fn dispatch_include_definition_target(
196-
db: &RootDb,
197-
file_id: FileId,
198-
offset: TextSize,
199-
) -> Option<Vec<IncludeDirective>> {
200-
let includes = include_directives_at(db, file_id, offset).ok()?;
201-
(!includes.is_empty()).then_some(includes)
202-
}
203-
204151
fn render_include_definition_target(
205152
db: &RootDb,
206153
includes: Vec<IncludeDirective>,

0 commit comments

Comments
 (0)