Skip to content

Commit a114d08

Browse files
committed
Refactor: move "delete x" handling into linter
1 parent d5adaec commit a114d08

15 files changed

+105
-33
lines changed

src/lint.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,16 @@ void linter::visit_variable_assignment(identifier name) {
345345
}
346346
}
347347

348-
void linter::visit_variable_delete_use(identifier name) {
348+
void linter::visit_variable_delete_use(identifier name,
349+
source_code_span delete_keyword) {
349350
this->visit_variable_use(name, used_variable_kind::use);
351+
QLJS_ASSERT(delete_keyword.end() <= name.span().begin());
352+
// TODO(strager): What if the variable was parenthesized? We should include
353+
// the closing parenthesis.
354+
this->error_reporter_->report(error_redundant_delete_statement_on_variable{
355+
.delete_expression =
356+
source_code_span(delete_keyword.begin(), name.span().end()),
357+
});
350358
}
351359

352360
void linter::visit_variable_export_use(identifier name) {

src/main.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,8 @@ class debug_visitor {
302302
<< '\n';
303303
}
304304

305-
void visit_variable_delete_use(identifier name) {
305+
void visit_variable_delete_use(
306+
identifier name, [[maybe_unused]] source_code_span delete_keyword) {
306307
std::cerr << "variable delete use: " << out_string8(name.normalized_name())
307308
<< '\n';
308309
}
@@ -415,9 +416,10 @@ class multi_visitor {
415416
this->visitor_2_->visit_variable_declaration(name, kind);
416417
}
417418

418-
void visit_variable_delete_use(identifier name) {
419-
this->visitor_1_->visit_variable_delete_use(name);
420-
this->visitor_2_->visit_variable_delete_use(name);
419+
void visit_variable_delete_use(identifier name,
420+
source_code_span delete_keyword) {
421+
this->visitor_1_->visit_variable_delete_use(name, delete_keyword);
422+
this->visitor_2_->visit_variable_delete_use(name, delete_keyword);
421423
}
422424

423425
void visit_variable_export_use(identifier name) {

src/parse.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -243,13 +243,6 @@ expression* parser::parse_primary_expression(precedence prec) {
243243
operator_span)
244244
: this->make_expression<expression::unary_operator>(
245245
child, operator_span);
246-
if (type == token_type::kw_delete &&
247-
child->kind() == expression_kind::variable) {
248-
this->error_reporter_->report(
249-
error_redundant_delete_statement_on_variable{
250-
.delete_expression = ast->span(),
251-
});
252-
}
253246
return ast;
254247
}
255248

src/quick-lint-js/buffering-visitor.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class buffering_visitor {
8484
target.visit_variable_assignment(v.name);
8585
break;
8686
case visit_kind::variable_delete_use:
87-
target.visit_variable_delete_use(v.name);
87+
target.visit_variable_delete_use(v.name, v.extra_span);
8888
break;
8989
case visit_kind::variable_export_use:
9090
target.visit_variable_export_use(v.name);
@@ -175,8 +175,10 @@ class buffering_visitor {
175175
this->visits_.emplace_back(visit_kind::variable_declaration, name, kind);
176176
}
177177

178-
void visit_variable_delete_use(identifier name) {
179-
this->visits_.emplace_back(visit_kind::variable_delete_use, name);
178+
void visit_variable_delete_use(identifier name,
179+
source_code_span delete_keyword) {
180+
this->visits_.emplace_back(visit_kind::variable_delete_use, name,
181+
delete_keyword);
180182
}
181183

182184
void visit_variable_export_use(identifier name) {
@@ -227,6 +229,10 @@ class buffering_visitor {
227229
variable_kind var_kind) noexcept
228230
: kind(kind), name(name), var_kind(var_kind) {}
229231

232+
explicit visit(visit_kind kind, identifier name,
233+
source_code_span extra_span) noexcept
234+
: kind(kind), name(name), extra_span(extra_span) {}
235+
230236
visit_kind kind;
231237

232238
union {
@@ -240,6 +246,10 @@ class buffering_visitor {
240246
// variable_declaration
241247
variable_kind var_kind;
242248
static_assert(std::is_trivially_destructible_v<variable_kind>);
249+
250+
// variable_delete_use
251+
source_code_span extra_span;
252+
static_assert(std::is_trivially_destructible_v<source_code_span>);
243253
};
244254
};
245255

src/quick-lint-js/expression.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,10 @@ class expression::expression_with_prefix_operator_base : public expression {
363363
this->child_->span().end());
364364
}
365365

366+
const char8 *unary_operator_begin() const noexcept {
367+
return this->unary_operator_begin_;
368+
}
369+
366370
protected:
367371
const char8 *unary_operator_begin_;
368372
expression *child_;
@@ -375,7 +379,15 @@ class expression::_delete final
375379

376380
explicit _delete(expression *child, source_code_span operator_span) noexcept
377381
: expression::expression_with_prefix_operator_base(kind, child,
378-
operator_span) {}
382+
operator_span) {
383+
QLJS_ASSERT(operator_span.string_view() == u8"delete");
384+
}
385+
386+
source_code_span unary_operator_span() {
387+
const char8 *operator_begin = this->unary_operator_begin();
388+
return source_code_span(operator_begin,
389+
operator_begin + strlen(u8"delete"));
390+
}
379391
};
380392
static_assert(expression_arena::is_allocatable<expression::_delete>);
381393

src/quick-lint-js/lint.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ class linter {
8282
void visit_property_declaration(std::optional<identifier>);
8383
void visit_variable_declaration(identifier name, variable_kind kind);
8484
void visit_variable_assignment(identifier name);
85-
void visit_variable_delete_use(identifier name);
85+
void visit_variable_delete_use(identifier name,
86+
source_code_span delete_keyword);
8687
void visit_variable_export_use(identifier name);
8788
void visit_variable_typeof_use(identifier name);
8889
void visit_variable_use(identifier name);

src/quick-lint-js/null-visitor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class null_visitor {
2828
void visit_property_declaration(std::optional<identifier>) {}
2929
void visit_variable_assignment(identifier) {}
3030
void visit_variable_declaration(identifier, variable_kind) {}
31-
void visit_variable_delete_use(identifier) {}
31+
void visit_variable_delete_use(identifier, source_code_span) {}
3232
void visit_variable_export_use(identifier) {}
3333
void visit_variable_typeof_use(identifier) {}
3434
void visit_variable_use(identifier) {}

src/quick-lint-js/parse-visitor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ namespace quick_lint_js {
3131
#if QLJS_HAVE_CXX_CONCEPTS
3232
template <class Visitor>
3333
concept parse_visitor = requires(Visitor v, identifier name,
34+
source_code_span span,
3435
variable_kind var_kind) {
3536
{v.visit_end_of_module()};
3637
{v.visit_enter_block_scope()};
@@ -50,7 +51,7 @@ concept parse_visitor = requires(Visitor v, identifier name,
5051
{v.visit_property_declaration(std::optional<identifier>(name))};
5152
{v.visit_variable_assignment(name)};
5253
{v.visit_variable_declaration(name, var_kind)};
53-
{v.visit_variable_delete_use(name)};
54+
{v.visit_variable_delete_use(name, span)};
5455
{v.visit_variable_export_use(name)};
5556
{v.visit_variable_typeof_use(name)};
5657
{v.visit_variable_use(name)};

src/quick-lint-js/parse.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,9 @@ class parser {
799799
case expression_kind::_delete: {
800800
expression *child = ast->child_0();
801801
if (child->kind() == expression_kind::variable) {
802-
v.visit_variable_delete_use(child->variable_identifier());
802+
v.visit_variable_delete_use(
803+
child->variable_identifier(),
804+
static_cast<expression::_delete *>(ast)->unary_operator_span());
803805
} else {
804806
this->visit_expression(child, v, context);
805807
}

test/quick-lint-js/spy-visitor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ struct spy_visitor : public error_collector {
158158
};
159159
std::vector<visited_variable_declaration> variable_declarations;
160160

161-
void visit_variable_delete_use(identifier name) {
161+
void visit_variable_delete_use(
162+
identifier name, [[maybe_unused]] source_code_span delete_keyword) {
162163
this->variable_uses.emplace_back(
163164
visited_variable_use{string8(name.normalized_name())});
164165
this->visits.emplace_back("visit_variable_delete_use");

0 commit comments

Comments
 (0)