diff --git a/javascript/ql/src/Expressions/MisspelledVariableName.ql b/javascript/ql/src/Expressions/MisspelledVariableName.ql index ce5dc546341..9eeeb288134 100644 --- a/javascript/ql/src/Expressions/MisspelledVariableName.ql +++ b/javascript/ql/src/Expressions/MisspelledVariableName.ql @@ -14,6 +14,37 @@ import Misspelling -from GlobalVarAccess gva, VarDecl lvd -where misspelledVariableName(gva, lvd) -select gva, "'" + gva + "' may be a typo for variable $@.", lvd, lvd.getName() +/** + * Gets the number of times a local variable with name `name` occurs in the program. + */ +bindingset[name] +int localAcceses(string name) { + result = count(VarAccess acc | acc.getName() = name and not acc instanceof GlobalVarAccess) +} + +/** + * Gets the number of times a global variable with name `name` occurs in the program. + */ +bindingset[name] +int globalAccesses(string name) { result = count(GlobalVarAccess acc | acc.getName() = name) } + +/** + * Holds if our heuristic says that the local variable `lvd` seems to be a misspelling of the global variable `gvd`. + * Otherwise the global variable is likely the misspelling. + */ +predicate globalIsLikelyCorrect(GlobalVarAccess gva, VarDecl lvd) { + // If there are more occurrences of the global (by a margin of at least 2), and the local is missing one letter compared to the global. + globalAccesses(gva.getName()) >= localAcceses(lvd.getName()) + 2 and + lvd.getName().length() = gva.getName().length() - 1 + or + // Or if there are many more of the global. + globalAccesses(gva.getName()) > 2 * localAcceses(lvd.getName()) + 2 +} + +from GlobalVarAccess gva, VarDecl lvd, string msg +where + misspelledVariableName(gva, lvd) and + if globalIsLikelyCorrect(gva, lvd) + then msg = "$@ may be a typo for '" + gva + "'." + else msg = "'" + gva + "' may be a typo for variable $@." +select gva, msg, lvd, lvd.getName() diff --git a/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/MisspelledVariableName.expected b/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/MisspelledVariableName.expected index 43098d60483..535682017e4 100644 --- a/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/MisspelledVariableName.expected +++ b/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/MisspelledVariableName.expected @@ -1,5 +1,13 @@ | MisspelledVariableName.js:2:40:2:45 | lenght | 'lenght' may be a typo for variable $@. | MisspelledVariableName.js:2:19:2:24 | length | length | | tst.js:2:10:2:20 | errorMesage | 'errorMesage' may be a typo for variable $@. | tst.js:1:12:1:23 | errorMessage | errorMessage | -| tst.js:6:10:6:21 | errorMessage | 'errorMessage' may be a typo for variable $@. | tst.js:5:12:5:22 | errorMesage | errorMesage | +| tst.js:6:10:6:21 | errorMessage | $@ may be a typo for 'errorMessage'. | tst.js:5:12:5:22 | errorMesage | errorMesage | | tst.js:11:12:11:22 | errorMesage | 'errorMesage' may be a typo for variable $@. | tst.js:9:12:9:23 | errorMessage | errorMessage | -| tst.js:17:5:17:16 | errorMessage | 'errorMessage' may be a typo for variable $@. | tst.js:15:12:15:22 | errorMesage | errorMesage | +| tst.js:17:5:17:16 | errorMessage | $@ may be a typo for 'errorMessage'. | tst.js:15:12:15:22 | errorMesage | errorMesage | +| tst.js:22:2:22:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | +| tst.js:23:2:23:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | +| tst.js:24:2:24:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | +| tst.js:25:2:25:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | +| tst.js:26:2:26:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | +| tst.js:27:2:27:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | +| tst.js:28:2:28:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | +| tst.js:29:2:29:12 | thisHandler | $@ may be a typo for 'thisHandler'. | tst.js:21:6:21:15 | thisHander | thisHander | diff --git a/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/tst.js b/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/tst.js index bc669b52957..cd6c027f1fc 100644 --- a/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/tst.js +++ b/javascript/ql/test/query-tests/Expressions/MisspelledVariableName/tst.js @@ -16,3 +16,15 @@ function k(errorMesage) { let inner = () => errorMessage; } + +function foo() { + var thisHander; + thisHandler.foo1; + thisHandler.foo2; + thisHandler.foo3; + thisHandler.foo4; + thisHandler.foo5; + thisHandler.foo6; + thisHandler.foo7; + thisHandler.foo8; +} \ No newline at end of file