Auto merge of #100082 - matthiaskrgr:rollup-ywu4iux, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #99933 (parallelize HTML checking tool) - #99958 (Improve position named arguments lint underline and formatting names) - #100008 (Update all pre-cloned submodules on startup) - #100049 (⬆️ rust-analyzer) - #100070 (Clarify Cargo.toml comments) - #100074 (rustc-docs: Be less specific about the representation of `+bundle`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
e141246cbb
59 changed files with 1104 additions and 424 deletions
|
@ -1788,6 +1788,7 @@ dependencies = [
|
|||
name = "html-checker"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rayon",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ use smallvec::SmallVec;
|
|||
|
||||
use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
|
||||
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId};
|
||||
use rustc_parse_format::Count;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
|
@ -57,26 +58,45 @@ struct PositionalNamedArg {
|
|||
replacement: Symbol,
|
||||
/// The span for the positional named argument (so the lint can point a message to it)
|
||||
positional_named_arg_span: Span,
|
||||
has_formatting: bool,
|
||||
}
|
||||
|
||||
impl PositionalNamedArg {
|
||||
/// Determines what span to replace with the name of the named argument
|
||||
fn get_span_to_replace(&self, cx: &Context<'_, '_>) -> Option<Span> {
|
||||
/// Determines:
|
||||
/// 1) span to be replaced with the name of the named argument and
|
||||
/// 2) span to be underlined for error messages
|
||||
fn get_positional_arg_spans(&self, cx: &Context<'_, '_>) -> (Option<Span>, Option<Span>) {
|
||||
if let Some(inner_span) = &self.inner_span_to_replace {
|
||||
return Some(
|
||||
cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }),
|
||||
);
|
||||
let span =
|
||||
cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end });
|
||||
(Some(span), Some(span))
|
||||
} else if self.ty == PositionalNamedArgType::Arg {
|
||||
// In the case of a named argument whose position is implicit, there will not be a span
|
||||
// to replace. Instead, we insert the name after the `{`, which is the first character
|
||||
// of arg_span.
|
||||
return cx
|
||||
.arg_spans
|
||||
.get(self.cur_piece)
|
||||
.map(|arg_span| arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo());
|
||||
// In the case of a named argument whose position is implicit, if the argument *has*
|
||||
// formatting, there will not be a span to replace. Instead, we insert the name after
|
||||
// the `{`, which will be the first character of arg_span. If the argument does *not*
|
||||
// have formatting, there may or may not be a span to replace. This is because
|
||||
// whitespace is allowed in arguments without formatting (such as `format!("{ }", 1);`)
|
||||
// but is not allowed in arguments with formatting (an error will be generated in cases
|
||||
// like `format!("{ :1.1}", 1.0f32);`.
|
||||
// For the message span, if there is formatting, we want to use the opening `{` and the
|
||||
// next character, which will the `:` indicating the start of formatting. If there is
|
||||
// not any formatting, we want to underline the entire span.
|
||||
cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
|
||||
if self.has_formatting {
|
||||
(
|
||||
Some(arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()),
|
||||
Some(arg_span.with_hi(arg_span.lo() + BytePos(2))),
|
||||
)
|
||||
} else {
|
||||
let replace_start = arg_span.lo() + BytePos(1);
|
||||
let replace_end = arg_span.hi() - BytePos(1);
|
||||
let to_replace = arg_span.with_lo(replace_start).with_hi(replace_end);
|
||||
(Some(to_replace), Some(*arg_span))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,10 +137,18 @@ impl PositionalNamedArgsLint {
|
|||
cur_piece: usize,
|
||||
inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
|
||||
names: &FxHashMap<Symbol, (usize, Span)>,
|
||||
has_formatting: bool,
|
||||
) {
|
||||
let start_of_named_args = total_args_length - names.len();
|
||||
if current_positional_arg >= start_of_named_args {
|
||||
self.maybe_push(format_argument_index, ty, cur_piece, inner_span_to_replace, names)
|
||||
self.maybe_push(
|
||||
format_argument_index,
|
||||
ty,
|
||||
cur_piece,
|
||||
inner_span_to_replace,
|
||||
names,
|
||||
has_formatting,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,6 +162,7 @@ impl PositionalNamedArgsLint {
|
|||
cur_piece: usize,
|
||||
inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
|
||||
names: &FxHashMap<Symbol, (usize, Span)>,
|
||||
has_formatting: bool,
|
||||
) {
|
||||
let named_arg = names
|
||||
.iter()
|
||||
|
@ -156,6 +185,7 @@ impl PositionalNamedArgsLint {
|
|||
inner_span_to_replace,
|
||||
replacement,
|
||||
positional_named_arg_span,
|
||||
has_formatting,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -414,6 +444,9 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
PositionalNamedArgType::Precision,
|
||||
);
|
||||
|
||||
let has_precision = arg.format.precision != Count::CountImplied;
|
||||
let has_width = arg.format.width != Count::CountImplied;
|
||||
|
||||
// argument second, if it's an implicit positional parameter
|
||||
// it's written second, so it should come after width/precision.
|
||||
let pos = match arg.position {
|
||||
|
@ -426,6 +459,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
self.curpiece,
|
||||
Some(arg.position_span),
|
||||
&self.names,
|
||||
has_precision || has_width,
|
||||
);
|
||||
|
||||
Exact(i)
|
||||
|
@ -439,6 +473,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
self.curpiece,
|
||||
None,
|
||||
&self.names,
|
||||
has_precision || has_width,
|
||||
);
|
||||
Exact(i)
|
||||
}
|
||||
|
@ -530,6 +565,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
self.curpiece,
|
||||
*inner_span,
|
||||
&self.names,
|
||||
true,
|
||||
);
|
||||
self.verify_arg_type(Exact(i), Count);
|
||||
}
|
||||
|
@ -1152,24 +1188,22 @@ pub fn expand_format_args_nl<'cx>(
|
|||
|
||||
fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>) {
|
||||
for named_arg in &cx.unused_names_lint.positional_named_args {
|
||||
let arg_span = named_arg.get_span_to_replace(cx);
|
||||
let (position_sp_to_replace, position_sp_for_msg) = named_arg.get_positional_arg_spans(cx);
|
||||
|
||||
let msg = format!("named argument `{}` is not used by name", named_arg.replacement);
|
||||
let replacement = match named_arg.ty {
|
||||
PositionalNamedArgType::Arg => named_arg.replacement.to_string(),
|
||||
_ => named_arg.replacement.to_string() + "$",
|
||||
};
|
||||
|
||||
cx.ecx.buffered_early_lint.push(BufferedEarlyLint {
|
||||
span: MultiSpan::from_span(named_arg.positional_named_arg_span),
|
||||
msg: msg.clone(),
|
||||
node_id: ast::CRATE_NODE_ID,
|
||||
lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
|
||||
diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally(
|
||||
arg_span,
|
||||
named_arg.positional_named_arg_span,
|
||||
replacement,
|
||||
),
|
||||
diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
|
||||
position_sp_to_replace,
|
||||
position_sp_for_msg,
|
||||
named_arg_sp: named_arg.positional_named_arg_span,
|
||||
named_arg_name: named_arg.replacement.to_string(),
|
||||
is_formatting_arg: named_arg.ty != PositionalNamedArgType::Arg,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -856,13 +856,18 @@ pub trait LintContext: Sized {
|
|||
Applicability::MachineApplicable,
|
||||
);
|
||||
},
|
||||
BuiltinLintDiagnostics::NamedArgumentUsedPositionally(positional_arg, named_arg, name) => {
|
||||
db.span_label(named_arg, "this named argument is only referred to by position in formatting string");
|
||||
if let Some(positional_arg) = positional_arg {
|
||||
let msg = format!("this formatting argument uses named argument `{}` by position", name);
|
||||
db.span_label(positional_arg, msg);
|
||||
BuiltinLintDiagnostics::NamedArgumentUsedPositionally{ position_sp_to_replace, position_sp_for_msg, named_arg_sp, named_arg_name, is_formatting_arg} => {
|
||||
db.span_label(named_arg_sp, "this named argument is referred to by position in formatting string");
|
||||
if let Some(positional_arg_for_msg) = position_sp_for_msg {
|
||||
let msg = format!("this formatting argument uses named argument `{}` by position", named_arg_name);
|
||||
db.span_label(positional_arg_for_msg, msg);
|
||||
}
|
||||
|
||||
if let Some(positional_arg_to_replace) = position_sp_to_replace {
|
||||
let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name };
|
||||
|
||||
db.span_suggestion_verbose(
|
||||
positional_arg,
|
||||
positional_arg_to_replace,
|
||||
"use the named argument by name to avoid ambiguity",
|
||||
name,
|
||||
Applicability::MaybeIncorrect,
|
||||
|
|
|
@ -467,7 +467,19 @@ pub enum BuiltinLintDiagnostics {
|
|||
/// If true, the lifetime will be fully elided.
|
||||
use_span: Option<(Span, bool)>,
|
||||
},
|
||||
NamedArgumentUsedPositionally(Option<Span>, Span, String),
|
||||
NamedArgumentUsedPositionally {
|
||||
/// Span where the named argument is used by position and will be replaced with the named
|
||||
/// argument name
|
||||
position_sp_to_replace: Option<Span>,
|
||||
/// Span where the named argument is used by position and is used for lint messages
|
||||
position_sp_for_msg: Option<Span>,
|
||||
/// Span where the named argument's name is (so we know where to put the warning message)
|
||||
named_arg_sp: Span,
|
||||
/// String containing the named arguments name
|
||||
named_arg_name: String,
|
||||
/// Indicates if the named argument is used as a width/precision for formatting
|
||||
is_formatting_arg: bool,
|
||||
},
|
||||
}
|
||||
|
||||
/// Lints that are buffered up early on in the `Session` before the
|
||||
|
|
|
@ -624,20 +624,6 @@ impl Build {
|
|||
/// If any submodule has been initialized already, sync it unconditionally.
|
||||
/// This avoids contributors checking in a submodule change by accident.
|
||||
pub fn maybe_update_submodules(&self) {
|
||||
// WARNING: keep this in sync with the submodules hard-coded in bootstrap.py
|
||||
let mut bootstrap_submodules: Vec<&str> = vec![
|
||||
"src/tools/rust-installer",
|
||||
"src/tools/cargo",
|
||||
"src/tools/rls",
|
||||
"src/tools/miri",
|
||||
"library/backtrace",
|
||||
"library/stdarch",
|
||||
];
|
||||
// As in bootstrap.py, we include `rust-analyzer` if `build.vendor` was set in
|
||||
// `config.toml`.
|
||||
if self.config.vendor {
|
||||
bootstrap_submodules.push("src/tools/rust-analyzer");
|
||||
}
|
||||
// Avoid running git when there isn't a git checkout.
|
||||
if !self.config.submodules(&self.rust_info) {
|
||||
return;
|
||||
|
@ -653,10 +639,8 @@ impl Build {
|
|||
// Look for `submodule.$name.path = $path`
|
||||
// Sample output: `submodule.src/rust-installer.path src/tools/rust-installer`
|
||||
let submodule = Path::new(line.splitn(2, ' ').nth(1).unwrap());
|
||||
// avoid updating submodules twice
|
||||
if !bootstrap_submodules.iter().any(|&p| Path::new(p) == submodule)
|
||||
&& channel::GitInfo::new(false, submodule).is_git()
|
||||
{
|
||||
// Don't update the submodule unless it's already been cloned.
|
||||
if channel::GitInfo::new(false, submodule).is_git() {
|
||||
self.update_submodule(submodule);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,9 +89,9 @@ but it is not guaranteed. If you need whole archive semantics use `+whole-archiv
|
|||
This modifier is only compatible with the `static` linking kind.
|
||||
Using any other kind will result in a compiler error.
|
||||
|
||||
When building a rlib or staticlib `+bundle` means that all object files from the native static
|
||||
library will be added to the rlib or staticlib archive, and then used from it during linking of
|
||||
the final binary.
|
||||
When building a rlib or staticlib `+bundle` means that the native static library
|
||||
will be packed into the rlib or staticlib archive, and then retrieved from there
|
||||
during linking of the final binary.
|
||||
|
||||
When building a rlib `-bundle` means that the native static library is registered as a dependency
|
||||
of that rlib "by name", and object files from it are included only during linking of the final
|
||||
|
|
|
@ -2,9 +2,9 @@ warning: named argument `_x` is not used by name
|
|||
--> $DIR/issue-98466.rs:7:26
|
||||
|
|
||||
LL | println!("_x is {}", _x = 5);
|
||||
| - ^^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `_x` by position
|
||||
| -- ^^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `_x` by position
|
||||
|
|
||||
= note: `#[warn(named_arguments_used_positionally)]` on by default
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
@ -16,9 +16,9 @@ warning: named argument `y` is not used by name
|
|||
--> $DIR/issue-98466.rs:10:26
|
||||
|
|
||||
LL | println!("_x is {}", y = _x);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `y` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `y` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -29,9 +29,9 @@ warning: named argument `y` is not used by name
|
|||
--> $DIR/issue-98466.rs:13:83
|
||||
|
|
||||
LL | println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `y` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `y` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -42,9 +42,9 @@ warning: named argument `_x` is not used by name
|
|||
--> $DIR/issue-98466.rs:19:34
|
||||
|
|
||||
LL | let _f = format!("_x is {}", _x = 5);
|
||||
| - ^^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `_x` by position
|
||||
| -- ^^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `_x` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -55,9 +55,9 @@ warning: named argument `y` is not used by name
|
|||
--> $DIR/issue-98466.rs:22:34
|
||||
|
|
||||
LL | let _f = format!("_x is {}", y = _x);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `y` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `y` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -68,9 +68,9 @@ warning: named argument `y` is not used by name
|
|||
--> $DIR/issue-98466.rs:25:91
|
||||
|
|
||||
LL | let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `y` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `y` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
|
|
@ -2,9 +2,9 @@ warning: named argument `a` is not used by name
|
|||
--> $DIR/issue-99265.rs:5:24
|
||||
|
|
||||
LL | println!("{b} {}", a=1, b=2);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `a` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `a` by position
|
||||
|
|
||||
= note: `#[warn(named_arguments_used_positionally)]` on by default
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
@ -16,9 +16,9 @@ warning: named argument `a` is not used by name
|
|||
--> $DIR/issue-99265.rs:9:35
|
||||
|
|
||||
LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `a` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `a` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -29,9 +29,9 @@ warning: named argument `b` is not used by name
|
|||
--> $DIR/issue-99265.rs:9:40
|
||||
|
|
||||
LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `b` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `b` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -42,9 +42,9 @@ warning: named argument `c` is not used by name
|
|||
--> $DIR/issue-99265.rs:9:45
|
||||
|
|
||||
LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `c` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `c` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -55,9 +55,9 @@ warning: named argument `d` is not used by name
|
|||
--> $DIR/issue-99265.rs:9:50
|
||||
|
|
||||
LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `d` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `d` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -68,9 +68,9 @@ warning: named argument `width` is not used by name
|
|||
--> $DIR/issue-99265.rs:19:35
|
||||
|
|
||||
LL | println!("Hello {:1$}!", "x", width = 5);
|
||||
| -- ^^^^^ this named argument is only referred to by position in formatting string
|
||||
| -- ^^^^^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `width$` by position
|
||||
| this formatting argument uses named argument `width` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -81,9 +81,9 @@ warning: named argument `width` is not used by name
|
|||
--> $DIR/issue-99265.rs:23:46
|
||||
|
|
||||
LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
|
||||
| -- ^^^^^ this named argument is only referred to by position in formatting string
|
||||
| -- ^^^^^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `width$` by position
|
||||
| this formatting argument uses named argument `width` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -94,9 +94,9 @@ warning: named argument `precision` is not used by name
|
|||
--> $DIR/issue-99265.rs:23:57
|
||||
|
|
||||
LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
|
||||
| -- ^^^^^^^^^ this named argument is only referred to by position in formatting string
|
||||
| -- ^^^^^^^^^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `precision$` by position
|
||||
| this formatting argument uses named argument `precision` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -107,9 +107,9 @@ warning: named argument `f` is not used by name
|
|||
--> $DIR/issue-99265.rs:23:33
|
||||
|
|
||||
LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `f` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `f` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -120,9 +120,9 @@ warning: named argument `width` is not used by name
|
|||
--> $DIR/issue-99265.rs:31:47
|
||||
|
|
||||
LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
|
||||
| -- ^^^^^ this named argument is only referred to by position in formatting string
|
||||
| -- ^^^^^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `width$` by position
|
||||
| this formatting argument uses named argument `width` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -133,9 +133,9 @@ warning: named argument `precision` is not used by name
|
|||
--> $DIR/issue-99265.rs:31:58
|
||||
|
|
||||
LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
|
||||
| -- ^^^^^^^^^ this named argument is only referred to by position in formatting string
|
||||
| -- ^^^^^^^^^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `precision$` by position
|
||||
| this formatting argument uses named argument `precision` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -146,7 +146,7 @@ warning: named argument `f` is not used by name
|
|||
--> $DIR/issue-99265.rs:31:34
|
||||
|
|
||||
LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| - ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `f` by position
|
||||
|
|
||||
|
@ -159,10 +159,10 @@ warning: named argument `width` is not used by name
|
|||
--> $DIR/issue-99265.rs:52:9
|
||||
|
|
||||
LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
|
||||
| -- this formatting argument uses named argument `width$` by position
|
||||
| -- this formatting argument uses named argument `width` by position
|
||||
...
|
||||
LL | width = 5,
|
||||
| ^^^^^ this named argument is only referred to by position in formatting string
|
||||
| ^^^^^ this named argument is referred to by position in formatting string
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -173,10 +173,10 @@ warning: named argument `precision` is not used by name
|
|||
--> $DIR/issue-99265.rs:54:9
|
||||
|
|
||||
LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
|
||||
| -- this formatting argument uses named argument `precision$` by position
|
||||
| -- this formatting argument uses named argument `precision` by position
|
||||
...
|
||||
LL | precision = 2,
|
||||
| ^^^^^^^^^ this named argument is only referred to by position in formatting string
|
||||
| ^^^^^^^^^ this named argument is referred to by position in formatting string
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -190,7 +190,7 @@ LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
|
|||
| - this formatting argument uses named argument `f` by position
|
||||
...
|
||||
LL | f = 0.02f32,
|
||||
| ^ this named argument is only referred to by position in formatting string
|
||||
| ^ this named argument is referred to by position in formatting string
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -201,10 +201,10 @@ warning: named argument `width2` is not used by name
|
|||
--> $DIR/issue-99265.rs:58:9
|
||||
|
|
||||
LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
|
||||
| -- this formatting argument uses named argument `width2$` by position
|
||||
| -- this formatting argument uses named argument `width2` by position
|
||||
...
|
||||
LL | width2 = 5,
|
||||
| ^^^^^^ this named argument is only referred to by position in formatting string
|
||||
| ^^^^^^ this named argument is referred to by position in formatting string
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -215,10 +215,10 @@ warning: named argument `precision2` is not used by name
|
|||
--> $DIR/issue-99265.rs:60:9
|
||||
|
|
||||
LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
|
||||
| -- this formatting argument uses named argument `precision2$` by position
|
||||
| -- this formatting argument uses named argument `precision2` by position
|
||||
...
|
||||
LL | precision2 = 2
|
||||
| ^^^^^^^^^^ this named argument is only referred to by position in formatting string
|
||||
| ^^^^^^^^^^ this named argument is referred to by position in formatting string
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -232,7 +232,7 @@ LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
|
|||
| - this formatting argument uses named argument `g` by position
|
||||
...
|
||||
LL | g = 0.02f32,
|
||||
| ^ this named argument is only referred to by position in formatting string
|
||||
| ^ this named argument is referred to by position in formatting string
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -246,7 +246,7 @@ LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
|
|||
| - this formatting argument uses named argument `f` by position
|
||||
...
|
||||
LL | f = 0.02f32,
|
||||
| ^ this named argument is only referred to by position in formatting string
|
||||
| ^ this named argument is referred to by position in formatting string
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -257,9 +257,9 @@ warning: named argument `f` is not used by name
|
|||
--> $DIR/issue-99265.rs:64:31
|
||||
|
|
||||
LL | println!("Hello {:0.1}!", f = 0.02f32);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `f` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `f` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -270,7 +270,7 @@ warning: named argument `f` is not used by name
|
|||
--> $DIR/issue-99265.rs:68:32
|
||||
|
|
||||
LL | println!("Hello {0:0.1}!", f = 0.02f32);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| - ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `f` by position
|
||||
|
|
||||
|
@ -283,9 +283,9 @@ warning: named argument `v` is not used by name
|
|||
--> $DIR/issue-99265.rs:79:23
|
||||
|
|
||||
LL | println!("{:0$}", v = val);
|
||||
| -- ^ this named argument is only referred to by position in formatting string
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `v$` by position
|
||||
| this formatting argument uses named argument `v` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -296,9 +296,9 @@ warning: named argument `v` is not used by name
|
|||
--> $DIR/issue-99265.rs:79:23
|
||||
|
|
||||
LL | println!("{:0$}", v = val);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `v` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `v` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -309,9 +309,9 @@ warning: named argument `v` is not used by name
|
|||
--> $DIR/issue-99265.rs:84:24
|
||||
|
|
||||
LL | println!("{0:0$}", v = val);
|
||||
| -- ^ this named argument is only referred to by position in formatting string
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `v$` by position
|
||||
| this formatting argument uses named argument `v` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -322,7 +322,7 @@ warning: named argument `v` is not used by name
|
|||
--> $DIR/issue-99265.rs:84:24
|
||||
|
|
||||
LL | println!("{0:0$}", v = val);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| - ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `v` by position
|
||||
|
|
||||
|
@ -335,9 +335,9 @@ warning: named argument `v` is not used by name
|
|||
--> $DIR/issue-99265.rs:89:26
|
||||
|
|
||||
LL | println!("{:0$.0$}", v = val);
|
||||
| -- ^ this named argument is only referred to by position in formatting string
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `v$` by position
|
||||
| this formatting argument uses named argument `v` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -348,9 +348,9 @@ warning: named argument `v` is not used by name
|
|||
--> $DIR/issue-99265.rs:89:26
|
||||
|
|
||||
LL | println!("{:0$.0$}", v = val);
|
||||
| -- ^ this named argument is only referred to by position in formatting string
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `v$` by position
|
||||
| this formatting argument uses named argument `v` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -361,9 +361,9 @@ warning: named argument `v` is not used by name
|
|||
--> $DIR/issue-99265.rs:89:26
|
||||
|
|
||||
LL | println!("{:0$.0$}", v = val);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `v` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `v` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -374,9 +374,9 @@ warning: named argument `v` is not used by name
|
|||
--> $DIR/issue-99265.rs:96:27
|
||||
|
|
||||
LL | println!("{0:0$.0$}", v = val);
|
||||
| -- ^ this named argument is only referred to by position in formatting string
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `v$` by position
|
||||
| this formatting argument uses named argument `v` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -387,9 +387,9 @@ warning: named argument `v` is not used by name
|
|||
--> $DIR/issue-99265.rs:96:27
|
||||
|
|
||||
LL | println!("{0:0$.0$}", v = val);
|
||||
| -- ^ this named argument is only referred to by position in formatting string
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `v$` by position
|
||||
| this formatting argument uses named argument `v` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -400,7 +400,7 @@ warning: named argument `v` is not used by name
|
|||
--> $DIR/issue-99265.rs:96:27
|
||||
|
|
||||
LL | println!("{0:0$.0$}", v = val);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| - ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `v` by position
|
||||
|
|
||||
|
@ -413,9 +413,9 @@ warning: named argument `a` is not used by name
|
|||
--> $DIR/issue-99265.rs:104:28
|
||||
|
|
||||
LL | println!("{} {a} {0}", a = 1);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `a` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `a` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -426,7 +426,7 @@ warning: named argument `a` is not used by name
|
|||
--> $DIR/issue-99265.rs:104:28
|
||||
|
|
||||
LL | println!("{} {a} {0}", a = 1);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| - ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `a` by position
|
||||
|
|
||||
|
@ -439,10 +439,10 @@ warning: named argument `b` is not used by name
|
|||
--> $DIR/issue-99265.rs:115:23
|
||||
|
|
||||
LL | {:1$.2$}",
|
||||
| -- this formatting argument uses named argument `b$` by position
|
||||
| -- this formatting argument uses named argument `b` by position
|
||||
...
|
||||
LL | a = 1.0, b = 1, c = 2,
|
||||
| ^ this named argument is only referred to by position in formatting string
|
||||
| ^ this named argument is referred to by position in formatting string
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -453,10 +453,10 @@ warning: named argument `c` is not used by name
|
|||
--> $DIR/issue-99265.rs:115:30
|
||||
|
|
||||
LL | {:1$.2$}",
|
||||
| -- this formatting argument uses named argument `c$` by position
|
||||
| -- this formatting argument uses named argument `c` by position
|
||||
...
|
||||
LL | a = 1.0, b = 1, c = 2,
|
||||
| ^ this named argument is only referred to by position in formatting string
|
||||
| ^ this named argument is referred to by position in formatting string
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -467,10 +467,10 @@ warning: named argument `a` is not used by name
|
|||
--> $DIR/issue-99265.rs:115:14
|
||||
|
|
||||
LL | {:1$.2$}",
|
||||
| - this formatting argument uses named argument `a` by position
|
||||
| -- this formatting argument uses named argument `a` by position
|
||||
...
|
||||
LL | a = 1.0, b = 1, c = 2,
|
||||
| ^ this named argument is only referred to by position in formatting string
|
||||
| ^ this named argument is referred to by position in formatting string
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -481,10 +481,10 @@ warning: named argument `b` is not used by name
|
|||
--> $DIR/issue-99265.rs:126:23
|
||||
|
|
||||
LL | {0:1$.2$}",
|
||||
| -- this formatting argument uses named argument `b$` by position
|
||||
| -- this formatting argument uses named argument `b` by position
|
||||
...
|
||||
LL | a = 1.0, b = 1, c = 2,
|
||||
| ^ this named argument is only referred to by position in formatting string
|
||||
| ^ this named argument is referred to by position in formatting string
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -495,10 +495,10 @@ warning: named argument `c` is not used by name
|
|||
--> $DIR/issue-99265.rs:126:30
|
||||
|
|
||||
LL | {0:1$.2$}",
|
||||
| -- this formatting argument uses named argument `c$` by position
|
||||
| -- this formatting argument uses named argument `c` by position
|
||||
...
|
||||
LL | a = 1.0, b = 1, c = 2,
|
||||
| ^ this named argument is only referred to by position in formatting string
|
||||
| ^ this named argument is referred to by position in formatting string
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -512,7 +512,7 @@ LL | {0:1$.2$}",
|
|||
| - this formatting argument uses named argument `a` by position
|
||||
...
|
||||
LL | a = 1.0, b = 1, c = 2,
|
||||
| ^ this named argument is only referred to by position in formatting string
|
||||
| ^ this named argument is referred to by position in formatting string
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -523,9 +523,9 @@ warning: named argument `width` is not used by name
|
|||
--> $DIR/issue-99265.rs:132:39
|
||||
|
|
||||
LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
|
||||
| -- ^^^^^ this named argument is only referred to by position in formatting string
|
||||
| -- ^^^^^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `width$` by position
|
||||
| this formatting argument uses named argument `width` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -536,9 +536,9 @@ warning: named argument `precision` is not used by name
|
|||
--> $DIR/issue-99265.rs:132:50
|
||||
|
|
||||
LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
|
||||
| -- ^^^^^^^^^ this named argument is only referred to by position in formatting string
|
||||
| -- ^^^^^^^^^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `precision$` by position
|
||||
| this formatting argument uses named argument `precision` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
@ -549,9 +549,9 @@ warning: named argument `x` is not used by name
|
|||
--> $DIR/issue-99265.rs:132:30
|
||||
|
|
||||
LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
|
||||
| - ^ this named argument is only referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `x` by position
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `x` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
|
|
24
src/test/ui/macros/issue-99907.fixed
Normal file
24
src/test/ui/macros/issue-99907.fixed
Normal file
|
@ -0,0 +1,24 @@
|
|||
// check-pass
|
||||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
println!("Hello {f:.1}!", f = 0.02f32);
|
||||
//~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
|
||||
//~| HELP use the named argument by name to avoid ambiguity
|
||||
|
||||
println!("Hello {f:1.1}!", f = 0.02f32);
|
||||
//~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
|
||||
//~| HELP use the named argument by name to avoid ambiguity
|
||||
|
||||
println!("Hello {f}!", f = 0.02f32);
|
||||
//~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
|
||||
//~| HELP use the named argument by name to avoid ambiguity
|
||||
|
||||
println!("Hello {f}!", f = 0.02f32);
|
||||
//~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
|
||||
//~| HELP use the named argument by name to avoid ambiguity
|
||||
|
||||
println!("Hello {f}!", f = 0.02f32);
|
||||
//~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
|
||||
//~| HELP use the named argument by name to avoid ambiguity
|
||||
}
|
24
src/test/ui/macros/issue-99907.rs
Normal file
24
src/test/ui/macros/issue-99907.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
// check-pass
|
||||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
println!("Hello {:.1}!", f = 0.02f32);
|
||||
//~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
|
||||
//~| HELP use the named argument by name to avoid ambiguity
|
||||
|
||||
println!("Hello {:1.1}!", f = 0.02f32);
|
||||
//~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
|
||||
//~| HELP use the named argument by name to avoid ambiguity
|
||||
|
||||
println!("Hello {}!", f = 0.02f32);
|
||||
//~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
|
||||
//~| HELP use the named argument by name to avoid ambiguity
|
||||
|
||||
println!("Hello { }!", f = 0.02f32);
|
||||
//~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
|
||||
//~| HELP use the named argument by name to avoid ambiguity
|
||||
|
||||
println!("Hello { }!", f = 0.02f32);
|
||||
//~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
|
||||
//~| HELP use the named argument by name to avoid ambiguity
|
||||
}
|
68
src/test/ui/macros/issue-99907.stderr
Normal file
68
src/test/ui/macros/issue-99907.stderr
Normal file
|
@ -0,0 +1,68 @@
|
|||
warning: named argument `f` is not used by name
|
||||
--> $DIR/issue-99907.rs:5:30
|
||||
|
|
||||
LL | println!("Hello {:.1}!", f = 0.02f32);
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `f` by position
|
||||
|
|
||||
= note: `#[warn(named_arguments_used_positionally)]` on by default
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
LL | println!("Hello {f:.1}!", f = 0.02f32);
|
||||
| +
|
||||
|
||||
warning: named argument `f` is not used by name
|
||||
--> $DIR/issue-99907.rs:9:31
|
||||
|
|
||||
LL | println!("Hello {:1.1}!", f = 0.02f32);
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `f` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
LL | println!("Hello {f:1.1}!", f = 0.02f32);
|
||||
| +
|
||||
|
||||
warning: named argument `f` is not used by name
|
||||
--> $DIR/issue-99907.rs:13:27
|
||||
|
|
||||
LL | println!("Hello {}!", f = 0.02f32);
|
||||
| -- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `f` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
LL | println!("Hello {f}!", f = 0.02f32);
|
||||
| +
|
||||
|
||||
warning: named argument `f` is not used by name
|
||||
--> $DIR/issue-99907.rs:17:28
|
||||
|
|
||||
LL | println!("Hello { }!", f = 0.02f32);
|
||||
| --- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `f` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
LL | println!("Hello {f}!", f = 0.02f32);
|
||||
| +
|
||||
|
||||
warning: named argument `f` is not used by name
|
||||
--> $DIR/issue-99907.rs:21:29
|
||||
|
|
||||
LL | println!("Hello { }!", f = 0.02f32);
|
||||
| ---- ^ this named argument is referred to by position in formatting string
|
||||
| |
|
||||
| this formatting argument uses named argument `f` by position
|
||||
|
|
||||
help: use the named argument by name to avoid ambiguity
|
||||
|
|
||||
LL | println!("Hello {f}!", f = 0.02f32);
|
||||
| +
|
||||
|
||||
warning: 5 warnings emitted
|
||||
|
|
@ -9,3 +9,4 @@ path = "main.rs"
|
|||
|
||||
[dependencies]
|
||||
walkdir = "2"
|
||||
rayon = "1.5"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use rayon::iter::{ParallelBridge, ParallelIterator};
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
use std::process::{Command, Output};
|
||||
|
@ -56,27 +57,30 @@ const DOCS_TO_CHECK: &[&str] =
|
|||
|
||||
// Returns the number of files read and the number of errors.
|
||||
fn find_all_html_files(dir: &Path) -> (usize, usize) {
|
||||
let mut files_read = 0;
|
||||
let mut errors = 0;
|
||||
|
||||
for entry in walkdir::WalkDir::new(dir).into_iter().filter_entry(|e| {
|
||||
e.depth() != 1
|
||||
|| e.file_name()
|
||||
.to_str()
|
||||
.map(|s| DOCS_TO_CHECK.into_iter().any(|d| *d == s))
|
||||
.unwrap_or(false)
|
||||
}) {
|
||||
let entry = entry.expect("failed to read file");
|
||||
if !entry.file_type().is_file() {
|
||||
continue;
|
||||
}
|
||||
let entry = entry.path();
|
||||
if entry.extension().and_then(|s| s.to_str()) == Some("html") {
|
||||
errors += check_html_file(&entry);
|
||||
files_read += 1;
|
||||
}
|
||||
}
|
||||
(files_read, errors)
|
||||
walkdir::WalkDir::new(dir)
|
||||
.into_iter()
|
||||
.filter_entry(|e| {
|
||||
e.depth() != 1
|
||||
|| e.file_name()
|
||||
.to_str()
|
||||
.map(|s| DOCS_TO_CHECK.into_iter().any(|d| *d == s))
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.par_bridge()
|
||||
.map(|entry| {
|
||||
let entry = entry.expect("failed to read file");
|
||||
if !entry.file_type().is_file() {
|
||||
return (0, 0);
|
||||
}
|
||||
let entry = entry.path();
|
||||
// (Number of files processed, number of errors)
|
||||
if entry.extension().and_then(|s| s.to_str()) == Some("html") {
|
||||
(1, check_html_file(&entry))
|
||||
} else {
|
||||
(0, 0)
|
||||
}
|
||||
})
|
||||
.reduce(|| (0, 0), |a, b| (a.0 + b.0, a.1 + b.1))
|
||||
}
|
||||
|
||||
/// Default `tidy` command for macOS is too old that it does not have `mute-id` and `mute` options.
|
||||
|
|
|
@ -34,8 +34,21 @@ jobs:
|
|||
git config --global user.email "runner@gha.local"
|
||||
git config --global user.name "Github Action"
|
||||
rm Cargo.lock
|
||||
# Fix names for crates that were published before switch to kebab-case.
|
||||
cargo workspaces rename --from base-db base_db
|
||||
cargo workspaces rename --from hir-def hir_def
|
||||
cargo workspaces rename --from hir-expand hir_expand
|
||||
cargo workspaces rename --from hir-ty hir_ty
|
||||
cargo workspaces rename --from ide-assists ide_assists
|
||||
cargo workspaces rename --from ide-completion ide_completion
|
||||
cargo workspaces rename --from ide-db ide_db
|
||||
cargo workspaces rename --from ide-diagnostics ide_diagnostics
|
||||
cargo workspaces rename --from ide-ssr ide_ssr
|
||||
cargo workspaces rename --from proc-macro-api proc_macro_api
|
||||
cargo workspaces rename --from proc-macro-srv proc_macro_srv
|
||||
cargo workspaces rename --from project-model project_model
|
||||
cargo workspaces rename --from test-utils test_utils
|
||||
cargo workspaces rename --from text-edit text_edit
|
||||
cargo workspaces rename ra_ap_%n
|
||||
find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} +
|
||||
# Fix names for crates that were published before switch to kebab-case.
|
||||
find crates -name 'Cargo.toml' -exec sed -i "s/ra_ap_base-db/ra_ap_base_db/g; s/ra_ap_hir-def/ra_ap_hir_def/g; s/ra_ap_hir-expand/ra_ap_hir_expand/g; s/ra_ap_hir-ty/ra_ap_hir_ty/g; s/ra_ap_ide-assists/ra_ap_ide_assists/g; s/ra_ap_ide-completion/ra_ap_ide_completion/g; s/ra_ap_ide-db/ra_ap_ide_db/g; s/ra_ap_ide-diagnostics/ra_ap_ide_diagnostics/g; s/ra_ap_ide-ssr/ra_ap_ide_ssr/g; s/ra_ap_proc-macro-api/ra_ap_proc_macro_api/g; s/ra_ap_proc-macro-srv/ra_ap_proc_macro_srv/g; s/ra_ap_project-model/ra_ap_project_model/g; s/ra_ap_test-utils/ra_ap_test_utils/g; s/ra_ap_text-edit/ra_ap_text_edit/g" {} +
|
||||
cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH
|
||||
|
|
|
@ -124,13 +124,24 @@ impl RawAttrs {
|
|||
|
||||
pub(crate) fn merge(&self, other: Self) -> Self {
|
||||
// FIXME: This needs to fixup `AttrId`s
|
||||
match (&self.entries, &other.entries) {
|
||||
match (&self.entries, other.entries) {
|
||||
(None, None) => Self::EMPTY,
|
||||
(Some(entries), None) | (None, Some(entries)) => {
|
||||
Self { entries: Some(entries.clone()) }
|
||||
}
|
||||
(None, entries @ Some(_)) => Self { entries },
|
||||
(Some(entries), None) => Self { entries: Some(entries.clone()) },
|
||||
(Some(a), Some(b)) => {
|
||||
Self { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
|
||||
let last_ast_index = a.last().map_or(0, |it| it.id.ast_index + 1);
|
||||
Self {
|
||||
entries: Some(
|
||||
a.iter()
|
||||
.cloned()
|
||||
.chain(b.iter().map(|it| {
|
||||
let mut it = it.clone();
|
||||
it.id.ast_index += last_ast_index;
|
||||
it
|
||||
}))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::collections::hash_map::Entry;
|
|||
|
||||
use base_db::CrateId;
|
||||
use hir_expand::{name::Name, AstId, MacroCallId};
|
||||
use itertools::Itertools;
|
||||
use once_cell::sync::Lazy;
|
||||
use profile::Count;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
@ -97,15 +98,14 @@ pub(crate) enum BuiltinShadowMode {
|
|||
impl ItemScope {
|
||||
pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
|
||||
// FIXME: shadowing
|
||||
let keys: FxHashSet<_> = self
|
||||
.types
|
||||
self.types
|
||||
.keys()
|
||||
.chain(self.values.keys())
|
||||
.chain(self.macros.keys())
|
||||
.chain(self.unresolved.iter())
|
||||
.collect();
|
||||
|
||||
keys.into_iter().map(move |name| (name, self.get(name)))
|
||||
.sorted()
|
||||
.unique()
|
||||
.map(move |name| (name, self.get(name)))
|
||||
}
|
||||
|
||||
pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
|
||||
|
|
|
@ -1055,7 +1055,7 @@ impl DefCollector<'_> {
|
|||
};
|
||||
let mut res = ReachedFixedPoint::Yes;
|
||||
macros.retain(|directive| {
|
||||
let resolver2 = |path| {
|
||||
let resolver = |path| {
|
||||
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
||||
self.db,
|
||||
ResolveMode::Other,
|
||||
|
@ -1068,7 +1068,7 @@ impl DefCollector<'_> {
|
|||
.take_macros()
|
||||
.map(|it| (it, macro_id_to_def_id(self.db, it)))
|
||||
};
|
||||
let resolver = |path| resolver2(path).map(|(_, it)| it);
|
||||
let resolver_def_id = |path| resolver(path).map(|(_, it)| it);
|
||||
|
||||
match &directive.kind {
|
||||
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
|
||||
|
@ -1077,7 +1077,7 @@ impl DefCollector<'_> {
|
|||
ast_id,
|
||||
*expand_to,
|
||||
self.def_map.krate,
|
||||
&resolver,
|
||||
&resolver_def_id,
|
||||
&mut |_err| (),
|
||||
);
|
||||
if let Ok(Ok(call_id)) = call_id {
|
||||
|
@ -1093,7 +1093,7 @@ impl DefCollector<'_> {
|
|||
*derive_attr,
|
||||
*derive_pos as u32,
|
||||
self.def_map.krate,
|
||||
&resolver2,
|
||||
&resolver,
|
||||
);
|
||||
|
||||
if let Ok((macro_id, def_id, call_id)) = id {
|
||||
|
@ -1158,7 +1158,7 @@ impl DefCollector<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
let def = match resolver(path.clone()) {
|
||||
let def = match resolver_def_id(path.clone()) {
|
||||
Some(def) if def.is_attribute() => def,
|
||||
_ => return true,
|
||||
};
|
||||
|
@ -1292,7 +1292,8 @@ impl DefCollector<'_> {
|
|||
true
|
||||
});
|
||||
// Attribute resolution can add unresolved macro invocations, so concatenate the lists.
|
||||
self.unresolved_macros.extend(macros);
|
||||
macros.extend(mem::take(&mut self.unresolved_macros));
|
||||
self.unresolved_macros = macros;
|
||||
|
||||
for (module_id, depth, container, macro_call_id) in resolved {
|
||||
self.collect_macro_expansion(module_id, macro_call_id, depth, container);
|
||||
|
|
|
@ -34,6 +34,7 @@ pub trait TyExt {
|
|||
fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
|
||||
|
||||
fn strip_references(&self) -> &Ty;
|
||||
fn strip_reference(&self) -> &Ty;
|
||||
|
||||
/// If this is a `dyn Trait`, returns that trait.
|
||||
fn dyn_trait(&self) -> Option<TraitId>;
|
||||
|
@ -182,6 +183,10 @@ impl TyExt for Ty {
|
|||
t
|
||||
}
|
||||
|
||||
fn strip_reference(&self) -> &Ty {
|
||||
self.as_reference().map_or(self, |(ty, _, _)| ty)
|
||||
}
|
||||
|
||||
fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
|
||||
match self.kind(Interner) {
|
||||
TyKind::OpaqueType(opaque_ty_id, subst) => {
|
||||
|
|
|
@ -2769,6 +2769,10 @@ impl Type {
|
|||
self.derived(self.ty.strip_references().clone())
|
||||
}
|
||||
|
||||
pub fn strip_reference(&self) -> Type {
|
||||
self.derived(self.ty.strip_reference().clone())
|
||||
}
|
||||
|
||||
pub fn is_unknown(&self) -> bool {
|
||||
self.ty.is_unknown()
|
||||
}
|
||||
|
|
|
@ -324,6 +324,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
|||
self.imp.resolve_type(ty)
|
||||
}
|
||||
|
||||
pub fn resolve_trait(&self, trait_: &ast::Path) -> Option<Trait> {
|
||||
self.imp.resolve_trait(trait_)
|
||||
}
|
||||
|
||||
// FIXME: Figure out a nice interface to inspect adjustments
|
||||
pub fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
|
||||
self.imp.is_implicit_reborrow(expr)
|
||||
|
@ -924,7 +928,12 @@ impl<'db> SemanticsImpl<'db> {
|
|||
}
|
||||
|
||||
fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
|
||||
self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map(|it| it.value)
|
||||
self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map(
|
||||
|InFile { file_id, value }| {
|
||||
self.cache(find_root(value.syntax()), file_id);
|
||||
value
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
|
||||
|
@ -1009,6 +1018,20 @@ impl<'db> SemanticsImpl<'db> {
|
|||
Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
|
||||
}
|
||||
|
||||
fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
|
||||
let analyze = self.analyze(path.syntax())?;
|
||||
let hygiene = hir_expand::hygiene::Hygiene::new(self.db.upcast(), analyze.file_id);
|
||||
let ctx = body::LowerCtx::with_hygiene(self.db.upcast(), &hygiene);
|
||||
let hir_path = Path::from_src(path.clone(), &ctx)?;
|
||||
match analyze
|
||||
.resolver
|
||||
.resolve_path_in_type_ns_fully(self.db.upcast(), hir_path.mod_path())?
|
||||
{
|
||||
TypeNs::TraitId(id) => Some(Trait { id }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
|
||||
self.analyze(expr.syntax())?.is_implicit_reborrow(self.db, expr)
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ use crate::{
|
|||
// pub struct Baz;
|
||||
// }
|
||||
//
|
||||
// use foo::{Baz, Bar};
|
||||
// use foo::{Bar, Baz};
|
||||
//
|
||||
// fn qux(bar: Bar, baz: Baz) {}
|
||||
// ```
|
||||
|
@ -281,7 +281,7 @@ mod foo {
|
|||
pub fn f() {}
|
||||
}
|
||||
|
||||
use foo::{Baz, Bar, f};
|
||||
use foo::{Bar, Baz, f};
|
||||
|
||||
fn qux(bar: Bar, baz: Baz) {
|
||||
f();
|
||||
|
@ -351,7 +351,7 @@ mod foo {
|
|||
pub fn f() {}
|
||||
}
|
||||
|
||||
use foo::{Baz, Bar, f};
|
||||
use foo::{Bar, Baz, f};
|
||||
|
||||
fn qux(bar: Bar, baz: Baz) {
|
||||
f();
|
||||
|
@ -440,7 +440,7 @@ mod foo {
|
|||
}
|
||||
}
|
||||
|
||||
use foo::{bar::{Baz, Bar, f}, baz::*};
|
||||
use foo::{bar::{Bar, Baz, f}, baz::*};
|
||||
|
||||
fn qux(bar: Bar, baz: Baz) {
|
||||
f();
|
||||
|
@ -561,7 +561,7 @@ mod foo {
|
|||
|
||||
use foo::{
|
||||
bar::{*, f},
|
||||
baz::{g, qux::{q, h}}
|
||||
baz::{g, qux::{h, q}}
|
||||
};
|
||||
|
||||
fn qux(bar: Bar, baz: Baz) {
|
||||
|
|
|
@ -7,7 +7,7 @@ use ide_db::{
|
|||
imports::insert_use::remove_path_if_in_use_stmt,
|
||||
path_transform::PathTransform,
|
||||
search::{FileReference, SearchScope},
|
||||
syntax_helpers::node_ext::expr_as_name_ref,
|
||||
syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref},
|
||||
RootDatabase,
|
||||
};
|
||||
use itertools::{izip, Itertools};
|
||||
|
@ -301,7 +301,16 @@ fn inline(
|
|||
params: &[(ast::Pat, Option<ast::Type>, hir::Param)],
|
||||
CallInfo { node, arguments, generic_arg_list }: &CallInfo,
|
||||
) -> ast::Expr {
|
||||
let body = fn_body.clone_for_update();
|
||||
let body = if sema.hir_file_for(fn_body.syntax()).is_macro() {
|
||||
cov_mark::hit!(inline_call_defined_in_macro);
|
||||
if let Some(body) = ast::BlockExpr::cast(insert_ws_into(fn_body.syntax().clone())) {
|
||||
body
|
||||
} else {
|
||||
fn_body.clone_for_update()
|
||||
}
|
||||
} else {
|
||||
fn_body.clone_for_update()
|
||||
};
|
||||
let usages_for_locals = |local| {
|
||||
Definition::Local(local)
|
||||
.usages(sema)
|
||||
|
@ -1144,6 +1153,41 @@ fn bar() -> u32 {
|
|||
x
|
||||
}) + foo()
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inline_call_defined_in_macro() {
|
||||
cov_mark::check!(inline_call_defined_in_macro);
|
||||
check_assist(
|
||||
inline_call,
|
||||
r#"
|
||||
macro_rules! define_foo {
|
||||
() => { fn foo() -> u32 {
|
||||
let x = 0;
|
||||
x
|
||||
} };
|
||||
}
|
||||
define_foo!();
|
||||
fn bar() -> u32 {
|
||||
foo$0()
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
macro_rules! define_foo {
|
||||
() => { fn foo() -> u32 {
|
||||
let x = 0;
|
||||
x
|
||||
} };
|
||||
}
|
||||
define_foo!();
|
||||
fn bar() -> u32 {
|
||||
{
|
||||
let x = 0;
|
||||
x
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -535,7 +535,7 @@ mod foo {
|
|||
pub struct Baz;
|
||||
}
|
||||
|
||||
use foo::{Baz, Bar};
|
||||
use foo::{Bar, Baz};
|
||||
|
||||
fn qux(bar: Bar, baz: Baz) {}
|
||||
"#####,
|
||||
|
|
|
@ -400,7 +400,7 @@ impl Completions {
|
|||
) {
|
||||
if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx {
|
||||
cov_mark::hit!(enum_variant_pattern_path);
|
||||
self.add_variant_pat(ctx, pat_ctx, variant, local_name);
|
||||
self.add_variant_pat(ctx, pat_ctx, Some(path_ctx), variant, local_name);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -484,12 +484,14 @@ impl Completions {
|
|||
&mut self,
|
||||
ctx: &CompletionContext<'_>,
|
||||
pattern_ctx: &PatternContext,
|
||||
path_ctx: Option<&PathCompletionCtx>,
|
||||
variant: hir::Variant,
|
||||
local_name: Option<hir::Name>,
|
||||
) {
|
||||
self.add_opt(render_variant_pat(
|
||||
RenderContext::new(ctx),
|
||||
pattern_ctx,
|
||||
path_ctx,
|
||||
variant,
|
||||
local_name.clone(),
|
||||
None,
|
||||
|
@ -504,7 +506,14 @@ impl Completions {
|
|||
path: hir::ModPath,
|
||||
) {
|
||||
let path = Some(&path);
|
||||
self.add_opt(render_variant_pat(RenderContext::new(ctx), pattern_ctx, variant, None, path));
|
||||
self.add_opt(render_variant_pat(
|
||||
RenderContext::new(ctx),
|
||||
pattern_ctx,
|
||||
None,
|
||||
variant,
|
||||
None,
|
||||
path,
|
||||
));
|
||||
}
|
||||
|
||||
pub(crate) fn add_struct_pat(
|
||||
|
|
|
@ -115,7 +115,7 @@ pub(crate) fn complete_attribute_path(
|
|||
});
|
||||
acc.add_nameref_keywords_with_colon(ctx);
|
||||
}
|
||||
Qualified::Infer | Qualified::With { .. } => {}
|
||||
Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
|
||||
}
|
||||
|
||||
let attributes = annotated_item_kind.and_then(|kind| {
|
||||
|
|
|
@ -97,7 +97,7 @@ pub(crate) fn complete_derive_path(
|
|||
});
|
||||
acc.add_nameref_keywords_with_colon(ctx);
|
||||
}
|
||||
Qualified::Infer | Qualified::With { .. } => {}
|
||||
Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,14 @@ pub(crate) fn complete_expr_path(
|
|||
acc: &mut Completions,
|
||||
ctx: &CompletionContext<'_>,
|
||||
path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
|
||||
&ExprCtx {
|
||||
expr_ctx: &ExprCtx,
|
||||
) {
|
||||
let _p = profile::span("complete_expr_path");
|
||||
if !ctx.qualifier_ctx.none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let &ExprCtx {
|
||||
in_block_expr,
|
||||
in_loop_body,
|
||||
after_if_expr,
|
||||
|
@ -23,12 +30,7 @@ pub(crate) fn complete_expr_path(
|
|||
ref impl_,
|
||||
in_match_guard,
|
||||
..
|
||||
}: &ExprCtx,
|
||||
) {
|
||||
let _p = profile::span("complete_expr_path");
|
||||
if !ctx.qualifier_ctx.none() {
|
||||
return;
|
||||
}
|
||||
} = expr_ctx;
|
||||
|
||||
let wants_mut_token =
|
||||
ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);
|
||||
|
@ -46,11 +48,32 @@ pub(crate) fn complete_expr_path(
|
|||
};
|
||||
|
||||
match qualified {
|
||||
Qualified::Infer => ctx
|
||||
Qualified::TypeAnchor { ty: None, trait_: None } => ctx
|
||||
.traits_in_scope()
|
||||
.iter()
|
||||
.flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
|
||||
.for_each(|item| add_assoc_item(acc, item)),
|
||||
Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
|
||||
trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
|
||||
}
|
||||
Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
|
||||
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
|
||||
cov_mark::hit!(completes_variant_through_alias);
|
||||
acc.add_enum_variants(ctx, path_ctx, e);
|
||||
}
|
||||
|
||||
ctx.iterate_path_candidates(&ty, |item| {
|
||||
add_assoc_item(acc, item);
|
||||
});
|
||||
|
||||
// Iterate assoc types separately
|
||||
ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
|
||||
if let hir::AssocItem::TypeAlias(ty) = item {
|
||||
acc.add_type_alias(ctx, ty)
|
||||
}
|
||||
None::<()>
|
||||
});
|
||||
}
|
||||
Qualified::With { resolution: None, .. } => {}
|
||||
Qualified::With { resolution: Some(resolution), .. } => {
|
||||
// Add associated types on type parameters and `Self`.
|
||||
|
@ -179,10 +202,21 @@ pub(crate) fn complete_expr_path(
|
|||
}
|
||||
}
|
||||
}
|
||||
ctx.process_all_names(&mut |name, def| {
|
||||
if scope_def_applicable(def) {
|
||||
acc.add_path_resolution(ctx, path_ctx, name, def);
|
||||
ctx.process_all_names(&mut |name, def| match def {
|
||||
ScopeDef::ModuleDef(hir::ModuleDef::Trait(t)) => {
|
||||
let assocs = t.items_with_supertraits(ctx.db);
|
||||
match &*assocs {
|
||||
// traits with no assoc items are unusable as expressions since
|
||||
// there is no associated item path that can be constructed with them
|
||||
[] => (),
|
||||
// FIXME: Render the assoc item with the trait qualified
|
||||
&[_item] => acc.add_path_resolution(ctx, path_ctx, name, def),
|
||||
// FIXME: Append `::` to the thing here, since a trait on its own won't work
|
||||
[..] => acc.add_path_resolution(ctx, path_ctx, name, def),
|
||||
}
|
||||
}
|
||||
_ if scope_def_applicable(def) => acc.add_path_resolution(ctx, path_ctx, name, def),
|
||||
_ => (),
|
||||
});
|
||||
|
||||
if is_func_update.is_none() {
|
||||
|
|
|
@ -66,7 +66,7 @@ pub(crate) fn complete_item_list(
|
|||
});
|
||||
acc.add_nameref_keywords_with_colon(ctx);
|
||||
}
|
||||
Qualified::Infer | Qualified::No | Qualified::With { .. } => {}
|
||||
Qualified::TypeAnchor { .. } | Qualified::No | Qualified::With { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ pub(crate) fn complete_pattern(
|
|||
hir::ModuleDef::Variant(variant)
|
||||
if refutable || single_variant_enum(variant.parent_enum(ctx.db)) =>
|
||||
{
|
||||
acc.add_variant_pat(ctx, pattern_ctx, variant, Some(name.clone()));
|
||||
acc.add_variant_pat(ctx, pattern_ctx, None, variant, Some(name.clone()));
|
||||
true
|
||||
}
|
||||
hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
|
||||
|
@ -180,6 +180,6 @@ pub(crate) fn complete_pattern_path(
|
|||
|
||||
acc.add_nameref_keywords_with_colon(ctx);
|
||||
}
|
||||
Qualified::Infer | Qualified::With { .. } => {}
|
||||
Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,11 +49,27 @@ pub(crate) fn complete_type_path(
|
|||
};
|
||||
|
||||
match qualified {
|
||||
Qualified::Infer => ctx
|
||||
Qualified::TypeAnchor { ty: None, trait_: None } => ctx
|
||||
.traits_in_scope()
|
||||
.iter()
|
||||
.flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
|
||||
.for_each(|item| add_assoc_item(acc, item)),
|
||||
Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
|
||||
trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
|
||||
}
|
||||
Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
|
||||
ctx.iterate_path_candidates(&ty, |item| {
|
||||
add_assoc_item(acc, item);
|
||||
});
|
||||
|
||||
// Iterate assoc types separately
|
||||
ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
|
||||
if let hir::AssocItem::TypeAlias(ty) = item {
|
||||
acc.add_type_alias(ctx, ty)
|
||||
}
|
||||
None::<()>
|
||||
});
|
||||
}
|
||||
Qualified::With { resolution: None, .. } => {}
|
||||
Qualified::With { resolution: Some(resolution), .. } => {
|
||||
// Add associated types on type parameters and `Self`.
|
||||
|
|
|
@ -115,6 +115,6 @@ pub(crate) fn complete_use_path(
|
|||
});
|
||||
acc.add_nameref_keywords_with_colon(ctx);
|
||||
}
|
||||
Qualified::Infer | Qualified::With { resolution: None, .. } => {}
|
||||
Qualified::TypeAnchor { .. } | Qualified::With { resolution: None, .. } => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ pub(crate) fn complete_vis_path(
|
|||
|
||||
acc.add_super_keyword(ctx, *super_chain_len);
|
||||
}
|
||||
Qualified::Absolute | Qualified::Infer | Qualified::With { .. } => {}
|
||||
Qualified::Absolute | Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
|
||||
Qualified::No => {
|
||||
if !has_in_token {
|
||||
cov_mark::hit!(kw_completion_in);
|
||||
|
|
|
@ -193,7 +193,10 @@ pub(super) enum Qualified {
|
|||
super_chain_len: Option<usize>,
|
||||
},
|
||||
/// <_>::
|
||||
Infer,
|
||||
TypeAnchor {
|
||||
ty: Option<hir::Type>,
|
||||
trait_: Option<hir::Trait>,
|
||||
},
|
||||
/// Whether the path is an absolute path
|
||||
Absolute,
|
||||
}
|
||||
|
|
|
@ -162,11 +162,52 @@ impl<'a> CompletionContext<'a> {
|
|||
}
|
||||
|
||||
/// Calculate the expected type and name of the cursor position.
|
||||
fn expected_type_and_name(&self) -> (Option<Type>, Option<NameOrNameRef>) {
|
||||
fn expected_type_and_name(
|
||||
&self,
|
||||
name_like: &ast::NameLike,
|
||||
) -> (Option<Type>, Option<NameOrNameRef>) {
|
||||
let mut node = match self.token.parent() {
|
||||
Some(it) => it,
|
||||
None => return (None, None),
|
||||
};
|
||||
|
||||
let strip_refs = |mut ty: Type| match name_like {
|
||||
ast::NameLike::NameRef(n) => {
|
||||
let p = match n.syntax().parent() {
|
||||
Some(it) => it,
|
||||
None => return ty,
|
||||
};
|
||||
let top_syn = match_ast! {
|
||||
match p {
|
||||
ast::FieldExpr(e) => e
|
||||
.syntax()
|
||||
.ancestors()
|
||||
.map_while(ast::FieldExpr::cast)
|
||||
.last()
|
||||
.map(|it| it.syntax().clone()),
|
||||
ast::PathSegment(e) => e
|
||||
.syntax()
|
||||
.ancestors()
|
||||
.skip(1)
|
||||
.take_while(|it| ast::Path::can_cast(it.kind()) || ast::PathExpr::can_cast(it.kind()))
|
||||
.find_map(ast::PathExpr::cast)
|
||||
.map(|it| it.syntax().clone()),
|
||||
_ => None
|
||||
}
|
||||
};
|
||||
let top_syn = match top_syn {
|
||||
Some(it) => it,
|
||||
None => return ty,
|
||||
};
|
||||
for _ in top_syn.ancestors().skip(1).map_while(ast::RefExpr::cast) {
|
||||
cov_mark::hit!(expected_type_fn_param_ref);
|
||||
ty = ty.strip_reference();
|
||||
}
|
||||
ty
|
||||
}
|
||||
_ => ty,
|
||||
};
|
||||
|
||||
loop {
|
||||
break match_ast! {
|
||||
match node {
|
||||
|
@ -199,13 +240,9 @@ impl<'a> CompletionContext<'a> {
|
|||
self.token.clone(),
|
||||
).map(|ap| {
|
||||
let name = ap.ident().map(NameOrNameRef::Name);
|
||||
let ty = if has_ref(&self.token) {
|
||||
cov_mark::hit!(expected_type_fn_param_ref);
|
||||
ap.ty.remove_ref()
|
||||
} else {
|
||||
Some(ap.ty)
|
||||
};
|
||||
(ty, name)
|
||||
|
||||
let ty = strip_refs(ap.ty);
|
||||
(Some(ty), name)
|
||||
})
|
||||
.unwrap_or((None, None))
|
||||
},
|
||||
|
@ -330,8 +367,6 @@ impl<'a> CompletionContext<'a> {
|
|||
return None;
|
||||
}
|
||||
|
||||
(self.expected_type, self.expected_name) = self.expected_type_and_name();
|
||||
|
||||
// Overwrite the path kind for derives
|
||||
if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx {
|
||||
if let Some(ast::NameLike::NameRef(name_ref)) =
|
||||
|
@ -389,6 +424,7 @@ impl<'a> CompletionContext<'a> {
|
|||
return Some(analysis);
|
||||
}
|
||||
};
|
||||
(self.expected_type, self.expected_name) = self.expected_type_and_name(&name_like);
|
||||
let analysis = match name_like {
|
||||
ast::NameLike::Lifetime(lifetime) => CompletionAnalysis::Lifetime(
|
||||
Self::classify_lifetime(&self.sema, original_file, lifetime)?,
|
||||
|
@ -556,7 +592,7 @@ impl<'a> CompletionContext<'a> {
|
|||
has_call_parens: false,
|
||||
has_macro_bang: false,
|
||||
qualified: Qualified::No,
|
||||
parent: path.parent_path(),
|
||||
parent: None,
|
||||
path: path.clone(),
|
||||
kind: PathKind::Item { kind: ItemListKind::SourceFile },
|
||||
has_type_args: false,
|
||||
|
@ -791,92 +827,125 @@ impl<'a> CompletionContext<'a> {
|
|||
PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
|
||||
};
|
||||
|
||||
let mut kind_macro_call = |it: ast::MacroCall| {
|
||||
path_ctx.has_macro_bang = it.excl_token().is_some();
|
||||
let parent = it.syntax().parent()?;
|
||||
// Any path in an item list will be treated as a macro call by the parser
|
||||
let kind = match_ast! {
|
||||
match parent {
|
||||
ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
|
||||
ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
|
||||
ast::MacroType(ty) => make_path_kind_type(ty.into()),
|
||||
ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
|
||||
ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
|
||||
Some(it) => match_ast! {
|
||||
match it {
|
||||
ast::Trait(_) => ItemListKind::Trait,
|
||||
ast::Impl(it) => if it.trait_().is_some() {
|
||||
ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
|
||||
} else {
|
||||
ItemListKind::Impl
|
||||
},
|
||||
_ => return None
|
||||
}
|
||||
},
|
||||
None => return None,
|
||||
} },
|
||||
ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
|
||||
ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
|
||||
_ => return None,
|
||||
}
|
||||
};
|
||||
Some(kind)
|
||||
};
|
||||
let make_path_kind_attr = |meta: ast::Meta| {
|
||||
let attr = meta.parent_attr()?;
|
||||
let kind = attr.kind();
|
||||
let attached = attr.syntax().parent()?;
|
||||
let is_trailing_outer_attr = kind != AttrKind::Inner
|
||||
&& non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next)
|
||||
.is_none();
|
||||
let annotated_item_kind =
|
||||
if is_trailing_outer_attr { None } else { Some(attached.kind()) };
|
||||
Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } })
|
||||
};
|
||||
|
||||
// Infer the path kind
|
||||
let parent = path.syntax().parent()?;
|
||||
let kind = match_ast! {
|
||||
match parent {
|
||||
ast::PathType(it) => make_path_kind_type(it.into()),
|
||||
ast::PathExpr(it) => {
|
||||
if let Some(p) = it.syntax().parent() {
|
||||
if ast::ExprStmt::can_cast(p.kind()) {
|
||||
if let Some(kind) = inbetween_body_and_decl_check(p) {
|
||||
return Some(make_res(NameRefKind::Keyword(kind)));
|
||||
}
|
||||
match parent {
|
||||
ast::PathType(it) => make_path_kind_type(it.into()),
|
||||
ast::PathExpr(it) => {
|
||||
if let Some(p) = it.syntax().parent() {
|
||||
if ast::ExprStmt::can_cast(p.kind()) {
|
||||
if let Some(kind) = inbetween_body_and_decl_check(p) {
|
||||
return Some(make_res(NameRefKind::Keyword(kind)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
|
||||
path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
|
||||
|
||||
make_path_kind_expr(it.into())
|
||||
},
|
||||
ast::TupleStructPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
|
||||
},
|
||||
ast::RecordPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
|
||||
},
|
||||
ast::PathPat(it) => {
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
|
||||
},
|
||||
ast::MacroCall(it) => {
|
||||
// A macro call in this position is usually a result of parsing recovery, so check that
|
||||
if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
|
||||
return Some(make_res(NameRefKind::Keyword(kind)));
|
||||
make_path_kind_expr(it.into())
|
||||
},
|
||||
ast::TupleStructPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
|
||||
},
|
||||
ast::RecordPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
|
||||
},
|
||||
ast::PathPat(it) => {
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
|
||||
},
|
||||
ast::MacroCall(it) => {
|
||||
// A macro call in this position is usually a result of parsing recovery, so check that
|
||||
if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
|
||||
return Some(make_res(NameRefKind::Keyword(kind)));
|
||||
}
|
||||
|
||||
kind_macro_call(it)?
|
||||
},
|
||||
ast::Meta(meta) => make_path_kind_attr(meta)?,
|
||||
ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
|
||||
ast::UseTree(_) => PathKind::Use,
|
||||
// completing inside a qualifier
|
||||
ast::Path(parent) => {
|
||||
path_ctx.parent = Some(parent.clone());
|
||||
let parent = iter::successors(Some(parent), |it| it.parent_path()).last()?.syntax().parent()?;
|
||||
match_ast! {
|
||||
match parent {
|
||||
ast::PathType(it) => make_path_kind_type(it.into()),
|
||||
ast::PathExpr(it) => {
|
||||
path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
|
||||
|
||||
make_path_kind_expr(it.into())
|
||||
},
|
||||
ast::TupleStructPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
|
||||
},
|
||||
ast::RecordPat(it) => {
|
||||
path_ctx.has_call_parens = true;
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
|
||||
},
|
||||
ast::PathPat(it) => {
|
||||
PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
|
||||
},
|
||||
ast::MacroCall(it) => {
|
||||
kind_macro_call(it)?
|
||||
},
|
||||
ast::Meta(meta) => make_path_kind_attr(meta)?,
|
||||
ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
|
||||
ast::UseTree(_) => PathKind::Use,
|
||||
ast::RecordExpr(it) => make_path_kind_expr(it.into()),
|
||||
_ => return None,
|
||||
}
|
||||
|
||||
path_ctx.has_macro_bang = it.excl_token().is_some();
|
||||
let parent = it.syntax().parent()?;
|
||||
// Any path in an item list will be treated as a macro call by the parser
|
||||
match_ast! {
|
||||
match parent {
|
||||
ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
|
||||
ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
|
||||
ast::MacroType(ty) => make_path_kind_type(ty.into()),
|
||||
ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
|
||||
ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
|
||||
Some(it) => match_ast! {
|
||||
match it {
|
||||
ast::Trait(_) => ItemListKind::Trait,
|
||||
ast::Impl(it) => if it.trait_().is_some() {
|
||||
ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
|
||||
} else {
|
||||
ItemListKind::Impl
|
||||
},
|
||||
_ => return None
|
||||
}
|
||||
},
|
||||
None => return None,
|
||||
} },
|
||||
ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
|
||||
ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
},
|
||||
ast::Meta(meta) => {
|
||||
let attr = meta.parent_attr()?;
|
||||
let kind = attr.kind();
|
||||
let attached = attr.syntax().parent()?;
|
||||
let is_trailing_outer_attr = kind != AttrKind::Inner
|
||||
&& non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none();
|
||||
let annotated_item_kind = if is_trailing_outer_attr {
|
||||
None
|
||||
} else {
|
||||
Some(attached.kind())
|
||||
};
|
||||
PathKind::Attr {
|
||||
attr_ctx: AttrCtx {
|
||||
kind,
|
||||
annotated_item_kind,
|
||||
}
|
||||
}
|
||||
},
|
||||
ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
|
||||
ast::UseTree(_) => PathKind::Use,
|
||||
_ => return None,
|
||||
|
||||
}
|
||||
},
|
||||
ast::RecordExpr(it) => make_path_kind_expr(it.into()),
|
||||
_ => return None,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -884,49 +953,53 @@ impl<'a> CompletionContext<'a> {
|
|||
path_ctx.has_type_args = segment.generic_arg_list().is_some();
|
||||
|
||||
// calculate the qualifier context
|
||||
if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
|
||||
if let Some((qualifier, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
|
||||
path_ctx.use_tree_parent = use_tree_parent;
|
||||
if !use_tree_parent && segment.coloncolon_token().is_some() {
|
||||
path_ctx.qualified = Qualified::Absolute;
|
||||
} else {
|
||||
let path = path
|
||||
let qualifier = qualifier
|
||||
.segment()
|
||||
.and_then(|it| find_node_in_file(original_file, &it))
|
||||
.map(|it| it.parent_path());
|
||||
if let Some(path) = path {
|
||||
// `<_>::$0`
|
||||
let is_infer_qualifier = path.qualifier().is_none()
|
||||
&& matches!(
|
||||
path.segment().and_then(|it| it.kind()),
|
||||
Some(ast::PathSegmentKind::Type {
|
||||
type_ref: Some(ast::Type::InferType(_)),
|
||||
trait_ref: None,
|
||||
})
|
||||
);
|
||||
if let Some(qualifier) = qualifier {
|
||||
let type_anchor = match qualifier.segment().and_then(|it| it.kind()) {
|
||||
Some(ast::PathSegmentKind::Type {
|
||||
type_ref: Some(type_ref),
|
||||
trait_ref,
|
||||
}) if qualifier.qualifier().is_none() => Some((type_ref, trait_ref)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
path_ctx.qualified = if is_infer_qualifier {
|
||||
Qualified::Infer
|
||||
path_ctx.qualified = if let Some((ty, trait_ref)) = type_anchor {
|
||||
let ty = match ty {
|
||||
ast::Type::InferType(_) => None,
|
||||
ty => sema.resolve_type(&ty),
|
||||
};
|
||||
let trait_ = trait_ref.and_then(|it| sema.resolve_trait(&it.path()?));
|
||||
Qualified::TypeAnchor { ty, trait_ }
|
||||
} else {
|
||||
let res = sema.resolve_path(&path);
|
||||
let res = sema.resolve_path(&qualifier);
|
||||
|
||||
// For understanding how and why super_chain_len is calculated the way it
|
||||
// is check the documentation at it's definition
|
||||
let mut segment_count = 0;
|
||||
let super_count = iter::successors(Some(path.clone()), |p| p.qualifier())
|
||||
.take_while(|p| {
|
||||
p.segment()
|
||||
.and_then(|s| {
|
||||
segment_count += 1;
|
||||
s.super_token()
|
||||
})
|
||||
.is_some()
|
||||
})
|
||||
.count();
|
||||
let super_count =
|
||||
iter::successors(Some(qualifier.clone()), |p| p.qualifier())
|
||||
.take_while(|p| {
|
||||
p.segment()
|
||||
.and_then(|s| {
|
||||
segment_count += 1;
|
||||
s.super_token()
|
||||
})
|
||||
.is_some()
|
||||
})
|
||||
.count();
|
||||
|
||||
let super_chain_len =
|
||||
if segment_count > super_count { None } else { Some(super_count) };
|
||||
|
||||
Qualified::With { path, resolution: res, super_chain_len }
|
||||
Qualified::With { path: qualifier, resolution: res, super_chain_len }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1141,19 +1214,6 @@ fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> {
|
|||
Some((use_tree.path()?, true))
|
||||
}
|
||||
|
||||
fn has_ref(token: &SyntaxToken) -> bool {
|
||||
let mut token = token.clone();
|
||||
for skip in [SyntaxKind::IDENT, SyntaxKind::WHITESPACE, T![mut]] {
|
||||
if token.kind() == skip {
|
||||
token = match token.prev_token() {
|
||||
Some(it) => it,
|
||||
None => return false,
|
||||
}
|
||||
}
|
||||
}
|
||||
token.kind() == T![&]
|
||||
}
|
||||
|
||||
pub(crate) fn is_in_token_of_for_loop(element: SyntaxElement) -> bool {
|
||||
// oh my ...
|
||||
(|| {
|
||||
|
|
|
@ -391,3 +391,23 @@ fn foo($0: Foo) {}
|
|||
expect![[r#"ty: ?, name: ?"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expected_type_ref_prefix_on_field() {
|
||||
check_expected_type_and_name(
|
||||
r#"
|
||||
fn foo(_: &mut i32) {}
|
||||
struct S {
|
||||
field: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = S {
|
||||
field: 100,
|
||||
};
|
||||
foo(&mut s.f$0);
|
||||
}
|
||||
"#,
|
||||
expect!["ty: i32, name: ?"],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1271,8 +1271,8 @@ fn main() {
|
|||
st S []
|
||||
st &mut S [type]
|
||||
st S []
|
||||
fn main() []
|
||||
fn foo(…) []
|
||||
fn main() []
|
||||
"#]],
|
||||
);
|
||||
check_relevance(
|
||||
|
@ -1288,8 +1288,8 @@ fn main() {
|
|||
lc s [type+name+local]
|
||||
st S [type]
|
||||
st S []
|
||||
fn main() []
|
||||
fn foo(…) []
|
||||
fn main() []
|
||||
"#]],
|
||||
);
|
||||
check_relevance(
|
||||
|
@ -1305,8 +1305,8 @@ fn main() {
|
|||
lc ssss [type+local]
|
||||
st S [type]
|
||||
st S []
|
||||
fn main() []
|
||||
fn foo(…) []
|
||||
fn main() []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1342,12 +1342,11 @@ fn main() {
|
|||
lc &t [type+local]
|
||||
st S []
|
||||
st &S [type]
|
||||
st T []
|
||||
st S []
|
||||
fn main() []
|
||||
st T []
|
||||
fn foo(…) []
|
||||
fn main() []
|
||||
md core []
|
||||
tt Sized []
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -1389,12 +1388,11 @@ fn main() {
|
|||
lc &mut t [type+local]
|
||||
st S []
|
||||
st &mut S [type]
|
||||
st T []
|
||||
st S []
|
||||
fn main() []
|
||||
st T []
|
||||
fn foo(…) []
|
||||
fn main() []
|
||||
md core []
|
||||
tt Sized []
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -1485,14 +1483,13 @@ fn main() {
|
|||
expect![[r#"
|
||||
st S []
|
||||
st &S [type]
|
||||
st T []
|
||||
st S []
|
||||
fn main() []
|
||||
st T []
|
||||
fn bar() []
|
||||
fn &bar() [type]
|
||||
fn foo(…) []
|
||||
fn main() []
|
||||
md core []
|
||||
tt Sized []
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -1636,8 +1633,8 @@ fn foo() {
|
|||
ev Foo::B [type_could_unify]
|
||||
fn foo() []
|
||||
en Foo []
|
||||
fn baz() []
|
||||
fn bar() []
|
||||
fn baz() []
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1727,9 +1724,9 @@ fn f() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
md std []
|
||||
st Buffer []
|
||||
fn f() []
|
||||
md std []
|
||||
tt BufRead (use std::io::BufRead) [requires_import]
|
||||
st BufReader (use std::io::BufReader) [requires_import]
|
||||
st BufWriter (use std::io::BufWriter) [requires_import]
|
||||
|
|
|
@ -85,7 +85,9 @@ fn render(
|
|||
item.ref_match(ref_match, path_ctx.path.syntax().text_range().start());
|
||||
}
|
||||
FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => {
|
||||
item.ref_match(ref_match, receiver.syntax().text_range().start());
|
||||
if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) {
|
||||
item.ref_match(ref_match, original_expr.syntax().text_range().start());
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use itertools::Itertools;
|
|||
use syntax::SmolStr;
|
||||
|
||||
use crate::{
|
||||
context::{ParamContext, ParamKind, PatternContext},
|
||||
context::{ParamContext, ParamKind, PathCompletionCtx, PatternContext},
|
||||
render::{
|
||||
variant::{format_literal_label, visible_fields},
|
||||
RenderContext,
|
||||
|
@ -42,6 +42,7 @@ pub(crate) fn render_struct_pat(
|
|||
pub(crate) fn render_variant_pat(
|
||||
ctx: RenderContext<'_>,
|
||||
pattern_ctx: &PatternContext,
|
||||
path_ctx: Option<&PathCompletionCtx>,
|
||||
variant: hir::Variant,
|
||||
local_name: Option<Name>,
|
||||
path: Option<&hir::ModPath>,
|
||||
|
@ -58,9 +59,23 @@ pub(crate) fn render_variant_pat(
|
|||
(name.to_smol_str(), name.escaped().to_smol_str())
|
||||
}
|
||||
};
|
||||
let kind = variant.kind(ctx.db());
|
||||
let label = format_literal_label(name.as_str(), kind);
|
||||
let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?;
|
||||
|
||||
let (label, pat) = match path_ctx {
|
||||
Some(PathCompletionCtx { has_call_parens: true, .. }) => (name, escaped_name.to_string()),
|
||||
_ => {
|
||||
let kind = variant.kind(ctx.db());
|
||||
let label = format_literal_label(name.as_str(), kind);
|
||||
let pat = render_pat(
|
||||
&ctx,
|
||||
pattern_ctx,
|
||||
&escaped_name,
|
||||
kind,
|
||||
&visible_fields,
|
||||
fields_omitted,
|
||||
)?;
|
||||
(label, pat)
|
||||
}
|
||||
};
|
||||
|
||||
Some(build_completion(ctx, label, pat, variant))
|
||||
}
|
||||
|
|
|
@ -23,8 +23,6 @@ mod type_pos;
|
|||
mod use_tree;
|
||||
mod visibility;
|
||||
|
||||
use std::mem;
|
||||
|
||||
use hir::{db::DefDatabase, PrefixKind, Semantics};
|
||||
use ide_db::{
|
||||
base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
|
||||
|
@ -107,12 +105,9 @@ fn completion_list_with_config(
|
|||
) -> String {
|
||||
// filter out all but one builtintype completion for smaller test outputs
|
||||
let items = get_all_items(config, ra_fixture, trigger_character);
|
||||
let mut bt_seen = false;
|
||||
let items = items
|
||||
.into_iter()
|
||||
.filter(|it| {
|
||||
it.kind() != CompletionItemKind::BuiltinType || !mem::replace(&mut bt_seen, true)
|
||||
})
|
||||
.filter(|it| it.kind() != CompletionItemKind::BuiltinType || it.label() == "u32")
|
||||
.filter(|it| include_keywords || it.kind() != CompletionItemKind::Keyword)
|
||||
.filter(|it| include_keywords || it.kind() != CompletionItemKind::Snippet)
|
||||
.sorted_by_key(|it| (it.kind(), it.label().to_owned(), it.detail().map(ToOwned::to_owned)))
|
||||
|
|
|
@ -44,7 +44,6 @@ fn baz() {
|
|||
st Record
|
||||
st Tuple
|
||||
st Unit
|
||||
tt Trait
|
||||
un Union
|
||||
ev TupleV(…) TupleV(u32)
|
||||
bt u32
|
||||
|
@ -137,7 +136,6 @@ impl Unit {
|
|||
st Record
|
||||
st Tuple
|
||||
st Unit
|
||||
tt Trait
|
||||
tp TypeParam
|
||||
un Union
|
||||
ev TupleV(…) TupleV(u32)
|
||||
|
@ -653,3 +651,22 @@ fn main() {
|
|||
"]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complete_record_expr_path() {
|
||||
check(
|
||||
r#"
|
||||
struct Zulu;
|
||||
impl Zulu {
|
||||
fn test() -> Self { }
|
||||
}
|
||||
fn boi(val: Zulu) { }
|
||||
fn main() {
|
||||
boi(Zulu:: $0 {});
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn test() fn() -> Zulu
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -443,7 +443,7 @@ fn foo() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
bn TupleVariant(…) TupleVariant($1)$0
|
||||
bn TupleVariant TupleVariant
|
||||
"#]],
|
||||
);
|
||||
check_empty(
|
||||
|
@ -458,7 +458,7 @@ fn foo() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
bn RecordVariant {…} RecordVariant { field$1 }$0
|
||||
bn RecordVariant RecordVariant
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -167,7 +167,6 @@ fn main() {
|
|||
st Foo
|
||||
st Foo {…} Foo { foo1: u32, foo2: u32 }
|
||||
tt Default
|
||||
tt Sized
|
||||
bt u32
|
||||
kw crate::
|
||||
kw self::
|
||||
|
|
|
@ -674,7 +674,60 @@ fn bar() -> Bar {
|
|||
expect![[r#"
|
||||
fn foo() (as Foo) fn() -> Self
|
||||
"#]],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_anchor_type() {
|
||||
check(
|
||||
r#"
|
||||
trait Foo {
|
||||
fn foo() -> Self;
|
||||
}
|
||||
struct Bar;
|
||||
impl Bar {
|
||||
fn bar() {}
|
||||
}
|
||||
impl Foo for Bar {
|
||||
fn foo() -> {
|
||||
Bar
|
||||
}
|
||||
}
|
||||
fn bar() -> Bar {
|
||||
<Bar>::$0
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn bar() fn()
|
||||
fn foo() (as Foo) fn() -> Self
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type_anchor_type_trait() {
|
||||
check(
|
||||
r#"
|
||||
trait Foo {
|
||||
fn foo() -> Self;
|
||||
}
|
||||
struct Bar;
|
||||
impl Bar {
|
||||
fn bar() {}
|
||||
}
|
||||
impl Foo for Bar {
|
||||
fn foo() -> {
|
||||
Bar
|
||||
}
|
||||
}
|
||||
fn bar() -> Bar {
|
||||
<Bar as Foo>::$0
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() (as Foo) fn() -> Self
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -13,7 +13,7 @@ mod html;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use hir::{InFile, Name, Semantics};
|
||||
use hir::{Name, Semantics};
|
||||
use ide_db::{FxHashMap, RootDatabase};
|
||||
use syntax::{
|
||||
ast, AstNode, AstToken, NodeOrToken, SyntaxKind::*, SyntaxNode, TextRange, WalkEvent, T,
|
||||
|
@ -325,7 +325,7 @@ fn traverse(
|
|||
Leave(NodeOrToken::Node(node)) => {
|
||||
// Doc comment highlighting injection, we do this when leaving the node
|
||||
// so that we overwrite the highlighting of the doc comment itself.
|
||||
inject::doc_comment(hl, sema, InFile::new(file_id.into(), &node));
|
||||
inject::doc_comment(hl, sema, file_id, &node);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,7 +5,8 @@ use std::mem;
|
|||
use either::Either;
|
||||
use hir::{InFile, Semantics};
|
||||
use ide_db::{
|
||||
active_parameter::ActiveParameter, defs::Definition, rust_doc::is_rust_fence, SymbolKind,
|
||||
active_parameter::ActiveParameter, base_db::FileId, defs::Definition, rust_doc::is_rust_fence,
|
||||
SymbolKind,
|
||||
};
|
||||
use syntax::{
|
||||
ast::{self, AstNode, IsString, QuoteOffsets},
|
||||
|
@ -81,16 +82,18 @@ pub(super) fn ra_fixture(
|
|||
const RUSTDOC_FENCE_LENGTH: usize = 3;
|
||||
const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
|
||||
|
||||
/// Injection of syntax highlighting of doctests.
|
||||
/// Injection of syntax highlighting of doctests and intra doc links.
|
||||
pub(super) fn doc_comment(
|
||||
hl: &mut Highlights,
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
InFile { file_id: src_file_id, value: node }: InFile<&SyntaxNode>,
|
||||
src_file_id: FileId,
|
||||
node: &SyntaxNode,
|
||||
) {
|
||||
let (attributes, def) = match doc_attributes(sema, node) {
|
||||
Some(it) => it,
|
||||
None => return,
|
||||
};
|
||||
let src_file_id = src_file_id.into();
|
||||
|
||||
// Extract intra-doc links and emit highlights for them.
|
||||
if let Some((docs, doc_mapping)) = attributes.docs_with_rangemap(sema.db) {
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
<style>
|
||||
body { margin: 0; }
|
||||
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
|
||||
|
||||
.lifetime { color: #DFAF8F; font-style: italic; }
|
||||
.label { color: #DFAF8F; font-style: italic; }
|
||||
.comment { color: #7F9F7F; }
|
||||
.documentation { color: #629755; }
|
||||
.intra_doc_link { font-style: italic; }
|
||||
.injected { opacity: 0.65 ; }
|
||||
.struct, .enum { color: #7CB8BB; }
|
||||
.enum_variant { color: #BDE0F3; }
|
||||
.string_literal { color: #CC9393; }
|
||||
.field { color: #94BFF3; }
|
||||
.function { color: #93E0E3; }
|
||||
.function.unsafe { color: #BC8383; }
|
||||
.trait.unsafe { color: #BC8383; }
|
||||
.operator.unsafe { color: #BC8383; }
|
||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||
.macro.unsafe { color: #BC8383; }
|
||||
.parameter { color: #94BFF3; }
|
||||
.text { color: #DCDCCC; }
|
||||
.type { color: #7CB8BB; }
|
||||
.builtin_type { color: #8CD0D3; }
|
||||
.type_param { color: #DFAF8F; }
|
||||
.attribute { color: #94BFF3; }
|
||||
.numeric_literal { color: #BFEBBF; }
|
||||
.bool_literal { color: #BFE6EB; }
|
||||
.macro { color: #94BFF3; }
|
||||
.derive { color: #94BFF3; font-style: italic; }
|
||||
.module { color: #AFD8AF; }
|
||||
.value_param { color: #DCDCCC; }
|
||||
.variable { color: #DCDCCC; }
|
||||
.format_specifier { color: #CC696B; }
|
||||
.mutable { text-decoration: underline; }
|
||||
.escape_sequence { color: #94BFF3; }
|
||||
.keyword { color: #F0DFAF; font-weight: bold; }
|
||||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
|
||||
<span class="comment documentation">//! This is an intra doc injection test for modules</span>
|
||||
<span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
|
||||
<span class="comment documentation">//! This is an intra doc injection test for modules</span>
|
||||
|
||||
<span class="keyword">pub</span> <span class="keyword">struct</span> <span class="struct declaration public">Struct</span><span class="semicolon">;</span>
|
||||
</code></pre>
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
<style>
|
||||
body { margin: 0; }
|
||||
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
|
||||
|
||||
.lifetime { color: #DFAF8F; font-style: italic; }
|
||||
.label { color: #DFAF8F; font-style: italic; }
|
||||
.comment { color: #7F9F7F; }
|
||||
.documentation { color: #629755; }
|
||||
.intra_doc_link { font-style: italic; }
|
||||
.injected { opacity: 0.65 ; }
|
||||
.struct, .enum { color: #7CB8BB; }
|
||||
.enum_variant { color: #BDE0F3; }
|
||||
.string_literal { color: #CC9393; }
|
||||
.field { color: #94BFF3; }
|
||||
.function { color: #93E0E3; }
|
||||
.function.unsafe { color: #BC8383; }
|
||||
.trait.unsafe { color: #BC8383; }
|
||||
.operator.unsafe { color: #BC8383; }
|
||||
.mutable.unsafe { color: #BC8383; text-decoration: underline; }
|
||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||
.macro.unsafe { color: #BC8383; }
|
||||
.parameter { color: #94BFF3; }
|
||||
.text { color: #DCDCCC; }
|
||||
.type { color: #7CB8BB; }
|
||||
.builtin_type { color: #8CD0D3; }
|
||||
.type_param { color: #DFAF8F; }
|
||||
.attribute { color: #94BFF3; }
|
||||
.numeric_literal { color: #BFEBBF; }
|
||||
.bool_literal { color: #BFE6EB; }
|
||||
.macro { color: #94BFF3; }
|
||||
.derive { color: #94BFF3; font-style: italic; }
|
||||
.module { color: #AFD8AF; }
|
||||
.value_param { color: #DCDCCC; }
|
||||
.variable { color: #DCDCCC; }
|
||||
.format_specifier { color: #CC696B; }
|
||||
.mutable { text-decoration: underline; }
|
||||
.escape_sequence { color: #94BFF3; }
|
||||
.keyword { color: #F0DFAF; font-weight: bold; }
|
||||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[crate::foo::Struct]</span>
|
||||
<span class="comment documentation">/// This is an intra doc injection test for modules</span>
|
||||
<span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[crate::foo::Struct]</span>
|
||||
<span class="comment documentation">/// This is an intra doc injection test for modules</span>
|
||||
<span class="keyword">mod</span> <span class="module declaration">foo</span><span class="semicolon">;</span>
|
||||
</code></pre>
|
|
@ -915,6 +915,52 @@ fn main() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_mod_hl_injection() {
|
||||
check_highlighting(
|
||||
r##"
|
||||
//- /foo.rs
|
||||
//! [Struct]
|
||||
//! This is an intra doc injection test for modules
|
||||
//! [Struct]
|
||||
//! This is an intra doc injection test for modules
|
||||
|
||||
pub struct Struct;
|
||||
//- /lib.rs crate:foo
|
||||
/// [crate::foo::Struct]
|
||||
/// This is an intra doc injection test for modules
|
||||
/// [crate::foo::Struct]
|
||||
/// This is an intra doc injection test for modules
|
||||
mod foo;
|
||||
"##,
|
||||
expect_file!["./test_data/highlight_module_docs_inline.html"],
|
||||
false,
|
||||
);
|
||||
check_highlighting(
|
||||
r##"
|
||||
//- /lib.rs crate:foo
|
||||
/// [crate::foo::Struct]
|
||||
/// This is an intra doc injection test for modules
|
||||
/// [crate::foo::Struct]
|
||||
/// This is an intra doc injection test for modules
|
||||
mod foo;
|
||||
//- /foo.rs
|
||||
//! [Struct]
|
||||
//! This is an intra doc injection test for modules
|
||||
//! [Struct]
|
||||
//! This is an intra doc injection test for modules
|
||||
|
||||
pub struct Struct;
|
||||
"##,
|
||||
expect_file!["./test_data/highlight_module_docs_outline.html"],
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(
|
||||
all(unix, not(target_pointer_width = "64")),
|
||||
ignore = "depends on `DefaultHasher` outputs"
|
||||
)]
|
||||
fn test_rainbow_highlighting() {
|
||||
check_highlighting(
|
||||
r#"
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
|
||||
#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
|
||||
|
||||
#[cfg(feature = "tracking")]
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
|
||||
/// Represents a struct used to enforce a numerical limit.
|
||||
pub struct Limit {
|
||||
upper_bound: usize,
|
||||
#[allow(unused)]
|
||||
#[cfg(feature = "tracking")]
|
||||
max: AtomicUsize,
|
||||
}
|
||||
|
||||
|
@ -15,14 +16,22 @@ impl Limit {
|
|||
/// Creates a new limit.
|
||||
#[inline]
|
||||
pub const fn new(upper_bound: usize) -> Self {
|
||||
Self { upper_bound, max: AtomicUsize::new(0) }
|
||||
Self {
|
||||
upper_bound,
|
||||
#[cfg(feature = "tracking")]
|
||||
max: AtomicUsize::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new limit.
|
||||
#[inline]
|
||||
#[cfg(feature = "tracking")]
|
||||
pub const fn new_tracking(upper_bound: usize) -> Self {
|
||||
Self { upper_bound, max: AtomicUsize::new(1) }
|
||||
Self {
|
||||
upper_bound,
|
||||
#[cfg(feature = "tracking")]
|
||||
max: AtomicUsize::new(1),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the underlying numeric limit.
|
||||
|
|
|
@ -54,7 +54,7 @@ fn path_for_qualifier(
|
|||
mut qual: CompletedMarker,
|
||||
) -> CompletedMarker {
|
||||
loop {
|
||||
let use_tree = matches!(p.nth(2), T![*] | T!['{']);
|
||||
let use_tree = mode == Mode::Use && matches!(p.nth(2), T![*] | T!['{']);
|
||||
if p.at(T![::]) && !use_tree {
|
||||
let path = qual.precede(p);
|
||||
p.bump(T![::]);
|
||||
|
|
|
@ -39,6 +39,8 @@ pub(crate) struct ProcMacroSrv {
|
|||
expanders: HashMap<(PathBuf, SystemTime), dylib::Expander>,
|
||||
}
|
||||
|
||||
const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024;
|
||||
|
||||
impl ProcMacroSrv {
|
||||
pub fn expand(&mut self, task: ExpandMacro) -> Result<FlatTree, PanicMessage> {
|
||||
let expander = self.expander(task.lib.as_ref()).map_err(|err| {
|
||||
|
@ -66,13 +68,18 @@ impl ProcMacroSrv {
|
|||
// FIXME: replace this with std's scoped threads once they stabilize
|
||||
// (then remove dependency on crossbeam)
|
||||
let result = crossbeam::scope(|s| {
|
||||
let res = s
|
||||
let res = match s
|
||||
.builder()
|
||||
.stack_size(EXPANDER_STACK_SIZE)
|
||||
.name(task.macro_name.clone())
|
||||
.spawn(|_| {
|
||||
expander
|
||||
.expand(&task.macro_name, ¯o_body, attributes.as_ref())
|
||||
.map(|it| FlatTree::new(&it))
|
||||
})
|
||||
.join();
|
||||
}) {
|
||||
Ok(handle) => handle.join(),
|
||||
Err(e) => std::panic::resume_unwind(Box::new(e)),
|
||||
};
|
||||
|
||||
match res {
|
||||
Ok(res) => res,
|
||||
|
|
|
@ -66,7 +66,9 @@ pub fn load_workspace(
|
|||
};
|
||||
|
||||
let crate_graph = ws.to_crate_graph(
|
||||
&mut |_, path: &AbsPath| load_proc_macro(proc_macro_client.as_ref(), path, &[]),
|
||||
&mut |_, path: &AbsPath| {
|
||||
load_proc_macro(proc_macro_client.as_ref().map_err(|e| &**e), path, &[])
|
||||
},
|
||||
&mut |path: &AbsPath| {
|
||||
let contents = loader.load_sync(path);
|
||||
let path = vfs::VfsPath::from(path.to_path_buf());
|
||||
|
|
|
@ -303,6 +303,9 @@ impl GlobalState {
|
|||
let files_config = self.config.files();
|
||||
let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
|
||||
|
||||
let standalone_server_name =
|
||||
format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
|
||||
|
||||
if self.proc_macro_clients.is_empty() {
|
||||
if let Some((path, args)) = self.config.proc_macro_srv() {
|
||||
self.proc_macro_clients = self
|
||||
|
@ -316,10 +319,8 @@ impl GlobalState {
|
|||
tracing::info!("Found a cargo workspace...");
|
||||
if let Some(sysroot) = sysroot.as_ref() {
|
||||
tracing::info!("Found a cargo workspace with a sysroot...");
|
||||
let server_path = sysroot
|
||||
.root()
|
||||
.join("libexec")
|
||||
.join("rust-analyzer-proc-macro-srv");
|
||||
let server_path =
|
||||
sysroot.root().join("libexec").join(&standalone_server_name);
|
||||
if std::fs::metadata(&server_path).is_ok() {
|
||||
tracing::info!(
|
||||
"And the server exists at {}",
|
||||
|
@ -389,7 +390,10 @@ impl GlobalState {
|
|||
|
||||
let mut crate_graph = CrateGraph::default();
|
||||
for (idx, ws) in self.workspaces.iter().enumerate() {
|
||||
let proc_macro_client = self.proc_macro_clients[idx].as_ref();
|
||||
let proc_macro_client = match self.proc_macro_clients.get(idx) {
|
||||
Some(res) => res.as_ref().map_err(|e| &**e),
|
||||
None => Err("Proc macros are disabled"),
|
||||
};
|
||||
let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| {
|
||||
load_proc_macro(
|
||||
proc_macro_client,
|
||||
|
@ -573,7 +577,7 @@ impl SourceRootConfig {
|
|||
/// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace`
|
||||
/// with an identity dummy expander.
|
||||
pub(crate) fn load_proc_macro(
|
||||
server: Result<&ProcMacroServer, &String>,
|
||||
server: Result<&ProcMacroServer, &str>,
|
||||
path: &AbsPath,
|
||||
dummy_replace: &[Box<str>],
|
||||
) -> ProcMacroLoadResult {
|
||||
|
|
|
@ -880,7 +880,6 @@ impl ForExpr {
|
|||
pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
|
||||
pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
|
||||
pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
|
||||
pub fn iterable(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -890,7 +889,6 @@ pub struct IfExpr {
|
|||
impl ast::HasAttrs for IfExpr {}
|
||||
impl IfExpr {
|
||||
pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
|
||||
pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||
pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
|
||||
}
|
||||
|
||||
|
@ -1051,7 +1049,6 @@ pub struct WhileExpr {
|
|||
impl ast::HasAttrs for WhileExpr {}
|
||||
impl WhileExpr {
|
||||
pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) }
|
||||
pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -1170,7 +1167,6 @@ pub struct MatchGuard {
|
|||
}
|
||||
impl MatchGuard {
|
||||
pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
|
||||
pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
|
|
@ -806,6 +806,19 @@ impl ast::GenericParamList {
|
|||
}
|
||||
}
|
||||
|
||||
impl ast::ForExpr {
|
||||
pub fn iterable(&self) -> Option<ast::Expr> {
|
||||
// If the iterable is a BlockExpr, check if the body is missing.
|
||||
// If it is assume the iterable is the expression that is missing instead.
|
||||
let mut exprs = support::children(self.syntax());
|
||||
let first = exprs.next();
|
||||
match first {
|
||||
Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
|
||||
first => first,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::HasLoopBody for ast::ForExpr {
|
||||
fn loop_body(&self) -> Option<ast::BlockExpr> {
|
||||
let mut exprs = support::children(self.syntax());
|
||||
|
@ -815,6 +828,19 @@ impl ast::HasLoopBody for ast::ForExpr {
|
|||
}
|
||||
}
|
||||
|
||||
impl ast::WhileExpr {
|
||||
pub fn condition(&self) -> Option<ast::Expr> {
|
||||
// If the condition is a BlockExpr, check if the body is missing.
|
||||
// If it is assume the condition is the expression that is missing instead.
|
||||
let mut exprs = support::children(self.syntax());
|
||||
let first = exprs.next();
|
||||
match first {
|
||||
Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
|
||||
first => first,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::HasLoopBody for ast::WhileExpr {
|
||||
fn loop_body(&self) -> Option<ast::BlockExpr> {
|
||||
let mut exprs = support::children(self.syntax());
|
||||
|
@ -835,3 +861,15 @@ impl From<ast::Adt> for ast::Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::IfExpr {
|
||||
pub fn condition(&self) -> Option<ast::Expr> {
|
||||
support::child(&self.syntax)
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::MatchGuard {
|
||||
pub fn condition(&self) -> Option<ast::Expr> {
|
||||
support::child(&self.syntax)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -682,6 +682,8 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, r
|
|||
| "value"
|
||||
| "trait"
|
||||
| "self_ty"
|
||||
| "iterable"
|
||||
| "condition"
|
||||
);
|
||||
if manually_implemented {
|
||||
return;
|
||||
|
|
|
@ -210,7 +210,8 @@ Release process is handled by `release`, `dist` and `promote` xtasks, `release`
|
|||
./rust-rust-analyzer # Note the name!
|
||||
```
|
||||
|
||||
Additionally, it assumes that the remote for `rust-analyzer` is called `upstream` (I use `origin` to point to my fork).
|
||||
The remote for `rust-analyzer` must be called `upstream` (I use `origin` to point to my fork).
|
||||
In addition, for `xtask promote` (see below), `rust-rust-analyzer` must have a `rust-analyzer` remote pointing to this repository on GitHub.
|
||||
|
||||
`release` calls the GitHub API calls to scrape pull request comments and categorize them in the changelog.
|
||||
This step uses the `curl` and `jq` applications, which need to be available in `PATH`.
|
||||
|
@ -225,13 +226,13 @@ Release steps:
|
|||
* push it to `upstream`. This triggers GitHub Actions which:
|
||||
* runs `cargo xtask dist` to package binaries and VS Code extension
|
||||
* makes a GitHub release
|
||||
* pushes VS Code extension to the marketplace
|
||||
* publishes the VS Code extension to the marketplace
|
||||
* call the GitHub API for PR details
|
||||
* create a new changelog in `rust-analyzer.github.io`
|
||||
3. While the release is in progress, fill in the changelog
|
||||
4. Commit & push the changelog
|
||||
5. Tweet
|
||||
6. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's submodule.
|
||||
6. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's subtree.
|
||||
Self-approve the PR.
|
||||
|
||||
If the GitHub Actions release fails because of a transient problem like a timeout, you can re-run the job from the Actions console.
|
||||
|
|
|
@ -77,18 +77,12 @@ impl flags::Promote {
|
|||
cmd!(sh, "git switch master").run()?;
|
||||
cmd!(sh, "git fetch upstream").run()?;
|
||||
cmd!(sh, "git reset --hard upstream/master").run()?;
|
||||
cmd!(sh, "git submodule update --recursive").run()?;
|
||||
|
||||
let date = date_iso(sh)?;
|
||||
let branch = format!("rust-analyzer-{date}");
|
||||
cmd!(sh, "git switch -c {branch}").run()?;
|
||||
{
|
||||
let _dir = sh.push_dir("src/tools/rust-analyzer");
|
||||
cmd!(sh, "git fetch origin").run()?;
|
||||
cmd!(sh, "git reset --hard origin/release").run()?;
|
||||
}
|
||||
cmd!(sh, "git add src/tools/rust-analyzer").run()?;
|
||||
cmd!(sh, "git commit -m':arrow_up: rust-analyzer'").run()?;
|
||||
cmd!(sh, "git subtree pull -P src/tools/rust-analyzer rust-analyzer master").run()?;
|
||||
|
||||
if !self.dry_run {
|
||||
cmd!(sh, "git push -u origin {branch}").run()?;
|
||||
cmd!(
|
||||
|
|
|
@ -79,11 +79,10 @@ crossbeam-utils = { version = "0.8.0", features = ["nightly"] }
|
|||
libc = { version = "0.2.79", features = ["align"] }
|
||||
# Ensure default features of libz-sys, which are disabled in some scenarios.
|
||||
libz-sys = { version = "1.1.2" }
|
||||
|
||||
# looks like the only user of deprecated `use_std` feature is `combine`, so this
|
||||
# can be removed if/when https://github.com/Marwes/combine/pull/348 be merged and released.
|
||||
# The only user of memchr's deprecated `use_std` feature is `combine`, so this can be
|
||||
# removed if/when https://github.com/Marwes/combine/pull/348 is merged and released.
|
||||
memchr = { version = "2.5", features = ["std", "use_std"] }
|
||||
# same for regex
|
||||
# Ensure default features of regex, which are disabled in some scenarios.
|
||||
regex = { version = "1.5.6" }
|
||||
proc-macro2 = { version = "1", features = ["default"] }
|
||||
quote = { version = "1", features = ["default"] }
|
||||
|
|
Loading…
Add table
Reference in a new issue