Skip to content

Commit e635d28

Browse files
committed
Add param deprecation and deprecate instance.new parent param
1 parent e73cccc commit e635d28

File tree

10 files changed

+158
-12
lines changed

10 files changed

+158
-12
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
44
## [Unreleased](https://github.com/Kampfkarren/selene/compare/0.26.1...HEAD)
55
### Added
66
- Added `CFrame.lookAlong` to the Roblox standard library
7+
- Added `deprecated` config field to standard library function parameters
78

89
### Changed
910
- Updated the warning message for the `mixed_table` lint to include why mixed tables should be avoided
11+
- Officially deprecated `Instance.new`'s parent argument
1012

1113
## [0.26.1](https://github.com/Kampfkarren/selene/releases/tag/0.26.1) - 2023-11-11
1214
### Fixed

docs/src/usage/std.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ globals:
154154
A field is understood as a table if it has fields of its own. Notice that `math` is not defined anywhere, but its fields are. This will create an implicit `math` with the property writability of `read-only`.
155155

156156
### Deprecated
157-
Any field can have a deprecation notice added to it, which will then be read by [the deprecated lint](../lints/deprecated.md).
157+
Any field or arg can have a deprecation notice added to it, which will then be read by [the deprecated lint](../lints/deprecated.md).
158158

