|
1 | 1 | use clippy_utils::diagnostics::span_lint;
|
| 2 | +use rustc_ast::ast; |
2 | 3 | use rustc_data_structures::fx::FxHashSet;
|
3 |
| -use rustc_hir::{Pat, PatKind}; |
4 |
| -use rustc_lint::{LateContext, LateLintPass}; |
| 4 | +use rustc_lint::{EarlyContext, EarlyLintPass, Level}; |
5 | 5 | use rustc_session::{declare_tool_lint, impl_lint_pass};
|
6 | 6 | use unicode_script::{Script, UnicodeScript};
|
7 | 7 |
|
@@ -59,34 +59,46 @@ impl DisallowedScriptIdents {
|
59 | 59 |
|
60 | 60 | impl_lint_pass!(DisallowedScriptIdents => [DISALLOWED_SCRIPT_IDENTS]);
|
61 | 61 |
|
62 |
| -impl<'tcx> LateLintPass<'tcx> for DisallowedScriptIdents { |
63 |
| - fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { |
64 |
| - let ident = if let PatKind::Binding(.., ident, _) = pat.kind { |
65 |
| - ident |
66 |
| - } else { |
67 |
| - return; |
68 |
| - }; |
| 62 | +impl EarlyLintPass for DisallowedScriptIdents { |
| 63 | + fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { |
| 64 | + // Implementation is heavily inspired by the implementation of [`non_ascii_idents`] lint: |
| 65 | + // https://github.com/rust-lang/rust/blob/master/compiler/rustc_lint/src/non_ascii_idents.rs |
| 66 | + |
| 67 | + let check_disallowed_script_idents = cx.builder.lint_level(DISALLOWED_SCRIPT_IDENTS).0 != Level::Allow; |
69 | 68 |
|
70 |
| - if ident.as_str().is_ascii() { |
71 |
| - // Fully-ASCII identifiers are valid by default, no need to analyze them further. |
| 69 | + if !check_disallowed_script_idents { |
72 | 70 | return;
|
73 | 71 | }
|
74 | 72 |
|
75 |
| - for symbol in ident.name.as_str().chars() { |
76 |
| - let script = symbol.script(); |
77 |
| - if !self.whitelist.contains(&script) { |
78 |
| - span_lint( |
79 |
| - cx, |
80 |
| - DISALLOWED_SCRIPT_IDENTS, |
81 |
| - ident.span, |
82 |
| - &format!( |
83 |
| - "identifier `{}` has a Unicode script that is not allowed by configuration: {}", |
84 |
| - ident.name, |
85 |
| - script.full_name() |
86 |
| - ), |
87 |
| - ); |
88 |
| - // We don't want to spawn warning multiple times over a single identifier. |
89 |
| - break; |
| 73 | + let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock(); |
| 74 | + |
| 75 | + // Sort by `Span` so that error messages make sense with respect to the |
| 76 | + // order of identifier locations in the code. |
| 77 | + let mut symbols: Vec<_> = symbols.iter().collect(); |
| 78 | + symbols.sort_unstable_by_key(|k| k.1); |
| 79 | + |
| 80 | + for (symbol, &span) in &symbols { |
| 81 | + let symbol_str = symbol.as_str(); |
| 82 | + if symbol_str.is_ascii() { |
| 83 | + continue; |
| 84 | + } |
| 85 | + |
| 86 | + for c in symbol_str.chars() { |
| 87 | + let script = c.script(); |
| 88 | + if !self.whitelist.contains(&script) { |
| 89 | + span_lint( |
| 90 | + cx, |
| 91 | + DISALLOWED_SCRIPT_IDENTS, |
| 92 | + span, |
| 93 | + &format!( |
| 94 | + "identifier `{}` has a Unicode script that is not allowed by configuration: {}", |
| 95 | + symbol_str, |
| 96 | + script.full_name() |
| 97 | + ), |
| 98 | + ); |
| 99 | + // We don't want to spawn warning multiple times over a single identifier. |
| 100 | + break; |
| 101 | + } |
90 | 102 | }
|
91 | 103 | }
|
92 | 104 | }
|
|
0 commit comments