-
Notifications
You must be signed in to change notification settings - Fork 901
/
unrecognized_platform.rs
147 lines (136 loc) · 4.24 KB
/
unrecognized_platform.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use ruff_python_ast::{self as ast, CmpOp, Expr};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::registry::Rule;
/// ## What it does
/// Check for unrecognized `sys.platform` checks. Platform checks should be
/// simple string comparisons.
///
/// **Note**: this rule is only enabled in `.pyi` stub files.
///
/// ## Why is this bad?
/// Some `sys.platform` checks are too complex for type checkers to
/// understand, and thus result in incorrect inferences by these tools.
/// `sys.platform` checks should be simple string comparisons, like
/// `if sys.platform == "linux"`.
///
/// ## Example
/// ```python
/// if sys.platform.startswith("linux"):
/// # Linux specific definitions
/// ...
/// else:
/// # Posix specific definitions
/// ...
/// ```
///
/// Instead, use a simple string comparison, such as `==` or `!=`:
/// ```python
/// if sys.platform == "linux":
/// # Linux specific definitions
/// ...
/// else:
/// # Posix specific definitions
/// ...
/// ```
///
/// ## References
/// - [Typing stubs documentation: Version and Platform Checks](https://typing.readthedocs.io/en/latest/source/stubs.html#version-and-platform-checks)
#[violation]
pub struct UnrecognizedPlatformCheck;
impl Violation for UnrecognizedPlatformCheck {
#[derive_message_formats]
fn message(&self) -> String {
format!("Unrecognized `sys.platform` check")
}
}
/// ## What it does
/// Check for unrecognized platform names in `sys.platform` checks.
///
/// **Note**: this rule is only enabled in `.pyi` stub files.
///
/// ## Why is this bad?
/// If a `sys.platform` check compares to a platform name outside of a
/// small set of known platforms (e.g. "linux", "win32", etc.), it's likely
/// a typo or a platform name that is not recognized by type checkers.
///
/// The list of known platforms is: "linux", "win32", "cygwin", "darwin".
///
/// ## Example
/// ```python
/// if sys.platform == "linus":
/// ...
/// ```
///
/// Use instead:
/// ```python
/// if sys.platform == "linux":
/// ...
/// ```
///
/// ## References
/// - [Typing stubs documentation: Version and Platform Checks](https://typing.readthedocs.io/en/latest/source/stubs.html#version-and-platform-checks)
#[violation]
pub struct UnrecognizedPlatformName {
platform: String,
}
impl Violation for UnrecognizedPlatformName {
#[derive_message_formats]
fn message(&self) -> String {
let UnrecognizedPlatformName { platform } = self;
format!("Unrecognized platform `{platform}`")
}
}
/// PYI007, PYI008
pub(crate) fn unrecognized_platform(checker: &mut Checker, test: &Expr) {
let Expr::Compare(ast::ExprCompare {
left,
ops,
comparators,
..
}) = test
else {
return;
};
let ([op], [right]) = (&**ops, &**comparators) else {
return;
};
if !checker
.semantic()
.resolve_qualified_name(left)
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["sys", "platform"]))
{
return;
}
// "in" might also make sense but we don't currently have one.
if !matches!(op, CmpOp::Eq | CmpOp::NotEq) {
if checker.enabled(Rule::UnrecognizedPlatformCheck) {
checker
.diagnostics
.push(Diagnostic::new(UnrecognizedPlatformCheck, test.range()));
}
return;
}
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = right {
// Other values are possible but we don't need them right now.
// This protects against typos.
if checker.enabled(Rule::UnrecognizedPlatformName) {
if !matches!(value.to_str(), "linux" | "win32" | "cygwin" | "darwin") {
checker.diagnostics.push(Diagnostic::new(
UnrecognizedPlatformName {
platform: value.to_string(),
},
right.range(),
));
}
}
} else {
if checker.enabled(Rule::UnrecognizedPlatformCheck) {
checker
.diagnostics
.push(Diagnostic::new(UnrecognizedPlatformCheck, test.range()));
}
}
}