|
| 1 | +import ql |
| 2 | +private import NodeName |
| 3 | +private import TypoDatabase |
| 4 | + |
| 5 | +predicate misspelling(string wrong, string right, string mistake) { |
| 6 | + mistake = "common misspelling" and |
| 7 | + typos(wrong, right) |
| 8 | + or |
| 9 | + mistake = "non-US spelling" and |
| 10 | + non_us_spelling(wrong, right) |
| 11 | +} |
| 12 | + |
| 13 | +/** |
| 14 | + * Holds if `word` is an acceptable spelling that would otherwise be considered |
| 15 | + * a mistake by the typo database. |
| 16 | + */ |
| 17 | +predicate isAllowed(string word) { |
| 18 | + word = |
| 19 | + [ |
| 20 | + "asign", // 'sign of a', not 'assign' |
| 21 | + "larg", // 'left argument', not 'large' |
| 22 | + "nto", // some comments refer to the variable `nTo` |
| 23 | + "thn" // deliberate misspelling of 'then' to avoid using a keyword |
| 24 | + ] |
| 25 | +} |
| 26 | + |
| 27 | +predicate non_us_spelling(string wrong, string right) { |
| 28 | + exists(string s | |
| 29 | + wrong = s.splitAt("/", 0) and |
| 30 | + right = s.splitAt("/", 1) and |
| 31 | + s = |
| 32 | + [ |
| 33 | + "colour/color", "authorise/authorize", "authorises/authorizes", "authorised/authorized", |
| 34 | + "analyse/analyze", "analysed/analyzed", "behaviour/behavior", "modelling/modeling", |
| 35 | + "modelled/modeled" |
| 36 | + ] |
| 37 | + ) |
| 38 | +} |
| 39 | + |
| 40 | +/** |
| 41 | + * Gets a word in the camel-case string `s`. For example, if `s` is |
| 42 | + * `"getFooBar"`, it returns `"get"`, `"Foo"`, and `"Bar"`. |
| 43 | + */ |
| 44 | +bindingset[s] |
| 45 | +string getACamelCaseWord(string s) { result = s.regexpFind("(^[a-z]+)|([A-Z][a-z]+)", _, _) } |
| 46 | + |
| 47 | +bindingset[s] |
| 48 | +string getACommentWord(string s) { result = s.regexpFind("\\b\\w+\\b", _, _) } |
| 49 | + |
| 50 | +string getAWord(AstNode node, string kind) { |
| 51 | + result = getACommentWord(node.(QLDoc).getContents()).toLowerCase() and |
| 52 | + kind = "QLDoc comment" |
| 53 | + or |
| 54 | + exists(string nodeKind | |
| 55 | + result = getACamelCaseWord(getName(node, nodeKind)).toLowerCase() and |
| 56 | + kind = nodeKind + " name" |
| 57 | + ) |
| 58 | +} |
| 59 | + |
| 60 | +predicate misspelled_element(AstNode node, string kind, string wrong, string right, string mistake) { |
| 61 | + wrong = getAWord(node, kind) and |
| 62 | + misspelling(wrong, right, mistake) and |
| 63 | + not isAllowed(wrong) |
| 64 | +} |
0 commit comments