mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Auto merge of #101777 - matthiaskrgr:rollup-x2dyaa2, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #101266 (translations(rustc_session): migrates rustc_session to use SessionDiagnostic - Final) - #101737 (rustdoc: remove no-op CSS `.search-results .result-name > span`) - #101752 (Improve Attribute doc methods) - #101754 (Fix doc of log function) - #101759 (⬆️ rust-analyzer) - #101765 (Add documentation for TyCtxt::visibility) - #101770 (Rustdoc-Json: Don't loose subitems of foreign traits.) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
17cbdfd071
@ -232,7 +232,8 @@ impl AttrItem {
|
|||||||
|
|
||||||
impl Attribute {
|
impl Attribute {
|
||||||
/// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
|
/// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
|
||||||
/// So `#[doc = "doc"]` will return `false`.
|
/// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not
|
||||||
|
/// a doc comment) will return `false`.
|
||||||
pub fn is_doc_comment(&self) -> bool {
|
pub fn is_doc_comment(&self) -> bool {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
AttrKind::Normal(..) => false,
|
AttrKind::Normal(..) => false,
|
||||||
@ -240,6 +241,11 @@ impl Attribute {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the documentation and its kind if this is a doc comment or a sugared doc comment.
|
||||||
|
/// * `///doc` returns `Some(("doc", CommentKind::Line))`.
|
||||||
|
/// * `/** doc */` returns `Some(("doc", CommentKind::Block))`.
|
||||||
|
/// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`.
|
||||||
|
/// * `#[doc(...)]` returns `None`.
|
||||||
pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
|
pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
AttrKind::DocComment(kind, data) => Some((data, kind)),
|
AttrKind::DocComment(kind, data) => Some((data, kind)),
|
||||||
@ -252,6 +258,10 @@ impl Attribute {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the documentation if this is a doc comment or a sugared doc comment.
|
||||||
|
/// * `///doc` returns `Some("doc")`.
|
||||||
|
/// * `#[doc = "doc"]` returns `Some("doc")`.
|
||||||
|
/// * `#[doc(...)]` returns `None`.
|
||||||
pub fn doc_str(&self) -> Option<Symbol> {
|
pub fn doc_str(&self) -> Option<Symbol> {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
AttrKind::DocComment(.., data) => Some(data),
|
AttrKind::DocComment(.., data) => Some(data),
|
||||||
|
@ -56,3 +56,13 @@ session_target_invalid_bits_size = {$err}
|
|||||||
session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored
|
session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored
|
||||||
|
|
||||||
session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform
|
session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform
|
||||||
|
|
||||||
|
session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions
|
||||||
|
|
||||||
|
session_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$s}` != `{$name}`
|
||||||
|
|
||||||
|
session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has a leading hyphen
|
||||||
|
|
||||||
|
session_crate_name_empty = crate name must not be empty
|
||||||
|
|
||||||
|
session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}`
|
||||||
|
@ -13,9 +13,9 @@ rustc_serialize = { path = "../rustc_serialize" }
|
|||||||
rustc_span = { path = "../rustc_span" }
|
rustc_span = { path = "../rustc_span" }
|
||||||
rustc_macros = { path = "../rustc_macros" }
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
|
rustc_target = { path = "../rustc_target" }
|
||||||
rustc_hir = { path = "../rustc_hir" }
|
rustc_hir = { path = "../rustc_hir" }
|
||||||
rustc_lint_defs = { path = "../rustc_lint_defs" }
|
rustc_lint_defs = { path = "../rustc_lint_defs" }
|
||||||
rustc_target = { path = "../rustc_target" }
|
|
||||||
unicode-width = "0.1.4"
|
unicode-width = "0.1.4"
|
||||||
atty = "0.2"
|
atty = "0.2"
|
||||||
termcolor = "1.0"
|
termcolor = "1.0"
|
||||||
|
@ -1611,6 +1611,16 @@ rustc_queries! {
|
|||||||
desc { "looking up late bound vars" }
|
desc { "looking up late bound vars" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes the visibility of the provided `def_id`.
|
||||||
|
///
|
||||||
|
/// If the item from the `def_id` doesn't have a visibility, it will panic. For example
|
||||||
|
/// a generic type parameter will panic if you call this method on it:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// pub trait Foo<T: Debug> {}
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// In here, if you call `visibility` on `T`, it'll panic.
|
||||||
query visibility(def_id: DefId) -> ty::Visibility<DefId> {
|
query visibility(def_id: DefId) -> ty::Visibility<DefId> {
|
||||||
desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
|
desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
|
@ -2,7 +2,7 @@ use std::num::NonZeroU32;
|
|||||||
|
|
||||||
use crate::cgu_reuse_tracker::CguReuse;
|
use crate::cgu_reuse_tracker::CguReuse;
|
||||||
use crate::{self as rustc_session, SessionDiagnostic};
|
use crate::{self as rustc_session, SessionDiagnostic};
|
||||||
use rustc_errors::{fluent, DiagnosticBuilder, Handler, MultiSpan};
|
use rustc_errors::{fluent, DiagnosticBuilder, ErrorGuaranteed, Handler, MultiSpan};
|
||||||
use rustc_macros::SessionDiagnostic;
|
use rustc_macros::SessionDiagnostic;
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
use rustc_target::abi::TargetDataLayoutErrors;
|
use rustc_target::abi::TargetDataLayoutErrors;
|
||||||
@ -170,3 +170,52 @@ pub struct StackProtectorNotSupportedForTarget<'a> {
|
|||||||
pub struct SplitDebugInfoUnstablePlatform {
|
pub struct SplitDebugInfoUnstablePlatform {
|
||||||
pub debuginfo: SplitDebuginfo,
|
pub debuginfo: SplitDebuginfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[diag(session::file_is_not_writeable)]
|
||||||
|
pub struct FileIsNotWriteable<'a> {
|
||||||
|
pub file: &'a std::path::Path,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[diag(session::crate_name_does_not_match)]
|
||||||
|
pub struct CrateNameDoesNotMatch<'a> {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
pub s: &'a str,
|
||||||
|
pub name: Symbol,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[diag(session::crate_name_invalid)]
|
||||||
|
pub struct CrateNameInvalid<'a> {
|
||||||
|
pub s: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[diag(session::crate_name_empty)]
|
||||||
|
pub struct CrateNameEmpty {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Option<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InvalidCharacterInCrateName<'a> {
|
||||||
|
pub span: Option<Span>,
|
||||||
|
pub character: char,
|
||||||
|
pub crate_name: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::SessionDiagnostic<'_> for InvalidCharacterInCrateName<'_> {
|
||||||
|
fn into_diagnostic(
|
||||||
|
self,
|
||||||
|
sess: &Handler,
|
||||||
|
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||||
|
let mut diag = sess.struct_err(fluent::session::invalid_character_in_create_name);
|
||||||
|
if let Some(sp) = self.span {
|
||||||
|
diag.set_span(sp);
|
||||||
|
}
|
||||||
|
diag.set_arg("character", self.character);
|
||||||
|
diag.set_arg("crate_name", self.crate_name);
|
||||||
|
diag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
#![feature(map_many_mut)]
|
#![feature(map_many_mut)]
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
#![allow(rustc::potential_query_instability)]
|
#![allow(rustc::potential_query_instability)]
|
||||||
|
#![deny(rustc::untranslatable_diagnostic)]
|
||||||
|
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rustc_macros;
|
extern crate rustc_macros;
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
//! Related to out filenames of compilation (e.g. save analysis, binaries).
|
//! Related to out filenames of compilation (e.g. save analysis, binaries).
|
||||||
use crate::config::{CrateType, Input, OutputFilenames, OutputType};
|
use crate::config::{CrateType, Input, OutputFilenames, OutputType};
|
||||||
|
use crate::errors::{
|
||||||
|
CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable,
|
||||||
|
InvalidCharacterInCrateName,
|
||||||
|
};
|
||||||
use crate::Session;
|
use crate::Session;
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
@ -30,11 +34,7 @@ pub fn out_filename(
|
|||||||
/// read-only file. We should be consistent.
|
/// read-only file. We should be consistent.
|
||||||
pub fn check_file_is_writeable(file: &Path, sess: &Session) {
|
pub fn check_file_is_writeable(file: &Path, sess: &Session) {
|
||||||
if !is_writeable(file) {
|
if !is_writeable(file) {
|
||||||
sess.fatal(&format!(
|
sess.emit_fatal(FileIsNotWriteable { file });
|
||||||
"output file {} is not writeable -- check its \
|
|
||||||
permissions",
|
|
||||||
file.display()
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,11 +61,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input)
|
|||||||
if let Some(ref s) = sess.opts.crate_name {
|
if let Some(ref s) = sess.opts.crate_name {
|
||||||
if let Some((attr, name)) = attr_crate_name {
|
if let Some((attr, name)) = attr_crate_name {
|
||||||
if name.as_str() != s {
|
if name.as_str() != s {
|
||||||
let msg = format!(
|
sess.emit_err(CrateNameDoesNotMatch { span: attr.span, s, name });
|
||||||
"`--crate-name` and `#[crate_name]` are \
|
|
||||||
required to match, but `{s}` != `{name}`"
|
|
||||||
);
|
|
||||||
sess.span_err(attr.span, &msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return validate(s.clone(), None);
|
return validate(s.clone(), None);
|
||||||
@ -77,11 +73,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input)
|
|||||||
if let Input::File(ref path) = *input {
|
if let Input::File(ref path) = *input {
|
||||||
if let Some(s) = path.file_stem().and_then(|s| s.to_str()) {
|
if let Some(s) = path.file_stem().and_then(|s| s.to_str()) {
|
||||||
if s.starts_with('-') {
|
if s.starts_with('-') {
|
||||||
let msg = format!(
|
sess.emit_err(CrateNameInvalid { s });
|
||||||
"crate names cannot start with a `-`, but \
|
|
||||||
`{s}` has a leading hyphen"
|
|
||||||
);
|
|
||||||
sess.err(&msg);
|
|
||||||
} else {
|
} else {
|
||||||
return validate(s.replace('-', "_"), None);
|
return validate(s.replace('-', "_"), None);
|
||||||
}
|
}
|
||||||
@ -94,15 +86,9 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input)
|
|||||||
pub fn validate_crate_name(sess: &Session, s: &str, sp: Option<Span>) {
|
pub fn validate_crate_name(sess: &Session, s: &str, sp: Option<Span>) {
|
||||||
let mut err_count = 0;
|
let mut err_count = 0;
|
||||||
{
|
{
|
||||||
let mut say = |s: &str| {
|
|
||||||
match sp {
|
|
||||||
Some(sp) => sess.span_err(sp, s),
|
|
||||||
None => sess.err(s),
|
|
||||||
};
|
|
||||||
err_count += 1;
|
|
||||||
};
|
|
||||||
if s.is_empty() {
|
if s.is_empty() {
|
||||||
say("crate name must not be empty");
|
err_count += 1;
|
||||||
|
sess.emit_err(CrateNameEmpty { span: sp });
|
||||||
}
|
}
|
||||||
for c in s.chars() {
|
for c in s.chars() {
|
||||||
if c.is_alphanumeric() {
|
if c.is_alphanumeric() {
|
||||||
@ -111,7 +97,8 @@ pub fn validate_crate_name(sess: &Session, s: &str, sp: Option<Span>) {
|
|||||||
if c == '_' {
|
if c == '_' {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
say(&format!("invalid character `{c}` in crate name: `{s}`"));
|
err_count += 1;
|
||||||
|
sess.emit_err(InvalidCharacterInCrateName { span: sp, character: c, crate_name: s });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,6 +297,8 @@ impl Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_span_warn<S: Into<MultiSpan>>(
|
pub fn struct_span_warn<S: Into<MultiSpan>>(
|
||||||
&self,
|
&self,
|
||||||
sp: S,
|
sp: S,
|
||||||
@ -305,6 +307,8 @@ impl Session {
|
|||||||
self.diagnostic().struct_span_warn(sp, msg)
|
self.diagnostic().struct_span_warn(sp, msg)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_span_warn_with_expectation<S: Into<MultiSpan>>(
|
pub fn struct_span_warn_with_expectation<S: Into<MultiSpan>>(
|
||||||
&self,
|
&self,
|
||||||
sp: S,
|
sp: S,
|
||||||
@ -314,6 +318,8 @@ impl Session {
|
|||||||
self.diagnostic().struct_span_warn_with_expectation(sp, msg, id)
|
self.diagnostic().struct_span_warn_with_expectation(sp, msg, id)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
|
pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
|
||||||
&self,
|
&self,
|
||||||
sp: S,
|
sp: S,
|
||||||
@ -323,10 +329,14 @@ impl Session {
|
|||||||
self.diagnostic().struct_span_warn_with_code(sp, msg, code)
|
self.diagnostic().struct_span_warn_with_code(sp, msg, code)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||||
self.diagnostic().struct_warn(msg)
|
self.diagnostic().struct_warn(msg)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_warn_with_expectation(
|
pub fn struct_warn_with_expectation(
|
||||||
&self,
|
&self,
|
||||||
msg: impl Into<DiagnosticMessage>,
|
msg: impl Into<DiagnosticMessage>,
|
||||||
@ -335,6 +345,8 @@ impl Session {
|
|||||||
self.diagnostic().struct_warn_with_expectation(msg, id)
|
self.diagnostic().struct_warn_with_expectation(msg, id)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_span_allow<S: Into<MultiSpan>>(
|
pub fn struct_span_allow<S: Into<MultiSpan>>(
|
||||||
&self,
|
&self,
|
||||||
sp: S,
|
sp: S,
|
||||||
@ -343,10 +355,14 @@ impl Session {
|
|||||||
self.diagnostic().struct_span_allow(sp, msg)
|
self.diagnostic().struct_span_allow(sp, msg)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||||
self.diagnostic().struct_allow(msg)
|
self.diagnostic().struct_allow(msg)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_expect(
|
pub fn struct_expect(
|
||||||
&self,
|
&self,
|
||||||
msg: impl Into<DiagnosticMessage>,
|
msg: impl Into<DiagnosticMessage>,
|
||||||
@ -355,6 +371,8 @@ impl Session {
|
|||||||
self.diagnostic().struct_expect(msg, id)
|
self.diagnostic().struct_expect(msg, id)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_span_err<S: Into<MultiSpan>>(
|
pub fn struct_span_err<S: Into<MultiSpan>>(
|
||||||
&self,
|
&self,
|
||||||
sp: S,
|
sp: S,
|
||||||
@ -363,6 +381,8 @@ impl Session {
|
|||||||
self.diagnostic().struct_span_err(sp, msg)
|
self.diagnostic().struct_span_err(sp, msg)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_span_err_with_code<S: Into<MultiSpan>>(
|
pub fn struct_span_err_with_code<S: Into<MultiSpan>>(
|
||||||
&self,
|
&self,
|
||||||
sp: S,
|
sp: S,
|
||||||
@ -373,6 +393,8 @@ impl Session {
|
|||||||
}
|
}
|
||||||
// FIXME: This method should be removed (every error should have an associated error code).
|
// FIXME: This method should be removed (every error should have an associated error code).
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_err(
|
pub fn struct_err(
|
||||||
&self,
|
&self,
|
||||||
msg: impl Into<DiagnosticMessage>,
|
msg: impl Into<DiagnosticMessage>,
|
||||||
@ -380,6 +402,8 @@ impl Session {
|
|||||||
self.parse_sess.struct_err(msg)
|
self.parse_sess.struct_err(msg)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_err_with_code(
|
pub fn struct_err_with_code(
|
||||||
&self,
|
&self,
|
||||||
msg: impl Into<DiagnosticMessage>,
|
msg: impl Into<DiagnosticMessage>,
|
||||||
@ -388,6 +412,8 @@ impl Session {
|
|||||||
self.diagnostic().struct_err_with_code(msg, code)
|
self.diagnostic().struct_err_with_code(msg, code)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_warn_with_code(
|
pub fn struct_warn_with_code(
|
||||||
&self,
|
&self,
|
||||||
msg: impl Into<DiagnosticMessage>,
|
msg: impl Into<DiagnosticMessage>,
|
||||||
@ -396,6 +422,8 @@ impl Session {
|
|||||||
self.diagnostic().struct_warn_with_code(msg, code)
|
self.diagnostic().struct_warn_with_code(msg, code)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_span_fatal<S: Into<MultiSpan>>(
|
pub fn struct_span_fatal<S: Into<MultiSpan>>(
|
||||||
&self,
|
&self,
|
||||||
sp: S,
|
sp: S,
|
||||||
@ -404,6 +432,8 @@ impl Session {
|
|||||||
self.diagnostic().struct_span_fatal(sp, msg)
|
self.diagnostic().struct_span_fatal(sp, msg)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
|
pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
|
||||||
&self,
|
&self,
|
||||||
sp: S,
|
sp: S,
|
||||||
@ -413,15 +443,21 @@ impl Session {
|
|||||||
self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
|
self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
|
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
|
||||||
self.diagnostic().struct_fatal(msg)
|
self.diagnostic().struct_fatal(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
|
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||||
self.diagnostic().span_fatal(sp, msg)
|
self.diagnostic().span_fatal(sp, msg)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn span_fatal_with_code<S: Into<MultiSpan>>(
|
pub fn span_fatal_with_code<S: Into<MultiSpan>>(
|
||||||
&self,
|
&self,
|
||||||
sp: S,
|
sp: S,
|
||||||
@ -431,10 +467,14 @@ impl Session {
|
|||||||
self.diagnostic().span_fatal_with_code(sp, msg, code)
|
self.diagnostic().span_fatal_with_code(sp, msg, code)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
|
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||||
self.diagnostic().fatal(msg).raise()
|
self.diagnostic().fatal(msg).raise()
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn span_err_or_warn<S: Into<MultiSpan>>(
|
pub fn span_err_or_warn<S: Into<MultiSpan>>(
|
||||||
&self,
|
&self,
|
||||||
is_warning: bool,
|
is_warning: bool,
|
||||||
@ -448,6 +488,8 @@ impl Session {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn span_err<S: Into<MultiSpan>>(
|
pub fn span_err<S: Into<MultiSpan>>(
|
||||||
&self,
|
&self,
|
||||||
sp: S,
|
sp: S,
|
||||||
@ -456,6 +498,8 @@ impl Session {
|
|||||||
self.diagnostic().span_err(sp, msg)
|
self.diagnostic().span_err(sp, msg)
|
||||||
}
|
}
|
||||||
#[rustc_lint_diagnostics]
|
#[rustc_lint_diagnostics]
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
pub fn span_err_with_code<S: Into<MultiSpan>>(
|
pub fn span_err_with_code<S: Into<MultiSpan>>(
|
||||||
&self,
|
&self,
|
||||||
sp: S,
|
sp: S,
|
||||||
|
@ -688,7 +688,7 @@ macro_rules! uint_impl {
|
|||||||
/// rounded down.
|
/// rounded down.
|
||||||
///
|
///
|
||||||
/// This method might not be optimized owing to implementation details;
|
/// This method might not be optimized owing to implementation details;
|
||||||
/// `log2` can produce results more efficiently for base 2, and `log10`
|
/// `ilog2` can produce results more efficiently for base 2, and `ilog10`
|
||||||
/// can produce results more efficiently for base 10.
|
/// can produce results more efficiently for base 10.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
|
@ -49,6 +49,8 @@ def check_generic_param(param):
|
|||||||
ty = param["kind"]["type"]
|
ty = param["kind"]["type"]
|
||||||
if ty["default"]:
|
if ty["default"]:
|
||||||
check_type(ty["default"])
|
check_type(ty["default"])
|
||||||
|
for bound in ty["bounds"]:
|
||||||
|
check_generic_bound(bound)
|
||||||
elif "const" in param["kind"]:
|
elif "const" in param["kind"]:
|
||||||
check_type(param["kind"]["const"])
|
check_type(param["kind"]["const"])
|
||||||
|
|
||||||
@ -88,8 +90,11 @@ def check_path(path):
|
|||||||
check_type(input_ty)
|
check_type(input_ty)
|
||||||
if args["parenthesized"]["output"]:
|
if args["parenthesized"]["output"]:
|
||||||
check_type(args["parenthesized"]["output"])
|
check_type(args["parenthesized"]["output"])
|
||||||
if not valid_id(path["id"]):
|
|
||||||
print("Type contained an invalid ID:", path["id"])
|
if path["id"] in crate["index"]:
|
||||||
|
work_list.add(path["id"])
|
||||||
|
elif path["id"] not in crate["paths"]:
|
||||||
|
print("Id not in index or paths:", path["id"])
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def check_type(ty):
|
def check_type(ty):
|
||||||
|
@ -986,12 +986,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
|
|||||||
padding-right: 1em;
|
padding-right: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-results .result-name > span {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover {
|
.popover {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -101,6 +101,7 @@ impl<'tcx> JsonRenderer<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_trait_items(&mut self) -> Vec<(types::Id, types::Item)> {
|
fn get_trait_items(&mut self) -> Vec<(types::Id, types::Item)> {
|
||||||
|
debug!("Adding foreign trait items");
|
||||||
Rc::clone(&self.cache)
|
Rc::clone(&self.cache)
|
||||||
.traits
|
.traits
|
||||||
.iter()
|
.iter()
|
||||||
@ -109,6 +110,7 @@ impl<'tcx> JsonRenderer<'tcx> {
|
|||||||
if !id.is_local() {
|
if !id.is_local() {
|
||||||
let trait_item = &trait_item.trait_;
|
let trait_item = &trait_item.trait_;
|
||||||
for item in &trait_item.items {
|
for item in &trait_item.items {
|
||||||
|
trace!("Adding subitem to {id:?}: {:?}", item.item_id);
|
||||||
self.item(item.clone()).unwrap();
|
self.item(item.clone()).unwrap();
|
||||||
}
|
}
|
||||||
let item_id = from_item_id(id.into(), self.tcx);
|
let item_id = from_item_id(id.into(), self.tcx);
|
||||||
@ -184,7 +186,9 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
|||||||
/// the hashmap because certain items (traits and types) need to have their mappings for trait
|
/// the hashmap because certain items (traits and types) need to have their mappings for trait
|
||||||
/// implementations filled out before they're inserted.
|
/// implementations filled out before they're inserted.
|
||||||
fn item(&mut self, item: clean::Item) -> Result<(), Error> {
|
fn item(&mut self, item: clean::Item) -> Result<(), Error> {
|
||||||
trace!("rendering {} {:?}", item.type_(), item.name);
|
let item_type = item.type_();
|
||||||
|
let item_name = item.name;
|
||||||
|
trace!("rendering {} {:?}", item_type, item_name);
|
||||||
|
|
||||||
// Flatten items that recursively store other items. We include orphaned items from
|
// Flatten items that recursively store other items. We include orphaned items from
|
||||||
// stripped modules and etc that are otherwise reachable.
|
// stripped modules and etc that are otherwise reachable.
|
||||||
@ -253,6 +257,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trace!("done rendering {} {:?}", item_type, item_name);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,14 +268,20 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
|||||||
fn after_krate(&mut self) -> Result<(), Error> {
|
fn after_krate(&mut self) -> Result<(), Error> {
|
||||||
debug!("Done with crate");
|
debug!("Done with crate");
|
||||||
|
|
||||||
|
debug!("Adding Primitve impls");
|
||||||
for primitive in Rc::clone(&self.cache).primitive_locations.values() {
|
for primitive in Rc::clone(&self.cache).primitive_locations.values() {
|
||||||
self.get_impls(*primitive);
|
self.get_impls(*primitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
let e = ExternalCrate { crate_num: LOCAL_CRATE };
|
let e = ExternalCrate { crate_num: LOCAL_CRATE };
|
||||||
|
|
||||||
|
// FIXME(adotinthevoid): Remove this, as it's not consistant with not
|
||||||
|
// inlining foreign items.
|
||||||
|
let foreign_trait_items = self.get_trait_items();
|
||||||
let mut index = (*self.index).clone().into_inner();
|
let mut index = (*self.index).clone().into_inner();
|
||||||
index.extend(self.get_trait_items());
|
index.extend(foreign_trait_items);
|
||||||
|
|
||||||
|
debug!("Constructing Output");
|
||||||
// This needs to be the default HashMap for compatibility with the public interface for
|
// This needs to be the default HashMap for compatibility with the public interface for
|
||||||
// rustdoc-json-types
|
// rustdoc-json-types
|
||||||
#[allow(rustc::default_hash_types)]
|
#[allow(rustc::default_hash_types)]
|
||||||
|
@ -13,6 +13,9 @@ size: (600, 100)
|
|||||||
// when computed it's larger.
|
// when computed it's larger.
|
||||||
assert-css: (".search-results div.desc", {"width": "566px"})
|
assert-css: (".search-results div.desc", {"width": "566px"})
|
||||||
|
|
||||||
|
// The result set is all on one line.
|
||||||
|
assert-css: (".search-results .result-name > span", {"display": "inline"})
|
||||||
|
|
||||||
// Check that the crate filter `<select>` is correctly handled when it goes to next line.
|
// Check that the crate filter `<select>` is correctly handled when it goes to next line.
|
||||||
// To do so we need to update the length of one of its `<option>`.
|
// To do so we need to update the length of one of its `<option>`.
|
||||||
size: (900, 900)
|
size: (900, 900)
|
||||||
|
7
src/test/rustdoc-json/traits/uses_extern_trait.rs
Normal file
7
src/test/rustdoc-json/traits/uses_extern_trait.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#![no_std]
|
||||||
|
pub fn drop_default<T: core::default::Default>(_x: T) {}
|
||||||
|
|
||||||
|
// FIXME(adotinthevoid): Theses shouldn't be here
|
||||||
|
// @has "$.index[*][?(@.name=='Debug')]"
|
||||||
|
// @set Debug_fmt = "$.index[*][?(@.name=='Debug')].inner.items[*]"
|
||||||
|
// @has "$.index[*][?(@.name=='fmt')].id" $Debug_fmt
|
@ -34,6 +34,7 @@ jobs:
|
|||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
target: x86_64-unknown-linux-gnu
|
target: x86_64-unknown-linux-gnu
|
||||||
code-target: linux-x64
|
code-target: linux-x64
|
||||||
|
container: ubuntu:18.04
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
target: aarch64-unknown-linux-gnu
|
target: aarch64-unknown-linux-gnu
|
||||||
code-target: linux-arm64
|
code-target: linux-arm64
|
||||||
@ -49,6 +50,7 @@ jobs:
|
|||||||
|
|
||||||
name: dist (${{ matrix.target }})
|
name: dist (${{ matrix.target }})
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
container: ${{ matrix.container }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
RA_TARGET: ${{ matrix.target }}
|
RA_TARGET: ${{ matrix.target }}
|
||||||
@ -59,6 +61,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: ${{ env.FETCH_DEPTH }}
|
fetch-depth: ${{ env.FETCH_DEPTH }}
|
||||||
|
|
||||||
|
- name: Install toolchain dependencies
|
||||||
|
if: matrix.container == 'ubuntu:18.04'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
apt-get update && apt-get install -y build-essential curl
|
||||||
|
curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL "https://sh.rustup.rs" | sh -s -- --profile minimal --default-toolchain none -y
|
||||||
|
echo "${CARGO_HOME:-$HOME/.cargo}/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
run: |
|
run: |
|
||||||
rustup update --no-self-update stable
|
rustup update --no-self-update stable
|
||||||
|
@ -164,6 +164,8 @@ impl TyExt for Ty {
|
|||||||
|
|
||||||
fn dyn_trait(&self) -> Option<TraitId> {
|
fn dyn_trait(&self) -> Option<TraitId> {
|
||||||
let trait_ref = match self.kind(Interner) {
|
let trait_ref = match self.kind(Interner) {
|
||||||
|
// The principal trait bound should be the first element of the bounds. This is an
|
||||||
|
// invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
|
||||||
TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
|
TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
|
||||||
match b.skip_binders() {
|
match b.skip_binders() {
|
||||||
WhereClause::Implemented(trait_ref) => Some(trait_ref),
|
WhereClause::Implemented(trait_ref) => Some(trait_ref),
|
||||||
|
@ -981,43 +981,72 @@ impl<'a> TyLoweringContext<'a> {
|
|||||||
|
|
||||||
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
|
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
|
||||||
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
|
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
|
||||||
|
// INVARIANT: The principal trait bound must come first. Others may be in any order but
|
||||||
|
// should be in the same order for the same set but possibly different order of bounds in
|
||||||
|
// the input.
|
||||||
|
// This invariant is used by `TyExt::dyn_trait()` and chalk.
|
||||||
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
||||||
let bounds =
|
let mut bounds: Vec<_> = bounds
|
||||||
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false));
|
.iter()
|
||||||
|
.flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false))
|
||||||
|
.collect();
|
||||||
|
|
||||||
let mut auto_traits = SmallVec::<[_; 8]>::new();
|
let mut multiple_regular_traits = false;
|
||||||
let mut regular_traits = SmallVec::<[_; 2]>::new();
|
let mut multiple_same_projection = false;
|
||||||
let mut other_bounds = SmallVec::<[_; 8]>::new();
|
bounds.sort_unstable_by(|lhs, rhs| {
|
||||||
for bound in bounds {
|
use std::cmp::Ordering;
|
||||||
if let Some(id) = bound.trait_id() {
|
match (lhs.skip_binders(), rhs.skip_binders()) {
|
||||||
if ctx.db.trait_data(from_chalk_trait_id(id)).is_auto {
|
(WhereClause::Implemented(lhs), WhereClause::Implemented(rhs)) => {
|
||||||
auto_traits.push(bound);
|
let lhs_id = lhs.trait_id;
|
||||||
} else {
|
let lhs_is_auto = ctx.db.trait_data(from_chalk_trait_id(lhs_id)).is_auto;
|
||||||
regular_traits.push(bound);
|
let rhs_id = rhs.trait_id;
|
||||||
}
|
let rhs_is_auto = ctx.db.trait_data(from_chalk_trait_id(rhs_id)).is_auto;
|
||||||
} else {
|
|
||||||
other_bounds.push(bound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if regular_traits.len() > 1 {
|
if !lhs_is_auto && !rhs_is_auto {
|
||||||
|
multiple_regular_traits = true;
|
||||||
|
}
|
||||||
|
// Note that the ordering here is important; this ensures the invariant
|
||||||
|
// mentioned above.
|
||||||
|
(lhs_is_auto, lhs_id).cmp(&(rhs_is_auto, rhs_id))
|
||||||
|
}
|
||||||
|
(WhereClause::Implemented(_), _) => Ordering::Less,
|
||||||
|
(_, WhereClause::Implemented(_)) => Ordering::Greater,
|
||||||
|
(WhereClause::AliasEq(lhs), WhereClause::AliasEq(rhs)) => {
|
||||||
|
match (&lhs.alias, &rhs.alias) {
|
||||||
|
(AliasTy::Projection(lhs_proj), AliasTy::Projection(rhs_proj)) => {
|
||||||
|
// We only compare the `associated_ty_id`s. We shouldn't have
|
||||||
|
// multiple bounds for an associated type in the correct Rust code,
|
||||||
|
// and if we do, we error out.
|
||||||
|
if lhs_proj.associated_ty_id == rhs_proj.associated_ty_id {
|
||||||
|
multiple_same_projection = true;
|
||||||
|
}
|
||||||
|
lhs_proj.associated_ty_id.cmp(&rhs_proj.associated_ty_id)
|
||||||
|
}
|
||||||
|
// We don't produce `AliasTy::Opaque`s yet.
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We don't produce `WhereClause::{TypeOutlives, LifetimeOutlives}` yet.
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if multiple_regular_traits || multiple_same_projection {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto_traits.sort_unstable_by_key(|b| b.trait_id().unwrap());
|
// As multiple occurrences of the same auto traits *are* permitted, we dedulicate the
|
||||||
auto_traits.dedup();
|
// bounds. We shouldn't have repeated elements besides auto traits at this point.
|
||||||
|
bounds.dedup();
|
||||||
|
|
||||||
Some(QuantifiedWhereClauses::from_iter(
|
Some(QuantifiedWhereClauses::from_iter(Interner, bounds))
|
||||||
Interner,
|
|
||||||
regular_traits.into_iter().chain(other_bounds).chain(auto_traits),
|
|
||||||
))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(bounds) = bounds {
|
if let Some(bounds) = bounds {
|
||||||
let bounds = crate::make_single_type_binders(bounds);
|
let bounds = crate::make_single_type_binders(bounds);
|
||||||
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
|
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
|
||||||
} else {
|
} else {
|
||||||
// FIXME: report error (additional non-auto traits)
|
// FIXME: report error (additional non-auto traits or associated type rebound)
|
||||||
TyKind::Error.intern(Interner)
|
TyKind::Error.intern(Interner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3900,6 +3900,34 @@ fn g(t: &(dyn Sync + T<Proj = ()> + Send)) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dyn_multiple_projection_bounds() {
|
||||||
|
check_no_mismatches(
|
||||||
|
r#"
|
||||||
|
trait Trait {
|
||||||
|
type T;
|
||||||
|
type U;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(t: &dyn Trait<T = (), U = ()>) {}
|
||||||
|
fn g(t: &dyn Trait<U = (), T = ()>) {
|
||||||
|
f(t);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
check_types(
|
||||||
|
r#"
|
||||||
|
trait Trait {
|
||||||
|
type T;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(t: &dyn Trait<T = (), T = ()>) {}
|
||||||
|
//^&{unknown}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dyn_duplicate_auto_trait() {
|
fn dyn_duplicate_auto_trait() {
|
||||||
check_no_mismatches(
|
check_no_mismatches(
|
||||||
|
@ -5,6 +5,7 @@ use hir::{Adt, Crate, HasAttrs, HasSource, ModuleDef, Semantics};
|
|||||||
use ide_db::RootDatabase;
|
use ide_db::RootDatabase;
|
||||||
use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
|
use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use syntax::ast::edit_in_place::Removable;
|
||||||
use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat};
|
use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -7,6 +7,7 @@ use ide_db::{
|
|||||||
imports::insert_use::remove_path_if_in_use_stmt,
|
imports::insert_use::remove_path_if_in_use_stmt,
|
||||||
path_transform::PathTransform,
|
path_transform::PathTransform,
|
||||||
search::{FileReference, SearchScope},
|
search::{FileReference, SearchScope},
|
||||||
|
source_change::SourceChangeBuilder,
|
||||||
syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref},
|
syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref},
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
@ -100,18 +101,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|
|||||||
builder.edit_file(file_id);
|
builder.edit_file(file_id);
|
||||||
let count = refs.len();
|
let count = refs.len();
|
||||||
// The collects are required as we are otherwise iterating while mutating 🙅♀️🙅♂️
|
// The collects are required as we are otherwise iterating while mutating 🙅♀️🙅♂️
|
||||||
let (name_refs, name_refs_use): (Vec<_>, Vec<_>) = refs
|
let (name_refs, name_refs_use) = split_refs_and_uses(builder, refs, Some);
|
||||||
.into_iter()
|
|
||||||
.filter_map(|file_ref| match file_ref.name {
|
|
||||||
ast::NameLike::NameRef(name_ref) => Some(name_ref),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.partition_map(|name_ref| {
|
|
||||||
match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) {
|
|
||||||
Some(use_tree) => Either::Right(builder.make_mut(use_tree)),
|
|
||||||
None => Either::Left(name_ref),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let call_infos: Vec<_> = name_refs
|
let call_infos: Vec<_> = name_refs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(CallInfo::from_name_ref)
|
.filter_map(CallInfo::from_name_ref)
|
||||||
@ -130,11 +120,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|
|||||||
.count();
|
.count();
|
||||||
if replaced + name_refs_use.len() == count {
|
if replaced + name_refs_use.len() == count {
|
||||||
// we replaced all usages in this file, so we can remove the imports
|
// we replaced all usages in this file, so we can remove the imports
|
||||||
name_refs_use.into_iter().for_each(|use_tree| {
|
name_refs_use.iter().for_each(remove_path_if_in_use_stmt);
|
||||||
if let Some(path) = use_tree.path() {
|
|
||||||
remove_path_if_in_use_stmt(&path);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
remove_def = false;
|
remove_def = false;
|
||||||
}
|
}
|
||||||
@ -153,6 +139,23 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn split_refs_and_uses<T: ast::AstNode>(
|
||||||
|
builder: &mut SourceChangeBuilder,
|
||||||
|
iter: impl IntoIterator<Item = FileReference>,
|
||||||
|
mut map_ref: impl FnMut(ast::NameRef) -> Option<T>,
|
||||||
|
) -> (Vec<T>, Vec<ast::Path>) {
|
||||||
|
iter.into_iter()
|
||||||
|
.filter_map(|file_ref| match file_ref.name {
|
||||||
|
ast::NameLike::NameRef(name_ref) => Some(name_ref),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.filter_map(|name_ref| match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) {
|
||||||
|
Some(use_tree) => builder.make_mut(use_tree).path().map(Either::Right),
|
||||||
|
None => map_ref(name_ref).map(Either::Left),
|
||||||
|
})
|
||||||
|
.partition_map(|either| either)
|
||||||
|
}
|
||||||
|
|
||||||
// Assist: inline_call
|
// Assist: inline_call
|
||||||
//
|
//
|
||||||
// Inlines a function or method body creating a `let` statement per parameter unless the parameter
|
// Inlines a function or method body creating a `let` statement per parameter unless the parameter
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
// - Remove unused aliases if there are no longer any users, see inline_call.rs.
|
// - Remove unused aliases if there are no longer any users, see inline_call.rs.
|
||||||
|
|
||||||
use hir::{HasSource, PathResolution};
|
use hir::{HasSource, PathResolution};
|
||||||
use ide_db::{defs::Definition, search::FileReference};
|
use ide_db::{
|
||||||
|
defs::Definition, imports::insert_use::ast_to_remove_for_path_in_use_stmt,
|
||||||
|
search::FileReference,
|
||||||
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
@ -16,6 +19,8 @@ use crate::{
|
|||||||
AssistId, AssistKind,
|
AssistId, AssistKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::inline_call::split_refs_and_uses;
|
||||||
|
|
||||||
// Assist: inline_type_alias_uses
|
// Assist: inline_type_alias_uses
|
||||||
//
|
//
|
||||||
// Inline a type alias into all of its uses where possible.
|
// Inline a type alias into all of its uses where possible.
|
||||||
@ -31,7 +36,7 @@ use crate::{
|
|||||||
// ```
|
// ```
|
||||||
// ->
|
// ->
|
||||||
// ```
|
// ```
|
||||||
// type A = i32;
|
//
|
||||||
// fn id(x: i32) -> i32 {
|
// fn id(x: i32) -> i32 {
|
||||||
// x
|
// x
|
||||||
// };
|
// };
|
||||||
@ -58,20 +63,20 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>)
|
|||||||
name.syntax().text_range(),
|
name.syntax().text_range(),
|
||||||
|builder| {
|
|builder| {
|
||||||
let usages = usages.all();
|
let usages = usages.all();
|
||||||
|
let mut definition_deleted = false;
|
||||||
|
|
||||||
let mut inline_refs_for_file = |file_id, refs: Vec<FileReference>| {
|
let mut inline_refs_for_file = |file_id, refs: Vec<FileReference>| {
|
||||||
builder.edit_file(file_id);
|
builder.edit_file(file_id);
|
||||||
|
|
||||||
let path_types: Vec<ast::PathType> = refs
|
let (path_types, path_type_uses) =
|
||||||
.into_iter()
|
split_refs_and_uses(builder, refs, |path_type| {
|
||||||
.filter_map(|file_ref| match file_ref.name {
|
|
||||||
ast::NameLike::NameRef(path_type) => {
|
|
||||||
path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast)
|
path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast)
|
||||||
}
|
});
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
|
path_type_uses
|
||||||
|
.iter()
|
||||||
|
.flat_map(ast_to_remove_for_path_in_use_stmt)
|
||||||
|
.for_each(|x| builder.delete(x.syntax().text_range()));
|
||||||
for (target, replacement) in path_types.into_iter().filter_map(|path_type| {
|
for (target, replacement) in path_types.into_iter().filter_map(|path_type| {
|
||||||
let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type);
|
let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type);
|
||||||
let target = path_type.syntax().text_range();
|
let target = path_type.syntax().text_range();
|
||||||
@ -79,11 +84,20 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>)
|
|||||||
}) {
|
}) {
|
||||||
builder.replace(target, replacement);
|
builder.replace(target, replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if file_id == ctx.file_id() {
|
||||||
|
builder.delete(ast_alias.syntax().text_range());
|
||||||
|
definition_deleted = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (file_id, refs) in usages.into_iter() {
|
for (file_id, refs) in usages.into_iter() {
|
||||||
inline_refs_for_file(file_id, refs);
|
inline_refs_for_file(file_id, refs);
|
||||||
}
|
}
|
||||||
|
if !definition_deleted {
|
||||||
|
builder.edit_file(ctx.file_id());
|
||||||
|
builder.delete(ast_alias.syntax().text_range());
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -929,7 +943,7 @@ fn foo() {
|
|||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
type A = u32;
|
|
||||||
|
|
||||||
fn foo() {
|
fn foo() {
|
||||||
let _: u32 = 3;
|
let _: u32 = 3;
|
||||||
@ -960,13 +974,13 @@ fn foo() {
|
|||||||
r#"
|
r#"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
mod foo;
|
mod foo;
|
||||||
type T<E> = Vec<E>;
|
|
||||||
fn f() -> Vec<&str> {
|
fn f() -> Vec<&str> {
|
||||||
vec!["hello"]
|
vec!["hello"]
|
||||||
}
|
}
|
||||||
|
|
||||||
//- /foo.rs
|
//- /foo.rs
|
||||||
use super::T;
|
|
||||||
fn foo() {
|
fn foo() {
|
||||||
let _: Vec<i8> = Vec::new();
|
let _: Vec<i8> = Vec::new();
|
||||||
}
|
}
|
||||||
@ -990,7 +1004,12 @@ fn foo() {
|
|||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
use super::I;
|
//- /lib.rs
|
||||||
|
mod foo;
|
||||||
|
|
||||||
|
|
||||||
|
//- /foo.rs
|
||||||
|
|
||||||
fn foo() {
|
fn foo() {
|
||||||
let _: i32 = 0;
|
let _: i32 = 0;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
use either::Either;
|
use either::Either;
|
||||||
use ide_db::imports::merge_imports::{try_merge_imports, try_merge_trees, MergeBehavior};
|
use ide_db::imports::merge_imports::{try_merge_imports, try_merge_trees, MergeBehavior};
|
||||||
use syntax::{algo::neighbor, ast, match_ast, ted, AstNode, SyntaxElement, SyntaxNode};
|
use syntax::{
|
||||||
|
algo::neighbor,
|
||||||
|
ast::{self, edit_in_place::Removable},
|
||||||
|
match_ast, ted, AstNode, SyntaxElement, SyntaxNode,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
assist_context::{AssistContext, Assists},
|
assist_context::{AssistContext, Assists},
|
||||||
@ -76,7 +80,7 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
|
|||||||
.collect();
|
.collect();
|
||||||
for edit in edits_mut {
|
for edit in edits_mut {
|
||||||
match edit {
|
match edit {
|
||||||
Remove(it) => it.as_ref().either(ast::Use::remove, ast::UseTree::remove),
|
Remove(it) => it.as_ref().either(Removable::remove, Removable::remove),
|
||||||
Replace(old, new) => ted::replace(old, new),
|
Replace(old, new) => ted::replace(old, new),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, HasName, HasTypeBounds},
|
ast::{
|
||||||
|
self,
|
||||||
|
edit_in_place::{GenericParamsOwnerEdit, Removable},
|
||||||
|
make, AstNode, HasName, HasTypeBounds,
|
||||||
|
},
|
||||||
match_ast,
|
match_ast,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, make, HasVisibility},
|
ast::{self, edit_in_place::Removable, make, HasVisibility},
|
||||||
ted::{self, Position},
|
ted::{self, Position},
|
||||||
AstNode, SyntaxKind,
|
AstNode, SyntaxKind,
|
||||||
};
|
};
|
||||||
|
@ -1390,7 +1390,7 @@ fn foo() {
|
|||||||
}
|
}
|
||||||
"#####,
|
"#####,
|
||||||
r#####"
|
r#####"
|
||||||
type A = i32;
|
|
||||||
fn id(x: i32) -> i32 {
|
fn id(x: i32) -> i32 {
|
||||||
x
|
x
|
||||||
};
|
};
|
||||||
|
@ -12,7 +12,7 @@ use syntax::{
|
|||||||
ast::{
|
ast::{
|
||||||
self,
|
self,
|
||||||
edit::{self, AstNodeEdit},
|
edit::{self, AstNodeEdit},
|
||||||
edit_in_place::AttrsOwnerEdit,
|
edit_in_place::{AttrsOwnerEdit, Removable},
|
||||||
make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
|
make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
|
||||||
},
|
},
|
||||||
ted, AstNode, AstToken, Direction, SmolStr, SourceFile,
|
ted, AstNode, AstToken, Direction, SmolStr, SourceFile,
|
||||||
|
@ -53,6 +53,7 @@ pub(crate) fn complete_mod(
|
|||||||
let existing_mod_declarations = current_module
|
let existing_mod_declarations = current_module
|
||||||
.children(ctx.db)
|
.children(ctx.db)
|
||||||
.filter_map(|module| Some(module.name(ctx.db)?.to_string()))
|
.filter_map(|module| Some(module.name(ctx.db)?.to_string()))
|
||||||
|
.filter(|module| module != ctx.original_token.text())
|
||||||
.collect::<FxHashSet<_>>();
|
.collect::<FxHashSet<_>>();
|
||||||
|
|
||||||
let module_declaration_file =
|
let module_declaration_file =
|
||||||
@ -351,4 +352,23 @@ fn ignored_bar() {}
|
|||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn semi_colon_completion() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /lib.rs
|
||||||
|
mod foo;
|
||||||
|
//- /foo.rs
|
||||||
|
mod bar {
|
||||||
|
mod baz$0
|
||||||
|
}
|
||||||
|
//- /foo/bar/baz.rs
|
||||||
|
fn baz() {}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
md baz;
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -671,6 +671,45 @@ fn main() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn varaiant_with_struct() {
|
||||||
|
check_empty(
|
||||||
|
r#"
|
||||||
|
pub struct YoloVariant {
|
||||||
|
pub f: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum HH {
|
||||||
|
Yolo(YoloVariant),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn brr() {
|
||||||
|
let t = HH::Yolo(Y$0);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
en HH
|
||||||
|
fn brr() fn()
|
||||||
|
st YoloVariant
|
||||||
|
st YoloVariant {…} YoloVariant { f: usize }
|
||||||
|
bt u32
|
||||||
|
kw crate::
|
||||||
|
kw false
|
||||||
|
kw for
|
||||||
|
kw if
|
||||||
|
kw if let
|
||||||
|
kw loop
|
||||||
|
kw match
|
||||||
|
kw return
|
||||||
|
kw self::
|
||||||
|
kw true
|
||||||
|
kw unsafe
|
||||||
|
kw while
|
||||||
|
kw while let
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn return_unit_block() {
|
fn return_unit_block() {
|
||||||
cov_mark::check!(return_unit_block);
|
cov_mark::check!(return_unit_block);
|
||||||
|
@ -12,7 +12,7 @@ use crate::RootDatabase;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ActiveParameter {
|
pub struct ActiveParameter {
|
||||||
pub ty: Type,
|
pub ty: Type,
|
||||||
pub pat: Either<ast::SelfParam, ast::Pat>,
|
pub pat: Option<Either<ast::SelfParam, ast::Pat>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActiveParameter {
|
impl ActiveParameter {
|
||||||
@ -27,12 +27,12 @@ impl ActiveParameter {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let (pat, ty) = params.swap_remove(idx);
|
let (pat, ty) = params.swap_remove(idx);
|
||||||
pat.map(|pat| ActiveParameter { ty, pat })
|
Some(ActiveParameter { ty, pat })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ident(&self) -> Option<ast::Name> {
|
pub fn ident(&self) -> Option<ast::Name> {
|
||||||
self.pat.as_ref().right().and_then(|param| match param {
|
self.pat.as_ref().and_then(|param| match param {
|
||||||
ast::Pat::IdentPat(ident) => ident.name(),
|
Either::Right(ast::Pat::IdentPat(ident)) => ident.name(),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,10 @@ use std::cmp::Ordering;
|
|||||||
use hir::Semantics;
|
use hir::Semantics;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo,
|
algo,
|
||||||
ast::{self, make, AstNode, HasAttrs, HasModuleItem, HasVisibility, PathSegmentKind},
|
ast::{
|
||||||
|
self, edit_in_place::Removable, make, AstNode, HasAttrs, HasModuleItem, HasVisibility,
|
||||||
|
PathSegmentKind,
|
||||||
|
},
|
||||||
ted, Direction, NodeOrToken, SyntaxKind, SyntaxNode,
|
ted, Direction, NodeOrToken, SyntaxKind, SyntaxNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -192,20 +195,24 @@ pub fn insert_use(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) {
|
|||||||
insert_use_(scope, &path, cfg.group, use_item);
|
insert_use_(scope, &path, cfg.group, use_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_path_if_in_use_stmt(path: &ast::Path) {
|
pub fn ast_to_remove_for_path_in_use_stmt(path: &ast::Path) -> Option<Box<dyn Removable>> {
|
||||||
// FIXME: improve this
|
// FIXME: improve this
|
||||||
if path.parent_path().is_some() {
|
if path.parent_path().is_some() {
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
if let Some(use_tree) = path.syntax().parent().and_then(ast::UseTree::cast) {
|
let use_tree = path.syntax().parent().and_then(ast::UseTree::cast)?;
|
||||||
if use_tree.use_tree_list().is_some() || use_tree.star_token().is_some() {
|
if use_tree.use_tree_list().is_some() || use_tree.star_token().is_some() {
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
if let Some(use_) = use_tree.syntax().parent().and_then(ast::Use::cast) {
|
if let Some(use_) = use_tree.syntax().parent().and_then(ast::Use::cast) {
|
||||||
use_.remove();
|
return Some(Box::new(use_));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
use_tree.remove();
|
Some(Box::new(use_tree))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_path_if_in_use_stmt(path: &ast::Path) {
|
||||||
|
if let Some(node) = ast_to_remove_for_path_in_use_stmt(path) {
|
||||||
|
node.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode {
|
|||||||
AS_KW | DYN_KW | IMPL_KW | CONST_KW => {
|
AS_KW | DYN_KW | IMPL_KW | CONST_KW => {
|
||||||
mods.push(do_ws(after, tok));
|
mods.push(do_ws(after, tok));
|
||||||
}
|
}
|
||||||
T![;] => {
|
T![;] if is_next(|it| it != R_CURLY, true) => {
|
||||||
if indent > 0 {
|
if indent > 0 {
|
||||||
mods.push(do_indent(after, tok, indent));
|
mods.push(do_indent(after, tok, indent));
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HirDisplay, Semantics, TypeInfo};
|
use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
base_db::SourceDatabase,
|
base_db::SourceDatabase,
|
||||||
defs::Definition,
|
defs::Definition,
|
||||||
famous_defs::FamousDefs,
|
famous_defs::FamousDefs,
|
||||||
generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
|
generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
|
||||||
|
syntax_helpers::insert_whitespace_into_node,
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -350,10 +351,24 @@ pub(super) fn definition(
|
|||||||
let body = it.eval(db);
|
let body = it.eval(db);
|
||||||
match body {
|
match body {
|
||||||
Ok(x) => Some(format!("{}", x)),
|
Ok(x) => Some(format!("{}", x)),
|
||||||
Err(_) => it.value(db).map(|x| format!("{}", x)),
|
Err(_) => {
|
||||||
|
let source = it.source(db)?;
|
||||||
|
let mut body = source.value.body()?.syntax().clone();
|
||||||
|
if source.file_id.is_macro() {
|
||||||
|
body = insert_whitespace_into_node::insert_ws_into(body);
|
||||||
|
}
|
||||||
|
Some(body.to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
Definition::Static(it) => label_value_and_docs(db, it, |it| it.value(db)),
|
Definition::Static(it) => label_value_and_docs(db, it, |it| {
|
||||||
|
let source = it.source(db)?;
|
||||||
|
let mut body = source.value.body()?.syntax().clone();
|
||||||
|
if source.file_id.is_macro() {
|
||||||
|
body = insert_whitespace_into_node::insert_ws_into(body);
|
||||||
|
}
|
||||||
|
Some(body.to_string())
|
||||||
|
}),
|
||||||
Definition::Trait(it) => label_and_docs(db, it),
|
Definition::Trait(it) => label_and_docs(db, it),
|
||||||
Definition::TypeAlias(it) => label_and_docs(db, it),
|
Definition::TypeAlias(it) => label_and_docs(db, it),
|
||||||
Definition::BuiltinType(it) => {
|
Definition::BuiltinType(it) => {
|
||||||
|
@ -5113,3 +5113,61 @@ fn f() {
|
|||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn static_const_macro_expanded_body() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
macro_rules! m {
|
||||||
|
() => {
|
||||||
|
pub const V: i8 = {
|
||||||
|
let e = 123;
|
||||||
|
f(e) // Prevent const eval from evaluating this constant, we want to print the body's code.
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
m!();
|
||||||
|
fn main() { $0V; }
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*V*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub const V: i8 = {
|
||||||
|
let e = 123;
|
||||||
|
f(e)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
macro_rules! m {
|
||||||
|
() => {
|
||||||
|
pub static V: i8 = {
|
||||||
|
let e = 123;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
m!();
|
||||||
|
fn main() { $0V; }
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*V*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub static V: i8 = {
|
||||||
|
let e = 123;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo};
|
use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
@ -69,7 +71,7 @@ pub enum InlayKind {
|
|||||||
pub struct InlayHint {
|
pub struct InlayHint {
|
||||||
pub range: TextRange,
|
pub range: TextRange,
|
||||||
pub kind: InlayKind,
|
pub kind: InlayKind,
|
||||||
pub label: String,
|
pub label: InlayHintLabel,
|
||||||
pub tooltip: Option<InlayTooltip>,
|
pub tooltip: Option<InlayTooltip>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +82,83 @@ pub enum InlayTooltip {
|
|||||||
HoverOffset(FileId, TextSize),
|
HoverOffset(FileId, TextSize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct InlayHintLabel {
|
||||||
|
pub parts: Vec<InlayHintLabelPart>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InlayHintLabel {
|
||||||
|
pub fn as_simple_str(&self) -> Option<&str> {
|
||||||
|
match &*self.parts {
|
||||||
|
[part] => part.as_simple_str(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prepend_str(&mut self, s: &str) {
|
||||||
|
match &mut *self.parts {
|
||||||
|
[part, ..] if part.as_simple_str().is_some() => part.text = format!("{s}{}", part.text),
|
||||||
|
_ => self.parts.insert(0, InlayHintLabelPart { text: s.into(), linked_location: None }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append_str(&mut self, s: &str) {
|
||||||
|
match &mut *self.parts {
|
||||||
|
[.., part] if part.as_simple_str().is_some() => part.text.push_str(s),
|
||||||
|
_ => self.parts.push(InlayHintLabelPart { text: s.into(), linked_location: None }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for InlayHintLabel {
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
Self { parts: vec![InlayHintLabelPart { text: s, linked_location: None }] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for InlayHintLabel {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.parts.iter().map(|part| &part.text).format(""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for InlayHintLabel {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_list().entries(&self.parts).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InlayHintLabelPart {
|
||||||
|
pub text: String,
|
||||||
|
/// Source location represented by this label part. The client will use this to fetch the part's
|
||||||
|
/// hover tooltip, and Ctrl+Clicking the label part will navigate to the definition the location
|
||||||
|
/// refers to (not necessarily the location itself).
|
||||||
|
/// When setting this, no tooltip must be set on the containing hint, or VS Code will display
|
||||||
|
/// them both.
|
||||||
|
pub linked_location: Option<FileRange>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InlayHintLabelPart {
|
||||||
|
pub fn as_simple_str(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
Self { text, linked_location: None } => Some(text),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for InlayHintLabelPart {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self.as_simple_str() {
|
||||||
|
Some(string) => string.fmt(f),
|
||||||
|
None => f
|
||||||
|
.debug_struct("InlayHintLabelPart")
|
||||||
|
.field("text", &self.text)
|
||||||
|
.field("linked_location", &self.linked_location)
|
||||||
|
.finish(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Feature: Inlay Hints
|
// Feature: Inlay Hints
|
||||||
//
|
//
|
||||||
// rust-analyzer shows additional information inline with the source code.
|
// rust-analyzer shows additional information inline with the source code.
|
||||||
@ -192,10 +271,10 @@ fn closing_brace_hints(
|
|||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let min_lines = config.closing_brace_hints_min_lines?;
|
let min_lines = config.closing_brace_hints_min_lines?;
|
||||||
|
|
||||||
let name = |it: ast::Name| it.syntax().text_range().start();
|
let name = |it: ast::Name| it.syntax().text_range();
|
||||||
|
|
||||||
let mut closing_token;
|
let mut closing_token;
|
||||||
let (label, name_offset) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
|
let (label, name_range) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
|
||||||
closing_token = item_list.r_curly_token()?;
|
closing_token = item_list.r_curly_token()?;
|
||||||
|
|
||||||
let parent = item_list.syntax().parent()?;
|
let parent = item_list.syntax().parent()?;
|
||||||
@ -205,11 +284,11 @@ fn closing_brace_hints(
|
|||||||
let imp = sema.to_def(&imp)?;
|
let imp = sema.to_def(&imp)?;
|
||||||
let ty = imp.self_ty(sema.db);
|
let ty = imp.self_ty(sema.db);
|
||||||
let trait_ = imp.trait_(sema.db);
|
let trait_ = imp.trait_(sema.db);
|
||||||
|
let hint_text = match trait_ {
|
||||||
(match trait_ {
|
|
||||||
Some(tr) => format!("impl {} for {}", tr.name(sema.db), ty.display_truncated(sema.db, config.max_length)),
|
Some(tr) => format!("impl {} for {}", tr.name(sema.db), ty.display_truncated(sema.db, config.max_length)),
|
||||||
None => format!("impl {}", ty.display_truncated(sema.db, config.max_length)),
|
None => format!("impl {}", ty.display_truncated(sema.db, config.max_length)),
|
||||||
}, None)
|
};
|
||||||
|
(hint_text, None)
|
||||||
},
|
},
|
||||||
ast::Trait(tr) => {
|
ast::Trait(tr) => {
|
||||||
(format!("trait {}", tr.name()?), tr.name().map(name))
|
(format!("trait {}", tr.name()?), tr.name().map(name))
|
||||||
@ -253,7 +332,7 @@ fn closing_brace_hints(
|
|||||||
|
|
||||||
(
|
(
|
||||||
format!("{}!", mac.path()?),
|
format!("{}!", mac.path()?),
|
||||||
mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range().start()),
|
mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range()),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
@ -278,11 +357,12 @@ fn closing_brace_hints(
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let linked_location = name_range.map(|range| FileRange { file_id, range });
|
||||||
acc.push(InlayHint {
|
acc.push(InlayHint {
|
||||||
range: closing_token.text_range(),
|
range: closing_token.text_range(),
|
||||||
kind: InlayKind::ClosingBraceHint,
|
kind: InlayKind::ClosingBraceHint,
|
||||||
label,
|
label: InlayHintLabel { parts: vec![InlayHintLabelPart { text: label, linked_location }] },
|
||||||
tooltip: name_offset.map(|it| InlayTooltip::HoverOffset(file_id, it)),
|
tooltip: None, // provided by label part location
|
||||||
});
|
});
|
||||||
|
|
||||||
None
|
None
|
||||||
@ -311,7 +391,7 @@ fn implicit_static_hints(
|
|||||||
acc.push(InlayHint {
|
acc.push(InlayHint {
|
||||||
range: t.text_range(),
|
range: t.text_range(),
|
||||||
kind: InlayKind::LifetimeHint,
|
kind: InlayKind::LifetimeHint,
|
||||||
label: "'static".to_owned(),
|
label: "'static".to_owned().into(),
|
||||||
tooltip: Some(InlayTooltip::String("Elided static lifetime".into())),
|
tooltip: Some(InlayTooltip::String("Elided static lifetime".into())),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -329,10 +409,10 @@ fn fn_lifetime_fn_hints(
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mk_lt_hint = |t: SyntaxToken, label| InlayHint {
|
let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint {
|
||||||
range: t.text_range(),
|
range: t.text_range(),
|
||||||
kind: InlayKind::LifetimeHint,
|
kind: InlayKind::LifetimeHint,
|
||||||
label,
|
label: label.into(),
|
||||||
tooltip: Some(InlayTooltip::String("Elided lifetime".into())),
|
tooltip: Some(InlayTooltip::String("Elided lifetime".into())),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -486,7 +566,8 @@ fn fn_lifetime_fn_hints(
|
|||||||
"{}{}",
|
"{}{}",
|
||||||
allocated_lifetimes.iter().format(", "),
|
allocated_lifetimes.iter().format(", "),
|
||||||
if is_empty { "" } else { ", " }
|
if is_empty { "" } else { ", " }
|
||||||
),
|
)
|
||||||
|
.into(),
|
||||||
tooltip: Some(InlayTooltip::String("Elided lifetimes".into())),
|
tooltip: Some(InlayTooltip::String("Elided lifetimes".into())),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -535,7 +616,8 @@ fn closure_ret_hints(
|
|||||||
range: param_list.syntax().text_range(),
|
range: param_list.syntax().text_range(),
|
||||||
kind: InlayKind::ClosureReturnTypeHint,
|
kind: InlayKind::ClosureReturnTypeHint,
|
||||||
label: hint_iterator(sema, &famous_defs, config, &ty)
|
label: hint_iterator(sema, &famous_defs, config, &ty)
|
||||||
.unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string()),
|
.unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string())
|
||||||
|
.into(),
|
||||||
tooltip: Some(InlayTooltip::HoverRanged(file_id, param_list.syntax().text_range())),
|
tooltip: Some(InlayTooltip::HoverRanged(file_id, param_list.syntax().text_range())),
|
||||||
});
|
});
|
||||||
Some(())
|
Some(())
|
||||||
@ -562,7 +644,7 @@ fn reborrow_hints(
|
|||||||
acc.push(InlayHint {
|
acc.push(InlayHint {
|
||||||
range: expr.syntax().text_range(),
|
range: expr.syntax().text_range(),
|
||||||
kind: InlayKind::ImplicitReborrowHint,
|
kind: InlayKind::ImplicitReborrowHint,
|
||||||
label: label.to_string(),
|
label: label.to_string().into(),
|
||||||
tooltip: Some(InlayTooltip::String("Compiler inserted reborrow".into())),
|
tooltip: Some(InlayTooltip::String("Compiler inserted reborrow".into())),
|
||||||
});
|
});
|
||||||
Some(())
|
Some(())
|
||||||
@ -620,9 +702,9 @@ fn chaining_hints(
|
|||||||
acc.push(InlayHint {
|
acc.push(InlayHint {
|
||||||
range: expr.syntax().text_range(),
|
range: expr.syntax().text_range(),
|
||||||
kind: InlayKind::ChainingHint,
|
kind: InlayKind::ChainingHint,
|
||||||
label: hint_iterator(sema, &famous_defs, config, &ty).unwrap_or_else(|| {
|
label: hint_iterator(sema, &famous_defs, config, &ty)
|
||||||
ty.display_truncated(sema.db, config.max_length).to_string()
|
.unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string())
|
||||||
}),
|
.into(),
|
||||||
tooltip: Some(InlayTooltip::HoverRanged(file_id, expr.syntax().text_range())),
|
tooltip: Some(InlayTooltip::HoverRanged(file_id, expr.syntax().text_range())),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -674,7 +756,7 @@ fn param_name_hints(
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range,
|
range,
|
||||||
kind: InlayKind::ParameterHint,
|
kind: InlayKind::ParameterHint,
|
||||||
label: param_name,
|
label: param_name.into(),
|
||||||
tooltip: tooltip.map(|it| InlayTooltip::HoverOffset(it.file_id, it.range.start())),
|
tooltip: tooltip.map(|it| InlayTooltip::HoverOffset(it.file_id, it.range.start())),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -705,7 +787,7 @@ fn binding_mode_hints(
|
|||||||
acc.push(InlayHint {
|
acc.push(InlayHint {
|
||||||
range,
|
range,
|
||||||
kind: InlayKind::BindingModeHint,
|
kind: InlayKind::BindingModeHint,
|
||||||
label: r.to_string(),
|
label: r.to_string().into(),
|
||||||
tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
|
tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -720,7 +802,7 @@ fn binding_mode_hints(
|
|||||||
acc.push(InlayHint {
|
acc.push(InlayHint {
|
||||||
range,
|
range,
|
||||||
kind: InlayKind::BindingModeHint,
|
kind: InlayKind::BindingModeHint,
|
||||||
label: bm.to_string(),
|
label: bm.to_string().into(),
|
||||||
tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
|
tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -772,7 +854,7 @@ fn bind_pat_hints(
|
|||||||
None => pat.syntax().text_range(),
|
None => pat.syntax().text_range(),
|
||||||
},
|
},
|
||||||
kind: InlayKind::TypeHint,
|
kind: InlayKind::TypeHint,
|
||||||
label,
|
label: label.into(),
|
||||||
tooltip: pat
|
tooltip: pat
|
||||||
.name()
|
.name()
|
||||||
.map(|it| it.syntax().text_range())
|
.map(|it| it.syntax().text_range())
|
||||||
@ -2223,7 +2305,9 @@ fn main() {
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range: 147..172,
|
range: 147..172,
|
||||||
kind: ChainingHint,
|
kind: ChainingHint,
|
||||||
label: "B",
|
label: [
|
||||||
|
"B",
|
||||||
|
],
|
||||||
tooltip: Some(
|
tooltip: Some(
|
||||||
HoverRanged(
|
HoverRanged(
|
||||||
FileId(
|
FileId(
|
||||||
@ -2236,7 +2320,9 @@ fn main() {
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range: 147..154,
|
range: 147..154,
|
||||||
kind: ChainingHint,
|
kind: ChainingHint,
|
||||||
label: "A",
|
label: [
|
||||||
|
"A",
|
||||||
|
],
|
||||||
tooltip: Some(
|
tooltip: Some(
|
||||||
HoverRanged(
|
HoverRanged(
|
||||||
FileId(
|
FileId(
|
||||||
@ -2294,7 +2380,9 @@ fn main() {
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range: 143..190,
|
range: 143..190,
|
||||||
kind: ChainingHint,
|
kind: ChainingHint,
|
||||||
label: "C",
|
label: [
|
||||||
|
"C",
|
||||||
|
],
|
||||||
tooltip: Some(
|
tooltip: Some(
|
||||||
HoverRanged(
|
HoverRanged(
|
||||||
FileId(
|
FileId(
|
||||||
@ -2307,7 +2395,9 @@ fn main() {
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range: 143..179,
|
range: 143..179,
|
||||||
kind: ChainingHint,
|
kind: ChainingHint,
|
||||||
label: "B",
|
label: [
|
||||||
|
"B",
|
||||||
|
],
|
||||||
tooltip: Some(
|
tooltip: Some(
|
||||||
HoverRanged(
|
HoverRanged(
|
||||||
FileId(
|
FileId(
|
||||||
@ -2350,7 +2440,9 @@ fn main() {
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range: 246..283,
|
range: 246..283,
|
||||||
kind: ChainingHint,
|
kind: ChainingHint,
|
||||||
label: "B<X<i32, bool>>",
|
label: [
|
||||||
|
"B<X<i32, bool>>",
|
||||||
|
],
|
||||||
tooltip: Some(
|
tooltip: Some(
|
||||||
HoverRanged(
|
HoverRanged(
|
||||||
FileId(
|
FileId(
|
||||||
@ -2363,7 +2455,9 @@ fn main() {
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range: 246..265,
|
range: 246..265,
|
||||||
kind: ChainingHint,
|
kind: ChainingHint,
|
||||||
label: "A<X<i32, bool>>",
|
label: [
|
||||||
|
"A<X<i32, bool>>",
|
||||||
|
],
|
||||||
tooltip: Some(
|
tooltip: Some(
|
||||||
HoverRanged(
|
HoverRanged(
|
||||||
FileId(
|
FileId(
|
||||||
@ -2408,7 +2502,9 @@ fn main() {
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range: 174..241,
|
range: 174..241,
|
||||||
kind: ChainingHint,
|
kind: ChainingHint,
|
||||||
label: "impl Iterator<Item = ()>",
|
label: [
|
||||||
|
"impl Iterator<Item = ()>",
|
||||||
|
],
|
||||||
tooltip: Some(
|
tooltip: Some(
|
||||||
HoverRanged(
|
HoverRanged(
|
||||||
FileId(
|
FileId(
|
||||||
@ -2421,7 +2517,9 @@ fn main() {
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range: 174..224,
|
range: 174..224,
|
||||||
kind: ChainingHint,
|
kind: ChainingHint,
|
||||||
label: "impl Iterator<Item = ()>",
|
label: [
|
||||||
|
"impl Iterator<Item = ()>",
|
||||||
|
],
|
||||||
tooltip: Some(
|
tooltip: Some(
|
||||||
HoverRanged(
|
HoverRanged(
|
||||||
FileId(
|
FileId(
|
||||||
@ -2434,7 +2532,9 @@ fn main() {
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range: 174..206,
|
range: 174..206,
|
||||||
kind: ChainingHint,
|
kind: ChainingHint,
|
||||||
label: "impl Iterator<Item = ()>",
|
label: [
|
||||||
|
"impl Iterator<Item = ()>",
|
||||||
|
],
|
||||||
tooltip: Some(
|
tooltip: Some(
|
||||||
HoverRanged(
|
HoverRanged(
|
||||||
FileId(
|
FileId(
|
||||||
@ -2447,7 +2547,9 @@ fn main() {
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range: 174..189,
|
range: 174..189,
|
||||||
kind: ChainingHint,
|
kind: ChainingHint,
|
||||||
label: "&mut MyIter",
|
label: [
|
||||||
|
"&mut MyIter",
|
||||||
|
],
|
||||||
tooltip: Some(
|
tooltip: Some(
|
||||||
HoverRanged(
|
HoverRanged(
|
||||||
FileId(
|
FileId(
|
||||||
@ -2489,7 +2591,9 @@ fn main() {
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range: 124..130,
|
range: 124..130,
|
||||||
kind: TypeHint,
|
kind: TypeHint,
|
||||||
label: "Struct",
|
label: [
|
||||||
|
"Struct",
|
||||||
|
],
|
||||||
tooltip: Some(
|
tooltip: Some(
|
||||||
HoverRanged(
|
HoverRanged(
|
||||||
FileId(
|
FileId(
|
||||||
@ -2502,7 +2606,9 @@ fn main() {
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range: 145..185,
|
range: 145..185,
|
||||||
kind: ChainingHint,
|
kind: ChainingHint,
|
||||||
label: "Struct",
|
label: [
|
||||||
|
"Struct",
|
||||||
|
],
|
||||||
tooltip: Some(
|
tooltip: Some(
|
||||||
HoverRanged(
|
HoverRanged(
|
||||||
FileId(
|
FileId(
|
||||||
@ -2515,7 +2621,9 @@ fn main() {
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range: 145..168,
|
range: 145..168,
|
||||||
kind: ChainingHint,
|
kind: ChainingHint,
|
||||||
label: "Struct",
|
label: [
|
||||||
|
"Struct",
|
||||||
|
],
|
||||||
tooltip: Some(
|
tooltip: Some(
|
||||||
HoverRanged(
|
HoverRanged(
|
||||||
FileId(
|
FileId(
|
||||||
@ -2528,7 +2636,9 @@ fn main() {
|
|||||||
InlayHint {
|
InlayHint {
|
||||||
range: 222..228,
|
range: 222..228,
|
||||||
kind: ParameterHint,
|
kind: ParameterHint,
|
||||||
label: "self",
|
label: [
|
||||||
|
"self",
|
||||||
|
],
|
||||||
tooltip: Some(
|
tooltip: Some(
|
||||||
HoverOffset(
|
HoverOffset(
|
||||||
FileId(
|
FileId(
|
||||||
|
@ -82,8 +82,8 @@ pub use crate::{
|
|||||||
highlight_related::{HighlightRelatedConfig, HighlightedRange},
|
highlight_related::{HighlightRelatedConfig, HighlightedRange},
|
||||||
hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
|
hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
|
||||||
inlay_hints::{
|
inlay_hints::{
|
||||||
ClosureReturnTypeHints, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip,
|
ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
|
||||||
LifetimeElisionHints, ReborrowHints,
|
InlayTooltip, LifetimeElisionHints, ReborrowHints,
|
||||||
},
|
},
|
||||||
join_lines::JoinLinesConfig,
|
join_lines::JoinLinesConfig,
|
||||||
markup::Markup,
|
markup::Markup,
|
||||||
|
@ -1362,7 +1362,7 @@ pub(crate) fn handle_inlay_hints(
|
|||||||
.map(|it| {
|
.map(|it| {
|
||||||
to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it)
|
to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it)
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect::<Result<Vec<_>>>()?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +314,9 @@ impl GlobalState {
|
|||||||
let mut args = args.clone();
|
let mut args = args.clone();
|
||||||
let mut path = path.clone();
|
let mut path = path.clone();
|
||||||
|
|
||||||
if let ProjectWorkspace::Cargo { sysroot, .. } = ws {
|
if let ProjectWorkspace::Cargo { sysroot, .. }
|
||||||
|
| ProjectWorkspace::Json { sysroot, .. } = ws
|
||||||
|
{
|
||||||
tracing::debug!("Found a cargo workspace...");
|
tracing::debug!("Found a cargo workspace...");
|
||||||
if let Some(sysroot) = sysroot.as_ref() {
|
if let Some(sysroot) = sysroot.as_ref() {
|
||||||
tracing::debug!("Found a cargo workspace with a sysroot...");
|
tracing::debug!("Found a cargo workspace with a sysroot...");
|
||||||
|
@ -9,8 +9,9 @@ use ide::{
|
|||||||
Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem,
|
Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem,
|
||||||
CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
|
CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
|
||||||
Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint,
|
Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint,
|
||||||
InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity,
|
InlayHintLabel, InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable,
|
||||||
SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
|
Severity, SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange,
|
||||||
|
TextSize,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use serde_json::to_value;
|
use serde_json::to_value;
|
||||||
@ -426,9 +427,16 @@ pub(crate) fn inlay_hint(
|
|||||||
snap: &GlobalStateSnapshot,
|
snap: &GlobalStateSnapshot,
|
||||||
line_index: &LineIndex,
|
line_index: &LineIndex,
|
||||||
render_colons: bool,
|
render_colons: bool,
|
||||||
inlay_hint: InlayHint,
|
mut inlay_hint: InlayHint,
|
||||||
) -> lsp_types::InlayHint {
|
) -> Result<lsp_types::InlayHint> {
|
||||||
lsp_types::InlayHint {
|
match inlay_hint.kind {
|
||||||
|
InlayKind::ParameterHint if render_colons => inlay_hint.label.append_str(":"),
|
||||||
|
InlayKind::TypeHint if render_colons => inlay_hint.label.prepend_str(": "),
|
||||||
|
InlayKind::ClosureReturnTypeHint => inlay_hint.label.prepend_str(" -> "),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(lsp_types::InlayHint {
|
||||||
position: match inlay_hint.kind {
|
position: match inlay_hint.kind {
|
||||||
// before annotated thing
|
// before annotated thing
|
||||||
InlayKind::ParameterHint
|
InlayKind::ParameterHint
|
||||||
@ -459,15 +467,9 @@ pub(crate) fn inlay_hint(
|
|||||||
| InlayKind::ImplicitReborrowHint
|
| InlayKind::ImplicitReborrowHint
|
||||||
| InlayKind::TypeHint
|
| InlayKind::TypeHint
|
||||||
| InlayKind::ClosingBraceHint => false,
|
| InlayKind::ClosingBraceHint => false,
|
||||||
InlayKind::BindingModeHint => inlay_hint.label != "&",
|
InlayKind::BindingModeHint => inlay_hint.label.as_simple_str() != Some("&"),
|
||||||
InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
|
InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
|
||||||
}),
|
}),
|
||||||
label: lsp_types::InlayHintLabel::String(match inlay_hint.kind {
|
|
||||||
InlayKind::ParameterHint if render_colons => format!("{}:", inlay_hint.label),
|
|
||||||
InlayKind::TypeHint if render_colons => format!(": {}", inlay_hint.label),
|
|
||||||
InlayKind::ClosureReturnTypeHint => format!(" -> {}", inlay_hint.label),
|
|
||||||
_ => inlay_hint.label.clone(),
|
|
||||||
}),
|
|
||||||
kind: match inlay_hint.kind {
|
kind: match inlay_hint.kind {
|
||||||
InlayKind::ParameterHint => Some(lsp_types::InlayHintKind::PARAMETER),
|
InlayKind::ParameterHint => Some(lsp_types::InlayHintKind::PARAMETER),
|
||||||
InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => {
|
InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => {
|
||||||
@ -506,9 +508,36 @@ pub(crate) fn inlay_hint(
|
|||||||
})(),
|
})(),
|
||||||
tooltip: Some(match inlay_hint.tooltip {
|
tooltip: Some(match inlay_hint.tooltip {
|
||||||
Some(ide::InlayTooltip::String(s)) => lsp_types::InlayHintTooltip::String(s),
|
Some(ide::InlayTooltip::String(s)) => lsp_types::InlayHintTooltip::String(s),
|
||||||
_ => lsp_types::InlayHintTooltip::String(inlay_hint.label),
|
_ => lsp_types::InlayHintTooltip::String(inlay_hint.label.to_string()),
|
||||||
}),
|
}),
|
||||||
}
|
label: inlay_hint_label(snap, inlay_hint.label)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inlay_hint_label(
|
||||||
|
snap: &GlobalStateSnapshot,
|
||||||
|
label: InlayHintLabel,
|
||||||
|
) -> Result<lsp_types::InlayHintLabel> {
|
||||||
|
Ok(match label.as_simple_str() {
|
||||||
|
Some(s) => lsp_types::InlayHintLabel::String(s.into()),
|
||||||
|
None => lsp_types::InlayHintLabel::LabelParts(
|
||||||
|
label
|
||||||
|
.parts
|
||||||
|
.into_iter()
|
||||||
|
.map(|part| {
|
||||||
|
Ok(lsp_types::InlayHintLabelPart {
|
||||||
|
value: part.text,
|
||||||
|
tooltip: None,
|
||||||
|
location: part
|
||||||
|
.linked_location
|
||||||
|
.map(|range| location(snap, range))
|
||||||
|
.transpose()?,
|
||||||
|
command: None,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>>>()?,
|
||||||
|
),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1);
|
static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1);
|
||||||
|
@ -248,8 +248,12 @@ impl ast::WhereClause {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::TypeBoundList {
|
pub trait Removable: AstNode {
|
||||||
pub fn remove(&self) {
|
fn remove(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Removable for ast::TypeBoundList {
|
||||||
|
fn remove(&self) {
|
||||||
match self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) {
|
match self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) {
|
||||||
Some(colon) => ted::remove_all(colon..=self.syntax().clone().into()),
|
Some(colon) => ted::remove_all(colon..=self.syntax().clone().into()),
|
||||||
None => ted::remove(self.syntax()),
|
None => ted::remove(self.syntax()),
|
||||||
@ -267,8 +271,8 @@ impl ast::PathSegment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::UseTree {
|
impl Removable for ast::UseTree {
|
||||||
pub fn remove(&self) {
|
fn remove(&self) {
|
||||||
for dir in [Direction::Next, Direction::Prev] {
|
for dir in [Direction::Next, Direction::Prev] {
|
||||||
if let Some(next_use_tree) = neighbor(self, dir) {
|
if let Some(next_use_tree) = neighbor(self, dir) {
|
||||||
let separators = self
|
let separators = self
|
||||||
@ -282,7 +286,9 @@ impl ast::UseTree {
|
|||||||
}
|
}
|
||||||
ted::remove(self.syntax());
|
ted::remove(self.syntax());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ast::UseTree {
|
||||||
pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList {
|
pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList {
|
||||||
match self.use_tree_list() {
|
match self.use_tree_list() {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
@ -373,8 +379,8 @@ impl ast::UseTreeList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::Use {
|
impl Removable for ast::Use {
|
||||||
pub fn remove(&self) {
|
fn remove(&self) {
|
||||||
let next_ws = self
|
let next_ws = self
|
||||||
.syntax()
|
.syntax()
|
||||||
.next_sibling_or_token()
|
.next_sibling_or_token()
|
||||||
@ -444,8 +450,8 @@ impl ast::Fn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::MatchArm {
|
impl Removable for ast::MatchArm {
|
||||||
pub fn remove(&self) {
|
fn remove(&self) {
|
||||||
if let Some(sibling) = self.syntax().prev_sibling_or_token() {
|
if let Some(sibling) = self.syntax().prev_sibling_or_token() {
|
||||||
if sibling.kind() == SyntaxKind::WHITESPACE {
|
if sibling.kind() == SyntaxKind::WHITESPACE {
|
||||||
ted::remove(sibling);
|
ted::remove(sibling);
|
||||||
|
Loading…
Reference in New Issue
Block a user