Skip to content

Commit 6d597be

Browse files
committed
JS: Refactor
1 parent 8a5b907 commit 6d597be

File tree

19 files changed

+59
-193
lines changed

19 files changed

+59
-193
lines changed

javascript/ql/lib/semmle/javascript/endpoints/EndpointNaming.qll

Lines changed: 18 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -167,24 +167,6 @@ predicate sinkHasPrimaryName(API::Node sink, string package, string name) {
167167
sinkHasPrimaryName(sink, package, name, _)
168168
}
169169

170-
/**
171-
* Holds if `(package, name)` is an alias for `node`.
172-
*
173-
* This means it is a valid name for it, but was not chosen as the primary name.
174-
*/
175-
private predicate sinkHasAlias(API::Node sink, string package, string name) {
176-
not sinkHasPrimaryName(sink, package, name) and
177-
(
178-
exists(string baseName, string step |
179-
sinkHasPrimaryName(getAPredecessor(sink, step, _), package, baseName) and
180-
name = join(baseName, step)
181-
)
182-
or
183-
sink = API::moduleExport(package) and
184-
name = ""
185-
)
186-
}
187-
188170
/** Gets a source node that can flow to `sink` without using a return step. */
189171
private DataFlow::SourceNode nodeReachingSink(API::Node sink, DataFlow::TypeBackTracker t) {
190172
t.start() and
@@ -243,49 +225,8 @@ private predicate classObjectHasNameCandidate(
243225
)
244226
or
245227
nameFromExterns(cls, package, name, badness)
246-
}
247-
248-
private predicate classObjectHasPrimaryName(
249-
DataFlow::ClassNode cls, string package, string name, int badness
250-
) {
251-
badness = min(int b | classObjectHasNameCandidate(cls, _, _, b) | b) and
252-
package = min(string p | classObjectHasNameCandidate(cls, p, _, badness) | p) and
253-
name = min(string n | classObjectHasNameCandidate(cls, package, n, badness) | n)
254-
}
255-
256-
/** Holds if `(package, name)` is the primary name for the class object of `cls`. */
257-
predicate classObjectHasPrimaryName(DataFlow::ClassNode cls, string package, string name) {
258-
classObjectHasPrimaryName(cls, package, name, _)
259-
}
260-
261-
/** Holds if an instance of `cls` can be exposed to client code. */
262-
private predicate hasEscapingInstance(DataFlow::ClassNode cls) {
263-
cls.getAnInstanceReference().flowsTo(any(API::Node n).asSink())
264-
}
265-
266-
/**
267-
* Holds if `(package, name)` is a potential name to use for instances of `cls`, with the given `badness`.
268-
*/
269-
private predicate classInstanceHasNameCandidate(
270-
DataFlow::ClassNode cls, string package, string name, int badness
271-
) {
272-
exists(string baseName |
273-
classObjectHasPrimaryName(cls, package, baseName, badness) and
274-
name = join(baseName, "prototype")
275-
)
276228
or
277-
// In case the class itself is unaccessible, but an instance is exposed via an access path,
278-
// consider using that access path. For example:
279-
//
280-
// class InternalClass {}
281-
// module.exports.foo = new InternalClass();
282-
//
283-
exists(int baseBadness |
284-
sinkHasPrimaryName(getASinkNode(cls.getAnInstanceReference()), package, name, baseBadness) and
285-
badness = baseBadness + 30 // add penalty, as we prefer to base this on the class name
286-
)
287-
or
288-
// If neither the class nor its instances are accessible via an access path, but instances of the
229+
// If the class is not accessible via an access path, but instances of the
289230
// class can still escape via more complex access patterns, resort to a synthesized name.
290231
// For example:
291232
//
@@ -297,62 +238,21 @@ private predicate classInstanceHasNameCandidate(
297238
hasEscapingInstance(cls) and
298239
exists(string baseName |
299240
InternalModuleNaming::fallbackModuleName(cls.getTopLevel(), package, baseName, badness - 100) and
300-
name = join(baseName, cls.getName()) + ".prototype"
241+
name = join(baseName, cls.getName())
301242
)
302243
}
303244

304-
private predicate classInstanceHasPrimaryName(
305-
DataFlow::ClassNode cls, string package, string name, int badness
306-
) {
307-
badness = min(int b | classInstanceHasNameCandidate(cls, _, _, b) | b) and
308-
package = min(string p | classInstanceHasNameCandidate(cls, p, _, badness) | p) and
309-
name =
310-
min(string n |
311-
classInstanceHasNameCandidate(cls, package, n, badness)
312-
|
313-
n order by n.length(), n
314-
)
315-
}
316-
317-
/** Holds if `(package, name)` is the primary name to use for instances of `cls`. */
318-
predicate classInstanceHasPrimaryName(DataFlow::ClassNode cls, string package, string name) {
319-
classInstanceHasPrimaryName(cls, package, name, _)
320-
}
321-
322-
/** Holds if `(package, name)` is an alias referring to some instance of `cls`. */
323-
predicate classInstanceHasAlias(DataFlow::ClassNode cls, string package, string name) {
324-
not classInstanceHasPrimaryName(cls, package, name) and
325-
exists(int badness |
326-
classInstanceHasNameCandidate(cls, package, name, badness) and
327-
badness < 100 // Badness 100 is when we start to synthesize names. Do not suggest these as aliases.
328-
)
329-
}
330-
331-
private predicate functionHasNameCandidate(
332-
DataFlow::FunctionNode function, string package, string name, int badness
333-
) {
334-
sinkHasPrimaryName(getASinkNode(function), package, name, badness)
335-
or
336-
exists(DataFlow::ClassNode cls |
337-
function = cls.getConstructor() and
338-
classObjectHasPrimaryName(cls, package, name, badness)
339-
or
340-
exists(string baseName, string memberName |
341-
function = cls.getStaticMethod(memberName) and
342-
classObjectHasPrimaryName(cls, package, baseName, badness) and
343-
name = join(baseName, memberName)
344-
)
345-
)
346-
or
347-
nameFromExterns(function, package, name, badness)
245+
/** Holds if an instance of `cls` can be exposed to client code. */
246+
private predicate hasEscapingInstance(DataFlow::ClassNode cls) {
247+
cls.getAnInstanceReference().flowsTo(any(API::Node n).asSink())
348248
}
349249

350250
private predicate sourceNodeHasNameCandidate(
351251
DataFlow::SourceNode node, string package, string name, int badness
352252
) {
353253
sinkHasPrimaryName(getASinkNode(node), package, name, badness)
354254
or
355-
functionHasNameCandidate(node, package, name, badness)
255+
nameFromExterns(node, package, name, badness)
356256
or
357257
classObjectHasNameCandidate(node, package, name, badness)
358258
}
@@ -371,13 +271,18 @@ private predicate sourceNodeHasPrimaryName(
371271
* Holds if `node` is a function or a call that returns a function.
372272
*/
373273
private predicate isFunctionSource(DataFlow::SourceNode node) {
374-
node instanceof DataFlow::FunctionNode
375-
or
376-
node instanceof DataFlow::InvokeNode and
377-
exists(node.getABoundFunctionValue(_)) and
378-
// `getASinkNode` steps through imports (but not other calls) so exclude calls that are imports (i.e. require calls)
379-
// as we want to get as close to the source as possible.
380-
not node instanceof DataFlow::ModuleImportNode
274+
exists(getASinkNode(node)) and
275+
(
276+
node instanceof DataFlow::FunctionNode
277+
or
278+
node instanceof DataFlow::ClassNode
279+
or
280+
node instanceof DataFlow::InvokeNode and
281+
exists(node.getABoundFunctionValue(_)) and
282+
// `getASinkNode` steps through imports (but not other calls) so exclude calls that are imports (i.e. require calls)
283+
// as we want to get as close to the source as possible.
284+
not node instanceof DataFlow::ModuleImportNode
285+
)
381286
}
382287

383288
/**
@@ -528,28 +433,6 @@ module Debug {
528433
)
529434
}
530435

531-
/** Holds if the given `node` has multiple primary names. */
532-
query string ambiguousClassObjectName(DataFlow::ClassNode node) {
533-
strictcount(string package, string name | classObjectHasPrimaryName(node, package, name)) > 1 and
534-
result =
535-
concat(string package, string name |
536-
classObjectHasPrimaryName(node, package, name)
537-
|
538-
renderName(package, name), ", "
539-
)
540-
}
541-
542-
/** Holds if the given `node` has multiple primary names. */
543-
query string ambiguousClassInstanceName(DataFlow::ClassNode node) {
544-
strictcount(string package, string name | classInstanceHasPrimaryName(node, package, name)) > 1 and
545-
result =
546-
concat(string package, string name |
547-
classInstanceHasPrimaryName(node, package, name)
548-
|
549-
renderName(package, name), ", "
550-
)
551-
}
552-
553436
/** Holds if the given `node` has multiple primary names. */
554437
query string ambiguousFunctionName(DataFlow::FunctionNode node) {
555438
strictcount(string package, string name | functionHasPrimaryName(node, package, name)) > 1 and
Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
testFailures
2-
| pack11/index.ts:33:1:33:16 | | Unexpected result: method=(pack11).C3.privateField |
3-
| pack11/index.ts:33:18:33:69 | // $ me ... ng.name | Missing result:method=(pack11).C3.publicField.really.long.name |
4-
| pack11/index.ts:41:23:41:24 | | Unexpected result: alias=(pack11).C3.publicField.really.long.name==(pack11).C3.privateField |
5-
failures
62
ambiguousPreferredPredecessor
73
| pack2/lib.js:1:1:3:1 | def moduleImport("pack2").getMember("exports").getMember("lib").getMember("LibClass").getInstance() |
84
| pack2/lib.js:8:22:8:34 | def moduleImport("pack2").getMember("exports").getMember("lib").getMember("LibClass").getMember("foo") |
95
| pack2/main.js:1:1:3:1 | def moduleImport("pack2").getMember("exports").getMember("MainClass").getInstance() |
106
ambiguousSinkName
11-
ambiguousClassObjectName
12-
ambiguousClassInstanceName
137
ambiguousFunctionName
8+
failures

javascript/ql/test/library-tests/EndpointNaming/EndpointNaming.ql

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,16 @@ private predicate isIgnored(DataFlow::FunctionNode function) {
1010
}
1111

1212
module TestConfig implements TestSig {
13-
string getARelevantTag() { result = ["instance", "class", "method", "alias"] }
13+
string getARelevantTag() { result = ["name", "alias"] }
1414

1515
predicate hasActualResult(Location location, string element, string tag, string value) {
16-
exists(string package, string name |
17-
element = "" and
16+
element = "" and
17+
tag = "name" and
18+
exists(DataFlow::SourceNode function, string package, string name |
19+
EndpointNaming::functionHasPrimaryName(function, package, name) and
20+
not isIgnored(function) and
21+
location = function.getAstNode().getLocation() and
1822
value = EndpointNaming::renderName(package, name)
19-
|
20-
exists(DataFlow::ClassNode cls | location = cls.getAstNode().getLocation() |
21-
tag = "class" and
22-
EndpointNaming::classObjectHasPrimaryName(cls, package, name)
23-
or
24-
tag = "instance" and
25-
EndpointNaming::classInstanceHasPrimaryName(cls, package, name)
26-
)
27-
or
28-
exists(DataFlow::SourceNode function |
29-
not isIgnored(function) and
30-
location = function.getAstNode().getLocation() and
31-
tag = "method" and
32-
EndpointNaming::functionHasPrimaryName(function, package, name) and
33-
not function instanceof DataFlow::ClassNode // reported with class tag
34-
)
3523
)
3624
or
3725
element = "" and
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
export class PublicClass {} // $ class=(pack1).PublicClass instance=(pack1).PublicClass.prototype
1+
export class PublicClass {} // $ name=(pack1).PublicClass
22

33
class PrivateClass {}
44

5-
export const ExportedConst = class ExportedConstClass {} // $ class=(pack1).ExportedConst instance=(pack1).ExportedConst.prototype
5+
export const ExportedConst = class ExportedConstClass {} // $ name=(pack1).ExportedConst
66

7-
class ClassWithEscapingInstance {} // $ instance=(pack1).ClassWithEscapingInstance.prototype
7+
class ClassWithEscapingInstance {}
88

99
export function getEscapingInstance() {
1010
return new ClassWithEscapingInstance();
11-
} // $ method=(pack1).getEscapingInstance
11+
} // $ name=(pack1).getEscapingInstance
1212

13-
export function publicFunction() {} // $ method=(pack1).publicFunction
13+
export function publicFunction() {} // $ name=(pack1).publicFunction
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export default class FooClass {} // $ class=(pack10).Foo instance=(pack10).Foo.prototype
1+
export default class FooClass {} // $ name=(pack10).Foo

javascript/ql/test/library-tests/EndpointNaming/pack11/index.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const f1 = {
2-
m() {} // $ method=(pack11).C1.publicField.really.long.name.m
2+
m() {} // $ name=(pack11).C1.publicField.really.long.name.m
33
};
44

55
export class C1 {
@@ -12,10 +12,10 @@ export class C1 {
1212
}
1313
}
1414
}
15-
} // $ class=(pack11).C1 instance=(pack11).C1.prototype
15+
} // $ name=(pack11).C1
1616

1717
const f2 = {
18-
m() {} // $ method=(pack11).C2.publicField.really.long.name.m
18+
m() {} // $ name=(pack11).C2.publicField.really.long.name.m
1919
}
2020

2121
export class C2 {
@@ -28,9 +28,9 @@ export class C2 {
2828
}
2929
}
3030
}
31-
} // $ class=(pack11).C2 instance=(pack11).C2.prototype
31+
} // $ name=(pack11).C2
3232

