Skip to content

Commit 1c53222

Browse files
authored
Merge pull request #557 from esben-semmle/js/unused-react-variable
Approved by xiemaisi
2 parents adc15ca + f3889e7 commit 1c53222

8 files changed

Lines changed: 54 additions & 16 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Improvements to JavaScript analysis
2+
3+
## General improvements
4+
5+
## New queries
6+
7+
| **Query** | **Tags** | **Purpose** |
8+
|-----------|----------|-------------|
9+
| | | |
10+
11+
## Changes to existing queries
12+
13+
| **Query** | **Expected impact** | **Change** |
14+
|--------------------------------------------|------------------------------|------------------------------------------------------------------------------|
15+
| Unused variable, import, function or class | Fewer false-positive results | This rule now flags fewer variables that are implictly used by JSX elements. |
16+
| | | |
17+
18+
## Changes to QL libraries

javascript/ql/src/Declarations/UnusedVariable.ql

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,24 +49,29 @@ predicate isPropertyFilter(UnusedLocal v) {
4949
)
5050
}
5151

52+
predicate hasJsxInScope(UnusedLocal v) {
53+
any(JSXNode n).getParent+() = v.getScope().getScopeElement()
54+
}
55+
5256
/**
53-
* Holds if `v` is an import of React, and there is a JSX element that implicitly
54-
* references it.
55-
*/
56-
predicate isReactImportForJSX(UnusedLocal v) {
57-
exists (ImportSpecifier is |
58-
is.getLocal() = v.getADeclaration() and
59-
exists (JSXNode jsx | jsx.getTopLevel() = is.getTopLevel())
60-
|
57+
* Holds if `v` is a "React" variable that is implicitly used by a JSX element.
58+
*/
59+
predicate isReactForJSX(UnusedLocal v) {
60+
hasJsxInScope(v) and
61+
(
6162
v.getName() = "React"
6263
or
63-
// legacy `@jsx` pragmas
64-
exists (JSXPragma p | p.getTopLevel() = is.getTopLevel() | p.getDOMName() = v.getName())
65-
or
66-
// JSX pragma from a .babelrc file
67-
exists (Babel::TransformReactJsxConfig plugin |
68-
plugin.appliesTo(is.getTopLevel()) and
69-
plugin.getJsxFactoryVariableName() = v.getName())
64+
exists(TopLevel tl |
65+
tl = v.getADeclaration().getTopLevel() |
66+
// legacy `@jsx` pragmas
67+
exists(JSXPragma p | p.getTopLevel() = tl | p.getDOMName() = v.getName())
68+
or
69+
// JSX pragma from a .babelrc file
70+
exists(Babel::TransformReactJsxConfig plugin |
71+
plugin.appliesTo(tl) and
72+
plugin.getJsxFactoryVariableName() = v.getName()
73+
)
74+
)
7075
)
7176
}
7277

@@ -150,7 +155,7 @@ predicate whitelisted(UnusedLocal v) {
150155
// exclude variables used to filter out unwanted properties
151156
isPropertyFilter(v) or
152157
// exclude imports of React that are implicitly referenced by JSX
153-
isReactImportForJSX(v) or
158+
isReactForJSX(v) or
154159
// exclude names that are used as types
155160
exists (VarDecl vd |
156161
v = vd.getVariable() |

javascript/ql/test/query-tests/Declarations/UnusedVariable/UnusedVariable.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
| importWithoutPragma.jsx:1:1:1:27 | import ... react'; | Unused import h. |
88
| multi-imports.js:1:1:1:29 | import ... om 'x'; | Unused imports a, b, d. |
99
| multi-imports.js:2:1:2:42 | import ... om 'x'; | Unused imports alphabetically, ordered. |
10+
| require-react-in-other-scope.js:2:9:2:13 | React | Unused variable React. |
1011
| typeoftype.ts:9:7:9:7 | y | Unused variable y. |
1112
| unusedShadowed.ts:1:1:1:26 | import ... where'; | Unused import T. |
1213
| unusedShadowed.ts:2:1:2:31 | import ... where'; | Unused import object. |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
var React = x; // OK
2+
(<e/>);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
var React = require("probably-react"); // OK
2+
(<e/>);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
var { React } = { React: require("probably-react") }; // OK
2+
(<e/>);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
var { React } = require("probably-react"); // OK
2+
(<e/>);
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
(function() {
2+
var React = require("probably-react"); // NOT OK
3+
})
4+
(function() {
5+
(<e/>);
6+
})

0 commit comments

Comments
 (0)