1 //! This module provides the functionality needed to convert diagnostics from
2 //! `cargo check` json format to the LSP diagnostic format.
3 use std
::collections
::HashMap
;
5 use flycheck
::{Applicability, DiagnosticLevel, DiagnosticSpan}
;
6 use itertools
::Itertools
;
8 use vfs
::{AbsPath, AbsPathBuf}
;
11 global_state
::GlobalStateSnapshot
, line_index
::PositionEncoding
, lsp_ext
,
12 to_proto
::url_from_abs_path
,
15 use super::{DiagnosticsMapConfig, Fix}
;
17 /// Determines the LSP severity from a diagnostic
18 fn diagnostic_severity(
19 config
: &DiagnosticsMapConfig
,
20 level
: flycheck
::DiagnosticLevel
,
21 code
: Option
<flycheck
::DiagnosticCode
>,
22 ) -> Option
<lsp_types
::DiagnosticSeverity
> {
23 let res
= match level
{
24 DiagnosticLevel
::Ice
=> lsp_types
::DiagnosticSeverity
::ERROR
,
25 DiagnosticLevel
::Error
=> lsp_types
::DiagnosticSeverity
::ERROR
,
26 DiagnosticLevel
::Warning
=> match &code
{
27 // HACK: special case for `warnings` rustc lint.
29 if config
.warnings_as_hint
.iter().any(|lint
| {
30 lint
== "warnings" || ide_db
::helpers
::lint_eq_or_in_group(&code
.code
, lint
)
33 lsp_types
::DiagnosticSeverity
::HINT
35 // HACK: special case for `warnings` rustc lint.
37 if config
.warnings_as_info
.iter().any(|lint
| {
38 lint
== "warnings" || ide_db
::helpers
::lint_eq_or_in_group(&code
.code
, lint
)
41 lsp_types
::DiagnosticSeverity
::INFORMATION
43 _
=> lsp_types
::DiagnosticSeverity
::WARNING
,
45 DiagnosticLevel
::Note
=> lsp_types
::DiagnosticSeverity
::INFORMATION
,
46 DiagnosticLevel
::Help
=> lsp_types
::DiagnosticSeverity
::HINT
,
52 /// Checks whether a file name is from macro invocation and does not refer to an actual file.
53 fn is_dummy_macro_file(file_name
: &str) -> bool
{
54 // FIXME: current rustc does not seem to emit `<macro file>` files anymore?
55 file_name
.starts_with('
<'
) && file_name
.ends_with('
>'
)
58 /// Converts a Rust span to a LSP location
60 config
: &DiagnosticsMapConfig
,
61 workspace_root
: &AbsPath
,
62 span
: &DiagnosticSpan
,
63 snap
: &GlobalStateSnapshot
,
64 ) -> lsp_types
::Location
{
65 let file_name
= resolve_path(config
, workspace_root
, &span
.file_name
);
66 let uri
= url_from_abs_path(&file_name
);
69 let position_encoding
= snap
.config
.position_encoding();
70 lsp_types
::Range
::new(
71 position(&position_encoding
, span
, span
.line_start
, span
.column_start
),
72 position(&position_encoding
, span
, span
.line_end
, span
.column_end
),
75 lsp_types
::Location
::new(uri
, range
)
79 position_encoding
: &PositionEncoding
,
80 span
: &DiagnosticSpan
,
83 ) -> lsp_types
::Position
{
84 let line_index
= line_offset
- span
.line_start
;
86 let mut true_column_offset
= column_offset
;
87 if let Some(line
) = span
.text
.get(line_index
) {
88 if line
.text
.chars().count() == line
.text
.len() {
89 // all one byte utf-8 char
90 return lsp_types
::Position
{
91 line
: (line_offset
as u32).saturating_sub(1),
92 character
: (column_offset
as u32).saturating_sub(1),
95 let mut char_offset
= 0;
96 let len_func
= match position_encoding
{
97 PositionEncoding
::Utf8
=> char::len_utf8
,
98 PositionEncoding
::Utf16
=> char::len_utf16
,
100 for c
in line
.text
.chars() {
102 if char_offset
> column_offset
{
105 true_column_offset
+= len_func(c
) - 1;
109 lsp_types
::Position
{
110 line
: (line_offset
as u32).saturating_sub(1),
111 character
: (true_column_offset
as u32).saturating_sub(1),
115 /// Extracts a suitable "primary" location from a rustc diagnostic.
117 /// This takes locations pointing into the standard library, or generally outside the current
118 /// workspace into account and tries to avoid those, in case macros are involved.
120 config
: &DiagnosticsMapConfig
,
121 workspace_root
: &AbsPath
,
122 span
: &DiagnosticSpan
,
123 snap
: &GlobalStateSnapshot
,
124 ) -> lsp_types
::Location
{
125 let span_stack
= std
::iter
::successors(Some(span
), |span
| Some(&span
.expansion
.as_ref()?
.span
));
126 for span
in span_stack
.clone() {
127 let abs_path
= resolve_path(config
, workspace_root
, &span
.file_name
);
128 if !is_dummy_macro_file(&span
.file_name
) && abs_path
.starts_with(workspace_root
) {
129 return location(config
, workspace_root
, span
, snap
);
133 // Fall back to the outermost macro invocation if no suitable span comes up.
134 let last_span
= span_stack
.last().unwrap();
135 location(config
, workspace_root
, last_span
, snap
)
138 /// Converts a secondary Rust span to a LSP related information
140 /// If the span is unlabelled this will return `None`.
141 fn diagnostic_related_information(
142 config
: &DiagnosticsMapConfig
,
143 workspace_root
: &AbsPath
,
144 span
: &DiagnosticSpan
,
145 snap
: &GlobalStateSnapshot
,
146 ) -> Option
<lsp_types
::DiagnosticRelatedInformation
> {
147 let message
= span
.label
.clone()?
;
148 let location
= location(config
, workspace_root
, span
, snap
);
149 Some(lsp_types
::DiagnosticRelatedInformation { location, message }
)
152 /// Resolves paths applying any matching path prefix remappings, and then
153 /// joining the path to the workspace root.
155 config
: &DiagnosticsMapConfig
,
156 workspace_root
: &AbsPath
,
162 .find_map(|(from
, to
)| file_name
.strip_prefix(from
).map(|file_name
| (to
, file_name
)))
164 Some((to
, file_name
)) => workspace_root
.join(format
!("{}{}", to
, file_name
)),
165 None
=> workspace_root
.join(file_name
),
169 struct SubDiagnostic
{
170 related
: lsp_types
::DiagnosticRelatedInformation
,
171 suggested_fix
: Option
<Fix
>,
174 enum MappedRustChildDiagnostic
{
175 SubDiagnostic(SubDiagnostic
),
179 fn map_rust_child_diagnostic(
180 config
: &DiagnosticsMapConfig
,
181 workspace_root
: &AbsPath
,
182 rd
: &flycheck
::Diagnostic
,
183 snap
: &GlobalStateSnapshot
,
184 ) -> MappedRustChildDiagnostic
{
185 let spans
: Vec
<&DiagnosticSpan
> = rd
.spans
.iter().filter(|s
| s
.is_primary
).collect();
186 if spans
.is_empty() {
187 // `rustc` uses these spanless children as a way to print multi-line
189 return MappedRustChildDiagnostic
::MessageLine(rd
.message
.clone());
192 let mut edit_map
: HashMap
<lsp_types
::Url
, Vec
<lsp_types
::TextEdit
>> = HashMap
::new();
193 let mut suggested_replacements
= Vec
::new();
194 for &span
in &spans
{
195 if let Some(suggested_replacement
) = &span
.suggested_replacement
{
196 if !suggested_replacement
.is_empty() {
197 suggested_replacements
.push(suggested_replacement
);
199 let location
= location(config
, workspace_root
, span
, snap
);
200 let edit
= lsp_types
::TextEdit
::new(location
.range
, suggested_replacement
.clone());
202 // Only actually emit a quickfix if the suggestion is "valid enough".
203 // We accept both "MaybeIncorrect" and "MachineApplicable". "MaybeIncorrect" means that
204 // the suggestion is *complete* (contains no placeholders where code needs to be
205 // inserted), but might not be what the user wants, or might need minor adjustments.
207 span
.suggestion_applicability
,
208 None
| Some(Applicability
::MaybeIncorrect
| Applicability
::MachineApplicable
)
210 edit_map
.entry(location
.uri
).or_default().push(edit
);
215 // rustc renders suggestion diagnostics by appending the suggested replacement, so do the same
216 // here, otherwise the diagnostic text is missing useful information.
217 let mut message
= rd
.message
.clone();
218 if !suggested_replacements
.is_empty() {
219 message
.push_str(": ");
221 suggested_replacements
.iter().map(|suggestion
| format
!("`{}`", suggestion
)).join(", ");
222 message
.push_str(&suggestions
);
225 if edit_map
.is_empty() {
226 MappedRustChildDiagnostic
::SubDiagnostic(SubDiagnostic
{
227 related
: lsp_types
::DiagnosticRelatedInformation
{
228 location
: location(config
, workspace_root
, spans
[0], snap
),
234 MappedRustChildDiagnostic
::SubDiagnostic(SubDiagnostic
{
235 related
: lsp_types
::DiagnosticRelatedInformation
{
236 location
: location(config
, workspace_root
, spans
[0], snap
),
237 message
: message
.clone(),
239 suggested_fix
: Some(Fix
{
242 .map(|&span
| location(config
, workspace_root
, span
, snap
).range
)
244 action
: lsp_ext
::CodeAction
{
247 kind
: Some(lsp_types
::CodeActionKind
::QUICKFIX
),
248 edit
: Some(lsp_ext
::SnippetWorkspaceEdit
{
249 // FIXME: there's no good reason to use edit_map here....
250 changes
: Some(edit_map
),
251 document_changes
: None
,
252 change_annotations
: None
,
254 is_preferred
: Some(true),
264 pub(crate) struct MappedRustDiagnostic
{
265 pub(crate) url
: lsp_types
::Url
,
266 pub(crate) diagnostic
: lsp_types
::Diagnostic
,
267 pub(crate) fix
: Option
<Fix
>,
270 /// Converts a Rust root diagnostic to LSP form
272 /// This flattens the Rust diagnostic by:
274 /// 1. Creating a LSP diagnostic with the root message and primary span.
275 /// 2. Adding any labelled secondary spans to `relatedInformation`
276 /// 3. Categorising child diagnostics as either `SuggestedFix`es,
277 /// `relatedInformation` or additional message lines.
279 /// If the diagnostic has no primary span this will return `None`
280 pub(crate) fn map_rust_diagnostic_to_lsp(
281 config
: &DiagnosticsMapConfig
,
282 rd
: &flycheck
::Diagnostic
,
283 workspace_root
: &AbsPath
,
284 snap
: &GlobalStateSnapshot
,
285 ) -> Vec
<MappedRustDiagnostic
> {
286 let primary_spans
: Vec
<&DiagnosticSpan
> = rd
.spans
.iter().filter(|s
| s
.is_primary
).collect();
287 if primary_spans
.is_empty() {
291 let severity
= diagnostic_severity(config
, rd
.level
, rd
.code
.clone());
293 let mut source
= String
::from("rustc");
294 let mut code
= rd
.code
.as_ref().map(|c
| c
.code
.clone());
295 if let Some(code_val
) = &code
{
296 // See if this is an RFC #2103 scoped lint (e.g. from Clippy)
297 let scoped_code
: Vec
<&str> = code_val
.split("::").collect();
298 if scoped_code
.len() == 2 {
299 source
= String
::from(scoped_code
[0]);
300 code
= Some(String
::from(scoped_code
[1]));
304 let mut needs_primary_span_label
= true;
305 let mut subdiagnostics
= Vec
::new();
306 let mut tags
= Vec
::new();
308 for secondary_span
in rd
.spans
.iter().filter(|s
| !s
.is_primary
) {
309 let related
= diagnostic_related_information(config
, workspace_root
, secondary_span
, snap
);
310 if let Some(related
) = related
{
311 subdiagnostics
.push(SubDiagnostic { related, suggested_fix: None }
);
315 let mut message
= rd
.message
.clone();
316 for child
in &rd
.children
{
317 let child
= map_rust_child_diagnostic(config
, workspace_root
, child
, snap
);
319 MappedRustChildDiagnostic
::SubDiagnostic(sub
) => {
320 subdiagnostics
.push(sub
);
322 MappedRustChildDiagnostic
::MessageLine(message_line
) => {
323 format_to
!(message
, "\n{}", message_line
);
325 // These secondary messages usually duplicate the content of the
326 // primary span label.
327 needs_primary_span_label
= false;
332 if let Some(code
) = &rd
.code
{
333 let code
= code
.code
.as_str();
339 | "unused_attributes"
344 tags
.push(lsp_types
::DiagnosticTag
::UNNECESSARY
);
347 if matches
!(code
, "deprecated") {
348 tags
.push(lsp_types
::DiagnosticTag
::DEPRECATED
);
352 let code_description
= match source
.as_str() {
353 "rustc" => rustc_code_description(code
.as_deref()),
354 "clippy" => clippy_code_description(code
.as_deref()),
360 .flat_map(|primary_span
| {
361 let primary_location
= primary_location(config
, workspace_root
, primary_span
, snap
);
363 let mut message
= message
.clone();
364 if needs_primary_span_label
{
365 if let Some(primary_span_label
) = &primary_span
.label
{
366 format_to
!(message
, "\n{}", primary_span_label
);
371 // Each primary diagnostic span may result in multiple LSP diagnostics.
372 let mut diagnostics
= Vec
::new();
374 let mut related_info_macro_calls
= vec
![];
376 // If error occurs from macro expansion, add related info pointing to
377 // where the error originated
378 // Also, we would generate an additional diagnostic, so that exact place of macro
379 // will be highlighted in the error origin place.
380 let span_stack
= std
::iter
::successors(Some(*primary_span
), |span
| {
381 Some(&span
.expansion
.as_ref()?
.span
)
383 for (i
, span
) in span_stack
.enumerate() {
384 if is_dummy_macro_file(&span
.file_name
) {
388 // First span is the original diagnostic, others are macro call locations that
389 // generated that code.
390 let is_in_macro_call
= i
!= 0;
392 let secondary_location
= location(config
, workspace_root
, span
, snap
);
393 if secondary_location
== primary_location
{
396 related_info_macro_calls
.push(lsp_types
::DiagnosticRelatedInformation
{
397 location
: secondary_location
.clone(),
398 message
: if is_in_macro_call
{
399 "Error originated from macro call here".to_string()
401 "Actual error occurred here".to_string()
404 // For the additional in-macro diagnostic we add the inverse message pointing to the error location in code.
405 let information_for_additional_diagnostic
=
406 vec
![lsp_types
::DiagnosticRelatedInformation
{
407 location
: primary_location
.clone(),
408 message
: "Exact error occurred here".to_string(),
411 let diagnostic
= lsp_types
::Diagnostic
{
412 range
: secondary_location
.range
,
413 // downgrade to hint if we're pointing at the macro
414 severity
: Some(lsp_types
::DiagnosticSeverity
::HINT
),
415 code
: code
.clone().map(lsp_types
::NumberOrString
::String
),
416 code_description
: code_description
.clone(),
417 source
: Some(source
.clone()),
418 message
: message
.clone(),
419 related_information
: Some(information_for_additional_diagnostic
),
420 tags
: if tags
.is_empty() { None }
else { Some(tags.clone()) }
,
421 data
: Some(serde_json
::json
!({ "rendered": rd.rendered }
)),
423 diagnostics
.push(MappedRustDiagnostic
{
424 url
: secondary_location
.uri
,
430 // Emit the primary diagnostic.
431 diagnostics
.push(MappedRustDiagnostic
{
432 url
: primary_location
.uri
.clone(),
433 diagnostic
: lsp_types
::Diagnostic
{
434 range
: primary_location
.range
,
436 code
: code
.clone().map(lsp_types
::NumberOrString
::String
),
437 code_description
: code_description
.clone(),
438 source
: Some(source
.clone()),
440 related_information
: {
441 let info
= related_info_macro_calls
444 .chain(subdiagnostics
.iter().map(|sub
| sub
.related
.clone()))
445 .collect
::<Vec
<_
>>();
452 tags
: if tags
.is_empty() { None }
else { Some(tags.clone()) }
,
453 data
: Some(serde_json
::json
!({ "rendered": rd.rendered }
)),
458 // Emit hint-level diagnostics for all `related_information` entries such as "help"s.
459 // This is useful because they will show up in the user's editor, unlike
460 // `related_information`, which just produces hard-to-read links, at least in VS Code.
461 let back_ref
= lsp_types
::DiagnosticRelatedInformation
{
462 location
: primary_location
,
463 message
: "original diagnostic".to_string(),
465 for sub
in &subdiagnostics
{
466 diagnostics
.push(MappedRustDiagnostic
{
467 url
: sub
.related
.location
.uri
.clone(),
468 fix
: sub
.suggested_fix
.clone(),
469 diagnostic
: lsp_types
::Diagnostic
{
470 range
: sub
.related
.location
.range
,
471 severity
: Some(lsp_types
::DiagnosticSeverity
::HINT
),
472 code
: code
.clone().map(lsp_types
::NumberOrString
::String
),
473 code_description
: code_description
.clone(),
474 source
: Some(source
.clone()),
475 message
: sub
.related
.message
.clone(),
476 related_information
: Some(vec
![back_ref
.clone()]),
477 tags
: None
, // don't apply modifiers again
488 fn rustc_code_description(code
: Option
<&str>) -> Option
<lsp_types
::CodeDescription
> {
490 let mut chars
= code
.chars();
491 chars
.next().map_or(false, |c
| c
== 'E'
)
492 && chars
.by_ref().take(4).all(|c
| c
.is_ascii_digit())
493 && chars
.next().is_none()
496 lsp_types
::Url
::parse(&format
!("https://doc.rust-lang.org/error-index.html#{}", code
))
498 .map(|href
| lsp_types
::CodeDescription { href }
)
502 fn clippy_code_description(code
: Option
<&str>) -> Option
<lsp_types
::CodeDescription
> {
503 code
.and_then(|code
| {
504 lsp_types
::Url
::parse(&format
!(
505 "https://rust-lang.github.io/rust-clippy/master/index.html#{}",
509 .map(|href
| lsp_types
::CodeDescription { href }
)
518 use crate::{config::Config, global_state::GlobalState}
;
522 use expect_test
::{expect_file, ExpectFile}
;
523 use lsp_types
::ClientCapabilities
;
525 fn check(diagnostics_json
: &str, expect
: ExpectFile
) {
526 check_with_config(DiagnosticsMapConfig
::default(), diagnostics_json
, expect
)
529 fn check_with_config(config
: DiagnosticsMapConfig
, diagnostics_json
: &str, expect
: ExpectFile
) {
530 let diagnostic
: flycheck
::Diagnostic
= serde_json
::from_str(diagnostics_json
).unwrap();
531 let workspace_root
: &AbsPath
= Path
::new("/test/").try_into().unwrap();
532 let (sender
, _
) = crossbeam_channel
::unbounded();
533 let state
= GlobalState
::new(
535 Config
::new(workspace_root
.to_path_buf(), ClientCapabilities
::default()),
537 let snap
= state
.snapshot();
538 let mut actual
= map_rust_diagnostic_to_lsp(&config
, &diagnostic
, workspace_root
, &snap
);
539 actual
.iter_mut().for_each(|diag
| diag
.diagnostic
.data
= None
);
540 expect
.assert_debug_eq(&actual
)
544 fn rustc_incompatible_type_for_trait() {
547 "message": "method `next` has an incompatible type for trait",
550 "explanation": "\nThe parameters of any trait method must match between a trait implementation\nand the trait definition.\n\nHere are a couple examples of this error:\n\n```compile_fail,E0053\ntrait Foo {\n fn foo(x: u16);\n fn bar(&self);\n}\n\nstruct Bar;\n\nimpl Foo for Bar {\n // error, expected u16, found i16\n fn foo(x: i16) { }\n\n // error, types differ in mutability\n fn bar(&mut self) { }\n}\n```\n"
555 "file_name": "compiler/ty/list_iter.rs",
565 "text": " fn next(&self) -> Option<&'list ty::Ref<M>> {",
566 "highlight_start": 5,
570 "label": "types differ in mutability",
571 "suggested_replacement": null
,
572 "suggestion_applicability": null
,
578 "message": "expected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>`",
586 "rendered": "error[E0053]: method `next` has an incompatible type for trait\n --> compiler/ty/list_iter.rs:52:5\n |\n52 | fn next(&self) -> Option<&'list ty::Ref<M>> {\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability\n |\n = note: expected type `fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>`\n\n"
589 expect_file!["./test_data
/rustc_incompatible_type_for_trait
.txt
"],
594 fn rustc_unused_variable() {
597 "message": "unused variable: `foo`",
599 "code": "unused_variables",
605 "file_name": "driver/subcommand/repl.rs",
615 "text": " let foo = 42;",
616 "highlight_start": 9,
621 "suggested_replacement": null
,
622 "suggestion_applicability": null
,
628 "message": "#[warn(unused_variables)] on by default",
636 "message": "consider prefixing with an underscore",
641 "file_name": "driver/subcommand/repl.rs",
651 "text": " let foo = 42;",
652 "highlight_start": 9,
657 "suggested_replacement": "_foo",
658 "suggestion_applicability": "MachineApplicable",
666 "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n"
668 expect_file!["./test_data
/rustc_unused_variable
.txt
"],
674 fn rustc_unused_variable_as_info() {
676 DiagnosticsMapConfig {
677 warnings_as_info: vec!["unused_variables
".to_string()],
678 ..DiagnosticsMapConfig::default()
681 "message": "unused variable: `foo`",
683 "code": "unused_variables",
689 "file_name": "driver/subcommand/repl.rs",
699 "text": " let foo = 42;",
700 "highlight_start": 9,
705 "suggested_replacement": null
,
706 "suggestion_applicability": null
,
712 "message": "#[warn(unused_variables)] on by default",
720 "message": "consider prefixing with an underscore",
725 "file_name": "driver/subcommand/repl.rs",
735 "text": " let foo = 42;",
736 "highlight_start": 9,
741 "suggested_replacement": "_foo",
742 "suggestion_applicability": "MachineApplicable",
750 "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n"
752 expect_file!["./test_data
/rustc_unused_variable_as_info
.txt
"],
758 fn rustc_unused_variable_as_hint() {
760 DiagnosticsMapConfig {
761 warnings_as_hint: vec!["unused_variables
".to_string()],
762 ..DiagnosticsMapConfig::default()
765 "message": "unused variable: `foo`",
767 "code": "unused_variables",
773 "file_name": "driver/subcommand/repl.rs",
783 "text": " let foo = 42;",
784 "highlight_start": 9,
789 "suggested_replacement": null
,
790 "suggestion_applicability": null
,
796 "message": "#[warn(unused_variables)] on by default",
804 "message": "consider prefixing with an underscore",
809 "file_name": "driver/subcommand/repl.rs",
819 "text": " let foo = 42;",
820 "highlight_start": 9,
825 "suggested_replacement": "_foo",
826 "suggestion_applicability": "MachineApplicable",
834 "rendered": "warning: unused variable: `foo`\n --> driver/subcommand/repl.rs:291:9\n |\n291 | let foo = 42;\n | ^^^ help: consider prefixing with an underscore: `_foo`\n |\n = note: #[warn(unused_variables)] on by default\n\n"
836 expect_file!["./test_data
/rustc_unused_variable_as_hint
.txt
"],
841 fn rustc_wrong_number_of_parameters() {
844 "message": "this function takes 2 parameters but 3 parameters were supplied",
847 "explanation": "\nThe number of arguments passed to a function must match the number of arguments\nspecified in the function signature.\n\nFor example, a function like:\n\n```\nfn f(a: u16, b: &str) {}\n```\n\nMust always be called with exactly two arguments, e.g., `f(2, \"test\")`.\n\nNote that Rust does not have a notion of optional function arguments or\nvariadic functions (except for its C-FFI).\n"
852 "file_name": "compiler/ty/select.rs",
862 "text": " pub fn add_evidence(",
863 "highlight_start": 5,
867 "text": " &mut self,",
868 "highlight_start": 1,
872 "text": " target_poly: &ty::Ref<ty::Poly>,",
873 "highlight_start": 1,
877 "text": " evidence_poly: &ty::Ref<ty::Poly>,",
878 "highlight_start": 1,
883 "highlight_start": 1,
887 "text": " match target_poly {",
888 "highlight_start": 1,
892 "text": " ty::Ref::Var(tvar, _) => self.add_var_evidence(tvar, evidence_poly),",
893 "highlight_start": 1,
897 "text": " ty::Ref::Fixed(target_ty) => {",
898 "highlight_start": 1,
902 "text": " let evidence_ty = evidence_poly.resolve_to_ty();",
903 "highlight_start": 1,
907 "text": " self.add_evidence_ty(target_ty, evidence_poly, evidence_ty)",
908 "highlight_start": 1,
913 "highlight_start": 1,
918 "highlight_start": 1,
923 "highlight_start": 1,
927 "label": "defined here",
928 "suggested_replacement": null
,
929 "suggestion_applicability": null
,
933 "file_name": "compiler/ty/select.rs",
943 "text": " self.add_evidence(target_fixed, evidence_fixed, false);",
944 "highlight_start": 18,
948 "label": "expected 2 parameters",
949 "suggested_replacement": null
,
950 "suggestion_applicability": null
,
955 "rendered": "error[E0061]: this function takes 2 parameters but 3 parameters were supplied\n --> compiler/ty/select.rs:104:18\n |\n104 | self.add_evidence(target_fixed, evidence_fixed, false);\n | ^^^^^^^^^^^^ expected 2 parameters\n...\n219 | / pub fn add_evidence(\n220 | | &mut self,\n221 | | target_poly: &ty::Ref<ty::Poly>,\n222 | | evidence_poly: &ty::Ref<ty::Poly>,\n... |\n230 | | }\n231 | | }\n | |_____- defined here\n\n"
957 expect_file!["./test_data
/rustc_wrong_number_of_parameters
.txt
"],
962 fn clippy_pass_by_ref() {
965 "message": "this argument is passed by reference, but would be more efficient if passed by value",
967 "code": "clippy::trivially_copy_pass_by_ref",
973 "file_name": "compiler/mir/tagset.rs",
983 "text": " pub fn is_disjoint(&self, other: Self) -> bool {",
984 "highlight_start": 24,
989 "suggested_replacement": null
,
990 "suggestion_applicability": null
,
996 "message": "lint level defined here",
1001 "file_name": "compiler/lib.rs",
1011 "text": "#![warn(clippy::all)]",
1012 "highlight_start": 9,
1017 "suggested_replacement": null
,
1018 "suggestion_applicability": null
,
1026 "message": "#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]",
1034 "message": "for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref",
1042 "message": "consider passing by value instead",
1047 "file_name": "compiler/mir/tagset.rs",
1057 "text": " pub fn is_disjoint(&self, other: Self) -> bool {",
1058 "highlight_start": 24,
1063 "suggested_replacement": "self",
1064 "suggestion_applicability": "Unspecified",
1072 "rendered": "warning: this argument is passed by reference, but would be more efficient if passed by value\n --> compiler/mir/tagset.rs:42:24\n |\n42 | pub fn is_disjoint(&self, other: Self) -> bool {\n | ^^^^^ help: consider passing by value instead: `self`\n |\nnote: lint level defined here\n --> compiler/lib.rs:1:9\n |\n1 | #![warn(clippy::all)]\n | ^^^^^^^^^^^\n = note: #[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref\n\n"
1074 expect_file!["./test_data
/clippy_pass_by_ref
.txt
"],
1079 fn rustc_range_map_lsp_position() {
1082 "message": "mismatched types",
1085 "explanation": "Expected type did not match the received type.\n\nErroneous code examples:\n\n```compile_fail,E0308\nfn plus_one(x: i32) -> i32 {\n x + 1\n}\n\nplus_one(\"Not a number\");\n// ^^^^^^^^^^^^^^ expected `i32`, found `&str`\n\nif \"Not a bool\" {\n// ^^^^^^^^^^^^ expected `bool`, found `&str`\n}\n\nlet x: f32 = \"Not a float\";\n// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`\n// |\n// expected due to this\n```\n\nThis error occurs when an expression was used in a place where the compiler\nexpected an expression of a different type. It can occur in several cases, the\nmost common being when calling a function and passing an argument which has a\ndifferent type than the matching type in the function declaration.\n"
1090 "file_name": "crates/test_diagnostics/src/main.rs",
1100 "text": " let x: u32 = \"𐐀𐐀𐐀𐐀\"; // 17-23",
1101 "highlight_start": 18,
1105 "label": "expected `u32`, found `&str`",
1106 "suggested_replacement": null
,
1107 "suggestion_applicability": null
,
1111 "file_name": "crates/test_diagnostics/src/main.rs",
1118 "is_primary": false,
1121 "text": " let x: u32 = \"𐐀𐐀𐐀𐐀\"; // 17-23",
1122 "highlight_start": 12,
1126 "label": "expected due to this",
1127 "suggested_replacement": null
,
1128 "suggestion_applicability": null
,
1133 "rendered": "error[E0308]: mismatched types\n --> crates/test_diagnostics/src/main.rs:4:18\n |\n4 | let x: u32 = \"𐐀𐐀𐐀𐐀\"; // 17-23\n | --- ^^^^^^ expected `u32`, found `&str`\n | |\n | expected due to this\n\n"
1135 expect_file!("./test_data
/rustc_range_map_lsp_position
.txt
"),
1140 fn rustc_mismatched_type() {
1143 "message": "mismatched types",
1146 "explanation": "\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"
1151 "file_name": "runtime/compiler_support.rs",
1161 "text": " let layout = alloc::Layout::from_size_align_unchecked(size, align);",
1162 "highlight_start": 65,
1166 "label": "expected usize, found u32",
1167 "suggested_replacement": null
,
1168 "suggestion_applicability": null
,
1173 "rendered": "error[E0308]: mismatched types\n --> runtime/compiler_support.rs:48:65\n |\n48 | let layout = alloc::Layout::from_size_align_unchecked(size, align);\n | ^^^^^ expected usize, found u32\n\n"
1175 expect_file!["./test_data
/rustc_mismatched_type
.txt
"],
1180 fn handles_macro_location() {
1183 "rendered": "error[E0277]: can't compare `{integer}` with `&str`\n --> src/main.rs:2:5\n |\n2 | assert_eq!(1, \"love\");\n | ^^^^^^^^^^^^^^^^^^^^^^ no implementation for `{integer} == &str`\n |\n = help: the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`\n = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)\n\n",
1189 "message": "the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`",
1196 "explanation": "\nYou tried to use a type which doesn't implement some trait in a place which\nexpected that trait. Erroneous code example:\n\n```compile_fail,E0277\n// here we declare the Foo trait with a bar method\ntrait Foo {\n fn bar(&self);\n}\n\n// we now declare a function which takes an object implementing the Foo trait\nfn some_func<T: Foo>(foo: T) {\n foo.bar();\n}\n\nfn main() {\n // we now call the method with the i32 type, which doesn't implement\n // the Foo trait\n some_func(5i32); // error: the trait bound `i32 : Foo` is not satisfied\n}\n```\n\nIn order to fix this error, verify that the type you're using does implement\nthe trait. Example:\n\n```\ntrait Foo {\n fn bar(&self);\n}\n\nfn some_func<T: Foo>(foo: T) {\n foo.bar(); // we can now use this method since i32 implements the\n // Foo trait\n}\n\n// we implement the trait on the i32 type\nimpl Foo for i32 {\n fn bar(&self) {}\n}\n\nfn main() {\n some_func(5i32); // ok!\n}\n```\n\nOr in a generic context, an erroneous code example would look like:\n\n```compile_fail,E0277\nfn some_func<T>(foo: T) {\n println!(\"{:?}\", foo); // error: the trait `core::fmt::Debug` is not\n // implemented for the type `T`\n}\n\nfn main() {\n // We now call the method with the i32 type,\n // which *does* implement the Debug trait.\n some_func(5i32);\n}\n```\n\nNote that the error here is in the definition of the generic function: Although\nwe only call it with a parameter that does implement `Debug`, the compiler\nstill rejects the function: It must work with all possible input types. In\norder to make this example compile, we need to restrict the generic type we're\naccepting:\n\n```\nuse std::fmt;\n\n// Restrict the input type to types that implement Debug.\nfn some_func<T: fmt::Debug>(foo: T) {\n println!(\"{:?}\", foo);\n}\n\nfn main() {\n // Calling the method is still fine, as i32 implements Debug.\n some_func(5i32);\n\n // This would fail to compile now:\n // struct WithoutDebug;\n // some_func(WithoutDebug);\n}\n```\n\nRust only looks at the signature of the called function, as such it must\nalready specify all requirements that will be used for every type parameter.\n"
1199 "message": "can't compare `{integer}` with `&str`",
1213 "file_name": "<::core::macros::assert_eq macros>",
1214 "is_primary": false,
1218 "suggested_replacement": null
,
1219 "suggestion_applicability": null
,
1222 "highlight_end": 35,
1223 "highlight_start": 1,
1224 "text": "($ left : expr, $ right : expr) =>"
1228 "highlight_start": 1,
1232 "highlight_end": 33,
1233 "highlight_start": 1,
1234 "text": " match (& $ left, & $ right)"
1238 "highlight_start": 1,
1242 "highlight_end": 34,
1243 "highlight_start": 1,
1244 "text": " (left_val, right_val) =>"
1247 "highlight_end": 11,
1248 "highlight_start": 1,
1252 "highlight_end": 46,
1253 "highlight_start": 1,
1254 "text": " if ! (* left_val == * right_val)"
1257 "highlight_end": 15,
1258 "highlight_start": 1,
1262 "highlight_end": 25,
1263 "highlight_start": 1,
1267 "highlight_end": 57,
1268 "highlight_start": 1,
1269 "text": " (r#\"assertion failed: `(left == right)`"
1272 "highlight_end": 16,
1273 "highlight_start": 1,
1274 "text": " left: `{:?}`,"
1277 "highlight_end": 18,
1278 "highlight_start": 1,
1279 "text": " right: `{:?}`\"#,"
1282 "highlight_end": 47,
1283 "highlight_start": 1,
1284 "text": " & * left_val, & * right_val)"
1287 "highlight_end": 15,
1288 "highlight_start": 1,
1292 "highlight_end": 11,
1293 "highlight_start": 1,
1298 "highlight_start": 1,
1302 "highlight_end": 42,
1303 "highlight_start": 1,
1304 "text": " }) ; ($ left : expr, $ right : expr,) =>"
1307 "highlight_end": 49,
1308 "highlight_start": 1,
1309 "text": "({ $ crate :: assert_eq ! ($ left, $ right) }) ;"
1312 "highlight_end": 53,
1313 "highlight_start": 1,
1314 "text": "($ left : expr, $ right : expr, $ ($ arg : tt) +) =>"
1318 "highlight_start": 1,
1322 "highlight_end": 37,
1323 "highlight_start": 1,
1324 "text": " match (& ($ left), & ($ right))"
1328 "highlight_start": 1,
1332 "highlight_end": 34,
1333 "highlight_start": 1,
1334 "text": " (left_val, right_val) =>"
1337 "highlight_end": 11,
1338 "highlight_start": 1,
1342 "highlight_end": 46,
1343 "highlight_start": 1,
1344 "text": " if ! (* left_val == * right_val)"
1347 "highlight_end": 15,
1348 "highlight_start": 1,
1352 "highlight_end": 25,
1353 "highlight_start": 1,
1357 "highlight_end": 57,
1358 "highlight_start": 1,
1359 "text": " (r#\"assertion failed: `(left == right)`"
1362 "highlight_end": 16,
1363 "highlight_start": 1,
1364 "text": " left: `{:?}`,"
1367 "highlight_end": 22,
1368 "highlight_start": 1,
1369 "text": " right: `{:?}`: {}\"#,"
1372 "highlight_end": 72,
1373 "highlight_start": 1,
1374 "text": " & * left_val, & * right_val, $ crate :: format_args !"
1377 "highlight_end": 33,
1378 "highlight_start": 1,
1379 "text": " ($ ($ arg) +))"
1382 "highlight_end": 15,
1383 "highlight_start": 1,
1387 "highlight_end": 11,
1388 "highlight_start": 1,
1393 "highlight_start": 1,
1398 "highlight_start": 1,
1403 "macro_decl_name": "assert_eq!",
1410 "file_name": "src/main.rs",
1411 "is_primary": false,
1415 "suggested_replacement": null
,
1416 "suggestion_applicability": null
,
1419 "highlight_end": 27,
1420 "highlight_start": 5,
1421 "text": " assert_eq!(1, \"love\");"
1426 "file_name": "<::core::macros::assert_eq macros>",
1428 "label": "no implementation for `{integer} == &str`",
1431 "suggested_replacement": null
,
1432 "suggestion_applicability": null
,
1435 "highlight_end": 33,
1436 "highlight_start": 31,
1437 "text": " if ! (* left_val == * right_val)"
1443 expect_file!["./test_data
/handles_macro_location
.txt
"],
1448 fn macro_compiler_error() {
1451 "rendered": "error: Please register your known path in the path module\n --> crates/hir_def/src/path.rs:265:9\n |\n265 | compile_error!(\"Please register your known path in the path module\")\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n | \n ::: crates/hir_def/src/data.rs:80:16\n |\n80 | let path = path![std::future::Future];\n | -------------------------- in this macro invocation\n\n",
1455 "message": "Please register your known path in the path module",
1469 "file_name": "crates/hir_def/src/path.rs",
1470 "is_primary": false,
1474 "suggested_replacement": null
,
1475 "suggestion_applicability": null
,
1478 "highlight_end": 28,
1479 "highlight_start": 1,
1480 "text": "macro_rules! __known_path {"
1483 "highlight_end": 37,
1484 "highlight_start": 1,
1485 "text": " (std::iter::IntoIterator) => {};"
1488 "highlight_end": 33,
1489 "highlight_start": 1,
1490 "text": " (std::result::Result) => {};"
1493 "highlight_end": 29,
1494 "highlight_start": 1,
1495 "text": " (std::ops::Range) => {};"
1498 "highlight_end": 33,
1499 "highlight_start": 1,
1500 "text": " (std::ops::RangeFrom) => {};"
1503 "highlight_end": 33,
1504 "highlight_start": 1,
1505 "text": " (std::ops::RangeFull) => {};"
1508 "highlight_end": 31,
1509 "highlight_start": 1,
1510 "text": " (std::ops::RangeTo) => {};"
1513 "highlight_end": 40,
1514 "highlight_start": 1,
1515 "text": " (std::ops::RangeToInclusive) => {};"
1518 "highlight_end": 38,
1519 "highlight_start": 1,
1520 "text": " (std::ops::RangeInclusive) => {};"
1523 "highlight_end": 27,
1524 "highlight_start": 1,
1525 "text": " (std::ops::Try) => {};"
1528 "highlight_end": 22,
1529 "highlight_start": 1,
1530 "text": " ($path:path) => {"
1533 "highlight_end": 77,
1534 "highlight_start": 1,
1535 "text": " compile_error!(\"Please register your known path in the path module\")"
1539 "highlight_start": 1,
1544 "highlight_start": 1,
1549 "macro_decl_name": "$crate::__known_path!",
1562 "file_name": "crates/hir_def/src/path.rs",
1563 "is_primary": false,
1567 "suggested_replacement": null
,
1568 "suggestion_applicability": null
,
1571 "highlight_end": 22,
1572 "highlight_start": 1,
1573 "text": "macro_rules! __path {"
1576 "highlight_end": 43,
1577 "highlight_start": 1,
1578 "text": " ($start:ident $(:: $seg:ident)*) => ({"
1581 "highlight_end": 51,
1582 "highlight_start": 1,
1583 "text": " $crate::__known_path!($start $(:: $seg)*);"
1586 "highlight_end": 87,
1587 "highlight_start": 1,
1588 "text": " $crate::path::ModPath::from_simple_segments($crate::path::PathKind::Abs, vec!["
1591 "highlight_end": 76,
1592 "highlight_start": 1,
1593 "text": " $crate::path::__name![$start], $($crate::path::__name![$seg],)*"
1596 "highlight_end": 11,
1597 "highlight_start": 1,
1602 "highlight_start": 1,
1607 "highlight_start": 1,
1612 "macro_decl_name": "path!",
1619 "file_name": "crates/hir_def/src/data.rs",
1620 "is_primary": false,
1624 "suggested_replacement": null
,
1625 "suggestion_applicability": null
,
1628 "highlight_end": 42,
1629 "highlight_start": 16,
1630 "text": " let path = path![std::future::Future];"
1635 "file_name": "crates/hir_def/src/path.rs",
1636 "is_primary": false,
1640 "suggested_replacement": null
,
1641 "suggestion_applicability": null
,
1644 "highlight_end": 51,
1645 "highlight_start": 9,
1646 "text": " $crate::__known_path!($start $(:: $seg)*);"
1651 "file_name": "crates/hir_def/src/path.rs",
1656 "suggested_replacement": null
,
1657 "suggestion_applicability": null
,
1660 "highlight_end": 77,
1661 "highlight_start": 9,
1662 "text": " compile_error!(\"Please register your known path in the path module\")"
1669 expect_file!["./test_data
/macro_compiler_error
.txt
"],
1674 fn snap_multi_line_fix() {
1677 "rendered": "warning: returning the result of a let binding from a block\n --> src/main.rs:4:5\n |\n3 | let a = (0..10).collect();\n | -------------------------- unnecessary let binding\n4 | a\n | ^\n |\n = note: `#[warn(clippy::let_and_return)]` on by default\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return\nhelp: return the expression directly\n |\n3 | \n4 | (0..10).collect()\n |\n\n",
1683 "message": "`#[warn(clippy::let_and_return)]` on by default",
1691 "message": "for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return",
1699 "message": "return the expression directly",
1708 "file_name": "src/main.rs",
1713 "suggested_replacement": "",
1714 "suggestion_applicability": "MachineApplicable",
1717 "highlight_end": 31,
1718 "highlight_start": 5,
1719 "text": " let a = (0..10).collect();"
1729 "file_name": "src/main.rs",
1734 "suggested_replacement": "(0..10).collect()",
1735 "suggestion_applicability": "MachineApplicable",
1739 "highlight_start": 5,
1748 "code": "clippy::let_and_return",
1752 "message": "returning the result of a let binding from a block",
1760 "file_name": "src/main.rs",
1761 "is_primary": false,
1762 "label": "unnecessary let binding",
1765 "suggested_replacement": null
,
1766 "suggestion_applicability": null
,
1769 "highlight_end": 31,
1770 "highlight_start": 5,
1771 "text": " let a = (0..10).collect();"
1781 "file_name": "src/main.rs",
1786 "suggested_replacement": null
,
1787 "suggestion_applicability": null
,
1791 "highlight_start": 5,
1799 expect_file!["./test_data
/snap_multi_line_fix
.txt
"],
1804 fn reasonable_line_numbers_from_empty_file() {
1807 "message": "`main` function not found in crate `current`",
1810 "explanation": "No `main` function was found in a binary crate.\n\nTo fix this error, add a `main` function:\n\n```\nfn main() {\n // Your program will start here.\n println!(\"Hello world!\");\n}\n```\n\nIf you don't know the basics of Rust, you can look at the\n[Rust Book][rust-book] to get started.\n\n[rust-book]: https://doc.rust-lang.org/book/\n"
1815 "file_name": "src/bin/current.rs",
1825 "suggested_replacement": null
,
1826 "suggestion_applicability": null
,
1832 "message": "consider adding a `main` function to `src/bin/current.rs`",
1840 "rendered": "error[E0601]: `main` function not found in crate `current`\n |\n = note: consider adding a `main` function to `src/bin/current.rs`\n\n"
1842 expect_file!["./test_data
/reasonable_line_numbers_from_empty_file
.txt
"],