Skip to content

Commit fe0a85c

Browse files
committed
Resolve implicit format args in syntax highlighting
1 parent d2cd300 commit fe0a85c

File tree

9 files changed

+136
-74
lines changed

9 files changed

+136
-74
lines changed

crates/hir/src/semantics.rs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -403,17 +403,29 @@ impl<'db> SemanticsImpl<'db> {
403403
)
404404
}
405405

406-
pub fn resolve_offset_in_format_args(
406+
pub fn as_format_args_parts(
407407
&self,
408-
string: ast::String,
409-
offset: TextSize,
410-
) -> Option<(TextRange, Option<PathResolution>)> {
411-
debug_assert!(offset <= string.syntax().text_range().len());
412-
let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?;
413-
let format_args = ast::FormatArgsExpr::cast(literal.parent()?)?;
414-
let source_analyzer = &self.analyze_no_infer(format_args.syntax())?;
415-
let format_args = self.wrap_node_infile(format_args);
416-
source_analyzer.resolve_offset_in_format_args(self.db, format_args.as_ref(), offset)
408+
string: &ast::String,
409+
) -> Option<Vec<(TextRange, Option<PathResolution>)>> {
410+
if let Some(quote) = string.open_quote_text_range() {
411+
return self
412+
.descend_into_macros(DescendPreference::SameText, string.syntax().clone())
413+
.into_iter()
414+
.find_map(|token| {
415+
let string = ast::String::cast(token)?;
416+
let literal =
417+
string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?;
418+
let format_args = ast::FormatArgsExpr::cast(literal.parent()?)?;
419+
let source_analyzer = self.analyze_no_infer(format_args.syntax())?;
420+
let format_args = self.wrap_node_infile(format_args);
421+
let res = source_analyzer
422+
.as_format_args_parts(self.db, format_args.as_ref())?
423+
.map(|(range, res)| (range + quote.end(), res))
424+
.collect();
425+
Some(res)
426+
});
427+
}
428+
None
417429
}
418430

419431
pub fn check_for_format_args_template(
@@ -438,6 +450,19 @@ impl<'db> SemanticsImpl<'db> {
438450
None
439451
}
440452

453+
fn resolve_offset_in_format_args(
454+
&self,
455+
string: ast::String,
456+
offset: TextSize,
457+
) -> Option<(TextRange, Option<PathResolution>)> {
458+
debug_assert!(offset <= string.syntax().text_range().len());
459+
let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?;
460+
let format_args = ast::FormatArgsExpr::cast(literal.parent()?)?;
461+
let source_analyzer = &self.analyze_no_infer(format_args.syntax())?;
462+
let format_args = self.wrap_node_infile(format_args);
463+
source_analyzer.resolve_offset_in_format_args(self.db, format_args.as_ref(), offset)
464+
}
465+
441466
/// Maps a node down by mapping its first and last token down.
442467
pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
443468
// This might not be the correct way to do this, but it works for now

crates/hir/src/source_analyzer.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,29 @@ impl SourceAnalyzer {
843843
})
844844
}
845845

846+
pub(crate) fn as_format_args_parts<'a>(
847+
&'a self,
848+
db: &'a dyn HirDatabase,
849+
format_args: InFile<&ast::FormatArgsExpr>,
850+
) -> Option<impl Iterator<Item = (TextRange, Option<PathResolution>)> + 'a> {
851+
Some(self.body_source_map()?.implicit_format_args(format_args)?.iter().map(
852+
move |(range, name)| {
853+
(
854+
*range,
855+
resolve_hir_value_path(
856+
db,
857+
&self.resolver,
858+
self.resolver.body_owner(),
859+
&Path::from_known_path_with_no_generic(ModPath::from_segments(
860+
PathKind::Plain,
861+
Some(name.clone()),
862+
)),
863+
),
864+
)
865+
},
866+
))
867+
}
868+
846869
fn resolve_impl_method_or_trait_def(
847870
&self,
848871
db: &dyn HirDatabase,

crates/ide/src/syntax_highlighting.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ fn traverse(
440440
{
441441
continue;
442442
}
443-
highlight_format_string(hl, &string, &expanded_string, range);
443+
highlight_format_string(hl, sema, krate, &string, &expanded_string, range);
444444

445445
if !string.is_raw() {
446446
highlight_escape_string(hl, &string, range.start());

crates/ide/src/syntax_highlighting/format.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
//! Syntax highlighting for format macro strings.
22
use ide_db::{
3+
defs::Definition,
34
syntax_helpers::format_string::{is_format_string, lex_format_specifiers, FormatSpecifier},
45
SymbolKind,
56
};
67
use syntax::{ast, TextRange};
78

8-
use crate::{syntax_highlighting::highlights::Highlights, HlRange, HlTag};
9+
use crate::{
10+
syntax_highlighting::{highlight::highlight_def, highlights::Highlights},
11+
HlRange, HlTag,
12+
};
913

1014
pub(super) fn highlight_format_string(
1115
stack: &mut Highlights,
16+
sema: &hir::Semantics<'_, ide_db::RootDatabase>,
17+
krate: hir::Crate,
1218
string: &ast::String,
1319
expanded_string: &ast::String,
1420
range: TextRange,
@@ -27,6 +33,18 @@ pub(super) fn highlight_format_string(
2733
});
2834
}
2935
});
36+
37+
if let Some(parts) = sema.as_format_args_parts(string) {
38+
parts.into_iter().for_each(|(range, res)| {
39+
if let Some(res) = res {
40+
stack.add(HlRange {
41+
range,
42+
highlight: highlight_def(sema, krate, Definition::from(res)),
43+
binding_hash: None,
44+
})
45+
}
46+
})
47+
}
3048
}
3149

3250
fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HlTag> {

crates/ide/src/syntax_highlighting/highlight.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 {
348348
hash((name, shadow_count))
349349
}
350350

351-
fn highlight_def(
351+
pub(super) fn highlight_def(
352352
sema: &Semantics<'_, RootDatabase>,
353353
krate: hir::Crate,
354354
def: Definition,

crates/ide/src/syntax_highlighting/test_data/highlight_macros.html

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,17 +90,11 @@
9090
<span class="brace">}</span>
9191
<span class="brace">}</span>
9292

93-
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
94-
<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">concat</span> <span class="brace">{</span><span class="brace">}</span>
95-
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
96-
<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">include</span> <span class="brace">{</span><span class="brace">}</span>
97-
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
98-
<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">format_args</span> <span class="brace">{</span><span class="brace">}</span>
9993

100-
<span class="macro">include</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">concat</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"foo/"</span><span class="comma macro">,</span> <span class="string_literal macro">"foo.rs"</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
94+
<span class="macro default_library library">include</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">concat</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"foo/"</span><span class="comma macro">,</span> <span class="string_literal macro">"foo.rs"</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
10195

10296
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
103-
<span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
97+
<span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
10498
<span class="macro">dont_color_me_braces</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
10599
<span class="macro">noop</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro macro">noop</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
106100
<span class="brace">}</span>

0 commit comments

Comments
 (0)