JS: Add library for naming endpoints

This commit is contained in:
Asger F
2024-01-15 13:54:41 +01:00
parent 6cfdd7aec4
commit 1737ba1a6b
29 changed files with 624 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
testFailures
ambiguousPreferredPredecessor
ambiguousSinkName
ambiguousClassObjectName
ambiguousClassInstanceName
ambiguousFunctionName
failures

View File

@@ -0,0 +1,41 @@
import javascript
import semmle.javascript.RestrictedLocations
import semmle.javascript.Lines
import semmle.javascript.endpoints.EndpointNaming as EndpointNaming
import testUtilities.InlineExpectationsTest
import EndpointNaming::Debug
module TestConfig implements TestSig {
string getARelevantTag() {
result = "instance"
or
result = "class"
or
result = "method"
}
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(string package, string name |
element = "" and
value = EndpointNaming::renderName(package, name)
|
exists(DataFlow::ClassNode cls | location = cls.getAstNode().getLocation() |
tag = "class" and
EndpointNaming::classObjectHasPrimaryName(cls, package, name)
or
tag = "instance" and
EndpointNaming::classInstanceHasPrimaryName(cls, package, name)
)
or
element = "" and
exists(DataFlow::FunctionNode function |
not function.getFunction() = any(ConstructorDeclaration decl | decl.isSynthetic()).getBody() and
location = function.getFunction().getLocation() and
tag = "method" and
EndpointNaming::functionHasPrimaryName(function, package, name)
)
)
}
}
import MakeTest<TestConfig>

View File

@@ -0,0 +1,13 @@
export class PublicClass {} // $ class=(pack1).PublicClass instance=(pack1).PublicClass.prototype
class PrivateClass {}
export const ExportedConst = class ExportedConstClass {} // $ class=(pack1).ExportedConst instance=(pack1).ExportedConst.prototype
class ClassWithEscapingInstance {} // $ instance=(pack1).ClassWithEscapingInstance.prototype
export function getEscapingInstance() {
return new ClassWithEscapingInstance();
} // $ method=(pack1).getEscapingInstance
export function publicFunction() {} // $ method=(pack1).publicFunction

View File

@@ -0,0 +1,4 @@
{
"name": "pack1",
"main": "./main.js"
}

View File

@@ -0,0 +1 @@
export default class FooClass {} // $ class=(pack10).Foo instance=(pack10).Foo.prototype

View File

@@ -0,0 +1,3 @@
import { default as Foo } from "./foo";
export { Foo }

View File

@@ -0,0 +1,4 @@
{
"name": "pack10",
"main": "./index.js"
}

View File

@@ -0,0 +1,6 @@
class AmbiguousClass {
instanceMethod(foo) {} // $ method=(pack2).lib.LibClass.prototype.instanceMethod
} // $ class=(pack2).lib.LibClass instance=(pack2).lib.LibClass.prototype
export default AmbiguousClass;
export { AmbiguousClass as LibClass }

View File

@@ -0,0 +1,9 @@
class AmbiguousClass {
instanceMethod() {} // $ method=(pack2).MainClass.prototype.instanceMethod
} // $ class=(pack2).MainClass instance=(pack2).MainClass.prototype
export default AmbiguousClass;
export { AmbiguousClass as MainClass }
import * as lib from "./lib";
export { lib }

View File

@@ -0,0 +1,4 @@
{
"name": "pack2",
"main": "./main.js"
}

View File

@@ -0,0 +1 @@
export default function(x,y,z) {} // $ method=(pack3).libFunction

View File

@@ -0,0 +1,7 @@
function ambiguousFunction(x, y, z) {} // $ method=(pack3).namedFunction
export default ambiguousFunction;
export { ambiguousFunction as namedFunction };
import libFunction from "./lib";
export { libFunction };

View File

@@ -0,0 +1,4 @@
{
"name": "pack3",
"main": "./main.js"
}

View File

@@ -0,0 +1 @@
export default class C {} // $ class=(pack4) instance=(pack4).prototype

View File

@@ -0,0 +1,4 @@
{
"name": "pack4",
"main": "./index.js"
}

View File

@@ -0,0 +1,4 @@
{
"name": "pack5",
"main": "./dist/index.js"
}

View File

@@ -0,0 +1 @@
export default class C {} // $ class=(pack5) instance=(pack5).prototype

View File

@@ -0,0 +1,6 @@
class C {
instanceMethod() {} // $ method=(pack6).instanceMethod
static staticMethod() {} // not accessible
} // $ instance=(pack6)
export default new C();

View File

@@ -0,0 +1,4 @@
{
"name": "pack6",
"main": "./index.js"
}

View File

@@ -0,0 +1,6 @@
export class D {} // $ class=(pack7).D instance=(pack7).D.prototype
// In this case we are forced to include ".default" to avoid ambiguity with class D above.
export default {
D: class {} // $ class=(pack7).default.D instance=(pack7).default.D.prototype
};

View File

@@ -0,0 +1,4 @@
{
"name": "pack7",
"main": "./index.js"
}

View File

@@ -0,0 +1,5 @@
class Foo {} // $ class=(pack8).Foo instance=(pack8).Foo.prototype
module.exports = Foo;
module.exports.default = Foo;
module.exports.Foo = Foo;

View File

@@ -0,0 +1,5 @@
class Main {} // $ class=(pack8) instance=(pack8).prototype
Main.Foo = require('./foo');
module.exports = Main;

View File

@@ -0,0 +1,4 @@
{
"name": "pack8",
"main": "./index.js"
}

View File

@@ -0,0 +1 @@
export class Foo {} // $ instance=(pack9/foo).Foo.prototype

View File

@@ -0,0 +1,9 @@
// Only the type is exposed. For the time being we do not consider type-only declarations or .d.ts files
// when naming classes.
export type { Foo } from "./foo";
import * as foo from "./foo";
export function expose() {
return new foo.Foo(); // expose an instance of Foo but not the class
} // $ method=(pack9).expose

View File

@@ -0,0 +1,4 @@
{
"name": "pack9",
"main": "./index.js"
}