33-
function f3() {} // $ method=(pack11).C3.publicField.really.long.name
33+
function f3() {} // $ name=(pack11).C3.publicField.really.long.name
3434

3535
export class C3 {
3636
private static privateField = f3;
@@ -42,11 +42,11 @@ export class C3 {
4242
}
4343
}
4444
}
45-
} // $ class=(pack11).C3 instance=(pack11).C3.prototype
45+
} // $ name=(pack11).C3
4646

4747

4848
const f4 = {
49-
m() {} // $ method=(pack11).C4.really.long.name.m
49+
m() {} // $ name=(pack11).C4.really.long.name.m
5050
};
5151

5252
export const C4 = {

javascript/ql/test/library-tests/EndpointNaming/pack12/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ function wrap(fn) {
33
}
44

55
function f() {}
6-
export const f1 = wrap(f); // $ method=(pack12).f1
7-
export const f2 = wrap(f); // $ method=(pack12).f2
6+
export const f1 = wrap(f); // $ name=(pack12).f1
7+
export const f2 = wrap(f); // $ name=(pack12).f2
88

99
function g() {}
10-
export const g1 = wrap(g); // $ method=(pack12).g1
10+
export const g1 = wrap(g); // $ name=(pack12).g1
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
class AmbiguousClass {
2-
instanceMethod(foo) {} // $ method=(pack2).lib.LibClass.prototype.instanceMethod
3-
} // $ class=(pack2).lib.LibClass instance=(pack2).lib.LibClass.prototype
2+
instanceMethod(foo) {} // $ name=(pack2).lib.LibClass.prototype.instanceMethod
3+
} // $ name=(pack2).lib.LibClass
44

55
export default AmbiguousClass; // $ alias=(pack2).lib.default==(pack2).lib.LibClass
66
export { AmbiguousClass as LibClass }
77

8-
AmbiguousClass.foo = function() {} // $ method=(pack2).lib.LibClass.foo
8+
AmbiguousClass.foo = function() {} // $ name=(pack2).lib.LibClass.foo

javascript/ql/test/library-tests/EndpointNaming/pack2/main.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
class AmbiguousClass {
2-
instanceMethod() {} // $ method=(pack2).MainClass.prototype.instanceMethod
3-
} // $ class=(pack2).MainClass instance=(pack2).MainClass.prototype
2+
instanceMethod() {} // $ name=(pack2).MainClass.prototype.instanceMethod
3+
} // $ name=(pack2).MainClass
44

55
export default AmbiguousClass; // $ alias=(pack2).default==(pack2).MainClass
66
export { AmbiguousClass as MainClass }
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export default function(x,y,z) {} // $ method=(pack3).libFunction alias=(pack3).libFunction.default==(pack3).libFunction
1+
export default function(x,y,z) {} // $ name=(pack3).libFunction alias=(pack3).libFunction.default==(pack3).libFunction

0 commit comments

Comments
 (0)