mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-16 17:58:16 +00:00
Merge #8068
8068: Correctly handle `#[cfg]` on function parameters r=jonas-schievink a=jonas-schievink Fixes https://github.com/rust-analyzer/rust-analyzer/issues/5649 Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
This commit is contained in:
commit
4fa56e3ab1
7 changed files with 172 additions and 79 deletions
|
@ -9,7 +9,7 @@ use crate::{
|
||||||
attr::Attrs,
|
attr::Attrs,
|
||||||
body::Expander,
|
body::Expander,
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem},
|
item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param},
|
||||||
type_ref::{TypeBound, TypeRef},
|
type_ref::{TypeBound, TypeRef},
|
||||||
visibility::RawVisibility,
|
visibility::RawVisibility,
|
||||||
AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
|
AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
|
||||||
|
@ -36,19 +36,38 @@ impl FunctionData {
|
||||||
pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
|
pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
|
||||||
let loc = func.lookup(db);
|
let loc = func.lookup(db);
|
||||||
let krate = loc.container.module(db).krate;
|
let krate = loc.container.module(db).krate;
|
||||||
|
let crate_graph = db.crate_graph();
|
||||||
|
let cfg_options = &crate_graph[krate].cfg_options;
|
||||||
let item_tree = db.item_tree(loc.id.file_id);
|
let item_tree = db.item_tree(loc.id.file_id);
|
||||||
let func = &item_tree[loc.id.value];
|
let func = &item_tree[loc.id.value];
|
||||||
|
|
||||||
|
let enabled_params = func
|
||||||
|
.params
|
||||||
|
.clone()
|
||||||
|
.filter(|¶m| item_tree.attrs(db, krate, param.into()).is_cfg_enabled(cfg_options));
|
||||||
|
|
||||||
|
// If last cfg-enabled param is a `...` param, it's a varargs function.
|
||||||
|
let is_varargs = enabled_params
|
||||||
|
.clone()
|
||||||
|
.next_back()
|
||||||
|
.map_or(false, |param| matches!(item_tree[param], Param::Varargs));
|
||||||
|
|
||||||
Arc::new(FunctionData {
|
Arc::new(FunctionData {
|
||||||
name: func.name.clone(),
|
name: func.name.clone(),
|
||||||
params: func.params.iter().map(|id| item_tree[*id].clone()).collect(),
|
params: enabled_params
|
||||||
|
.clone()
|
||||||
|
.filter_map(|id| match &item_tree[id] {
|
||||||
|
Param::Normal(ty) => Some(item_tree[*ty].clone()),
|
||||||
|
Param::Varargs => None,
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
ret_type: item_tree[func.ret_type].clone(),
|
ret_type: item_tree[func.ret_type].clone(),
|
||||||
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
|
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
|
||||||
has_self_param: func.has_self_param,
|
has_self_param: func.has_self_param,
|
||||||
has_body: func.has_body,
|
has_body: func.has_body,
|
||||||
qualifier: func.qualifier.clone(),
|
qualifier: func.qualifier.clone(),
|
||||||
is_in_extern_block: func.is_in_extern_block,
|
is_in_extern_block: func.is_in_extern_block,
|
||||||
is_varargs: func.is_varargs,
|
is_varargs,
|
||||||
visibility: item_tree[func.visibility].clone(),
|
visibility: item_tree[func.visibility].clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,7 @@ impl ItemTree {
|
||||||
imports,
|
imports,
|
||||||
extern_crates,
|
extern_crates,
|
||||||
functions,
|
functions,
|
||||||
|
params,
|
||||||
structs,
|
structs,
|
||||||
fields,
|
fields,
|
||||||
unions,
|
unions,
|
||||||
|
@ -157,6 +158,7 @@ impl ItemTree {
|
||||||
imports.shrink_to_fit();
|
imports.shrink_to_fit();
|
||||||
extern_crates.shrink_to_fit();
|
extern_crates.shrink_to_fit();
|
||||||
functions.shrink_to_fit();
|
functions.shrink_to_fit();
|
||||||
|
params.shrink_to_fit();
|
||||||
structs.shrink_to_fit();
|
structs.shrink_to_fit();
|
||||||
fields.shrink_to_fit();
|
fields.shrink_to_fit();
|
||||||
unions.shrink_to_fit();
|
unions.shrink_to_fit();
|
||||||
|
@ -303,6 +305,7 @@ struct ItemTreeData {
|
||||||
imports: Arena<Import>,
|
imports: Arena<Import>,
|
||||||
extern_crates: Arena<ExternCrate>,
|
extern_crates: Arena<ExternCrate>,
|
||||||
functions: Arena<Function>,
|
functions: Arena<Function>,
|
||||||
|
params: Arena<Param>,
|
||||||
structs: Arena<Struct>,
|
structs: Arena<Struct>,
|
||||||
fields: Arena<Field>,
|
fields: Arena<Field>,
|
||||||
unions: Arena<Union>,
|
unions: Arena<Union>,
|
||||||
|
@ -334,6 +337,7 @@ pub enum AttrOwner {
|
||||||
|
|
||||||
Variant(Idx<Variant>),
|
Variant(Idx<Variant>),
|
||||||
Field(Idx<Field>),
|
Field(Idx<Field>),
|
||||||
|
Param(Idx<Param>),
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! from_attrs {
|
macro_rules! from_attrs {
|
||||||
|
@ -348,7 +352,7 @@ macro_rules! from_attrs {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>));
|
from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>), Param(Idx<Param>));
|
||||||
|
|
||||||
/// Trait implemented by all item nodes in the item tree.
|
/// Trait implemented by all item nodes in the item tree.
|
||||||
pub trait ItemTreeNode: Clone {
|
pub trait ItemTreeNode: Clone {
|
||||||
|
@ -484,7 +488,7 @@ macro_rules! impl_index {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_index!(fields: Field, variants: Variant);
|
impl_index!(fields: Field, variants: Variant, params: Param);
|
||||||
|
|
||||||
impl Index<RawVisibilityId> for ItemTree {
|
impl Index<RawVisibilityId> for ItemTree {
|
||||||
type Output = RawVisibility;
|
type Output = RawVisibility;
|
||||||
|
@ -560,12 +564,17 @@ pub struct Function {
|
||||||
/// Whether the function is located in an `extern` block (*not* whether it is an
|
/// Whether the function is located in an `extern` block (*not* whether it is an
|
||||||
/// `extern "abi" fn`).
|
/// `extern "abi" fn`).
|
||||||
pub is_in_extern_block: bool,
|
pub is_in_extern_block: bool,
|
||||||
pub params: Box<[Idx<TypeRef>]>,
|
pub params: IdRange<Param>,
|
||||||
pub is_varargs: bool,
|
|
||||||
pub ret_type: Idx<TypeRef>,
|
pub ret_type: Idx<TypeRef>,
|
||||||
pub ast_id: FileAstId<ast::Fn>,
|
pub ast_id: FileAstId<ast::Fn>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub enum Param {
|
||||||
|
Normal(Idx<TypeRef>),
|
||||||
|
Varargs,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct FunctionQualifier {
|
pub struct FunctionQualifier {
|
||||||
pub is_default: bool,
|
pub is_default: bool,
|
||||||
|
@ -796,6 +805,7 @@ pub struct Variant {
|
||||||
pub fields: Fields,
|
pub fields: Fields,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A range of densely allocated ItemTree IDs.
|
||||||
pub struct IdRange<T> {
|
pub struct IdRange<T> {
|
||||||
range: Range<u32>,
|
range: Range<u32>,
|
||||||
_p: PhantomData<T>,
|
_p: PhantomData<T>,
|
||||||
|
@ -814,6 +824,12 @@ impl<T> Iterator for IdRange<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> DoubleEndedIterator for IdRange<T> {
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
self.range.next_back().map(|raw| Idx::from_raw(raw.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> fmt::Debug for IdRange<T> {
|
impl<T> fmt::Debug for IdRange<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_tuple(&format!("IdRange::<{}>", type_name::<T>())).field(&self.range).finish()
|
f.debug_tuple(&format!("IdRange::<{}>", type_name::<T>())).field(&self.range).finish()
|
||||||
|
|
|
@ -333,8 +333,8 @@ impl Ctx {
|
||||||
let visibility = self.lower_visibility(func);
|
let visibility = self.lower_visibility(func);
|
||||||
let name = func.name()?.as_name();
|
let name = func.name()?.as_name();
|
||||||
|
|
||||||
let mut params = Vec::new();
|
|
||||||
let mut has_self_param = false;
|
let mut has_self_param = false;
|
||||||
|
let start_param = self.next_param_idx();
|
||||||
if let Some(param_list) = func.param_list() {
|
if let Some(param_list) = func.param_list() {
|
||||||
if let Some(self_param) = param_list.self_param() {
|
if let Some(self_param) = param_list.self_param() {
|
||||||
let self_type = match self_param.ty() {
|
let self_type = match self_param.ty() {
|
||||||
|
@ -356,22 +356,25 @@ impl Ctx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
params.push(self_type);
|
let ty = self.data().type_refs.intern(self_type);
|
||||||
|
let idx = self.data().params.alloc(Param::Normal(ty));
|
||||||
|
self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene));
|
||||||
has_self_param = true;
|
has_self_param = true;
|
||||||
}
|
}
|
||||||
for param in param_list.params() {
|
for param in param_list.params() {
|
||||||
let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
|
let idx = match param.dotdotdot_token() {
|
||||||
params.push(type_ref);
|
Some(_) => self.data().params.alloc(Param::Varargs),
|
||||||
}
|
None => {
|
||||||
}
|
let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
|
||||||
let params = params.into_iter().map(|param| self.data().type_refs.intern(param)).collect();
|
let ty = self.data().type_refs.intern(type_ref);
|
||||||
|
self.data().params.alloc(Param::Normal(ty))
|
||||||
let mut is_varargs = false;
|
}
|
||||||
if let Some(params) = func.param_list() {
|
};
|
||||||
if let Some(last) = params.params().last() {
|
self.add_attrs(idx.into(), RawAttrs::new(¶m, &self.hygiene));
|
||||||
is_varargs = last.dotdotdot_token().is_some();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let end_param = self.next_param_idx();
|
||||||
|
let params = IdRange::new(start_param..end_param);
|
||||||
|
|
||||||
let ret_type = match func.ret_type().and_then(|rt| rt.ty()) {
|
let ret_type = match func.ret_type().and_then(|rt| rt.ty()) {
|
||||||
Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
|
Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
|
||||||
|
@ -419,7 +422,6 @@ impl Ctx {
|
||||||
qualifier,
|
qualifier,
|
||||||
is_in_extern_block: false,
|
is_in_extern_block: false,
|
||||||
params,
|
params,
|
||||||
is_varargs,
|
|
||||||
ret_type,
|
ret_type,
|
||||||
ast_id,
|
ast_id,
|
||||||
};
|
};
|
||||||
|
@ -682,9 +684,11 @@ impl Ctx {
|
||||||
GenericsOwner::Function(func) => {
|
GenericsOwner::Function(func) => {
|
||||||
generics.fill(&self.body_ctx, sm, node);
|
generics.fill(&self.body_ctx, sm, node);
|
||||||
// lower `impl Trait` in arguments
|
// lower `impl Trait` in arguments
|
||||||
for param in &*func.params {
|
for id in func.params.clone() {
|
||||||
let param = self.data().type_refs.lookup(*param);
|
if let Param::Normal(ty) = self.data().params[id] {
|
||||||
generics.fill_implicit_impl_trait_args(param);
|
let ty = self.data().type_refs.lookup(ty);
|
||||||
|
generics.fill_implicit_impl_trait_args(ty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GenericsOwner::Struct
|
GenericsOwner::Struct
|
||||||
|
@ -769,6 +773,11 @@ impl Ctx {
|
||||||
self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
|
self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
fn next_param_idx(&self) -> Idx<Param> {
|
||||||
|
Idx::from_raw(RawIdx::from(
|
||||||
|
self.tree.data.as_ref().map_or(0, |data| data.params.len() as u32),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn desugar_future_path(orig: TypeRef) -> Path {
|
fn desugar_future_path(orig: TypeRef) -> Path {
|
||||||
|
|
|
@ -713,4 +713,38 @@ fn main() {
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cfgd_out_fn_params() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
fn foo(#[cfg(NEVER)] x: ()) {}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl S {
|
||||||
|
fn method(#[cfg(NEVER)] self) {}
|
||||||
|
fn method2(#[cfg(NEVER)] self, arg: u8) {}
|
||||||
|
fn method3(self, #[cfg(NEVER)] arg: u8) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn fixed(fixed: u8, #[cfg(NEVER)] ...);
|
||||||
|
fn varargs(#[cfg(not(NEVER))] ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
foo();
|
||||||
|
S::method();
|
||||||
|
S::method2(0);
|
||||||
|
S::method3(S);
|
||||||
|
S.method3();
|
||||||
|
unsafe {
|
||||||
|
fixed(0);
|
||||||
|
varargs(1, 2, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,22 +41,32 @@ fn list_(p: &mut Parser, flavor: Flavor) {
|
||||||
FnDef | FnTrait | FnPointer => (T!['('], T![')']),
|
FnDef | FnTrait | FnPointer => (T!['('], T![')']),
|
||||||
};
|
};
|
||||||
|
|
||||||
let m = p.start();
|
let list_marker = p.start();
|
||||||
p.bump(bra);
|
p.bump(bra);
|
||||||
|
|
||||||
|
let mut param_marker = None;
|
||||||
if let FnDef = flavor {
|
if let FnDef = flavor {
|
||||||
// test self_param_outer_attr
|
// test self_param_outer_attr
|
||||||
// fn f(#[must_use] self) {}
|
// fn f(#[must_use] self) {}
|
||||||
let m = p.start();
|
let m = p.start();
|
||||||
attributes::outer_attrs(p);
|
attributes::outer_attrs(p);
|
||||||
opt_self_param(p, m);
|
match opt_self_param(p, m) {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(m) => param_marker = Some(m),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while !p.at(EOF) && !p.at(ket) {
|
while !p.at(EOF) && !p.at(ket) {
|
||||||
// test param_outer_arg
|
// test param_outer_arg
|
||||||
// fn f(#[attr1] pat: Type) {}
|
// fn f(#[attr1] pat: Type) {}
|
||||||
let m = p.start();
|
let m = match param_marker.take() {
|
||||||
attributes::outer_attrs(p);
|
Some(m) => m,
|
||||||
|
None => {
|
||||||
|
let m = p.start();
|
||||||
|
attributes::outer_attrs(p);
|
||||||
|
m
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if !p.at_ts(PARAM_FIRST) {
|
if !p.at_ts(PARAM_FIRST) {
|
||||||
p.error("expected value parameter");
|
p.error("expected value parameter");
|
||||||
|
@ -72,8 +82,12 @@ fn list_(p: &mut Parser, flavor: Flavor) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(m) = param_marker {
|
||||||
|
m.abandon(p);
|
||||||
|
}
|
||||||
|
|
||||||
p.expect(ket);
|
p.expect(ket);
|
||||||
m.complete(p, PARAM_LIST);
|
list_marker.complete(p, PARAM_LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST);
|
const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST);
|
||||||
|
@ -153,7 +167,7 @@ fn variadic_param(p: &mut Parser) -> bool {
|
||||||
// fn d(&'a mut self, x: i32) {}
|
// fn d(&'a mut self, x: i32) {}
|
||||||
// fn e(mut self) {}
|
// fn e(mut self) {}
|
||||||
// }
|
// }
|
||||||
fn opt_self_param(p: &mut Parser, m: Marker) {
|
fn opt_self_param(p: &mut Parser, m: Marker) -> Result<(), Marker> {
|
||||||
if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] {
|
if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] {
|
||||||
p.eat(T![mut]);
|
p.eat(T![mut]);
|
||||||
self_as_name(p);
|
self_as_name(p);
|
||||||
|
@ -176,7 +190,7 @@ fn opt_self_param(p: &mut Parser, m: Marker) {
|
||||||
| (T![&], LIFETIME_IDENT, T![self], _)
|
| (T![&], LIFETIME_IDENT, T![self], _)
|
||||||
| (T![&], LIFETIME_IDENT, T![mut], T![self])
|
| (T![&], LIFETIME_IDENT, T![mut], T![self])
|
||||||
) {
|
) {
|
||||||
return m.abandon(p);
|
return Err(m);
|
||||||
}
|
}
|
||||||
p.bump(T![&]);
|
p.bump(T![&]);
|
||||||
if p.at(LIFETIME_IDENT) {
|
if p.at(LIFETIME_IDENT) {
|
||||||
|
@ -189,6 +203,7 @@ fn opt_self_param(p: &mut Parser, m: Marker) {
|
||||||
if !p.at(T![')']) {
|
if !p.at(T![')']) {
|
||||||
p.expect(T![,]);
|
p.expect(T![,]);
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn self_as_name(p: &mut Parser) {
|
fn self_as_name(p: &mut Parser) {
|
||||||
|
|
|
@ -6,16 +6,16 @@ SOURCE_FILE@0..28
|
||||||
IDENT@3..4 "f"
|
IDENT@3..4 "f"
|
||||||
PARAM_LIST@4..24
|
PARAM_LIST@4..24
|
||||||
L_PAREN@4..5 "("
|
L_PAREN@4..5 "("
|
||||||
ATTR@5..13
|
PARAM@5..23
|
||||||
POUND@5..6 "#"
|
ATTR@5..13
|
||||||
L_BRACK@6..7 "["
|
POUND@5..6 "#"
|
||||||
PATH@7..12
|
L_BRACK@6..7 "["
|
||||||
PATH_SEGMENT@7..12
|
PATH@7..12
|
||||||
NAME_REF@7..12
|
PATH_SEGMENT@7..12
|
||||||
IDENT@7..12 "attr1"
|
NAME_REF@7..12
|
||||||
R_BRACK@12..13 "]"
|
IDENT@7..12 "attr1"
|
||||||
WHITESPACE@13..14 " "
|
R_BRACK@12..13 "]"
|
||||||
PARAM@14..23
|
WHITESPACE@13..14 " "
|
||||||
IDENT_PAT@14..17
|
IDENT_PAT@14..17
|
||||||
NAME@14..17
|
NAME@14..17
|
||||||
IDENT@14..17 "pat"
|
IDENT@14..17 "pat"
|
||||||
|
|
|
@ -6,25 +6,25 @@ SOURCE_FILE@0..519
|
||||||
IDENT@3..5 "g1"
|
IDENT@3..5 "g1"
|
||||||
PARAM_LIST@5..34
|
PARAM_LIST@5..34
|
||||||
L_PAREN@5..6 "("
|
L_PAREN@5..6 "("
|
||||||
ATTR@6..14
|
PARAM@6..33
|
||||||
POUND@6..7 "#"
|
ATTR@6..14
|
||||||
L_BRACK@7..8 "["
|
POUND@6..7 "#"
|
||||||
PATH@8..13
|
L_BRACK@7..8 "["
|
||||||
PATH_SEGMENT@8..13
|
PATH@8..13
|
||||||
NAME_REF@8..13
|
PATH_SEGMENT@8..13
|
||||||
IDENT@8..13 "attr1"
|
NAME_REF@8..13
|
||||||
R_BRACK@13..14 "]"
|
IDENT@8..13 "attr1"
|
||||||
WHITESPACE@14..15 " "
|
R_BRACK@13..14 "]"
|
||||||
ATTR@15..23
|
WHITESPACE@14..15 " "
|
||||||
POUND@15..16 "#"
|
ATTR@15..23
|
||||||
L_BRACK@16..17 "["
|
POUND@15..16 "#"
|
||||||
PATH@17..22
|
L_BRACK@16..17 "["
|
||||||
PATH_SEGMENT@17..22
|
PATH@17..22
|
||||||
NAME_REF@17..22
|
PATH_SEGMENT@17..22
|
||||||
IDENT@17..22 "attr2"
|
NAME_REF@17..22
|
||||||
R_BRACK@22..23 "]"
|
IDENT@17..22 "attr2"
|
||||||
WHITESPACE@23..24 " "
|
R_BRACK@22..23 "]"
|
||||||
PARAM@24..33
|
WHITESPACE@23..24 " "
|
||||||
IDENT_PAT@24..27
|
IDENT_PAT@24..27
|
||||||
NAME@24..27
|
NAME@24..27
|
||||||
IDENT@24..27 "pat"
|
IDENT@24..27 "pat"
|
||||||
|
@ -48,16 +48,16 @@ SOURCE_FILE@0..519
|
||||||
IDENT@41..43 "g2"
|
IDENT@41..43 "g2"
|
||||||
PARAM_LIST@43..59
|
PARAM_LIST@43..59
|
||||||
L_PAREN@43..44 "("
|
L_PAREN@43..44 "("
|
||||||
ATTR@44..52
|
PARAM@44..58
|
||||||
POUND@44..45 "#"
|
ATTR@44..52
|
||||||
L_BRACK@45..46 "["
|
POUND@44..45 "#"
|
||||||
PATH@46..51
|
L_BRACK@45..46 "["
|
||||||
PATH_SEGMENT@46..51
|
PATH@46..51
|
||||||
NAME_REF@46..51
|
PATH_SEGMENT@46..51
|
||||||
IDENT@46..51 "attr1"
|
NAME_REF@46..51
|
||||||
R_BRACK@51..52 "]"
|
IDENT@46..51 "attr1"
|
||||||
WHITESPACE@52..53 " "
|
R_BRACK@51..52 "]"
|
||||||
PARAM@53..58
|
WHITESPACE@52..53 " "
|
||||||
IDENT_PAT@53..54
|
IDENT_PAT@53..54
|
||||||
NAME@53..54
|
NAME@53..54
|
||||||
IDENT@53..54 "x"
|
IDENT@53..54 "x"
|
||||||
|
@ -203,16 +203,16 @@ SOURCE_FILE@0..519
|
||||||
IDENT@193..196 "bar"
|
IDENT@193..196 "bar"
|
||||||
PARAM_LIST@196..233
|
PARAM_LIST@196..233
|
||||||
L_PAREN@196..197 "("
|
L_PAREN@196..197 "("
|
||||||
ATTR@197..204
|
PARAM@197..211
|
||||||
POUND@197..198 "#"
|
ATTR@197..204
|
||||||
L_BRACK@198..199 "["
|
POUND@197..198 "#"
|
||||||
PATH@199..203
|
L_BRACK@198..199 "["
|
||||||
PATH_SEGMENT@199..203
|
PATH@199..203
|
||||||
NAME_REF@199..203
|
PATH_SEGMENT@199..203
|
||||||
IDENT@199..203 "attr"
|
NAME_REF@199..203
|
||||||
R_BRACK@203..204 "]"
|
IDENT@199..203 "attr"
|
||||||
WHITESPACE@204..205 " "
|
R_BRACK@203..204 "]"
|
||||||
PARAM@205..211
|
WHITESPACE@204..205 " "
|
||||||
WILDCARD_PAT@205..206
|
WILDCARD_PAT@205..206
|
||||||
UNDERSCORE@205..206 "_"
|
UNDERSCORE@205..206 "_"
|
||||||
COLON@206..207 ":"
|
COLON@206..207 ":"
|
||||||
|
|
Loading…
Reference in a new issue