mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-11-18 19:21:38 +00:00
Properly implement might_be_inside_macro_call() using semantic information instead of syntactical hacks
And rename it to `is_inside_macro_call()` accordingly.
This commit is contained in:
parent
1511c5b7fd
commit
87529e8631
9 changed files with 125 additions and 85 deletions
|
|
@ -8,8 +8,8 @@ use std::{iter, ops::ControlFlow};
|
|||
|
||||
use base_db::RootQueryDb as _;
|
||||
use hir::{
|
||||
DisplayTarget, HasAttrs, Local, ModuleDef, ModuleSource, Name, PathResolution, ScopeDef,
|
||||
Semantics, SemanticsScope, Symbol, Type, TypeInfo,
|
||||
DisplayTarget, HasAttrs, InFile, Local, ModuleDef, ModuleSource, Name, PathResolution,
|
||||
ScopeDef, Semantics, SemanticsScope, Symbol, Type, TypeInfo,
|
||||
};
|
||||
use ide_db::{
|
||||
FilePosition, FxHashMap, FxHashSet, RootDatabase, famous_defs::FamousDefs,
|
||||
|
|
@ -751,7 +751,7 @@ impl<'a> CompletionContext<'a> {
|
|||
original_offset,
|
||||
} = expand_and_analyze(
|
||||
&sema,
|
||||
original_file.syntax().clone(),
|
||||
InFile::new(editioned_file_id.into(), original_file.syntax().clone()),
|
||||
file_with_fake_ident.syntax().clone(),
|
||||
offset,
|
||||
&original_token,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Module responsible for analyzing the code surrounding the cursor for completion.
|
||||
use std::iter;
|
||||
|
||||
use hir::{ExpandResult, Semantics, Type, TypeInfo, Variant};
|
||||
use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant};
|
||||
use ide_db::{RootDatabase, active_parameter::ActiveParameter};
|
||||
use itertools::Either;
|
||||
use syntax::{
|
||||
|
|
@ -50,7 +50,7 @@ pub(super) struct AnalysisResult {
|
|||
|
||||
pub(super) fn expand_and_analyze(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
original_file: SyntaxNode,
|
||||
original_file: InFile<SyntaxNode>,
|
||||
speculative_file: SyntaxNode,
|
||||
offset: TextSize,
|
||||
original_token: &SyntaxToken,
|
||||
|
|
@ -72,7 +72,7 @@ pub(super) fn expand_and_analyze(
|
|||
relative_offset,
|
||||
)
|
||||
.unwrap_or(ExpansionResult {
|
||||
original_file,
|
||||
original_file: original_file.value,
|
||||
speculative_file,
|
||||
original_offset: offset,
|
||||
speculative_offset: fake_ident_token.text_range().start(),
|
||||
|
|
@ -125,7 +125,7 @@ fn token_at_offset_ignore_whitespace(file: &SyntaxNode, offset: TextSize) -> Opt
|
|||
/// the best we can do.
|
||||
fn expand_maybe_stop(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
original_file: SyntaxNode,
|
||||
original_file: InFile<SyntaxNode>,
|
||||
speculative_file: SyntaxNode,
|
||||
original_offset: TextSize,
|
||||
fake_ident_token: SyntaxToken,
|
||||
|
|
@ -142,17 +142,16 @@ fn expand_maybe_stop(
|
|||
return result;
|
||||
}
|
||||
|
||||
// This needs to come after the recursive call, because our "inside macro" detection is subtly wrong
|
||||
// with regard to attribute macros named `test` that are not std's test. So hopefully we will expand
|
||||
// them successfully above and be able to analyze.
|
||||
// Left biased since there may already be an identifier token there, and we appended to it.
|
||||
if !sema.might_be_inside_macro_call(&fake_ident_token)
|
||||
&& token_at_offset_ignore_whitespace(&original_file, original_offset + relative_offset)
|
||||
.is_some_and(|original_token| !sema.might_be_inside_macro_call(&original_token))
|
||||
// We can't check whether the fake expansion is inside macro call, because that requires semantic info.
|
||||
// But hopefully checking just the real one should be enough.
|
||||
if token_at_offset_ignore_whitespace(&original_file.value, original_offset + relative_offset)
|
||||
.is_some_and(|original_token| {
|
||||
!sema.is_inside_macro_call(original_file.with_value(&original_token))
|
||||
})
|
||||
{
|
||||
// Recursion base case.
|
||||
Some(ExpansionResult {
|
||||
original_file,
|
||||
original_file: original_file.value,
|
||||
speculative_file,
|
||||
original_offset,
|
||||
speculative_offset: fake_ident_token.text_range().start(),
|
||||
|
|
@ -166,7 +165,7 @@ fn expand_maybe_stop(
|
|||
|
||||
fn expand(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
original_file: SyntaxNode,
|
||||
original_file: InFile<SyntaxNode>,
|
||||
speculative_file: SyntaxNode,
|
||||
original_offset: TextSize,
|
||||
fake_ident_token: SyntaxToken,
|
||||
|
|
@ -176,7 +175,7 @@ fn expand(
|
|||
|
||||
let parent_item =
|
||||
|item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
|
||||
let original_node = token_at_offset_ignore_whitespace(&original_file, original_offset)
|
||||
let original_node = token_at_offset_ignore_whitespace(&original_file.value, original_offset)
|
||||
.and_then(|token| token.parent_ancestors().find_map(ast::Item::cast));
|
||||
let ancestor_items = iter::successors(
|
||||
Option::zip(
|
||||
|
|
@ -249,7 +248,7 @@ fn expand(
|
|||
}
|
||||
|
||||
// No attributes have been expanded, so look for macro_call! token trees or derive token trees
|
||||
let orig_tt = ancestors_at_offset(&original_file, original_offset)
|
||||
let orig_tt = ancestors_at_offset(&original_file.value, original_offset)
|
||||
.map_while(Either::<ast::TokenTree, ast::Meta>::cast)
|
||||
.last()?;
|
||||
let spec_tt = ancestors_at_offset(&speculative_file, fake_ident_token.text_range().start())
|
||||
|
|
@ -292,7 +291,7 @@ fn expand(
|
|||
fake_mapped_tokens.into_iter().min_by_key(|(_, rank)| *rank)
|
||||
{
|
||||
return Some(ExpansionResult {
|
||||
original_file,
|
||||
original_file: original_file.value,
|
||||
speculative_file,
|
||||
original_offset,
|
||||
speculative_offset: fake_ident_token.text_range().start(),
|
||||
|
|
@ -349,7 +348,7 @@ fn expand(
|
|||
}
|
||||
let result = expand_maybe_stop(
|
||||
sema,
|
||||
actual_expansion.clone(),
|
||||
InFile::new(file.into(), actual_expansion.clone()),
|
||||
fake_expansion.clone(),
|
||||
new_offset,
|
||||
fake_mapped_token,
|
||||
|
|
|
|||
|
|
@ -2111,6 +2111,56 @@ fn foo() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cfg_attr_attr_macro() {
|
||||
check(
|
||||
r#"
|
||||
//- proc_macros: identity
|
||||
#[cfg_attr(test, proc_macros::identity)]
|
||||
fn foo() {
|
||||
$0
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() fn()
|
||||
md proc_macros
|
||||
bt u32 u32
|
||||
kw async
|
||||
kw const
|
||||
kw crate::
|
||||
kw enum
|
||||
kw extern
|
||||
kw false
|
||||
kw fn
|
||||
kw for
|
||||
kw if
|
||||
kw if let
|
||||
kw impl
|
||||
kw impl for
|
||||
kw let
|
||||
kw letm
|
||||
kw loop
|
||||
kw match
|
||||
kw mod
|
||||
kw return
|
||||
kw self::
|
||||
kw static
|
||||
kw struct
|
||||
kw trait
|
||||
kw true
|
||||
kw type
|
||||
kw union
|
||||
kw unsafe
|
||||
kw use
|
||||
kw while
|
||||
kw while let
|
||||
sn macro_rules
|
||||
sn pd
|
||||
sn ppd
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn escaped_label() {
|
||||
check(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue