perf(linter/react/no-string-refs): narrow AST dispatch (#28366)

Inspect this expressions instead of all member accesses while retaining
JSX attributes and component context. Reduce fixture callbacks from
15,882 to 5,112.


---

<sub>Stack created with <a
href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a
href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Cam McHenryandCopilot authored and GitHub committed 2026-10-28 22:28:50 -04:00
1 parent bbfd692af6
commit ee51c01aff
4 files changed
+26 -12

No files matched your search

+2 -6
View File
@@ -2928,12 +2928,8 @@ impl RuleRunner for crate::rules::react::no_set_state::NoSetState {
}
impl RuleRunner for crate::rules::react::no_string_refs::NoStringRefs {
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::ComputedMemberExpression,
AstType::JSXAttribute,
AstType::PrivateFieldExpression,
AstType::StaticMemberExpression,
]));
const NODE_TYPES: Option<&AstTypesBitset> =
Some(&AstTypesBitset::from_types(&[AstType::JSXAttribute, AstType::ThisExpression]));
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
}
@@ -1,8 +1,7 @@
use oxc_ast::{
AstKind,
ast::{
Expression, JSXAttribute, JSXAttributeName, JSXAttributeValue, JSXExpression,
JSXExpressionContainer,
JSXAttribute, JSXAttributeName, JSXAttributeValue, JSXExpression, JSXExpressionContainer,
},
};
use oxc_diagnostics::OxcDiagnostic;
@@ -131,11 +130,12 @@ impl Rule for NoStringRefs {
{
ctx.diagnostic(string_in_ref_deprecated(attr.span));
}
member_expr if member_expr.is_member_expression_kind() => {
let Some(member_expr) = member_expr.as_member_expression_kind() else {
AstKind::ThisExpression(this) => {
let node = ctx.nodes().parent_node(node.id());
let Some(member_expr) = node.kind().as_member_expression_kind() else {
return;
};
if matches!(member_expr.object(), Expression::ThisExpression(_))
if member_expr.object().span() == this.span
&& member_expr.static_property_name().is_some_and(|name| name == "refs")
&& get_parent_component(node, ctx).is_some()
{
@@ -156,6 +156,8 @@ fn test() {
use crate::tester::Tester;
let pass = vec![
("class C extends React.Component { method() { return other[this]; } }", None),
("class C extends React.Component { method() { return (this).refs; } }", None),
(
"
var Hello = function() {
@@ -226,6 +228,8 @@ fn test() {
];
let fail = vec![
("class C extends React.Component { method() { return this['refs']; } }", None),
("class C extends React.Component { method() { return this?.refs; } }", None),
(
"
var Hello = createReactClass({
@@ -2,6 +2,20 @@
source: crates/oxc_linter/src/tester.rs
---
⚠ react(no-string-refs): Using this.refs is deprecated.
╭─[no_string_refs.tsx:1:53]
1 │ class C extends React.Component { method() { return this['refs']; } }
· ────────────
╰────
help: Using this.xxx instead of this.refs.xxx
⚠ react(no-string-refs): Using this.refs is deprecated.
╭─[no_string_refs.tsx:1:53]
1 │ class C extends React.Component { method() { return this?.refs; } }
· ──────────
╰────
help: Using this.xxx instead of this.refs.xxx
⚠ react(no-string-refs): Using this.refs is deprecated.
╭─[no_string_refs.tsx:4:35]
3 │ componentDidMount: function() {
@@ -428,7 +428,7 @@ react/no-react-children | 62606
react/no-redundant-should-component-update | 300
react/no-render-return-value | 6567
react/no-set-state | 6567
react/no-string-refs | 15882
react/no-string-refs | 5112
react/no-this-in-sfc | 4308
react/no-unescaped-entities | 672
react/no-unknown-property | 452