159159
```yaml
160160
---

selene-lib/default_std/roblox_base.yml

+5
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,11 @@ globals:
320320
Instance.new:
321321
args:
322322
- type: string
323+
- required: false
324+
type:
325+
display: Instance
326+
deprecated:
327+
message: set the instance's parent separately
323328
# This is only must_use because we don't allow the second parameter
324329
must_use: true
325330
NumberRange.new:

selene-lib/src/lints/deprecated.rs

+61-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::convert::Infallible;
33
use full_moon::{ast, visitors::Visitor};
44
use serde::Deserialize;
55

6-
use crate::ast_util::{name_paths::*, scopes::ScopeManager};
6+
use crate::ast_util::{name_paths::*, range, scopes::ScopeManager};
77

88
use super::{super::standard_library::*, *};
99

@@ -48,6 +48,11 @@ struct DeprecatedVisitor<'a> {
4848
standard_library: &'a StandardLibrary,
4949
}
5050

51+
struct Argument {
52+
display: String,
53+
range: (usize, usize),
54+
}
55+
5156
impl<'a> DeprecatedVisitor<'a> {
5257
fn new(
5358
config: &DeprecatedLintConfig,
@@ -194,21 +199,62 @@ impl Visitor for DeprecatedVisitor<'_> {
194199
feature = "force_exhaustive_checks",
195200
deny(non_exhaustive_omitted_patterns)
196201
)]
197-
let argument_displays = match function_args {
202+
let arguments = match function_args {
198203
ast::FunctionArgs::Parentheses { arguments, .. } => arguments
199204
.iter()
200-
.map(|argument| argument.to_string())
205+
.map(|argument| Argument {
206+
display: argument.to_string().trim_end().to_string(),
207+
range: range(argument),
208+
})
201209
.collect(),
202210

203-
ast::FunctionArgs::String(token) => vec![token.to_string()],
211+
ast::FunctionArgs::String(token) => vec![
212+
(Argument {
213+
display: token.to_string(),
214+
range: range(token),
215+
}),
216+
],
204217
ast::FunctionArgs::TableConstructor(table_constructor) => {
205-
vec![table_constructor.to_string()]
218+
vec![Argument {
219+
display: table_constructor.to_string(),
220+
range: range(table_constructor),
221+
}]
206222
}
207223

208224
_ => Vec::new(),
209225
};
210226

211-
self.check_name_path(call, "function", &name_path, &argument_displays);
227+
if let Some(Field {
228+
field_kind: FieldKind::Function(function),
229+
..
230+
}) = self.standard_library.find_global(&name_path)
231+
{
232+
for (arg, arg_std) in arguments.iter().zip(&function.arguments) {
233+
if arg.display == "nil" {
234+
continue;
235+
}
236+
237+
if let Some(deprecated) = &arg_std.deprecated {
238+
self.diagnostics.push(Diagnostic::new_complete(
239+
"deprecated",
240+
"this parameter is deprecated".to_string(),
241+
Label::new(arg.range),
242+
vec![deprecated.message.clone()],
243+
Vec::new(),
244+
));
245+
};
246+
}
247+
}
248+
249+
self.check_name_path(
250+
call,
251+
"function",
252+
&name_path,
253+
&arguments
254+
.iter()
255+
.map(|arg| arg.display.clone())
256+
.collect::<Vec<_>>(),
257+
);
212258
}
213259
}
214260

@@ -234,6 +280,15 @@ mod tests {
234280
);
235281
}
236282

283+
#[test]
284+
fn test_deprecated_params() {
285+
test_lint(
286+
DeprecatedLint::new(DeprecatedLintConfig::default()).unwrap(),
287+
"deprecated",
288+
"deprecated_params",
289+
);
290+
}
291+
237292
#[test]
238293
fn test_specific_allow() {
239294
test_lint(

selene-lib/src/standard_library/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,10 @@ pub struct Argument {
603603
#[serde(default)]
604604
#[serde(skip_serializing_if = "is_default")]
605605
pub observes: Observes,
606+
607+
#[serde(default)]
608+
#[serde(skip_serializing_if = "Option::is_none")]
609+
pub deprecated: Option<Deprecated>,
606610
}
607611

608612
#[derive(Clone, Debug, Hash, PartialEq, Eq)]

selene-lib/src/standard_library/v1_upgrade.rs

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ impl From<v1::Argument> for Argument {
4141
required: v1_argument.required.into(),
4242
argument_type: v1_argument.argument_type.into(),
4343
observes: Observes::ReadWrite,
44+
deprecated: None,
4445
}
4546
}
4647
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
local _ = Instance.new(a)
2+
local _ = Instance.new(a, b)
3+
local _ = Instance.new(a, nil )
4+
local _ = Instance.new(a, "nil")
5+
6+
a(1)
7+
a ""
8+
a {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
globals:
3+
Instance.new:
4+
args:
5+
- type: string
6+
- required: false
7+
type:
8+
display: Instance
9+
deprecated:
10+
message: set the instance's parent separately
11+
a:
12+
args:
13+
- required: false
14+
type:
15+
display: any
16+
deprecated:
17+
message: this is deprecated
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
error[deprecated]: this parameter is deprecated
2+
┌─ deprecated_params.lua:2:27
3+
4+
2 │ local _ = Instance.new(a, b)
5+
│ ^
6+
7+
= set the instance's parent separately
8+
9+
error[deprecated]: this parameter is deprecated
10+
┌─ deprecated_params.lua:4:27
11+
12+
4 │ local _ = Instance.new(a, "nil")
13+
│ ^^^^^
14+
15+
= set the instance's parent separately
16+
17+
error[deprecated]: this parameter is deprecated
18+
┌─ deprecated_params.lua:6:3
19+
20+
6 │ a(1)
21+
│ ^
22+
23+
= this is deprecated
24+
25+
error[deprecated]: this parameter is deprecated
26+
┌─ deprecated_params.lua:7:3
27+
28+
7 │ a ""
29+
│ ^^
30+
31+
= this is deprecated
32+
33+
error[deprecated]: this parameter is deprecated
34+
┌─ deprecated_params.lua:8:3
35+
36+
8 │ a {}
37+
│ ^^
38+
39+
= this is deprecated
40+

selene/src/roblox/generate_std.rs

+19-5
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ impl RobloxGenerator {
125125
argument_type: ArgumentType::Any,
126126
required: Required::NotRequired,
127127
observes: Observes::ReadWrite,
128+
deprecated: None,
128129
})
129130
.collect(),
130131
method: true,
@@ -260,11 +261,23 @@ impl RobloxGenerator {
260261
self.std.globals.insert(
261262
"Instance.new".to_owned(),
262263
Field::from_field_kind(FieldKind::Function(FunctionBehavior {
263-
arguments: vec![Argument {
264-
argument_type: ArgumentType::Constant(instance_names),
265-
required: Required::Required(None),
266-
observes: Observes::ReadWrite,
267-
}],
264+
arguments: vec![
265+
Argument {
266+
argument_type: ArgumentType::Constant(instance_names),
267+
required: Required::Required(None),
268+
observes: Observes::ReadWrite,
269+
deprecated: None,
270+
},
271+
Argument {
272+
argument_type: ArgumentType::Display("Instance".to_string()),
273+
required: Required::Required(None),
274+
observes: Observes::ReadWrite,
275+
deprecated: Some(Deprecated {
276+
message: "set the instance's parent separately".to_owned(),
277+
replace: vec![],
278+
}),
279+
},
280+
],
268281
method: false,
269282

270283
// Only true because we don't allow the second parameter
@@ -294,6 +307,7 @@ impl RobloxGenerator {
294307
argument_type: ArgumentType::Constant(service_names),
295308
required: Required::Required(None),
296309
observes: Observes::ReadWrite,
310+
deprecated: None,
297311
}],
298312
method: true,
299313
must_use: true,

0 commit comments

Comments
 (0)