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
use super::Context;
use super::LintRule;
use swc_ecmascript::ast::BlockStmt;
use swc_ecmascript::ast::Class;
use swc_ecmascript::ast::ClassMember;
use swc_ecmascript::ast::MethodKind;
use swc_ecmascript::ast::SetterProp;
use swc_ecmascript::ast::Stmt;
use swc_ecmascript::visit::noop_visit_type;
use swc_ecmascript::visit::Node;
use swc_ecmascript::visit::Visit;
pub struct NoSetterReturn;
impl LintRule for NoSetterReturn {
fn new() -> Box<Self> {
Box::new(NoSetterReturn)
}
fn tags(&self) -> &[&'static str] {
&["recommended"]
}
fn code(&self) -> &'static str {
"no-setter-return"
}
fn lint_module(
&self,
context: &mut Context,
module: &swc_ecmascript::ast::Module,
) {
let mut visitor = NoSetterReturnVisitor::new(context);
visitor.visit_module(module, module);
}
}
struct NoSetterReturnVisitor<'c> {
context: &'c mut Context,
}
impl<'c> NoSetterReturnVisitor<'c> {
fn new(context: &'c mut Context) -> Self {
Self { context }
}
fn check_block_stmt(&mut self, block_stmt: &BlockStmt) {
for stmt in &block_stmt.stmts {
if let Stmt::Return(return_stmt) = stmt {
if return_stmt.arg.is_some() {
self.context.add_diagnostic(
return_stmt.span,
"no-setter-return",
"Setter cannot return a value",
);
}
}
}
}
}
impl<'c> Visit for NoSetterReturnVisitor<'c> {
noop_visit_type!();
fn visit_class(&mut self, class: &Class, _parent: &dyn Node) {
for member in &class.body {
match member {
ClassMember::Method(class_method) => {
if class_method.kind == MethodKind::Setter {
if let Some(block_stmt) = &class_method.function.body {
self.check_block_stmt(block_stmt);
}
}
}
ClassMember::PrivateMethod(private_method) => {
if private_method.kind == MethodKind::Setter {
if let Some(block_stmt) = &private_method.function.body {
self.check_block_stmt(block_stmt);
}
}
}
_ => {}
}
}
}
fn visit_setter_prop(
&mut self,
setter_prop: &SetterProp,
_parent: &dyn Node,
) {
if let Some(block_stmt) = &setter_prop.body {
self.check_block_stmt(block_stmt);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_util::*;
#[test]
fn setter_return() {
assert_lint_err::<NoSetterReturn>(
r#"const a = { set setter(a) { return "something"; } };"#,
28,
);
assert_lint_err_on_line_n::<NoSetterReturn>(
r#"
class b {
set setterA(a) {
return "something";
}
private set setterB(a) {
return "something";
}
}
"#,
vec![(4, 4), (7, 4)],
);
}
}