diff --git a/Cargo.lock b/Cargo.lock index 6f29120455e55..fd23b2764c081 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -726,9 +726,9 @@ dependencies = [ [[package]] name = "const_fn" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce90df4c658c62f12d78f7508cf92f9173e5184a539c10bfe54a3107b3ffd0f2" +checksum = "c478836e029dcef17fb47c89023448c64f781a046e0300e257ad8225ae59afab" [[package]] name = "constant_time_eq" @@ -3914,6 +3914,7 @@ dependencies = [ "rustc_index", "rustc_middle", "rustc_parse_format", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_target", diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index e61476bf23e1e..ef4a45cab4135 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -4,7 +4,9 @@ use crate::Level; use crate::Substitution; use crate::SubstitutionPart; use crate::SuggestionStyle; +use crate::ToolMetadata; use rustc_lint_defs::Applicability; +use rustc_serialize::json::Json; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use std::fmt; @@ -303,6 +305,7 @@ impl Diagnostic { msg: msg.to_owned(), style: SuggestionStyle::ShowCode, applicability, + tool_metadata: Default::default(), }); self } @@ -328,6 +331,7 @@ impl Diagnostic { msg: msg.to_owned(), style: SuggestionStyle::ShowCode, applicability, + tool_metadata: Default::default(), }); self } @@ -354,6 +358,7 @@ impl Diagnostic { msg: msg.to_owned(), style: SuggestionStyle::CompletelyHidden, applicability, + tool_metadata: Default::default(), }); self } @@ -408,6 +413,7 @@ impl Diagnostic { msg: msg.to_owned(), style, applicability, + tool_metadata: Default::default(), }); self } @@ -446,6 +452,7 @@ impl Diagnostic { msg: msg.to_owned(), style: SuggestionStyle::ShowCode, applicability, + tool_metadata: Default::default(), }); self } @@ -515,6 +522,23 @@ impl Diagnostic { self } + /// Adds a suggestion intended only for a tool. The intent is that the metadata encodes + /// the suggestion in a tool-specific way, as it may not even directly involve Rust code. + pub fn tool_only_suggestion_with_metadata( + &mut self, + msg: &str, + applicability: Applicability, + tool_metadata: Json, + ) { + self.suggestions.push(CodeSuggestion { + substitutions: vec![], + msg: msg.to_owned(), + style: SuggestionStyle::CompletelyHidden, + applicability, + tool_metadata: ToolMetadata::new(tool_metadata), + }) + } + pub fn set_span>(&mut self, sp: S) -> &mut Self { self.span = sp.into(); if let Some(span) = self.span.primary_span() { diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index d57beb1148a25..c27b39a9d62ff 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -14,6 +14,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap}; use crate::emitter::{Emitter, HumanReadableErrorType}; use crate::registry::Registry; use crate::DiagnosticId; +use crate::ToolMetadata; use crate::{CodeSuggestion, SubDiagnostic}; use rustc_lint_defs::{Applicability, FutureBreakage}; @@ -26,6 +27,7 @@ use std::sync::{Arc, Mutex}; use std::vec; use rustc_serialize::json::{as_json, as_pretty_json}; +use rustc_serialize::{Encodable, Encoder}; #[cfg(test)] mod tests; @@ -168,7 +170,8 @@ impl Emitter for JsonEmitter { // The following data types are provided just for serialisation. -#[derive(Encodable)] +// NOTE: this has a manual implementation of Encodable which needs to be updated in +// parallel. struct Diagnostic { /// The primary error message. message: String, @@ -180,6 +183,65 @@ struct Diagnostic { children: Vec, /// The message as rustc would render it. rendered: Option, + /// Extra tool metadata + tool_metadata: ToolMetadata, +} + +macro_rules! encode_fields { + ( + $enc:expr, // encoder + $idx:expr, // starting field index + $struct:expr, // struct we're serializing + $struct_name:ident, // struct name + [ $($name:ident),+$(,)? ], // fields to encode + [ $($ignore:ident),+$(,)? ] // fields we're skipping + ) => { + { + // Pattern match to make sure all fields are accounted for + let $struct_name { $($name,)+ $($ignore: _,)+ } = $struct; + let mut idx = $idx; + $( + $enc.emit_struct_field( + stringify!($name), + idx, + |enc| $name.encode(enc), + )?; + idx += 1; + )+ + idx + } + }; +} + +// Special-case encoder to skip tool_metadata if not set +impl Encodable for Diagnostic { + fn encode(&self, s: &mut E) -> Result<(), E::Error> { + s.emit_struct("diagnostic", 7, |s| { + let mut idx = 0; + + idx = encode_fields!( + s, + idx, + self, + Self, + [message, code, level, spans, children, rendered], + [tool_metadata] + ); + if self.tool_metadata.is_set() { + idx = encode_fields!( + s, + idx, + self, + Self, + [tool_metadata], + [message, code, level, spans, children, rendered] + ); + } + + let _ = idx; + Ok(()) + }) + } } #[derive(Encodable)] @@ -269,6 +331,7 @@ impl Diagnostic { spans: DiagnosticSpan::from_suggestion(sugg, je), children: vec![], rendered: None, + tool_metadata: sugg.tool_metadata.clone(), }); // generate regular command line output and store it in the json @@ -312,6 +375,7 @@ impl Diagnostic { .chain(sugg) .collect(), rendered: Some(output), + tool_metadata: ToolMetadata::default(), } } @@ -327,6 +391,7 @@ impl Diagnostic { .unwrap_or_else(|| DiagnosticSpan::from_multispan(&diag.span, je)), children: vec![], rendered: None, + tool_metadata: ToolMetadata::default(), } } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index aa88233209940..9800ed9bfa948 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -23,10 +23,13 @@ use rustc_data_structures::sync::{self, Lock, Lrc}; use rustc_data_structures::AtomicRef; use rustc_lint_defs::FutureBreakage; pub use rustc_lint_defs::{pluralize, Applicability}; +use rustc_serialize::json::Json; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::source_map::SourceMap; use rustc_span::{Loc, MultiSpan, Span}; use std::borrow::Cow; +use std::hash::{Hash, Hasher}; use std::panic; use std::path::Path; use std::{error, fmt}; @@ -73,6 +76,39 @@ impl SuggestionStyle { } } +#[derive(Clone, Debug, PartialEq, Default)] +pub struct ToolMetadata(pub Option); + +impl ToolMetadata { + fn new(json: Json) -> Self { + ToolMetadata(Some(json)) + } + + fn is_set(&self) -> bool { + self.0.is_some() + } +} + +impl Hash for ToolMetadata { + fn hash(&self, _state: &mut H) {} +} + +// Doesn't really need to round-trip +impl Decodable for ToolMetadata { + fn decode(_d: &mut D) -> Result { + Ok(ToolMetadata(None)) + } +} + +impl Encodable for ToolMetadata { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { + match &self.0 { + None => e.emit_unit(), + Some(json) => json.encode(e), + } + } +} + #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)] pub struct CodeSuggestion { /// Each substitute can have multiple variants due to multiple @@ -106,6 +142,8 @@ pub struct CodeSuggestion { /// which are useful for users but not useful for /// tools like rustfix pub applicability: Applicability, + /// Tool-specific metadata + pub tool_metadata: ToolMetadata, } #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)] @@ -775,7 +813,6 @@ impl HandlerInner { } let already_emitted = |this: &mut Self| { - use std::hash::Hash; let mut hasher = StableHasher::new(); diagnostic.hash(&mut hasher); let diagnostic_hash = hasher.finish(); diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index c56eb09b63471..90badd3d573a8 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -19,5 +19,6 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_feature = { path = "../rustc_feature" } rustc_index = { path = "../rustc_index" } rustc_session = { path = "../rustc_session" } +rustc_serialize = { path = "../rustc_serialize" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_parse_format = { path = "../rustc_parse_format" } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 254220839aa47..b8db51f590d84 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -21,7 +21,9 @@ use crate::passes::{EarlyLintPassObject, LateLintPassObject}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync; -use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err, Applicability}; +use rustc_errors::{ + add_elided_lifetime_in_path_suggestion, struct_span_err, Applicability, SuggestionStyle, +}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; @@ -32,7 +34,8 @@ use rustc_middle::middle::stability; use rustc_middle::ty::layout::{LayoutError, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt}; -use rustc_session::lint::BuiltinLintDiagnostics; +use rustc_serialize::json::Json; +use rustc_session::lint::{BuiltinLintDiagnostics, ExternDepSpec}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; use rustc_session::Session; use rustc_session::SessionLintStore; @@ -639,6 +642,30 @@ pub trait LintContext: Sized { BuiltinLintDiagnostics::LegacyDeriveHelpers(span) => { db.span_label(span, "the attribute is introduced here"); } + BuiltinLintDiagnostics::ExternDepSpec(krate, loc) => { + let json = match loc { + ExternDepSpec::Json(json) => { + db.help(&format!("remove unnecessary dependency `{}`", krate)); + json + } + ExternDepSpec::Raw(raw) => { + db.help(&format!("remove unnecessary dependency `{}` at `{}`", krate, raw)); + db.span_suggestion_with_style( + DUMMY_SP, + "raw extern location", + raw.clone(), + Applicability::Unspecified, + SuggestionStyle::CompletelyHidden, + ); + Json::String(raw) + } + }; + db.tool_only_suggestion_with_metadata( + "json extern location", + Applicability::Unspecified, + json + ); + } } // Rewrap `db`, and pass control to the user. decorate(LintDiagnosticBuilder::new(db)); diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 594e2cbd3aed9..4c7d3f6c8c072 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -4,6 +4,7 @@ extern crate rustc_macros; pub use self::Level::*; use rustc_ast::node_id::{NodeId, NodeMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_serialize::json::Json; use rustc_span::edition::Edition; use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol}; use rustc_target::spec::abi::Abi; @@ -239,6 +240,13 @@ impl ToStableHashKey for LintId { } } +// Duplicated from rustc_session::config::ExternDepSpec to avoid cyclic dependency +#[derive(PartialEq)] +pub enum ExternDepSpec { + Json(Json), + Raw(String), +} + // This could be a closure, but then implementing derive trait // becomes hacky (and it gets allocated). #[derive(PartialEq)] @@ -257,6 +265,7 @@ pub enum BuiltinLintDiagnostics { UnusedDocComment(Span), PatternsInFnsWithoutBody(Span, Ident), LegacyDeriveHelpers(Span), + ExternDepSpec(String, ExternDepSpec), } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index e3fbd1a2b29ea..63c6f369eb685 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -16,8 +16,9 @@ use rustc_index::vec::IndexVec; use rustc_middle::middle::cstore::{CrateDepKind, CrateSource, ExternCrate}; use rustc_middle::middle::cstore::{ExternCrateSource, MetadataLoaderDyn}; use rustc_middle::ty::TyCtxt; +use rustc_serialize::json::ToJson; use rustc_session::config::{self, CrateType, ExternLocation}; -use rustc_session::lint; +use rustc_session::lint::{self, BuiltinLintDiagnostics, ExternDepSpec}; use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; use rustc_session::{CrateDisambiguator, Session}; @@ -27,6 +28,7 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::{PanicStrategy, TargetTriple}; use proc_macro::bridge::client::ProcMacro; +use std::collections::BTreeMap; use std::path::Path; use std::{cmp, env}; use tracing::{debug, info}; @@ -871,8 +873,25 @@ impl<'a> CrateLoader<'a> { // Don't worry about pathless `--extern foo` sysroot references continue; } - if !self.used_extern_options.contains(&Symbol::intern(name)) { - self.sess.parse_sess.buffer_lint( + if self.used_extern_options.contains(&Symbol::intern(name)) { + continue; + } + + // Got a real unused --extern + let diag = match self.sess.opts.extern_dep_specs.get(name) { + Some(loc) => BuiltinLintDiagnostics::ExternDepSpec(name.clone(), loc.into()), + None => { + // If we don't have a specific location, provide a json encoding of the `--extern` + // option. + let meta: BTreeMap = + std::iter::once(("name".to_string(), name.to_string())).collect(); + BuiltinLintDiagnostics::ExternDepSpec( + name.clone(), + ExternDepSpec::Json(meta.to_json()), + ) + } + }; + self.sess.parse_sess.buffer_lint_with_diagnostic( lint::builtin::UNUSED_CRATE_DEPENDENCIES, span, ast::CRATE_NODE_ID, @@ -881,8 +900,8 @@ impl<'a> CrateLoader<'a> { name, self.local_crate_name, name), + diag, ); - } } } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 9d73c3b4424cb..e9ea0ab6f98f5 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -15,6 +15,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_target::abi::{Align, TargetDataLayout}; use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple}; +use rustc_serialize::json; + use crate::parse::CrateConfig; use rustc_feature::UnstableFeatures; use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST}; @@ -408,6 +410,9 @@ impl OutputTypes { #[derive(Clone)] pub struct Externs(BTreeMap); +#[derive(Clone)] +pub struct ExternDepSpecs(BTreeMap); + #[derive(Clone, Debug)] pub struct ExternEntry { pub location: ExternLocation, @@ -439,6 +444,27 @@ pub enum ExternLocation { ExactPaths(BTreeSet), } +/// Supplied source location of a dependency - for example in a build specification +/// file like Cargo.toml. We support several syntaxes: if it makes sense to reference +/// a file and line, then the build system can specify that. On the other hand, it may +/// make more sense to have an arbitrary raw string. +#[derive(Clone, PartialEq)] +pub enum ExternDepSpec { + /// Raw string + Raw(String), + /// Raw data in json format + Json(json::Json), +} + +impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec { + fn from(from: &'a ExternDepSpec) -> Self { + match from { + ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()), + ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()), + } + } +} + impl Externs { pub fn new(data: BTreeMap) -> Externs { Externs(data) @@ -466,6 +492,25 @@ impl ExternEntry { } } +impl ExternDepSpecs { + pub fn new(data: BTreeMap) -> ExternDepSpecs { + ExternDepSpecs(data) + } + + pub fn get(&self, key: &str) -> Option<&ExternDepSpec> { + self.0.get(key) + } +} + +impl fmt::Display for ExternDepSpec { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ExternDepSpec::Raw(raw) => fmt.write_str(raw), + ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt), + } + } +} + #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum PrintRequest { FileNames, @@ -679,6 +724,7 @@ impl Default for Options { cg: basic_codegen_options(), error_format: ErrorOutputType::default(), externs: Externs(BTreeMap::new()), + extern_dep_specs: ExternDepSpecs(BTreeMap::new()), crate_name: None, alt_std_name: None, libs: Vec::new(), @@ -1105,6 +1151,12 @@ pub fn rustc_optgroups() -> Vec { "Specify where an external rust library is located", "NAME[=PATH]", ), + opt::multi_s( + "", + "extern-location", + "Location where an external crate dependency is specified", + "NAME=LOCATION", + ), opt::opt_s("", "sysroot", "Override the system root", "PATH"), opt::multi("Z", "", "Set internal debugging options", "FLAG"), opt::opt_s( @@ -1727,6 +1779,68 @@ pub fn parse_externs( Externs(externs) } +fn parse_extern_dep_specs( + matches: &getopts::Matches, + debugging_opts: &DebuggingOptions, + error_format: ErrorOutputType, +) -> ExternDepSpecs { + let is_unstable_enabled = debugging_opts.unstable_options; + let mut map = BTreeMap::new(); + + for arg in matches.opt_strs("extern-location") { + if !is_unstable_enabled { + early_error( + error_format, + "`--extern-location` option is unstable: set `-Z unstable-options`", + ); + } + + let mut parts = arg.splitn(2, '='); + let name = parts.next().unwrap_or_else(|| { + early_error(error_format, "`--extern-location` value must not be empty") + }); + let loc = parts.next().unwrap_or_else(|| { + early_error( + error_format, + &format!("`--extern-location`: specify location for extern crate `{}`", name), + ) + }); + + let locparts: Vec<_> = loc.split(":").collect(); + let spec = match &locparts[..] { + ["raw", ..] => { + // Don't want `:` split string + let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| { + early_error(error_format, "`--extern-location`: missing `raw` location") + }); + ExternDepSpec::Raw(raw.to_string()) + } + ["json", ..] => { + // Don't want `:` split string + let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| { + early_error(error_format, "`--extern-location`: missing `json` location") + }); + let json = json::from_str(raw).unwrap_or_else(|_| { + early_error( + error_format, + &format!("`--extern-location`: malformed json location `{}`", raw), + ) + }); + ExternDepSpec::Json(json) + } + [bad, ..] => early_error( + error_format, + &format!("unknown location type `{}`: use `raw` or `json`", bad), + ), + [] => early_error(error_format, "missing location specification"), + }; + + map.insert(name.to_string(), spec); + } + + ExternDepSpecs::new(map) +} + fn parse_remap_path_prefix( matches: &getopts::Matches, error_format: ErrorOutputType, @@ -1888,6 +2002,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } let externs = parse_externs(matches, &debugging_opts, error_format); + let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format); let crate_name = matches.opt_str("crate-name"); @@ -1924,6 +2039,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { error_format, externs, unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()), + extern_dep_specs, crate_name, alt_std_name: None, libs, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 779e042163698..f78df8a7e29fa 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -112,6 +112,7 @@ top_level_options!( borrowck_mode: BorrowckMode [UNTRACKED], cg: CodegenOptions [TRACKED], externs: Externs [UNTRACKED], + extern_dep_specs: ExternDepSpecs [UNTRACKED], crate_name: Option [TRACKED], // An optional name to use as the crate for std during std injection, // written `extern crate name as std`. Defaults to `std`. Used by diff --git a/src/doc/unstable-book/src/compiler-flags/extern-location.md b/src/doc/unstable-book/src/compiler-flags/extern-location.md new file mode 100644 index 0000000000000..1c80d5426bf75 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/extern-location.md @@ -0,0 +1,31 @@ +# `extern-location` + +MCP for this feature: [#303] + +[#303]: https://github.com/rust-lang/compiler-team/issues/303 + +------------------------ + +The `unused-extern-crates` lint reports when a crate was specified on the rustc +command-line with `--extern name=path` but no symbols were referenced in it. +This is useful to know, but it's hard to map that back to a specific place a user +or tool could fix (ie, to remove the unused dependency). + +The `--extern-location` flag allows the build system to associate a location with +the `--extern` option, which is then emitted as part of the diagnostics. This location +is abstract and just round-tripped through rustc; the compiler never attempts to +interpret it in any way. + +There are two supported forms of location: a bare string, or a blob of json: +- `--extern-location foo=raw:Makefile:123` would associate the raw string `Makefile:123` +- `--extern-location 'bar=json:{"target":"//my_project:library","dep":"//common:serde"}` would + associate the json structure with `--extern bar=`, indicating which dependency of + which rule introduced the unused extern crate. + +This primarily intended to be used with tooling - for example a linter which can automatically +remove unused dependencies - rather than being directly presented to users. + +`raw` locations are presented as part of the normal rendered diagnostics and included in +the json form. `json` locations are only included in the json form of diagnostics, +as a `tool_metadata` field. For `raw` locations `tool_metadata` is simply a json string, +whereas `json` allows the rustc invoker to fully control its form and content. diff --git a/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.rs b/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.rs new file mode 100644 index 0000000000000..3e1527e2c2e71 --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.rs @@ -0,0 +1,8 @@ +// --extern-location with bad location type + +// aux-crate:bar=bar.rs +// compile-flags:--extern-location bar=badloc:in-the-test-file + +#![warn(unused_crate_dependencies)] + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.stderr b/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.stderr new file mode 100644 index 0000000000000..12378f12557b7 --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.stderr @@ -0,0 +1,2 @@ +error: unknown location type `badloc`: use `raw` or `json` + diff --git a/src/test/ui/unused-crate-deps/extern-loc-defl-json.rs b/src/test/ui/unused-crate-deps/extern-loc-defl-json.rs new file mode 100644 index 0000000000000..a023f535b8198 --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-defl-json.rs @@ -0,0 +1,10 @@ +// Default extern location from name and path if one isn't specified + +// check-pass +// aux-crate:bar=bar.rs +// compile-flags:--error-format json + +#![warn(unused_crate_dependencies)] +//~^ WARNING external crate `bar` unused in + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/extern-loc-defl-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-defl-json.stderr new file mode 100644 index 0000000000000..cee3f6c1495c7 --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-defl-json.stderr @@ -0,0 +1,17 @@ +{"message":"external crate `bar` unused in `extern_loc_defl_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-defl-json.rs","byte_start":146,"byte_end":146,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-defl-json.rs","byte_start":154,"byte_end":179,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"name":"bar"}}],"rendered":"warning: external crate `bar` unused in `extern_loc_defl_json`: remove the dependency or add `use bar as _;` + --> $DIR/extern-loc-defl-json.rs:7:1 + | +LL | #![warn(unused_crate_dependencies)] + | ^ + | +note: the lint level is defined here + --> $DIR/extern-loc-defl-json.rs:7:9 + | +LL | #![warn(unused_crate_dependencies)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: remove unnecessary dependency `bar` + +"} +{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted + +"} diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.rs b/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.rs new file mode 100644 index 0000000000000..6fdf710a1268d --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.rs @@ -0,0 +1,8 @@ +// --extern-location with a raw reference + +// aux-crate:bar=bar.rs +// compile-flags:--extern-location bar=json:[{"malformed + +#![warn(unused_crate_dependencies)] + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.stderr new file mode 100644 index 0000000000000..20d606372e027 --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.stderr @@ -0,0 +1,2 @@ +error: `--extern-location`: malformed json location `[{"malformed` + diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-json.rs b/src/test/ui/unused-crate-deps/extern-loc-json-json.rs new file mode 100644 index 0000000000000..02a9869151f32 --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-json-json.rs @@ -0,0 +1,10 @@ +// --extern-location with a raw reference + +// check-pass +// aux-crate:bar=bar.rs +// compile-flags:--extern-location bar=json:{"key":123,"value":{}} --error-format json + +#![warn(unused_crate_dependencies)] +//~^ WARNING external crate `bar` unused in + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-json-json.stderr new file mode 100644 index 0000000000000..5fc8397e4698c --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-json-json.stderr @@ -0,0 +1,17 @@ +{"message":"external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":169,"byte_end":169,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":177,"byte_end":202,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"key":123,"value":{}}}],"rendered":"warning: external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;` + --> $DIR/extern-loc-json-json.rs:7:1 + | +LL | #![warn(unused_crate_dependencies)] + | ^ + | +note: the lint level is defined here + --> $DIR/extern-loc-json-json.rs:7:9 + | +LL | #![warn(unused_crate_dependencies)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: remove unnecessary dependency `bar` + +"} +{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted + +"} diff --git a/src/test/ui/unused-crate-deps/extern-loc-json.rs b/src/test/ui/unused-crate-deps/extern-loc-json.rs new file mode 100644 index 0000000000000..212610d532e1c --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-json.rs @@ -0,0 +1,10 @@ +// --extern-location with a raw reference + +// check-pass +// aux-crate:bar=bar.rs +// compile-flags:--extern-location bar=json:{"key":123,"value":{}} + +#![warn(unused_crate_dependencies)] +//~^ WARNING external crate `bar` unused in + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/extern-loc-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-json.stderr new file mode 100644 index 0000000000000..a6bbc0da1c6b4 --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-json.stderr @@ -0,0 +1,15 @@ +warning: external crate `bar` unused in `extern_loc_json`: remove the dependency or add `use bar as _;` + --> $DIR/extern-loc-json.rs:7:1 + | +LL | #![warn(unused_crate_dependencies)] + | ^ + | +note: the lint level is defined here + --> $DIR/extern-loc-json.rs:7:9 + | +LL | #![warn(unused_crate_dependencies)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: remove unnecessary dependency `bar` + +warning: 1 warning emitted + diff --git a/src/test/ui/unused-crate-deps/extern-loc-missing-loc.rs b/src/test/ui/unused-crate-deps/extern-loc-missing-loc.rs new file mode 100644 index 0000000000000..9339a004d3b74 --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-missing-loc.rs @@ -0,0 +1,8 @@ +// --extern-location with a raw reference + +// aux-crate:bar=bar.rs +// compile-flags:--extern-location bar + +#![warn(unused_crate_dependencies)] + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/extern-loc-missing-loc.stderr b/src/test/ui/unused-crate-deps/extern-loc-missing-loc.stderr new file mode 100644 index 0000000000000..4584fbfb67ff7 --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-missing-loc.stderr @@ -0,0 +1,2 @@ +error: `--extern-location`: specify location for extern crate `bar` + diff --git a/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.rs b/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.rs new file mode 100644 index 0000000000000..4768365a65325 --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.rs @@ -0,0 +1,8 @@ +// --extern-location with no type + +// aux-crate:bar=bar.rs +// compile-flags:--extern-location bar=missing-loc-type + +#![warn(unused_crate_dependencies)] + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.stderr b/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.stderr new file mode 100644 index 0000000000000..d0c36ebeb142e --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.stderr @@ -0,0 +1,2 @@ +error: unknown location type `missing-loc-type`: use `raw` or `json` + diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-json.rs b/src/test/ui/unused-crate-deps/extern-loc-raw-json.rs new file mode 100644 index 0000000000000..207615ccc87b6 --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-raw-json.rs @@ -0,0 +1,10 @@ +// --extern-location with a raw reference + +// check-pass +// aux-crate:bar=bar.rs +// compile-flags:--extern-location bar=raw:in-the-test-file --error-format json + +#![warn(unused_crate_dependencies)] +//~^ WARNING external crate `bar` unused in + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-raw-json.stderr new file mode 100644 index 0000000000000..25f099927fd0a --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-raw-json.stderr @@ -0,0 +1,17 @@ +{"message":"external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":162,"byte_end":162,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":170,"byte_end":195,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar` at `in-the-test-file`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"raw extern location","code":null,"level":"help","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":null,"suggested_replacement":"in-the-test-file","suggestion_applicability":"Unspecified","expansion":null}],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":"in-the-test-file"}],"rendered":"warning: external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;` + --> $DIR/extern-loc-raw-json.rs:7:1 + | +LL | #![warn(unused_crate_dependencies)] + | ^ + | +note: the lint level is defined here + --> $DIR/extern-loc-raw-json.rs:7:9 + | +LL | #![warn(unused_crate_dependencies)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: remove unnecessary dependency `bar` at `in-the-test-file` + +"} +{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted + +"} diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.rs b/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.rs new file mode 100644 index 0000000000000..65b6426839471 --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.rs @@ -0,0 +1,8 @@ +// --extern-location with a raw reference + +// aux-crate:bar=bar.rs +// compile-flags:--extern-location bar=raw + +#![warn(unused_crate_dependencies)] + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.stderr b/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.stderr new file mode 100644 index 0000000000000..4b51266e4f6fa --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.stderr @@ -0,0 +1,2 @@ +error: `--extern-location`: missing `raw` location + diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw.rs b/src/test/ui/unused-crate-deps/extern-loc-raw.rs new file mode 100644 index 0000000000000..fc3fed1e10e80 --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-raw.rs @@ -0,0 +1,10 @@ +// --extern-location with a raw reference + +// check-pass +// aux-crate:bar=bar.rs +// compile-flags:--extern-location bar=raw:in-the-test-file + +#![warn(unused_crate_dependencies)] +//~^ WARNING external crate `bar` unused in + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw.stderr b/src/test/ui/unused-crate-deps/extern-loc-raw.stderr new file mode 100644 index 0000000000000..2cdd005586673 --- /dev/null +++ b/src/test/ui/unused-crate-deps/extern-loc-raw.stderr @@ -0,0 +1,15 @@ +warning: external crate `bar` unused in `extern_loc_raw`: remove the dependency or add `use bar as _;` + --> $DIR/extern-loc-raw.rs:7:1 + | +LL | #![warn(unused_crate_dependencies)] + | ^ + | +note: the lint level is defined here + --> $DIR/extern-loc-raw.rs:7:9 + | +LL | #![warn(unused_crate_dependencies)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: remove unnecessary dependency `bar` at `in-the-test-file` + +warning: 1 warning emitted + diff --git a/src/test/ui/unused-crate-deps/libfib.stderr b/src/test/ui/unused-crate-deps/libfib.stderr index 15833126bd620..479f51bff464d 100644 --- a/src/test/ui/unused-crate-deps/libfib.stderr +++ b/src/test/ui/unused-crate-deps/libfib.stderr @@ -5,6 +5,7 @@ LL | pub fn fib(n: u32) -> Vec { | ^ | = note: requested on the command line with `-W unused-crate-dependencies` + = help: remove unnecessary dependency `bar` warning: 1 warning emitted diff --git a/src/test/ui/unused-crate-deps/test.mk b/src/test/ui/unused-crate-deps/test.mk new file mode 100644 index 0000000000000..0b98b4e44fb2a --- /dev/null +++ b/src/test/ui/unused-crate-deps/test.mk @@ -0,0 +1,7 @@ +# Everyone uses make for building Rust + +foo: bar.rlib + $(RUSTC) --crate-type bin --extern bar=bar.rlib + +%.rlib: %.rs + $(RUSTC) --crate-type lib $< diff --git a/src/test/ui/unused-crate-deps/unused-aliases.stderr b/src/test/ui/unused-crate-deps/unused-aliases.stderr index c8c6c4507b0c5..1142d156d0e96 100644 --- a/src/test/ui/unused-crate-deps/unused-aliases.stderr +++ b/src/test/ui/unused-crate-deps/unused-aliases.stderr @@ -9,6 +9,7 @@ note: the lint level is defined here | LL | #![warn(unused_crate_dependencies)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: remove unnecessary dependency `barbar` warning: 1 warning emitted diff --git a/src/test/ui/unused-crate-deps/warn-attr.stderr b/src/test/ui/unused-crate-deps/warn-attr.stderr index 0d38315704b11..29667d9525cb4 100644 --- a/src/test/ui/unused-crate-deps/warn-attr.stderr +++ b/src/test/ui/unused-crate-deps/warn-attr.stderr @@ -9,6 +9,7 @@ note: the lint level is defined here | LL | #![warn(unused_crate_dependencies)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: remove unnecessary dependency `bar` warning: 1 warning emitted diff --git a/src/test/ui/unused-crate-deps/warn-cmdline-static.stderr b/src/test/ui/unused-crate-deps/warn-cmdline-static.stderr index 65956461d6439..2c0c921512986 100644 --- a/src/test/ui/unused-crate-deps/warn-cmdline-static.stderr +++ b/src/test/ui/unused-crate-deps/warn-cmdline-static.stderr @@ -5,6 +5,7 @@ LL | fn main() {} | ^ | = note: requested on the command line with `-W unused-crate-dependencies` + = help: remove unnecessary dependency `bar` warning: 1 warning emitted diff --git a/src/test/ui/unused-crate-deps/warn-cmdline.stderr b/src/test/ui/unused-crate-deps/warn-cmdline.stderr index ea675ba9a1eb1..2cd49218f5ad8 100644 --- a/src/test/ui/unused-crate-deps/warn-cmdline.stderr +++ b/src/test/ui/unused-crate-deps/warn-cmdline.stderr @@ -5,6 +5,7 @@ LL | fn main() {} | ^ | = note: requested on the command line with `-W unused-crate-dependencies` + = help: remove unnecessary dependency `bar` warning: 1 warning emitted