-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathSuspiciousMethodNameDeclaration.ql
More file actions
80 lines (71 loc) · 2.66 KB
/
SuspiciousMethodNameDeclaration.ql
File metadata and controls
80 lines (71 loc) · 2.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/**
* @name Suspicious method name declaration
* @description A method having the name "function", "new", or "constructor"
* is usually caused by a programmer being confused about the TypeScript syntax.
* @kind problem
* @problem.severity warning
* @id js/suspicious-method-name-declaration
* @precision high
* @tags correctness
* typescript
* methods
*/
import javascript
/**
* Holds if the method name on the given container is likely to be a mistake.
*/
predicate isSuspisousMethodName(string name, ClassOrInterface container) {
name = "function"
or
// "constructor" is only suspicious outside a class.
name = "constructor" and not container instanceof ClassDefinition
or
// "new" is only suspicious inside a class.
name = "new" and container instanceof ClassDefinition
}
/**
* Holds if the beginning of the location is before the end.
*/
predicate isRealLocation(Location l) {
l.getEndLine() > l.getStartLine() or
(l.getStartLine() = l.getEndLine() and l.getEndColumn() > l.getStartColumn())
}
from MethodDeclaration member, ClassOrInterface container, string suffixMsg
where
container.getLocation().getFile().getFileType().isTypeScript() and
container.getAMember() = member and
isSuspisousMethodName(member.getName(), container) and
// Assume that a "new" method is intentional if the class has an explicit constructor.
not (
member.getName() = "new" and
container instanceof ClassDefinition and
exists(MemberDeclaration constructor |
container.getAMember() = constructor and
constructor.getName() = "constructor" and
// Test that it is not an implicitly declared constructor.
isRealLocation(constructor.getLocation())
)
) and
// Explicitly declared static methods are fine.
not (
container instanceof ClassDefinition and
member.isStatic()
) and
// Only looking for declared methods. Methods with a body are OK.
not exists(member.getBody().getBody()) and
// The developer was not confused about "function" when there are other methods in the interface.
not (
member.getName() = "function" and
exists(MethodDeclaration other | other = container.getMethod(_) |
other.getName() != "function" and
isRealLocation(other.getLocation())
)
) and
(
member.getName() = "constructor" and suffixMsg = "Did you mean to write a class instead of an interface?"
or
member.getName() = "new" and suffixMsg = "Did you mean \"constructor\"?"
or
member.getName() = "function" and suffixMsg = "Did you mean to omit \"function\"?"
)
select member, "Declares a suspiciously named method \"" + member.getName() + "\". " + suffixMsg