|
15 | 15 | //! for all lint attributes.
|
16 | 16 |
|
17 | 17 | use rustc::hir;
|
18 |
| -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; |
| 18 | +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; |
19 | 19 | use rustc::hir::intravisit as hir_visit;
|
20 | 20 | use rustc::hir::intravisit::Visitor;
|
| 21 | +use rustc::hir::map::{definitions::DisambiguatedDefPathData, DefPathData}; |
21 | 22 | use rustc::lint::LateContext;
|
22 | 23 | use rustc::lint::LintPass;
|
23 | 24 | use rustc::lint::{LateLintPass, LateLintPassObject};
|
24 |
| -use rustc::ty::{self, TyCtxt}; |
| 25 | +use rustc::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt}; |
25 | 26 | use rustc::util::common::time;
|
26 | 27 |
|
27 | 28 | use rustc_data_structures::sync::{join, par_iter, ParallelIterator};
|
| 29 | +use rustc_span::symbol::Symbol; |
28 | 30 | use rustc_span::Span;
|
29 | 31 | use std::slice;
|
30 | 32 | use syntax::ast;
|
31 | 33 |
|
32 | 34 | use log::debug;
|
33 | 35 | use syntax::walk_list;
|
34 | 36 |
|
| 37 | +pub(crate) trait LateContextExt { |
| 38 | + fn current_lint_root(&self) -> hir::HirId; |
| 39 | + |
| 40 | + /// Check if a `DefId`'s path matches the given absolute type path usage. |
| 41 | + /// |
| 42 | + /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`; |
| 43 | + /// inherent `impl` blocks are matched with the name of the type. |
| 44 | + /// |
| 45 | + /// # Examples |
| 46 | + /// |
| 47 | + /// ```rust,ignore (no context or def id available) |
| 48 | + /// if cx.match_def_path(def_id, &[sym::core, sym::option, sym::Option]) { |
| 49 | + /// // The given `def_id` is that of an `Option` type |
| 50 | + /// } |
| 51 | + /// ``` |
| 52 | + fn match_def_path(&self, def_id: DefId, path: &[Symbol]) -> bool; |
| 53 | + |
| 54 | + /// Gets the absolute path of `def_id` as a vector of `Symbol`. |
| 55 | + /// |
| 56 | + /// # Examples |
| 57 | + /// |
| 58 | + /// ```rust,ignore (no context or def id available) |
| 59 | + /// let def_path = cx.get_def_path(def_id); |
| 60 | + /// if let &[sym::core, sym::option, sym::Option] = &def_path[..] { |
| 61 | + /// // The given `def_id` is that of an `Option` type |
| 62 | + /// } |
| 63 | + /// ``` |
| 64 | + fn get_def_path(&self, def_id: DefId) -> Vec<Symbol>; |
| 65 | +} |
| 66 | + |
| 67 | +impl<'a, 'tcx> LateContextExt for LateContext<'a, 'tcx> { |
| 68 | + fn current_lint_root(&self) -> hir::HirId { |
| 69 | + self.last_node_with_lint_attrs |
| 70 | + } |
| 71 | + |
| 72 | + /// Check if a `DefId`'s path matches the given absolute type path usage. |
| 73 | + /// |
| 74 | + /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`; |
| 75 | + /// inherent `impl` blocks are matched with the name of the type. |
| 76 | + /// |
| 77 | + /// # Examples |
| 78 | + /// |
| 79 | + /// ```rust,ignore (no context or def id available) |
| 80 | + /// if cx.match_def_path(def_id, &[sym::core, sym::option, sym::Option]) { |
| 81 | + /// // The given `def_id` is that of an `Option` type |
| 82 | + /// } |
| 83 | + /// ``` |
| 84 | + fn match_def_path(&self, def_id: DefId, path: &[Symbol]) -> bool { |
| 85 | + let names = self.get_def_path(def_id); |
| 86 | + |
| 87 | + names.len() == path.len() && names.into_iter().zip(path.iter()).all(|(a, &b)| a == b) |
| 88 | + } |
| 89 | + |
| 90 | + /// Gets the absolute path of `def_id` as a vector of `Symbol`. |
| 91 | + /// |
| 92 | + /// # Examples |
| 93 | + /// |
| 94 | + /// ```rust,ignore (no context or def id available) |
| 95 | + /// let def_path = cx.get_def_path(def_id); |
| 96 | + /// if let &[sym::core, sym::option, sym::Option] = &def_path[..] { |
| 97 | + /// // The given `def_id` is that of an `Option` type |
| 98 | + /// } |
| 99 | + /// ``` |
| 100 | + fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> { |
| 101 | + pub struct AbsolutePathPrinter<'tcx> { |
| 102 | + pub tcx: TyCtxt<'tcx>, |
| 103 | + } |
| 104 | + |
| 105 | + impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { |
| 106 | + type Error = !; |
| 107 | + |
| 108 | + type Path = Vec<Symbol>; |
| 109 | + type Region = (); |
| 110 | + type Type = (); |
| 111 | + type DynExistential = (); |
| 112 | + type Const = (); |
| 113 | + |
| 114 | + fn tcx(&self) -> TyCtxt<'tcx> { |
| 115 | + self.tcx |
| 116 | + } |
| 117 | + |
| 118 | + fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { |
| 119 | + Ok(()) |
| 120 | + } |
| 121 | + |
| 122 | + fn print_type(self, _ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { |
| 123 | + Ok(()) |
| 124 | + } |
| 125 | + |
| 126 | + fn print_dyn_existential( |
| 127 | + self, |
| 128 | + _predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>, |
| 129 | + ) -> Result<Self::DynExistential, Self::Error> { |
| 130 | + Ok(()) |
| 131 | + } |
| 132 | + |
| 133 | + fn print_const(self, _ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { |
| 134 | + Ok(()) |
| 135 | + } |
| 136 | + |
| 137 | + fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { |
| 138 | + Ok(vec![self.tcx.original_crate_name(cnum)]) |
| 139 | + } |
| 140 | + |
| 141 | + fn path_qualified( |
| 142 | + self, |
| 143 | + self_ty: Ty<'tcx>, |
| 144 | + trait_ref: Option<ty::TraitRef<'tcx>>, |
| 145 | + ) -> Result<Self::Path, Self::Error> { |
| 146 | + if trait_ref.is_none() { |
| 147 | + if let ty::Adt(def, substs) = self_ty.kind { |
| 148 | + return self.print_def_path(def.did, substs); |
| 149 | + } |
| 150 | + } |
| 151 | + |
| 152 | + // This shouldn't ever be needed, but just in case: |
| 153 | + Ok(vec![match trait_ref { |
| 154 | + Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)), |
| 155 | + None => Symbol::intern(&format!("<{}>", self_ty)), |
| 156 | + }]) |
| 157 | + } |
| 158 | + |
| 159 | + fn path_append_impl( |
| 160 | + self, |
| 161 | + print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, |
| 162 | + _disambiguated_data: &DisambiguatedDefPathData, |
| 163 | + self_ty: Ty<'tcx>, |
| 164 | + trait_ref: Option<ty::TraitRef<'tcx>>, |
| 165 | + ) -> Result<Self::Path, Self::Error> { |
| 166 | + let mut path = print_prefix(self)?; |
| 167 | + |
| 168 | + // This shouldn't ever be needed, but just in case: |
| 169 | + path.push(match trait_ref { |
| 170 | + Some(trait_ref) => Symbol::intern(&format!( |
| 171 | + "<impl {} for {}>", |
| 172 | + trait_ref.print_only_trait_path(), |
| 173 | + self_ty |
| 174 | + )), |
| 175 | + None => Symbol::intern(&format!("<impl {}>", self_ty)), |
| 176 | + }); |
| 177 | + |
| 178 | + Ok(path) |
| 179 | + } |
| 180 | + |
| 181 | + fn path_append( |
| 182 | + self, |
| 183 | + print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, |
| 184 | + disambiguated_data: &DisambiguatedDefPathData, |
| 185 | + ) -> Result<Self::Path, Self::Error> { |
| 186 | + let mut path = print_prefix(self)?; |
| 187 | + |
| 188 | + // Skip `::{{constructor}}` on tuple/unit structs. |
| 189 | + match disambiguated_data.data { |
| 190 | + DefPathData::Ctor => return Ok(path), |
| 191 | + _ => {} |
| 192 | + } |
| 193 | + |
| 194 | + path.push(disambiguated_data.data.as_symbol()); |
| 195 | + Ok(path) |
| 196 | + } |
| 197 | + |
| 198 | + fn path_generic_args( |
| 199 | + self, |
| 200 | + print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, |
| 201 | + _args: &[GenericArg<'tcx>], |
| 202 | + ) -> Result<Self::Path, Self::Error> { |
| 203 | + print_prefix(self) |
| 204 | + } |
| 205 | + } |
| 206 | + |
| 207 | + AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]).unwrap() |
| 208 | + } |
| 209 | +} |
| 210 | + |
35 | 211 | macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
|
36 | 212 | $cx.pass.$f(&$cx.context, $($args),*);
|
37 | 213 | }) }
|
|
0 commit comments