Skip to content

Commit 2c39921

Browse files
committed
JS: Make UnreachableMethodOverloads compile
This query depended on the cons-hashing performed by type extraction to determine if two types are the same. This is not trivial to restore, but not important enough to reimplement right now, so for now just simplifying the query's ability to recognise that two types are the same.
1 parent 319210a commit 2c39921

File tree

3 files changed

+30
-21
lines changed

3 files changed

+30
-21
lines changed

javascript/ql/src/Declarations/UnreachableMethodOverloads.ql

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,20 +43,22 @@ string getKind(MemberDeclaration m) {
4343
/**
4444
* A call-signature that originates from a MethodSignature in the AST.
4545
*/
46-
private class MethodCallSig extends CallSignatureType {
47-
string name;
48-
49-
MethodCallSig() {
50-
exists(MethodSignature sig |
51-
this = sig.getBody().getCallSignature() and
52-
name = sig.getName()
53-
)
46+
private class MethodCallSig extends Function {
47+
private MethodSignature signature;
48+
49+
MethodCallSig() { this = signature.getBody() }
50+
51+
int getNumOptionalParameter() {
52+
result = count(Parameter p | p = this.getParameter(_) and p.isDeclaredOptional())
53+
}
54+
55+
int getNumRequiredParameter() {
56+
result = count(Parameter p | p = this.getParameter(_) and not p.isDeclaredOptional())
5457
}
5558

56-
/**
57-
* Gets the name of any member that has this signature.
58-
*/
59-
string getName() { result = name }
59+
SignatureKind getKind() { result = SignatureKind::function() }
60+
61+
TypeExpr getTypeParameterBound(int i) { result = this.getTypeParameter(i).getBound() }
6062
}
6163

6264
pragma[noinline]
@@ -73,6 +75,7 @@ private MethodCallSig getMethodCallSigWithFingerprint(
7375
/**
7476
* Holds if the two call signatures could be overloads of each other and have the same parameter types.
7577
*/
78+
pragma[inline]
7679
predicate matchingCallSignature(MethodCallSig method, MethodCallSig other) {
7780
other =
7881
getMethodCallSigWithFingerprint(method.getName(), method.getNumOptionalParameter(),
@@ -107,6 +110,16 @@ private MethodSignature getMethodSignatureWithFingerprint(
107110
result.getBody().getNumParameter() = numParameters
108111
}
109112

113+
bindingset[t1, t2]
114+
pragma[inline_late]
115+
private predicate sameType(TypeExpr t1, TypeExpr t2) {
116+
t1.(PredefinedTypeExpr).getName() = t2.(PredefinedTypeExpr).getName()
117+
or
118+
t1 instanceof ThisTypeExpr and t2 instanceof ThisTypeExpr
119+
or
120+
t1.(LocalTypeAccess).getLocalTypeName() = t2.(LocalTypeAccess).getLocalTypeName()
121+
}
122+
110123
/**
111124
* Holds if the two method signatures are overloads of each other and have the same parameter types.
112125
*/
@@ -120,14 +133,13 @@ predicate signaturesMatch(MethodSignature method, MethodSignature other) {
120133
not exists(method.getBody().getThisTypeAnnotation()) and
121134
not exists(other.getBody().getThisTypeAnnotation())
122135
or
123-
method.getBody().getThisTypeAnnotation().getType() =
124-
other.getBody().getThisTypeAnnotation().getType()
136+
sameType(method.getBody().getThisTypeAnnotation(), other.getBody().getThisTypeAnnotation())
125137
) and
126138
// The types are compared in matchingCallSignature. This is a consistency check that the textual representation of the type-annotations are somewhat similar.
127139
forall(int i | i in [0 .. -1 + method.getBody().getNumParameter()] |
128140
getParameterTypeAnnotation(method, i) = getParameterTypeAnnotation(other, i)
129141
) and
130-
matchingCallSignature(method.getBody().getCallSignature(), other.getBody().getCallSignature())
142+
matchingCallSignature(method.getBody(), other.getBody())
131143
}
132144

133145
from ClassOrInterface decl, string name, MethodSignature previous, MethodSignature unreachable
Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,2 @@
1-
| tst.ts:3:3:3:30 | method( ... number; | This overload of method() is unreachable, the $@ overload will always be selected. | tst.ts:2:3:2:30 | method( ... string; | previous |
21
| tst.ts:6:3:6:17 | types1(): any[] | This overload of types1() is unreachable, the $@ overload will always be selected. | tst.ts:5:3:5:18 | types1<T>(): T[] | previous |
3-
| tst.ts:15:3:15:74 | on(even ... nction; | This overload of on() is unreachable, the $@ overload will always be selected. | tst.ts:14:3:14:74 | on(even ... nction; | previous |
42
| tst.ts:21:3:21:28 | bar(thi ... number; | This overload of bar() is unreachable, the $@ overload will always be selected. | tst.ts:20:3:20:28 | bar(thi ... string; | previous |
5-
| tst.ts:27:3:27:30 | method( ... number; | This overload of method() is unreachable, the $@ overload will always be selected. | tst.ts:26:3:26:30 | method( ... string; | previous |

javascript/ql/test/query-tests/Declarations/UnreachableOverloads/tst.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
declare class Foobar {
22
method(foo: number): string;
3-
method(foo: number): number; // $ Alert
3+
method(foo: number): number; // $ MISSING: Alert
44

55
types1<T>(): T[]
66
types1(): any[] // $ Alert
@@ -12,7 +12,7 @@ declare class Foobar {
1212
types3<T extends string>(t: T): number
1313

1414
on(event: string, fn?: (event?: any, ...args: any[]) => void): Function;
15-
on(event: string, fn?: (event?: any, ...args: any[]) => void): Function; // $ Alert
15+
on(event: string, fn?: (event?: any, ...args: any[]) => void): Function; // $ MISSING: Alert
1616

1717
foo(this: string): string;
1818
foo(this: number): number;
@@ -24,7 +24,7 @@ declare class Foobar {
2424

2525
declare class Base {
2626
method(foo: number): string;
27-
method(foo: number): number; // $ Alert
27+
method(foo: number): number; // $ MISSING: Alert
2828

2929
overRiddenInSub(): string;
3030
overRiddenInSub(): number;

0 commit comments

Comments
 (0)