Skip to content

Commit

Permalink
Resolve implicit format args in syntax highlighting
Browse files Browse the repository at this point in the history
  • Loading branch information
Veykril committed Dec 5, 2023
1 parent 8a7958d commit ba47b36
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 74 deletions.
45 changes: 35 additions & 10 deletions crates/hir/src/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,17 +403,29 @@ impl<'db> SemanticsImpl<'db> {
)
}

pub fn resolve_offset_in_format_args(
pub fn as_format_args_parts(
&self,
string: ast::String,
offset: TextSize,
) -> Option<(TextRange, Option<PathResolution>)> {
debug_assert!(offset <= string.syntax().text_range().len());
let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?;
let format_args = ast::FormatArgsExpr::cast(literal.parent()?)?;
let source_analyzer = &self.analyze_no_infer(format_args.syntax())?;
let format_args = self.wrap_node_infile(format_args);
source_analyzer.resolve_offset_in_format_args(self.db, format_args.as_ref(), offset)
string: &ast::String,
) -> Option<Vec<(TextRange, Option<PathResolution>)>> {
if let Some(quote) = string.open_quote_text_range() {
return self
.descend_into_macros(DescendPreference::SameText, string.syntax().clone())
.into_iter()
.find_map(|token| {
let string = ast::String::cast(token)?;
let literal =
string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?;
let format_args = ast::FormatArgsExpr::cast(literal.parent()?)?;
let source_analyzer = self.analyze_no_infer(format_args.syntax())?;
let format_args = self.wrap_node_infile(format_args);
let res = source_analyzer
.as_format_args_parts(self.db, format_args.as_ref())?
.map(|(range, res)| (range + quote.end(), res))
.collect();
Some(res)
});
}
None
}

pub fn check_for_format_args_template(
Expand All @@ -438,6 +450,19 @@ impl<'db> SemanticsImpl<'db> {
None
}

fn resolve_offset_in_format_args(
&self,
string: ast::String,
offset: TextSize,
) -> Option<(TextRange, Option<PathResolution>)> {
debug_assert!(offset <= string.syntax().text_range().len());
let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?;
let format_args = ast::FormatArgsExpr::cast(literal.parent()?)?;
let source_analyzer = &self.analyze_no_infer(format_args.syntax())?;
let format_args = self.wrap_node_infile(format_args);
source_analyzer.resolve_offset_in_format_args(self.db, format_args.as_ref(), offset)
}

/// Maps a node down by mapping its first and last token down.
pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
// This might not be the correct way to do this, but it works for now
Expand Down
23 changes: 23 additions & 0 deletions crates/hir/src/source_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,29 @@ impl SourceAnalyzer {
})
}

pub(crate) fn as_format_args_parts<'a>(
&'a self,
db: &'a dyn HirDatabase,
format_args: InFile<&ast::FormatArgsExpr>,
) -> Option<impl Iterator<Item = (TextRange, Option<PathResolution>)> + 'a> {
Some(self.body_source_map()?.implicit_format_args(format_args)?.iter().map(
move |(range, name)| {
(
*range,
resolve_hir_value_path(
db,
&self.resolver,
self.resolver.body_owner(),
&Path::from_known_path_with_no_generic(ModPath::from_segments(
PathKind::Plain,
Some(name.clone()),
)),
),
)
},
))
}

fn resolve_impl_method_or_trait_def(
&self,
db: &dyn HirDatabase,
Expand Down
2 changes: 1 addition & 1 deletion crates/ide/src/syntax_highlighting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ fn traverse(
{
continue;
}
highlight_format_string(hl, &string, &expanded_string, range);
highlight_format_string(hl, sema, krate, &string, &expanded_string, range);

if !string.is_raw() {
highlight_escape_string(hl, &string, range.start());
Expand Down
20 changes: 19 additions & 1 deletion crates/ide/src/syntax_highlighting/format.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
//! Syntax highlighting for format macro strings.
use ide_db::{
defs::Definition,
syntax_helpers::format_string::{is_format_string, lex_format_specifiers, FormatSpecifier},
SymbolKind,
};
use syntax::{ast, TextRange};

use crate::{syntax_highlighting::highlights::Highlights, HlRange, HlTag};
use crate::{
syntax_highlighting::{highlight::highlight_def, highlights::Highlights},
HlRange, HlTag,
};

pub(super) fn highlight_format_string(
stack: &mut Highlights,
sema: &hir::Semantics<'_, ide_db::RootDatabase>,
krate: hir::Crate,
string: &ast::String,
expanded_string: &ast::String,
range: TextRange,
Expand All @@ -27,6 +33,18 @@ pub(super) fn highlight_format_string(
});
}
});

if let Some(parts) = sema.as_format_args_parts(string) {
parts.into_iter().for_each(|(range, res)| {
if let Some(res) = res {
stack.add(HlRange {
range,
highlight: highlight_def(sema, krate, Definition::from(res)),
binding_hash: None,
})
}
})
}
}

fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HlTag> {
Expand Down
2 changes: 1 addition & 1 deletion crates/ide/src/syntax_highlighting/highlight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 {
hash((name, shadow_count))
}

fn highlight_def(
pub(super) fn highlight_def(
sema: &Semantics<'_, RootDatabase>,
krate: hir::Crate,
def: Definition,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,11 @@
<span class="brace">}</span>
<span class="brace">}</span>

<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>
<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>
<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>
<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>
<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>
<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>

<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>
<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>

<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
<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>
<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>
<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>
<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>
<span class="brace">}</span>
Expand Down
Loading

0 comments on commit ba47b36

Please sign in to comment.