mirror of
https://github.com/github/codeql.git
synced 2026-03-24 00:16:49 +01:00
123 lines
4.2 KiB
Plaintext
123 lines
4.2 KiB
Plaintext
/**
|
|
* @name Misspelled identifier
|
|
* @description Misspelled identifiers make code harder to read and understand.
|
|
* @kind problem
|
|
* @problem.severity recommendation
|
|
* @id js/misspelled-identifier
|
|
* @tags maintainability
|
|
* readability
|
|
* @precision high
|
|
*/
|
|
|
|
import Misspelling
|
|
|
|
/**
|
|
* An identifier part.
|
|
*/
|
|
class IdentifierPart extends string {
|
|
IdentifierPart() {
|
|
idPart(_, this, _)
|
|
}
|
|
|
|
/**
|
|
* Holds if this element is at the specified location.
|
|
* The location spans column `startcolumn` of line `startline` to
|
|
* column `endcolumn` of line `endline` in file `filepath`.
|
|
* For more information, see
|
|
* [LGTM locations](https://lgtm.com/help/ql/locations).
|
|
*/
|
|
predicate hasLocationInfo(string filepath, int startline, int startcolumn,
|
|
int endline, int endcolumn) {
|
|
exists (Identifier id, int start, Location l, int len | occursIn(id, start, len) and l = id.getLocation() |
|
|
filepath = l.getFile().getAbsolutePath() and
|
|
startline = l.getStartLine() and startcolumn = l.getStartColumn() + start and
|
|
// identifiers cannot span more than one line
|
|
endline = startline and endcolumn = startcolumn + len - 1
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Holds if this identifier part occurs at offset `start` inside identifier `id`,
|
|
* and has length `len`.
|
|
*/
|
|
predicate occursIn(Identifier id, int start, int len) {
|
|
idPart(id, this, start) and len = this.length()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An identifier part that corresponds to a typo in `normalized_typos`.
|
|
*/
|
|
class WrongIdentifierPart extends IdentifierPart {
|
|
WrongIdentifierPart() {
|
|
normalized_typos(this, _, _, _, _, _)
|
|
}
|
|
|
|
/**
|
|
* Gets an identifier part that corresponds to a correction of this typo.
|
|
*/
|
|
string getASuggestion() {
|
|
exists (IdentifierPart right | normalized_typos(this, right, _, _, _, _) |
|
|
result = "'" + right + "'"
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Gets a pretty-printed string representation of all corrections of
|
|
* this typo that appear as identifier parts in the code.
|
|
*/
|
|
string ppSuggestions() {
|
|
exists (string cat |
|
|
// first, concatenate with commas
|
|
cat = concat(getASuggestion(), ", ") and
|
|
// then, replace last comma with "or"
|
|
result = cat.regexpReplaceAll(", ([^,]++)$", " or $1")
|
|
)
|
|
}
|
|
|
|
override predicate occursIn(Identifier id, int start, int len) {
|
|
super.occursIn(id, start, len) and
|
|
// throw out cases where the wrong word appears as a prefix or suffix of a right word,
|
|
// and thus the result is most likely a false positive caused by our word segmentation algorithm
|
|
exists (string lowerid | lowerid = id.getName().toLowerCase() |
|
|
not exists (string right, int rightlen |
|
|
this.prefixOf(right, rightlen) and lowerid.substring(start, start+rightlen) = right or
|
|
this.suffixOf(right, rightlen) and lowerid.substring(start+len-rightlen, start+len) = right
|
|
)
|
|
) and
|
|
// also throw out cases flagged by another query
|
|
not misspelledVariableName(id, _)
|
|
}
|
|
|
|
/**
|
|
* Holds if this identifier part is a (proper) prefix of `right`, which is
|
|
* a correct spelling with length `rightlen`.
|
|
*/
|
|
predicate prefixOf(string right, int rightlen) {
|
|
exists (string c, int wronglen |
|
|
normalized_typos(this, _, c, _, _, _) and normalized_typos(_, right, _, _, c, _) and
|
|
wronglen = this.length() and rightlen = right.length() and
|
|
wronglen < rightlen and right.prefix(wronglen) = this
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Holds if this identifier part is a (proper) suffix of `right`, which is
|
|
* a correct spelling with length `rightlen`.
|
|
*/
|
|
predicate suffixOf(string right, int rightlen) {
|
|
exists (string c, int wronglen |
|
|
normalized_typos(this, _, _, c, _, _) and normalized_typos(_, right, _, _, _, c) and
|
|
wronglen = this.length() and rightlen = right.length() and
|
|
wronglen < rightlen and right.suffix(rightlen-wronglen) = this
|
|
)
|
|
}
|
|
}
|
|
|
|
from WrongIdentifierPart wrong
|
|
where // make sure we have at least one occurrence of a correction
|
|
exists(wrong.getASuggestion()) and
|
|
// make sure we have at least one unambiguous occurrence of the wrong word
|
|
wrong.occursIn(_, _, _)
|
|
select wrong, "'" + wrong + "' may be a typo for " + wrong.ppSuggestions() + "."
|