mirror of
https://github.com/github/codeql.git
synced 2026-04-26 09:15:12 +02:00
Merge pull request #15380 from asgerf/js/endpoint-naming
JS: Add library for naming endpoints
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
testFailures
|
||||
ambiguousPreferredPredecessor
|
||||
ambiguousSinkName
|
||||
ambiguousClassObjectName
|
||||
ambiguousClassInstanceName
|
||||
ambiguousFunctionName
|
||||
failures
|
||||
@@ -0,0 +1,47 @@
|
||||
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", "class", "method", "alias"] }
|
||||
|
||||
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
|
||||
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)
|
||||
)
|
||||
)
|
||||
or
|
||||
element = "" and
|
||||
tag = "alias" and
|
||||
exists(
|
||||
API::Node aliasDef, string primaryPackage, string primaryName, string aliasPackage,
|
||||
string aliasName
|
||||
|
|
||||
EndpointNaming::aliasDefinition(primaryPackage, primaryName, aliasPackage, aliasName, aliasDef) and
|
||||
value =
|
||||
EndpointNaming::renderName(aliasPackage, aliasName) + "==" +
|
||||
EndpointNaming::renderName(primaryPackage, primaryName) and
|
||||
location = aliasDef.asSink().asExpr().getLocation()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<TestConfig>
|
||||
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "pack1",
|
||||
"main": "./main.js"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export default class FooClass {} // $ class=(pack10).Foo instance=(pack10).Foo.prototype
|
||||
@@ -0,0 +1,3 @@
|
||||
import { default as Foo } from "./foo";
|
||||
|
||||
export { Foo }
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "pack10",
|
||||
"main": "./index.js"
|
||||
}
|
||||
@@ -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; // $ alias=(pack2).lib.default==(pack2).lib.LibClass
|
||||
export { AmbiguousClass as LibClass }
|
||||
@@ -0,0 +1,9 @@
|
||||
class AmbiguousClass {
|
||||
instanceMethod() {} // $ method=(pack2).MainClass.prototype.instanceMethod
|
||||
} // $ class=(pack2).MainClass instance=(pack2).MainClass.prototype
|
||||
|
||||
export default AmbiguousClass; // $ alias=(pack2).default==(pack2).MainClass
|
||||
export { AmbiguousClass as MainClass }
|
||||
|
||||
import * as lib from "./lib";
|
||||
export { lib }
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "pack2",
|
||||
"main": "./main.js"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export default function(x,y,z) {} // $ method=(pack3).libFunction alias=(pack3).libFunction.default==(pack3).libFunction
|
||||
@@ -0,0 +1,7 @@
|
||||
function ambiguousFunction(x, y, z) {} // $ method=(pack3).namedFunction
|
||||
|
||||
export default ambiguousFunction; // $ alias=(pack3).default==(pack3).namedFunction
|
||||
export { ambiguousFunction as namedFunction };
|
||||
|
||||
import libFunction from "./lib";
|
||||
export { libFunction };
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "pack3",
|
||||
"main": "./main.js"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export default class C {} // $ class=(pack4) instance=(pack4).prototype
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "pack4",
|
||||
"main": "./index.js"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "pack5",
|
||||
"main": "./dist/index.js"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export default class C {} // $ class=(pack5) instance=(pack5).prototype
|
||||
@@ -0,0 +1,6 @@
|
||||
class C {
|
||||
instanceMethod() {} // $ method=(pack6).instanceMethod
|
||||
static staticMethod() {} // not accessible
|
||||
} // $ instance=(pack6)
|
||||
|
||||
export default new C();
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "pack6",
|
||||
"main": "./index.js"
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "pack7",
|
||||
"main": "./index.js"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
class Foo {} // $ class=(pack8).Foo instance=(pack8).Foo.prototype
|
||||
|
||||
module.exports = Foo;
|
||||
module.exports.default = Foo; // $ alias=(pack8).Foo.default==(pack8).Foo
|
||||
module.exports.Foo = Foo; // $ alias=(pack8).Foo.Foo==(pack8).Foo
|
||||
@@ -0,0 +1,5 @@
|
||||
class Main {} // $ class=(pack8) instance=(pack8).prototype
|
||||
|
||||
Main.Foo = require('./foo');
|
||||
|
||||
module.exports = Main;
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "pack8",
|
||||
"main": "./index.js"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export class Foo {} // $ instance=(pack9/foo).Foo.prototype
|
||||
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "pack9",
|
||||
"main": "./index.js"
|
||||
}
|
||||
@@ -3,6 +3,7 @@ groups: [javascript, test]
|
||||
dependencies:
|
||||
codeql/javascript-all: ${workspace}
|
||||
codeql/javascript-queries: ${workspace}
|
||||
codeql/util: ${workspace}
|
||||
extractor: javascript
|
||||
tests: .
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Inline expectation tests for JS.
|
||||
* See `shared/util/codeql/util/test/InlineExpectationsTest.qll`
|
||||
*/
|
||||
|
||||
private import codeql.util.test.InlineExpectationsTest
|
||||
private import internal.InlineExpectationsTestImpl
|
||||
import Make<Impl>
|
||||
@@ -0,0 +1,12 @@
|
||||
private import javascript as JS
|
||||
private import codeql.util.test.InlineExpectationsTest
|
||||
|
||||
module Impl implements InlineExpectationsTestSig {
|
||||
private import javascript
|
||||
|
||||
class ExpectationComment extends LineComment {
|
||||
string getContents() { result = this.getText() }
|
||||
}
|
||||
|
||||
class Location = JS::Location;
|
||||
}
|
||||
Reference in New Issue
Block a user