From e2703e4768b523218c94562c812eef6df942d4af Mon Sep 17 00:00:00 2001 From: Dimitri Stallenberg Date: Wed, 16 Aug 2023 14:10:48 +0200 Subject: [PATCH 01/14] fix: add types matches for call and array --- .../resolving/InferenceTypeModelFactory.ts | 63 ++++++++++-------- .../lib/type/resolving/Type.ts | 4 +- .../lib/type/resolving/TypeModel.ts | 66 +++++++++---------- .../sampling/JavaScriptRandomSampler.ts | 53 +++++---------- .../sampling/JavaScriptTestCaseSampler.ts | 6 +- .../statements/complex/ArrayStatement.ts | 6 +- 6 files changed, 91 insertions(+), 107 deletions(-) diff --git a/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts b/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts index 3eaff0cf0..21b3bf695 100644 --- a/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts +++ b/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts @@ -211,16 +211,16 @@ export class InferenceTypeModelFactory extends TypeModelFactory { if (argumentId !== undefined) { this._typeModel.addRelationScore(relationId, argumentId); - this._typeModel.addReturn(functionId, argumentId); + this._typeModel.addReturnType(functionId, argumentId); } break; } case RelationType.Call: { // TODO currently not possible because of the way the relations are created - // const [functionId, ...arguments_] = involved; + const [functionId, ...arguments_] = involved; - const [functionId] = involved; + // const [functionId] = involved; this._typeModel.addTypeScore(functionId, TypeEnum.FUNCTION); @@ -232,15 +232,16 @@ export class InferenceTypeModelFactory extends TypeModelFactory { } // TODO - // // couple function arguments with function parameters - // if (arguments_.length > type.parameters.size) { - // throw new Error(`Function ${functionId} has ${type.parameters.size} parameters, but was called with ${arguments_.length} arguments`) - // } - - // for (const [index, argumentId] of arguments_.entries()) { - // const parameterId = type.parameters.get(index) - // this._typeModel.addRelationScore(parameterId, argumentId) - // } + // couple function arguments with function parameters + if (type && type.parameters.size > 0) { + const smallest = Math.min(arguments_.length, type.parameters.size); + + for (let index = 0; index < smallest; index++) { + const argumentId = arguments_[index]; + const parameterId = type.parameters.get(index); + this._typeModel.addRelationScore(parameterId, argumentId); + } + } break; } @@ -259,7 +260,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { ? propertyElement.name : propertyElement.value; - this._typeModel.addProperty(relationId, propertyName, propertyId); + this._typeModel.addPropertyType(relationId, propertyName, propertyId); } else { // TODO what if the property is not an element (spread element for example) } @@ -281,11 +282,11 @@ export class InferenceTypeModelFactory extends TypeModelFactory { ? propertyElement.name : propertyElement.value; - this._typeModel.addProperty(relationId, propertyName, functionId); + this._typeModel.addPropertyType(relationId, propertyName, functionId); // create function type for (const [index, id] of parameters.entries()) { - this._typeModel.addParameter(functionId, index, id); + this._typeModel.addParameterType(functionId, index, id); } break; @@ -311,7 +312,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { : propertyElement.value; // make object for the class - this._typeModel.addProperty(classId, propertyName, propertyId); + this._typeModel.addPropertyType(classId, propertyName, propertyId); // connect property to value if (valueId !== undefined) { @@ -350,7 +351,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { // TODO maybe not for setter / getter // make function for the method for (const [index, id] of parameters.entries()) { - this._typeModel.addParameter(functionId, index, id); + this._typeModel.addParameterType(functionId, index, id); } break; @@ -361,8 +362,8 @@ export class InferenceTypeModelFactory extends TypeModelFactory { this._typeModel.addTypeScore(relationId, TypeEnum.ARRAY); // create array type - for (const [index, id] of elements.entries()) { - this._typeModel.addElement(relationId, index, id); + for (const id of elements) { + this._typeModel.addElementType(relationId, id); } break; @@ -470,8 +471,8 @@ export class InferenceTypeModelFactory extends TypeModelFactory { const elements = involved; // create array type - for (const [index, id] of elements.entries()) { - this._typeModel.addElement(relationId, index, id); + for (const id of elements) { + this._typeModel.addElementType(relationId, id); } break; @@ -509,7 +510,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { const [_identifierId, ...parameters] = involved; for (const [index, id] of parameters.entries()) { - this._typeModel.addParameter(functionId, index, id); + this._typeModel.addParameterType(functionId, index, id); } // connect function to relation @@ -552,18 +553,22 @@ export class InferenceTypeModelFactory extends TypeModelFactory { // e.g. object[0] // add array type to object this._typeModel.addTypeScore(objectId, TypeEnum.ARRAY); - this._typeModel.addTypeScore(objectId, TypeEnum.STRING); + this._typeModel.addElementType(objectId, relationId); } else if (propertyElement.type === ElementType.StringLiteral) { // e.g. object["abc"] // add array type to object this._typeModel.addTypeScore(objectId, TypeEnum.OBJECT); + this._typeModel.addPropertyType( + objectId, + propertyElement.value, + propertyId + ); } else { - const propertyName = - "name" in propertyElement - ? propertyElement.name - : propertyElement.value; - - this._typeModel.addProperty(objectId, propertyName, propertyId); + // const propertyName = + // "name" in propertyElement + // ? propertyElement.name + // : propertyElement.value; + // this._typeModel.addProperty(objectId, propertyName, propertyId); } // we don't have to connect the relationid to the propertyId since they are equal already diff --git a/libraries/analysis-javascript/lib/type/resolving/Type.ts b/libraries/analysis-javascript/lib/type/resolving/Type.ts index a4e659d3a..5fc59837d 100644 --- a/libraries/analysis-javascript/lib/type/resolving/Type.ts +++ b/libraries/analysis-javascript/lib/type/resolving/Type.ts @@ -21,8 +21,8 @@ export interface ObjectType { properties: Map; // array - // index -> id - elements: Map; + // id + elements: Set; // function // index -> id diff --git a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts index 8a66426ff..0f1954ab0 100644 --- a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts +++ b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts @@ -81,7 +81,7 @@ export class TypeModel { this._objectTypeDescription.set(id, { properties: new Map(), - elements: new Map(), + elements: new Set(), parameters: new Map(), return: new Set(), }); @@ -114,22 +114,21 @@ export class TypeModel { if (!this._elementTypeScoreMap.get(id).has(type)) { this._elementTypeScoreMap.get(id).set(type, 0); } + if (!this._typeExecutionScoreMap.get(id).has(type)) { + this._typeExecutionScoreMap.get(id).set(type, 0); + } const currentScore = this._elementTypeScoreMap.get(id).get(type); this._elementTypeScoreMap.get(id).set(type, currentScore + score); this._scoreHasChangedMap.set(id, true); - if (!this._typeExecutionScoreMap.get(id).has(type)) { - this._typeExecutionScoreMap.get(id).set(type, 0); - } - if (type === TypeEnum.NUMERIC) { this.addTypeScore(id, TypeEnum.INTEGER, score); } } - addProperty(element: string, property: string, id: string) { + addPropertyType(element: string, property: string, id: string) { // check if the property is from a string/array/function if (functionProperties.has(property)) { @@ -149,19 +148,19 @@ export class TypeModel { this.getObjectDescription(element).properties.set(property, id); } - addParameter(element: string, index: number, id: string) { + addParameterType(element: string, index: number, id: string) { this.addTypeScore(element, TypeEnum.FUNCTION); this.getObjectDescription(element).parameters.set(index, id); } - addReturn(element: string, returnId: string) { + addReturnType(element: string, returnId: string) { this.addTypeScore(element, TypeEnum.FUNCTION); this.getObjectDescription(element).return.add(returnId); } - addElement(element: string, index: number, id: string) { + addElementType(element: string, id: string) { this.addTypeScore(element, TypeEnum.ARRAY); - this.getObjectDescription(element).elements.set(index, id); + this.getObjectDescription(element).elements.add(id); } // TODO type should be TypeEnum? @@ -210,6 +209,8 @@ export class TypeModel { id ); + console.log(probabilities); + const genericTypes = [ TypeEnum.ARRAY, TypeEnum.BOOLEAN, @@ -227,7 +228,10 @@ export class TypeModel { return prng.pickOne(genericTypes); } - if (prng.nextBoolean(randomTypeProbability)) { + if ( + this._sum(probabilities.values()) === 0 || + prng.nextBoolean(randomTypeProbability) + ) { return prng.pickOne([ ...new Set([...probabilities.keys(), ...genericTypes]), ]); @@ -387,6 +391,10 @@ export class TypeModel { totalScore += score; } + if (totalScore === 0) { + totalScore = 1; + } + for (const [type, score] of typeScoreMap.entries()) { probabilityMap.set(type, score / totalScore); } @@ -434,15 +442,6 @@ export class TypeModel { } } - // sanity check - // const totalProbability = this._sum(probabilityMap.values()); - - // if (Math.abs(totalProbability - 1) > 0.0001) { - // throw new Error( - // `Total probability should be 1, but is ${totalProbability}` - // ); - // } - // incorporate execution scores const executionScoreMap = this._typeExecutionScoreMap.get(id); @@ -454,10 +453,7 @@ export class TypeModel { let totalScore = 0; for (const type of probabilityMap.keys()) { - let score = executionScoreMap.has(type) - ? executionScoreMap.get(type) - : 0; - + let score = executionScoreMap.get(type) ?? 0; score -= minValue; score += 1; totalScore += score; @@ -471,6 +467,10 @@ export class TypeModel { throw new Error("Total score should be positive"); } + if (Number.isNaN(totalScore)) { + throw new TypeError("Total score should be positive"); + } + // incorporate execution score for (const type of probabilityMap.keys()) { let score = executionScoreMap.has(type) @@ -485,17 +485,17 @@ export class TypeModel { probabilityMap.set(type, newProbability); } + } - // normalize to 1 - let totalProbability = 0; - for (const probability of probabilityMap.values()) { - totalProbability += probability; - } + // normalize to 1 + let totalProbability = 0; + for (const probability of probabilityMap.values()) { + totalProbability += probability; + } - if (totalProbability !== 0) { - for (const [type, probability] of probabilityMap.entries()) { - probabilityMap.set(type, probability / totalProbability); - } + if (totalProbability !== 0) { + for (const [type, probability] of probabilityMap.entries()) { + probabilityMap.set(type, probability / totalProbability); } } diff --git a/libraries/search-javascript/lib/testcase/sampling/JavaScriptRandomSampler.ts b/libraries/search-javascript/lib/testcase/sampling/JavaScriptRandomSampler.ts index ae6e80298..dc37cc979 100644 --- a/libraries/search-javascript/lib/testcase/sampling/JavaScriptRandomSampler.ts +++ b/libraries/search-javascript/lib/testcase/sampling/JavaScriptRandomSampler.ts @@ -431,21 +431,12 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { } // arguments - sampleArrayArgument( - depth: number, - arrayId: string, - index: number - ): Statement { + sampleArrayArgument(depth: number, arrayId: string): Statement { const arrayType = this.rootContext .getTypeModel() .getObjectDescription(arrayId); - const element = arrayType.elements.get(index); - if (element) { - return this.sampleArgument(depth, element, String(index)); - } - - const childIds = [...arrayType.elements.values()]; + const childIds = [...arrayType.elements]; if (childIds.length === 0) { // TODO should be done in the typemodel somehow @@ -454,7 +445,8 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { return this.sampleArgument(depth, "anon", "anon"); } - return this.sampleArgument(depth, prng.pickOne(childIds), String(index)); + const element = prng.pickOne(childIds); + return this.sampleArgument(depth, element, ""); } sampleObjectArgument( @@ -479,6 +471,7 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { sampleArgument(depth: number, id: string, name: string): Statement { let chosenType: string; + console.log(id, name); switch (this.typeInferenceMode) { case "none": { chosenType = this.rootContext @@ -515,7 +508,7 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { ); } } - + console.log("type", chosenType); if (chosenType.endsWith("object")) { return this.sampleObject(depth, id, name, chosenType); } else if (chosenType.endsWith("array")) { @@ -679,30 +672,20 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { .getTypeModel() .getObjectDescription(typeId); - const children: Statement[] = []; - - for (const [index] of typeObject.elements.entries()) { - children[index] = this.sampleArrayArgument(depth + 1, id, index); - } - - // TODO should be done in the typemodel somehow - // maybe create types for the subproperties by doing /main/array/id::1::1[element-index] - // maybe create types for the subproperties by doing /main/array/id::1::1.property + console.log("------------------"); + console.log("id", id); + console.log("type", typeId); + console.log(typeObject.elements); + console.log("------------------"); - if (children.length === 0) { - children.push(this.sampleArrayArgument(depth + 1, id, 0)); - } + const children: Statement[] = []; - // if some children are missing, fill them with fake params - const childIds = [...typeObject.elements.values()]; - for (let index = 0; index < children.length; index++) { - if (!children[index]) { - children[index] = this.sampleArgument( - depth + 1, - prng.pickOne(childIds), - String(index) - ); - } + for ( + let index = 0; + index < prng.nextInt(0, this.maxActionStatements); + index++ + ) { + children.push(this.sampleArrayArgument(depth + 1, typeId)); } return new ArrayStatement( diff --git a/libraries/search-javascript/lib/testcase/sampling/JavaScriptTestCaseSampler.ts b/libraries/search-javascript/lib/testcase/sampling/JavaScriptTestCaseSampler.ts index fb62b54c4..03e7df840 100644 --- a/libraries/search-javascript/lib/testcase/sampling/JavaScriptTestCaseSampler.ts +++ b/libraries/search-javascript/lib/testcase/sampling/JavaScriptTestCaseSampler.ts @@ -240,11 +240,7 @@ export abstract class JavaScriptTestCaseSampler extends EncodingSampler Date: Wed, 16 Aug 2023 22:15:35 +0200 Subject: [PATCH 02/14] feat: improve type inference model --- libraries/analysis-javascript/index.ts | 1 + libraries/analysis-javascript/lib/Events.ts | 48 +++++ .../analysis-javascript/lib/RootContext.ts | 199 +++++++++++++++--- .../lib/type/discovery/TypeExtractor.ts | 86 ++------ .../type/discovery/object/ObjectVisitor.ts | 28 +-- .../discovery/relation/RelationVisitor.ts | 6 +- .../resolving/InferenceTypeModelFactory.ts | 138 +++++++----- .../lib/type/resolving/Type.ts | 2 + .../lib/type/resolving/TypeModel.ts | 18 +- .../lib/type/resolving/TypeModelFactory.ts | 4 +- .../lib/type/resolving/TypePool.ts | 15 +- .../lib/AbstractSyntaxTreeVisitor.ts | 4 +- .../sampling/JavaScriptRandomSampler.ts | 19 +- .../generators/action/CallGenerator.ts | 36 +--- .../statements/complex/ArrayStatement.ts | 1 - .../CHANGELOG.md | 4 + .../LICENSE.header.ts | 17 ++ .../NOTICE | 5 + .../README.md | 1 + .../index.ts | 19 ++ .../lib/StateStorage.ts | 158 ++++++++++++++ .../lib/StateStorageEventListenerPlugin.ts | 120 +++++++++++ .../lib/StateStorageModule.ts | 45 ++++ .../package.json | 64 ++++++ .../test/simulation.test.ts | 31 +++ .../tsconfig.json | 9 + tools/javascript/lib/JavaScriptLauncher.ts | 4 +- 27 files changed, 844 insertions(+), 238 deletions(-) create mode 100644 libraries/analysis-javascript/lib/Events.ts create mode 100644 plugins/plugin-javascript-event-listener-state-storage/CHANGELOG.md create mode 100644 plugins/plugin-javascript-event-listener-state-storage/LICENSE.header.ts create mode 100644 plugins/plugin-javascript-event-listener-state-storage/NOTICE create mode 100644 plugins/plugin-javascript-event-listener-state-storage/README.md create mode 100644 plugins/plugin-javascript-event-listener-state-storage/index.ts create mode 100644 plugins/plugin-javascript-event-listener-state-storage/lib/StateStorage.ts create mode 100644 plugins/plugin-javascript-event-listener-state-storage/lib/StateStorageEventListenerPlugin.ts create mode 100644 plugins/plugin-javascript-event-listener-state-storage/lib/StateStorageModule.ts create mode 100644 plugins/plugin-javascript-event-listener-state-storage/package.json create mode 100644 plugins/plugin-javascript-event-listener-state-storage/test/simulation.test.ts create mode 100644 plugins/plugin-javascript-event-listener-state-storage/tsconfig.json diff --git a/libraries/analysis-javascript/index.ts b/libraries/analysis-javascript/index.ts index 671022577..18aff41c5 100644 --- a/libraries/analysis-javascript/index.ts +++ b/libraries/analysis-javascript/index.ts @@ -59,4 +59,5 @@ export * from "./lib/type/resolving/InferenceTypeModelFactory"; export * from "./lib/utils/fileSystem"; +export * from "./lib/Events"; export * from "./lib/RootContext"; diff --git a/libraries/analysis-javascript/lib/Events.ts b/libraries/analysis-javascript/lib/Events.ts new file mode 100644 index 000000000..28001fc05 --- /dev/null +++ b/libraries/analysis-javascript/lib/Events.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2020-2023 Delft University of Technology and SynTest contributors + * + * This file is part of SynTest Framework - SynTest JavaScript. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { RootContext } from "./RootContext"; + +export type Events = { + exportExtractionStart: (rootContext: RootContext, filepath: string) => void; + exportExtractionComplete: ( + rootContext: RootContext, + filepath: string + ) => void; + elementExtractionStart: (rootContext: RootContext, filepath: string) => void; + elementExtractionComplete: ( + rootContext: RootContext, + filepath: string + ) => void; + relationExtractionStart: (rootContext: RootContext, filepath: string) => void; + relationExtractionComplete: ( + rootContext: RootContext, + filepath: string + ) => void; + objectTypeExtractionStart: ( + rootContext: RootContext, + filepath: string + ) => void; + objectTypeExtractionComplete: ( + rootContext: RootContext, + filepath: string + ) => void; + + typeResolvingStart: (rootContext: RootContext) => void; + typeResolvingComplete: (rootContext: RootContext) => void; +}; diff --git a/libraries/analysis-javascript/lib/RootContext.ts b/libraries/analysis-javascript/lib/RootContext.ts index 06044df5a..e1dbfefbc 100644 --- a/libraries/analysis-javascript/lib/RootContext.ts +++ b/libraries/analysis-javascript/lib/RootContext.ts @@ -35,6 +35,8 @@ import { Element } from "./type/discovery/element/Element"; import { DiscoveredObjectType } from "./type/discovery/object/DiscoveredType"; import { Relation } from "./type/discovery/relation/Relation"; import { TypePool } from "./type/resolving/TypePool"; +import TypedEmitter from "typed-emitter"; +import { Events } from "./Events"; export class RootContext extends CoreRootContext { protected _exportFactory: ExportFactory; @@ -42,9 +44,12 @@ export class RootContext extends CoreRootContext { protected _typeResolver: TypeModelFactory; protected _files: string[]; - protected _elementMap: Map; - protected _relationMap: Map; - protected _objectMap: Map; + // filepath -> id -> element + protected _elementMap: Map>; + // filepath -> id -> relation + protected _relationMap: Map>; + // filepath -> id -> object + protected _objectMap: Map>; protected _typeModel: TypeModel; protected _typePool: TypePool; @@ -126,13 +131,26 @@ export class RootContext extends CoreRootContext { return this._sources.get(absoluteTargetPath); } - private getExports(filePath: string): Export[] { + getExports(filePath: string): Export[] { const absolutePath = this.resolvePath(filePath); if (!this._exportMap.has(absolutePath)) { - return this._exportFactory.extract( + (>process).emit( + "exportExtractionStart", + this, + absolutePath + ); + this._exportMap.set( absolutePath, - this.getAbstractSyntaxTree(absolutePath) + this._exportFactory.extract( + absolutePath, + this.getAbstractSyntaxTree(absolutePath) + ) + ); + (>process).emit( + "exportExtractionComplete", + this, + absolutePath ); } @@ -150,26 +168,137 @@ export class RootContext extends CoreRootContext { return this._exportMap; } - extractTypes(): void { - if (!this._elementMap || !this._relationMap || !this._objectMap) { - this._typeExtractor.extractAll(this); - this._elementMap = this._typeExtractor.elementMap; - this._relationMap = this._typeExtractor.relationMap; - this._objectMap = this._typeExtractor.objectMap; + getElements(filepath: string) { + const absolutePath = this.resolvePath(filepath); + + if (!this._elementMap.has(absolutePath)) { + (>process).emit( + "elementExtractionStart", + this, + absolutePath + ); + const elementMap = this._typeExtractor.extractElements( + absolutePath, + this.getAbstractSyntaxTree(absolutePath) + ); + + this._elementMap.set(absolutePath, elementMap); + (>process).emit( + "elementExtractionComplete", + this, + absolutePath + ); + } + + return this._elementMap.get(absolutePath); + } + + getAllElements() { + if (!this._elementMap) { + this._elementMap = new Map(); + + for (const filepath of this.getFiles()) { + this._elementMap.set(filepath, this.getElements(filepath)); + } + } + return this._elementMap; + } + + getRelations(filepath: string) { + const absolutePath = this.resolvePath(filepath); + + if (!this._relationMap.has(absolutePath)) { + (>process).emit( + "relationExtractionStart", + this, + absolutePath + ); + const relationsMap = this._typeExtractor.extractRelations( + absolutePath, + this.getAbstractSyntaxTree(absolutePath) + ); + + this._relationMap.set(absolutePath, relationsMap); + (>process).emit( + "relationExtractionComplete", + this, + absolutePath + ); } + + return this._relationMap.get(absolutePath); + } + + getAllRelations() { + if (!this._relationMap) { + this._relationMap = new Map(); + + for (const filepath of this.getFiles()) { + this._relationMap.set(filepath, this.getRelations(filepath)); + } + } + return this._relationMap; + } + + getObjectTypes(filepath: string) { + const absolutePath = this.resolvePath(filepath); + + if (!this._objectMap.has(absolutePath)) { + (>process).emit( + "objectTypeExtractionStart", + this, + absolutePath + ); + const objectsMap = this._typeExtractor.extractObjectTypes( + absolutePath, + this.getAbstractSyntaxTree(absolutePath) + ); + + this._objectMap.set(absolutePath, objectsMap); + (>process).emit( + "objectTypeExtractionComplete", + this, + absolutePath + ); + } + + return this._objectMap.get(absolutePath); + } + + getAllObjectTypes() { + if (!this._objectMap) { + this._objectMap = new Map(); + + for (const filepath of this.getFiles()) { + this._objectMap.set(filepath, this.getObjectTypes(filepath)); + } + } + return this._objectMap; } resolveTypes(): void { - if (!this._elementMap || !this._relationMap || !this._objectMap) { - this.extractTypes(); + // TODO allow sub selections of files (do not consider entire context) + if (!this._elementMap) { + this.getAllElements(); + } + if (!this._relationMap) { + this.getAllRelations(); + } + if (!this._objectMap) { + this.getAllObjectTypes(); + } + if (!this._exportMap) { + this.getAllExports(); } if (!this._typeModel) { + (>process).emit("typeResolvingStart", this); this._typeModel = this._typeResolver.resolveTypes( this._elementMap, this._relationMap ); - this._typePool = new TypePool(this._objectMap, this.getAllExports()); + this._typePool = new TypePool(this._objectMap, this._exportMap); + (>process).emit("typeResolvingComplete", this); } } @@ -189,24 +318,24 @@ export class RootContext extends CoreRootContext { return this._typePool; } - getElement(id: string): Element { - if (!this._elementMap || !this._elementMap.has(id)) { - this.extractTypes(); - } - return this._elementMap.get(id); - } - - getRelation(id: string): Relation { - if (!this._relationMap || !this._relationMap.has(id)) { - this.extractTypes(); - } - return this._relationMap.get(id); - } - - getObject(id: string): DiscoveredObjectType { - if (!this._objectMap || !this._objectMap.has(id)) { - this.extractTypes(); - } - return this._objectMap.get(id); - } + // getElement(id: string): Element { + // if (!this._elementMap || !this._elementMap.has(id)) { + // this.extractTypes(); + // } + // return this._elementMap.get(id); + // } + + // getRelation(id: string): Relation { + // if (!this._relationMap || !this._relationMap.has(id)) { + // this.extractTypes(); + // } + // return this._relationMap.get(id); + // } + + // getObject(id: string): DiscoveredObjectType { + // if (!this._objectMap || !this._objectMap.has(id)) { + // this.extractTypes(); + // } + // return this._objectMap.get(id); + // } } diff --git a/libraries/analysis-javascript/lib/type/discovery/TypeExtractor.ts b/libraries/analysis-javascript/lib/type/discovery/TypeExtractor.ts index 813834e56..710749d92 100644 --- a/libraries/analysis-javascript/lib/type/discovery/TypeExtractor.ts +++ b/libraries/analysis-javascript/lib/type/discovery/TypeExtractor.ts @@ -19,89 +19,33 @@ import { ObjectVisitor } from "./object/ObjectVisitor"; import traverse from "@babel/traverse"; import { ElementVisitor } from "./element/ElementVisitor"; import { RelationVisitor } from "./relation/RelationVisitor"; -import { RootContext } from "../../RootContext"; -import { Element } from "./element/Element"; -import { Relation } from "./relation/Relation"; -import { DiscoveredObjectType } from "./object/DiscoveredType"; +// import { Element } from "./element/Element"; +// import { Relation } from "./relation/Relation"; +// import { DiscoveredObjectType } from "./object/DiscoveredType"; +import * as t from "@babel/types"; export class TypeExtractor { - private _elementMap: Map; - private _relationMap: Map; - private _objectMap: Map; - - constructor() { - this._elementMap = new Map(); - this._relationMap = new Map(); - this._objectMap = new Map(); - } - - extractAll(rootContext: RootContext) { - const files = rootContext.getFiles(); - - for (const file of files) { - this.extract(rootContext, file); - } - } - - extract(rootContext: RootContext, filePath: string) { - const elementVisitor = new ElementVisitor(filePath); - const relationVisitor = new RelationVisitor(filePath); - const objectVisitor = new ObjectVisitor(filePath); - - const ast = rootContext.getAbstractSyntaxTree(filePath); - // traverse( - // ast, - // visitors.merge([elementVisitor, relationVisitor, complexTypeVisitor]) - // ); + extractElements(filepath: string, ast: t.Node) { + const elementVisitor = new ElementVisitor(filepath); traverse(ast, elementVisitor); - traverse(ast, relationVisitor); - traverse(ast, objectVisitor); - this._elementMap = new Map([ - ...this._elementMap, - ...elementVisitor.elementMap, - ]); - this._relationMap = new Map([ - ...this._relationMap, - ...relationVisitor.relationMap, - ]); - this._objectMap = new Map([ - ...this._objectMap, - ...objectVisitor.complexTypeMap, - ]); + return elementVisitor.elementMap; } - getElement(id: string): Element { - if (!this._elementMap.has(id)) { - throw new Error(`Element with id ${id} does not exist`); - } - return this._elementMap.get(id); - } + extractRelations(filepath: string, ast: t.Node) { + const relationVisitor = new RelationVisitor(filepath); - getRelation(id: string): Relation { - if (!this._relationMap.has(id)) { - throw new Error(`Relation with id ${id} does not exist`); - } - return this._relationMap.get(id); - } + traverse(ast, relationVisitor); - getObjectType(id: string): DiscoveredObjectType { - if (!this._objectMap.has(id)) { - throw new Error(`ComplexType with id ${id} does not exist`); - } - return this._objectMap.get(id); + return relationVisitor.relationMap; } - get elementMap(): Map { - return this._elementMap; - } + extractObjectTypes(filepath: string, ast: t.Node) { + const objectVisitor = new ObjectVisitor(filepath); - get relationMap(): Map { - return this._relationMap; - } + traverse(ast, objectVisitor); - get objectMap(): Map { - return this._objectMap; + return objectVisitor.objectTypeMap; } } diff --git a/libraries/analysis-javascript/lib/type/discovery/object/ObjectVisitor.ts b/libraries/analysis-javascript/lib/type/discovery/object/ObjectVisitor.ts index eb1864b08..b00603f31 100644 --- a/libraries/analysis-javascript/lib/type/discovery/object/ObjectVisitor.ts +++ b/libraries/analysis-javascript/lib/type/discovery/object/ObjectVisitor.ts @@ -21,18 +21,18 @@ import { AbstractSyntaxTreeVisitor } from "@syntest/ast-visitor-javascript"; import { DiscoveredObjectKind, DiscoveredType } from "./DiscoveredType"; export class ObjectVisitor extends AbstractSyntaxTreeVisitor { - private _complexTypeMap: Map; + private _objectTypeMap: Map; // TODO separate stack for static and non-static properties private _objectStack: DiscoveredType[]; - get complexTypeMap(): Map { - return this._complexTypeMap; + get objectTypeMap(): Map { + return this._objectTypeMap; } constructor(filePath: string) { super(filePath); - this._complexTypeMap = new Map(); + this._objectTypeMap = new Map(); this._objectStack = []; } @@ -87,7 +87,7 @@ export class ObjectVisitor extends AbstractSyntaxTreeVisitor { kind: DiscoveredObjectKind.CLASS, properties: new Map(), }; - this._complexTypeMap.set(this._getNodeId(path), complexType); + this._objectTypeMap.set(this._getNodeId(path), complexType); this._objectStack.push(complexType); path.get("body").visit(); @@ -105,7 +105,7 @@ export class ObjectVisitor extends AbstractSyntaxTreeVisitor { kind: DiscoveredObjectKind.CLASS, properties: new Map(), }; - this._complexTypeMap.set(this._getNodeId(path), complexType); + this._objectTypeMap.set(this._getNodeId(path), complexType); this._objectStack.push(complexType); path.get("body").visit(); @@ -169,7 +169,7 @@ export class ObjectVisitor extends AbstractSyntaxTreeVisitor { kind: DiscoveredObjectKind.OBJECT, properties: new Map(), }; - this._complexTypeMap.set(this._getNodeId(path), complexType); + this._objectTypeMap.set(this._getNodeId(path), complexType); this._objectStack.push(complexType); for (const property of path.get("properties")) { @@ -189,7 +189,7 @@ export class ObjectVisitor extends AbstractSyntaxTreeVisitor { kind: DiscoveredObjectKind.OBJECT, properties: new Map(), }; - this._complexTypeMap.set(this._getNodeId(path), complexType); + this._objectTypeMap.set(this._getNodeId(path), complexType); this._objectStack.push(complexType); for (const property of path.get("properties")) { @@ -236,7 +236,7 @@ export class ObjectVisitor extends AbstractSyntaxTreeVisitor { kind: DiscoveredObjectKind.FUNCTION, properties: new Map(), }; - this._complexTypeMap.set(this._getNodeId(path), complexType); + this._objectTypeMap.set(this._getNodeId(path), complexType); this._objectStack.push(complexType); path.get("body").visit(); @@ -254,7 +254,7 @@ export class ObjectVisitor extends AbstractSyntaxTreeVisitor { kind: DiscoveredObjectKind.FUNCTION, properties: new Map(), }; - this._complexTypeMap.set(this._getNodeId(path), complexType); + this._objectTypeMap.set(this._getNodeId(path), complexType); this._objectStack.push(complexType); path.get("body").visit(); @@ -272,7 +272,7 @@ export class ObjectVisitor extends AbstractSyntaxTreeVisitor { kind: DiscoveredObjectKind.FUNCTION, properties: new Map(), }; - this._complexTypeMap.set(this._getNodeId(path), complexType); + this._objectTypeMap.set(this._getNodeId(path), complexType); this._objectStack.push(complexType); path.get("body").visit(); @@ -292,7 +292,7 @@ export class ObjectVisitor extends AbstractSyntaxTreeVisitor { if (path.node.object.type === "ThisExpression") { const parent = this._getThisParent(path); - const _object = this.complexTypeMap.get(this._getNodeId(parent)); + const _object = this.objectTypeMap.get(this._getNodeId(parent)); if (!_object) { throw new Error(`Unexpected object type: ${path.node.object.type}`); @@ -309,7 +309,7 @@ export class ObjectVisitor extends AbstractSyntaxTreeVisitor { } } else if (path.node.object.type === "Identifier") { const bindingId = this._getBindingId(path.get("object")); - let _object = this.complexTypeMap.get(bindingId); + let _object = this.objectTypeMap.get(bindingId); if (!_object) { _object = { @@ -317,7 +317,7 @@ export class ObjectVisitor extends AbstractSyntaxTreeVisitor { kind: DiscoveredObjectKind.OBJECT, // not sure actually properties: new Map(), }; - this._complexTypeMap.set(bindingId, _object); + this._objectTypeMap.set(bindingId, _object); } if (path.node.property.type === "PrivateName") { diff --git a/libraries/analysis-javascript/lib/type/discovery/relation/RelationVisitor.ts b/libraries/analysis-javascript/lib/type/discovery/relation/RelationVisitor.ts index 20b428825..7505876f7 100644 --- a/libraries/analysis-javascript/lib/type/discovery/relation/RelationVisitor.ts +++ b/libraries/analysis-javascript/lib/type/discovery/relation/RelationVisitor.ts @@ -49,8 +49,8 @@ export class RelationVisitor extends AbstractSyntaxTreeVisitor { p.node === null || p.node === undefined ) { - // throw new Error(`Involved node is undefined or null for ${id}`); - return `${id}::anonymous`; // TODO we should look into this + throw new Error(`Involved node is undefined or null for ${id}`); + // return `${id}::anonymous`; // TODO we should look into this } return this._getNodeId(p); }), @@ -329,7 +329,7 @@ export class RelationVisitor extends AbstractSyntaxTreeVisitor { ) => void = (path) => { const type = RelationType.FunctionDefinition; // no id for arrow functions - this._createRelation(path, type, [undefined, ...path.get("params")]); + this._createRelation(path, type, [path, ...path.get("params")]); }; public ClassExpression: (path: NodePath) => void = ( diff --git a/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts b/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts index 21b3bf695..de2b6daa8 100644 --- a/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts +++ b/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts @@ -16,7 +16,11 @@ * limitations under the License. */ -import { Relation, RelationType } from "../discovery/relation/Relation"; +import { + Relation, + RelationType, + getRelationName, +} from "../discovery/relation/Relation"; import { elementTypeToTypingType, TypeEnum } from "./TypeEnum"; import { TypeModelFactory } from "./TypeModelFactory"; @@ -26,35 +30,33 @@ import { TypeModel } from "./TypeModel"; export class InferenceTypeModelFactory extends TypeModelFactory { private _typeModel: TypeModel; - private _elementMap: Map; - private _relationsMap: Map; - private _idToBindingIdMap: Map; - // private _processedIds: Set; - constructor() { super(); - this._elementMap = new Map(); - this._relationsMap = new Map(); - - this._idToBindingIdMap = new Map(); - - // this._processedIds = new Set(); } resolveTypes( - elementMap: Map, - relationMap: Map + elementMaps: Map>, + relationMaps: Map> ) { this._typeModel = new TypeModel(); - this._elementMap = elementMap; - this._relationsMap = relationMap; + this._idToBindingIdMap = new Map(); - this.createLiteralTypeMaps(elementMap); - this.createIdentifierTypeMaps(elementMap); - this.createRelationTypeMaps(relationMap); - this.inferRelationTypes(relationMap); + for (const filepath of elementMaps.keys()) { + const elementMap = elementMaps.get(filepath); + const relationMap = relationMaps.get(filepath); + + if (!elementMap || !relationMap) { + throw new Error( + "Filepath should exist in both the element and relation map" + ); + } + this.createLiteralTypeMaps(elementMap); + this.createIdentifierTypeMaps(elementMap); + this.createRelationTypeMaps(elementMap, relationMap); + this.inferRelationTypes(elementMap, relationMap); + } // TODO check for array/function/string type @@ -114,14 +116,17 @@ export class InferenceTypeModelFactory extends TypeModelFactory { } } - createRelationTypeMaps(relationMap: Map) { + createRelationTypeMaps( + elementMap: Map, + relationMap: Map + ) { for (const relation of relationMap.values()) { this.createNewTypeProbability(relation.id, relation.id); for (let index = 0; index < relation.involved.length; index++) { const involvedId = relation.involved[index]; - if (this._elementMap.has(involvedId)) { - const element = this._elementMap.get(involvedId); + if (elementMap.has(involvedId)) { + const element = elementMap.get(involvedId); if (element.type === ElementType.Identifier) { this.createNewTypeProbability(element.id, element.bindingId); @@ -136,7 +141,10 @@ export class InferenceTypeModelFactory extends TypeModelFactory { } } - inferRelationTypes(relationMap: Map) { + inferRelationTypes( + elementMap: Map, + relationMap: Map + ) { const solveOrder = [ RelationType.ClassDefinition, RelationType.ObjectPattern, @@ -181,19 +189,15 @@ export class InferenceTypeModelFactory extends TypeModelFactory { }); for (const relation of sortedRelations) { - this.resolveRelation(relation); + this.resolveRelation(elementMap, relationMap, relation); } } - getElement(id: string): Element { - return this._elementMap.get(id); - } - - getRelation(id: string): Relation { - return this._relationsMap.get(id); - } - - resolveRelation(relation: Relation): void { + resolveRelation( + elementMap: Map, + relationMap: Map, + relation: Relation + ): void { const relationId = relation.id; const relationType: RelationType = relation.type; const originalInvolved: string[] = relation.involved; @@ -252,7 +256,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { case RelationType.ObjectProperty: { const [propertyId, valueId] = involved; - const propertyElement = this._elementMap.get(propertyId); + const propertyElement = elementMap.get(propertyId); if (propertyElement) { const propertyName = @@ -276,18 +280,19 @@ export class InferenceTypeModelFactory extends TypeModelFactory { const [functionId, ...parameters] = involved; // TODO what if the property is not an element - const propertyElement = this._elementMap.get(functionId); + const propertyElement = elementMap.get(functionId); const propertyName = "name" in propertyElement ? propertyElement.name : propertyElement.value; this._typeModel.addPropertyType(relationId, propertyName, functionId); - - // create function type - for (const [index, id] of parameters.entries()) { - this._typeModel.addParameterType(functionId, index, id); - } + this.addFunctionParameters( + elementMap, + relationMap, + functionId, + parameters + ); break; } @@ -305,7 +310,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { const valueId = involved[2]; // TODO what if the property is not an element - const propertyElement = this.getElement(propertyId); + const propertyElement = elementMap.get(propertyId); const propertyName = "name" in propertyElement ? propertyElement.name @@ -350,9 +355,12 @@ export class InferenceTypeModelFactory extends TypeModelFactory { // TODO maybe not for setter / getter // make function for the method - for (const [index, id] of parameters.entries()) { - this._typeModel.addParameterType(functionId, index, id); - } + this.addFunctionParameters( + elementMap, + relationMap, + functionId, + parameters + ); break; } @@ -509,12 +517,15 @@ export class InferenceTypeModelFactory extends TypeModelFactory { const functionId = relationId; const [_identifierId, ...parameters] = involved; - for (const [index, id] of parameters.entries()) { - this._typeModel.addParameterType(functionId, index, id); - } + this.addFunctionParameters( + elementMap, + relationMap, + functionId, + parameters + ); - // connect function to relation - this._typeModel.addRelationScore(functionId, relationId); + // connect function to identifier + this._typeModel.addRelationScore(functionId, _identifierId); break; } @@ -536,7 +547,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { const [objectId, propertyId] = involved; const [, originalProperty] = originalInvolved; - const propertyElement = this.getElement(originalProperty); + const propertyElement = elementMap.get(originalProperty); // TODO // we add these scores by default because it is likely a string/object/array @@ -936,4 +947,29 @@ export class InferenceTypeModelFactory extends TypeModelFactory { } } } + + private addFunctionParameters( + elementMap: Map, + relationMap: Map, + functionId: string, + parameters: string[] + ) { + // create function type + for (const [index, id] of parameters.entries()) { + let name: string; + const element = elementMap.get(id); + if (element) { + name = "name" in element ? element.name : element.value; + } + if (!name) { + const relation = relationMap.get(id); + if (relation) { + name = getRelationName(relation.type); + } else { + throw new Error(`Could not find element or relation with id ${id}`); + } + } + this._typeModel.addParameterType(functionId, index, id, name); + } + } } diff --git a/libraries/analysis-javascript/lib/type/resolving/Type.ts b/libraries/analysis-javascript/lib/type/resolving/Type.ts index 5fc59837d..1fcdb2209 100644 --- a/libraries/analysis-javascript/lib/type/resolving/Type.ts +++ b/libraries/analysis-javascript/lib/type/resolving/Type.ts @@ -27,6 +27,8 @@ export interface ObjectType { // function // index -> id parameters: Map; + // index -> name + parameterNames: Map; // id return: Set; } diff --git a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts index 0f1954ab0..1402f6e49 100644 --- a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts +++ b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts @@ -59,6 +59,18 @@ export class TypeModel { this.addId("anon"); // should be removed at some point } + get relationScoreMap() { + return this._relationScoreMap; + } + + get elementTypeScoreMap() { + return this._elementTypeScoreMap; + } + + get typeExecutionScoreMap() { + return this._typeExecutionScoreMap; + } + getObjectDescription(element: string): ObjectType { if (!this._objectTypeDescription.has(element)) { throw new Error(`Element ${element} does not have an object description`); @@ -83,6 +95,7 @@ export class TypeModel { properties: new Map(), elements: new Set(), parameters: new Map(), + parameterNames: new Map(), return: new Set(), }); } @@ -148,9 +161,10 @@ export class TypeModel { this.getObjectDescription(element).properties.set(property, id); } - addParameterType(element: string, index: number, id: string) { + addParameterType(element: string, index: number, id: string, name: string) { this.addTypeScore(element, TypeEnum.FUNCTION); this.getObjectDescription(element).parameters.set(index, id); + this.getObjectDescription(element).parameterNames.set(index, name); } addReturnType(element: string, returnId: string) { @@ -209,8 +223,6 @@ export class TypeModel { id ); - console.log(probabilities); - const genericTypes = [ TypeEnum.ARRAY, TypeEnum.BOOLEAN, diff --git a/libraries/analysis-javascript/lib/type/resolving/TypeModelFactory.ts b/libraries/analysis-javascript/lib/type/resolving/TypeModelFactory.ts index a4ca0942f..209a41739 100644 --- a/libraries/analysis-javascript/lib/type/resolving/TypeModelFactory.ts +++ b/libraries/analysis-javascript/lib/type/resolving/TypeModelFactory.ts @@ -32,7 +32,7 @@ export abstract class TypeModelFactory { * @param relationMap the relations to resolve the types of */ abstract resolveTypes( - elementMap: Map, - relationMap: Map + elementMaps: Map>, + relationMaps: Map> ): TypeModel; } diff --git a/libraries/analysis-javascript/lib/type/resolving/TypePool.ts b/libraries/analysis-javascript/lib/type/resolving/TypePool.ts index 4adef1dc8..f63616d29 100644 --- a/libraries/analysis-javascript/lib/type/resolving/TypePool.ts +++ b/libraries/analysis-javascript/lib/type/resolving/TypePool.ts @@ -23,13 +23,13 @@ import { Export } from "../../target/export/Export"; // TODO we could cache some of this stuff (unless we do dynamic adding of properties at some point) export class TypePool { - private _objectMap: Map; + private _objectMap: Map>; private _exports: Map; private _exportedObjects: Map; constructor( - objectMap: Map, + objectMap: Map>, exports: Map ) { this._objectMap = objectMap; @@ -43,12 +43,11 @@ export class TypePool { for (const [, exports] of this._exports.entries()) { for (const export_ of exports) { - for (const [ - objectName, - discoveredObject, - ] of this._objectMap.entries()) { - if (discoveredObject.id === export_.id) { - exportedTypes.set(objectName, discoveredObject); + for (const objectMap of this._objectMap.values()) { + for (const [objectName, discoveredObject] of objectMap.entries()) { + if (discoveredObject.id === export_.id) { + exportedTypes.set(objectName, discoveredObject); + } } } } diff --git a/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts b/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts index 039f05fc3..b22b2ddaa 100644 --- a/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts +++ b/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts @@ -167,8 +167,8 @@ export class AbstractSyntaxTreeVisitor implements TraverseOptions { // so the binding id is equal to the object of the member expression relation + the id of the property // e.g. bar.foo return ( - this._getBindingId(path.parentPath.get("object")) + - " <-> " + + // this._getBindingId(path.parentPath.get("object")) + + // " <-> " + this._getNodeId(path) ); } diff --git a/libraries/search-javascript/lib/testcase/sampling/JavaScriptRandomSampler.ts b/libraries/search-javascript/lib/testcase/sampling/JavaScriptRandomSampler.ts index dc37cc979..8dfa42b4d 100644 --- a/libraries/search-javascript/lib/testcase/sampling/JavaScriptRandomSampler.ts +++ b/libraries/search-javascript/lib/testcase/sampling/JavaScriptRandomSampler.ts @@ -471,7 +471,6 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { sampleArgument(depth: number, id: string, name: string): Statement { let chosenType: string; - console.log(id, name); switch (this.typeInferenceMode) { case "none": { chosenType = this.rootContext @@ -508,7 +507,7 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { ); } } - console.log("type", chosenType); + if (chosenType.endsWith("object")) { return this.sampleObject(depth, id, name, chosenType); } else if (chosenType.endsWith("array")) { @@ -668,16 +667,6 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { sampleArray(depth: number, id: string, name: string, type: string) { const typeId = type.includes("<>") ? type.split("<>")[0] : id; - const typeObject = this.rootContext - .getTypeModel() - .getObjectDescription(typeId); - - console.log("------------------"); - console.log("id", id); - console.log("type", typeId); - console.log(typeObject.elements); - console.log("------------------"); - const children: Statement[] = []; for ( @@ -712,11 +701,7 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { const parameters: string[] = []; - for (const [index, parameterId] of typeObject.parameters.entries()) { - const element = this.rootContext.getElement(parameterId); - - const name = "name" in element ? element.name : element.value; - + for (const [index, name] of typeObject.parameterNames.entries()) { parameters[index] = name; } diff --git a/libraries/search-javascript/lib/testcase/sampling/generators/action/CallGenerator.ts b/libraries/search-javascript/lib/testcase/sampling/generators/action/CallGenerator.ts index 90f37ace3..bd810d916 100644 --- a/libraries/search-javascript/lib/testcase/sampling/generators/action/CallGenerator.ts +++ b/libraries/search-javascript/lib/testcase/sampling/generators/action/CallGenerator.ts @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ObjectType, getRelationName } from "@syntest/analysis-javascript"; +import { ObjectType } from "@syntest/analysis-javascript"; import { Statement } from "../../../statements/Statement"; import { prng } from "@syntest/prng"; import { Generator } from "../Generator"; @@ -25,35 +25,11 @@ export abstract class CallGenerator extends Generator { const arguments_: Statement[] = []; for (const [index, parameterId] of type_.parameters.entries()) { - const element = this.rootContext.getElement(parameterId); - - if (element) { - const name = "name" in element ? element.name : element.value; - - arguments_[index] = this.sampler.sampleArgument( - depth + 1, - parameterId, - name - ); - continue; - } - - const relation = this.rootContext.getRelation(parameterId); - - if (relation) { - const name = getRelationName(relation.type); - // TODO look deeper into the relation - - arguments_[index] = this.sampler.sampleArgument( - depth + 1, - parameterId, - name - ); - continue; - } - - throw new Error( - `Could not find element or relation with id ${parameterId}` + const name = type_.parameterNames.get(index); + arguments_[index] = this.sampler.sampleArgument( + depth + 1, + parameterId, + name ); } diff --git a/libraries/search-javascript/lib/testcase/statements/complex/ArrayStatement.ts b/libraries/search-javascript/lib/testcase/statements/complex/ArrayStatement.ts index ac2179785..28877cb57 100644 --- a/libraries/search-javascript/lib/testcase/statements/complex/ArrayStatement.ts +++ b/libraries/search-javascript/lib/testcase/statements/complex/ArrayStatement.ts @@ -45,7 +45,6 @@ export class ArrayStatement extends Statement { // check for circular for (const [index, statement] of this._children.entries()) { if (statement && statement.uniqueId === this.uniqueId) { - console.log("circular detected"); this._children.splice(index, 1); } } diff --git a/plugins/plugin-javascript-event-listener-state-storage/CHANGELOG.md b/plugins/plugin-javascript-event-listener-state-storage/CHANGELOG.md new file mode 100644 index 000000000..e4d87c4d4 --- /dev/null +++ b/plugins/plugin-javascript-event-listener-state-storage/CHANGELOG.md @@ -0,0 +1,4 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. diff --git a/plugins/plugin-javascript-event-listener-state-storage/LICENSE.header.ts b/plugins/plugin-javascript-event-listener-state-storage/LICENSE.header.ts new file mode 100644 index 000000000..58fa806c5 --- /dev/null +++ b/plugins/plugin-javascript-event-listener-state-storage/LICENSE.header.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020-<%= YEAR %> Delft University of Technology and SynTest contributors + * + * This file is part of SynTest Framework - SynTest Core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/plugins/plugin-javascript-event-listener-state-storage/NOTICE b/plugins/plugin-javascript-event-listener-state-storage/NOTICE new file mode 100644 index 000000000..cddb04897 --- /dev/null +++ b/plugins/plugin-javascript-event-listener-state-storage/NOTICE @@ -0,0 +1,5 @@ +SynTest Framework - SynTest Core +Copyright 2020-2023 Delft University of Technology and SynTest contributors + +This product includes software developed at +Delft University of Technology (http://www.tudelft.nl/). diff --git a/plugins/plugin-javascript-event-listener-state-storage/README.md b/plugins/plugin-javascript-event-listener-state-storage/README.md new file mode 100644 index 000000000..3a4e2c5b7 --- /dev/null +++ b/plugins/plugin-javascript-event-listener-state-storage/README.md @@ -0,0 +1 @@ +# State Storage plugin for the SynTest Core. diff --git a/plugins/plugin-javascript-event-listener-state-storage/index.ts b/plugins/plugin-javascript-event-listener-state-storage/index.ts new file mode 100644 index 000000000..5846fdbc6 --- /dev/null +++ b/plugins/plugin-javascript-event-listener-state-storage/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2020-2023 Delft University of Technology and SynTest contributors + * + * This file is part of SynTest Framework - SynTest Core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * as module from "./lib/StateStorageModule"; diff --git a/plugins/plugin-javascript-event-listener-state-storage/lib/StateStorage.ts b/plugins/plugin-javascript-event-listener-state-storage/lib/StateStorage.ts new file mode 100644 index 000000000..39d549369 --- /dev/null +++ b/plugins/plugin-javascript-event-listener-state-storage/lib/StateStorage.ts @@ -0,0 +1,158 @@ +/* + * Copyright 2020-2023 Delft University of Technology and SynTest contributors + * + * This file is part of SynTest Framework - SynTest Core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as path from "node:path"; + +import { StorageManager } from "@syntest/storage"; +import { RootContext, TypeModel } from "@syntest/analysis-javascript"; + +export class StateStorage { + private storageManager: StorageManager; + private storagePath: string; + + constructor(storageManager: StorageManager, storagePath: string) { + this.storageManager = storageManager; + this.storagePath = storagePath; + } + + exportExtractionComplete(rootContext: RootContext, filepath: string): void { + const exports = rootContext.getExports(filepath); + this.save( + JSON.stringify(Object.fromEntries(exports.entries()), undefined, 2), + filepath, + "exports.json" + ); + } + + elementExtractionComplete(rootContext: RootContext, filepath: string): void { + const elements = rootContext.getElements(filepath); + this.save( + JSON.stringify(Object.fromEntries(elements.entries()), undefined, 2), + filepath, + "elements.json" + ); + } + + relationExtractionComplete(rootContext: RootContext, filepath: string): void { + const relations = rootContext.getRelations(filepath); + this.save( + JSON.stringify(Object.fromEntries(relations.entries()), undefined, 2), + filepath, + "relations.json" + ); + } + + objectTypeExtractionComplete( + rootContext: RootContext, + filepath: string + ): void { + const objects = rootContext.getObjectTypes(filepath); + this.save( + JSON.stringify(Object.fromEntries(objects.entries()), undefined, 2), + filepath, + "objects.json" + ); + } + + typeResolvingComplete(rootContext: RootContext): void { + const typeModel = rootContext.getTypeModel(); + const graph = this.typeModelToGraphFormat(typeModel); + const data = JSON.stringify(graph, undefined, 2); + + this.storageManager.store([this.storagePath], "typemodel.json", data); + } + + save( + data: string, + filepath: string, + type: "exports.json" | "elements.json" | "relations.json" | "objects.json" + ) { + const name = path.basename(filepath, path.extname(filepath)); + + this.storageManager.store([this.storagePath, name], type, data); + } + + private typeModelToGraphFormat(typeModel: TypeModel) { + const graph: Graph = { + nodes: [], + edges: [], + }; + + for (const [id, typeScores] of typeModel.elementTypeScoreMap.entries()) { + const executionScores = typeModel.typeExecutionScoreMap.get(id); + const scores: Score[] = []; + + for (const [type, score] of typeScores.entries()) { + scores.push({ + type: type, + typeScore: score, + executionScore: + executionScores && executionScores.has(type) + ? executionScores.get(type) + : 0, + }); + } + + graph.nodes.push({ + id: id, + scores: scores, + }); + } + + for (const [id1, relationScores] of typeModel.relationScoreMap.entries()) { + const executionScores = typeModel.typeExecutionScoreMap.get(id1); + + for (const [id2, score] of relationScores) { + graph.edges.push({ + source: id1, + target: id2, + relationScore: score, + relationExecutionScore: + executionScores && executionScores.has(id2) + ? executionScores.get(id2) + : 0, + }); + } + } + + return graph; + } +} + +type Score = { + type: string; + typeScore: number; + executionScore: number; +}; + +type Node = { + id: string; + scores: Score[]; + // probabilities? no supported rn +}; + +type Edge = { + source: string; + target: string; + relationScore: number; + relationExecutionScore: number; +}; + +type Graph = { + nodes: Node[]; + edges: Edge[]; +}; diff --git a/plugins/plugin-javascript-event-listener-state-storage/lib/StateStorageEventListenerPlugin.ts b/plugins/plugin-javascript-event-listener-state-storage/lib/StateStorageEventListenerPlugin.ts new file mode 100644 index 000000000..d11d5e7a3 --- /dev/null +++ b/plugins/plugin-javascript-event-listener-state-storage/lib/StateStorageEventListenerPlugin.ts @@ -0,0 +1,120 @@ +/* + * Copyright 2020-2023 Delft University of Technology and SynTest contributors + * + * This file is part of SynTest Framework - SynTest Core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Events, RootContext } from "@syntest/analysis-javascript"; +import { EventListenerPlugin } from "@syntest/module"; +import { StorageManager } from "@syntest/storage"; +import TypedEventEmitter from "typed-emitter"; +import Yargs = require("yargs"); + +import { StateStorage } from "./StateStorage"; + +export type StateStorageOptions = { + javascriptStateStorageDirectory: string; +}; + +/** + * This graphing plugin creates a listener that creates an SVG based on the generated CFG. + * + * @author Dimitri Stallenberg + */ +export class StateStorageEventListenerPlugin extends EventListenerPlugin { + private storageManager: StorageManager; + + constructor(storageManager: StorageManager) { + super( + "javascript-state-storage", + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-var-requires, unicorn/prefer-module, @typescript-eslint/no-unsafe-member-access + require("../../package.json").description + ); + this.storageManager = storageManager; + } + + setupEventListener(): void { + const stateStore = ((this.args)) + .javascriptStateStorageDirectory; + + const stateStorage = new StateStorage(this.storageManager, stateStore); + + (>process).on( + "exportExtractionComplete", + (rootContext: RootContext, filepath: string) => + stateStorage.exportExtractionComplete(rootContext, filepath) + ); + + (>process).on( + "elementExtractionComplete", + (rootContext: RootContext, filepath: string) => + stateStorage.elementExtractionComplete(rootContext, filepath) + ); + + (>process).on( + "relationExtractionComplete", + (rootContext: RootContext, filepath: string) => + stateStorage.relationExtractionComplete(rootContext, filepath) + ); + + (>process).on( + "objectTypeExtractionComplete", + (rootContext: RootContext, filepath: string) => + stateStorage.objectTypeExtractionComplete(rootContext, filepath) + ); + + (>process).on( + "typeResolvingComplete", + (rootContext: RootContext) => + stateStorage.typeResolvingComplete(rootContext) + ); + } + + override getOptions( + tool: string, + labels: string[], + command: string + ): Map { + const optionsMap = new Map(); + + if (!labels.includes("testing")) { + return optionsMap; + } + + if (command !== "test") { + return optionsMap; + } + + optionsMap.set("directory", { + alias: [], + default: "state", + description: "The path where the state should be saved", + group: OptionGroups.StateStorage, + hidden: false, + normalize: true, + type: "string", + }); + + return optionsMap; + } + + override getOptionChoices(): string[] { + return []; + } +} + +export enum OptionGroups { + StateStorage = "State Storage Options:", +} diff --git a/plugins/plugin-javascript-event-listener-state-storage/lib/StateStorageModule.ts b/plugins/plugin-javascript-event-listener-state-storage/lib/StateStorageModule.ts new file mode 100644 index 000000000..ed3635f5d --- /dev/null +++ b/plugins/plugin-javascript-event-listener-state-storage/lib/StateStorageModule.ts @@ -0,0 +1,45 @@ +/* + * Copyright 2020-2023 Delft University of Technology and SynTest contributors + * + * This file is part of SynTest Framework - SynTest Core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { MetricManager } from "@syntest/metric"; +import { Module, ModuleManager } from "@syntest/module"; +import { StorageManager } from "@syntest/storage"; + +import { StateStorageEventListenerPlugin } from "./StateStorageEventListenerPlugin"; + +export default class StateStorageModule extends Module { + constructor() { + super( + // eslint-disable-next-line @typescript-eslint/no-var-requires,unicorn/prefer-module, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access + require("../../package.json").name, + // eslint-disable-next-line @typescript-eslint/no-var-requires,unicorn/prefer-module, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access + require("../../package.json").version + ); + } + + register( + moduleManager: ModuleManager, + _metricManager: MetricManager, + storageManager: StorageManager + ): void { + moduleManager.registerPlugin( + this, + new StateStorageEventListenerPlugin(storageManager) + ); + } +} diff --git a/plugins/plugin-javascript-event-listener-state-storage/package.json b/plugins/plugin-javascript-event-listener-state-storage/package.json new file mode 100644 index 000000000..2e017b939 --- /dev/null +++ b/plugins/plugin-javascript-event-listener-state-storage/package.json @@ -0,0 +1,64 @@ +{ + "name": "@syntest/plugin-javascript-event-listener-state-storage", + "version": "0.0.1", + "description": "A listener plugin for SynTest JavaScript containing state storage functionalities", + "keywords": [ + "syntest", + "automatic-test-generation" + ], + "homepage": "https://www.syntest.org", + "bugs": { + "url": "https://github.com/syntest-framework/syntest-core/issues" + }, + "license": "Apache-2.0", + "contributors": [ + "Annibale Panichella", + "Mitchell Olsthoorn", + "Dimitri Stallenberg" + ], + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist/lib", + "dist/index.d.ts", + "dist/index.d.ts.map", + "dist/index.js", + "dist/index.js.map", + "NOTICE", + "README.md" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/syntest-framework/syntest-core.git" + }, + "scripts": { + "build": "tsc --build", + "build:watch": "tsc --build --watch", + "clean": "rm -rf .nyc_output dist node_modules coverage", + "clean:dist": "rm -rf dist", + "format": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --write .", + "format:check": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --check .", + "lint": "eslint --config ../../.eslintrc.json --ignore-path ../../.eslintignore .", + "lint:fix": "eslint --config ../../.eslintrc.json --ignore-path ../../.eslintignore . --fix", + "test": "mocha --config ../../.mocharc.json", + "test:coverage": "nyc --reporter=text --reporter=html mocha --config ../../.mocharc.json", + "test:coverage:ci": "nyc --reporter=lcovonly mocha --config ../../.mocharc.json --reporter json --reporter-option output=test-results.json", + "test:watch": "mocha --config ../../.mocharc.json --watch" + }, + "dependencies": { + "@syntest/analysis": "*", + "@syntest/analysis-javascript": "*", + "@syntest/base-language": "*", + "@syntest/cfg": "*", + "@syntest/logging": "*", + "@syntest/metric": "*", + "@syntest/module": "*", + "@syntest/search": "*" + }, + "engines": { + "node": ">=16" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/plugins/plugin-javascript-event-listener-state-storage/test/simulation.test.ts b/plugins/plugin-javascript-event-listener-state-storage/test/simulation.test.ts new file mode 100644 index 000000000..e9385b5bc --- /dev/null +++ b/plugins/plugin-javascript-event-listener-state-storage/test/simulation.test.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2020-2023 Delft University of Technology and SynTest contributors + * + * This file is part of SynTest Framework - SynTest Core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { StorageManager } from "@syntest/storage"; +import * as chai from "chai"; + +import { StateStorage } from "../lib/StateStorage"; + +const expect = chai.expect; + +describe("simulationTest", () => { + it("SimpleTest", () => { + new StateStorage(new StorageManager(), ""); + + expect(true); + }); +}); diff --git a/plugins/plugin-javascript-event-listener-state-storage/tsconfig.json b/plugins/plugin-javascript-event-listener-state-storage/tsconfig.json new file mode 100644 index 000000000..97ea4a6a1 --- /dev/null +++ b/plugins/plugin-javascript-event-listener-state-storage/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig-base.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": ".", + "composite": true + }, + "include": ["**/*.ts"] +} diff --git a/tools/javascript/lib/JavaScriptLauncher.ts b/tools/javascript/lib/JavaScriptLauncher.ts index f9ffb6156..716885b1f 100644 --- a/tools/javascript/lib/JavaScriptLauncher.ts +++ b/tools/javascript/lib/JavaScriptLauncher.ts @@ -363,7 +363,9 @@ export class JavaScriptLauncher extends Launcher { const startTypeResolving = Date.now(); JavaScriptLauncher.LOGGER.info("Extracting types"); - this.rootContext.extractTypes(); + this.rootContext.getAllElements(); + this.rootContext.getAllRelations(); + this.rootContext.getAllObjectTypes(); JavaScriptLauncher.LOGGER.info("Resolving types"); this.rootContext.resolveTypes(); timeInMs = (Date.now() - startTypeResolving) / 1000; From 5325245715ea54790bcea74fb26febb8be4d8039 Mon Sep 17 00:00:00 2001 From: Dimitri Stallenberg Date: Thu, 17 Aug 2023 01:00:54 +0200 Subject: [PATCH 03/14] fix: call type connection --- .../lib/target/TargetVisitor.ts | 30 ++++++++- .../discovery/relation/RelationVisitor.ts | 10 ++- .../resolving/InferenceTypeModelFactory.ts | 6 +- .../lib/type/resolving/TypeModel.ts | 44 ++++++------- libraries/analysis-javascript/package.json | 2 +- .../type/InferenceTypeModelFactory.test.ts | 63 +++++++++++++++++++ .../lib/AbstractSyntaxTreeVisitor.ts | 20 ------ .../generators/action/CallGenerator.ts | 12 ++-- 8 files changed, 129 insertions(+), 58 deletions(-) create mode 100644 libraries/analysis-javascript/test/type/InferenceTypeModelFactory.test.ts diff --git a/libraries/analysis-javascript/lib/target/TargetVisitor.ts b/libraries/analysis-javascript/lib/target/TargetVisitor.ts index d1603b326..7473d25e3 100644 --- a/libraries/analysis-javascript/lib/target/TargetVisitor.ts +++ b/libraries/analysis-javascript/lib/target/TargetVisitor.ts @@ -349,10 +349,34 @@ export class TargetVisitor extends AbstractSyntaxTreeVisitor { // only thing left where these can be found is: // call(() => {}) const targetName = this._getTargetNameOfExpression(path); - const id = this._getNodeId(path); - const export_ = this._getExport(id); - this._extractFromFunction(path, id, id, targetName, export_, false, false); + if (path.parentPath.isVariableDeclarator()) { + const id = this._getNodeId(path); + const export_ = this._getExport(id); + + this._extractFromFunction( + path, + id, + id, + targetName, + export_, + false, + false + ); + } else { + const id = this._getNodeId(path); + const export_ = this._getExport(id); + + this._extractFromFunction( + path, + id, + id, + targetName, + export_, + false, + false + ); + } path.skip(); }; diff --git a/libraries/analysis-javascript/lib/type/discovery/relation/RelationVisitor.ts b/libraries/analysis-javascript/lib/type/discovery/relation/RelationVisitor.ts index 7505876f7..99c372639 100644 --- a/libraries/analysis-javascript/lib/type/discovery/relation/RelationVisitor.ts +++ b/libraries/analysis-javascript/lib/type/discovery/relation/RelationVisitor.ts @@ -329,7 +329,15 @@ export class RelationVisitor extends AbstractSyntaxTreeVisitor { ) => void = (path) => { const type = RelationType.FunctionDefinition; // no id for arrow functions - this._createRelation(path, type, [path, ...path.get("params")]); + + if (path.parentPath.isVariableDeclarator()) { + this._createRelation(path, type, [ + path.parentPath, + ...path.get("params"), + ]); + } else { + this._createRelation(path, type, [path, ...path.get("params")]); + } }; public ClassExpression: (path: NodePath) => void = ( diff --git a/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts b/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts index de2b6daa8..af1b12315 100644 --- a/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts +++ b/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts @@ -171,6 +171,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { RelationType.ObjectProperty, RelationType.Return, + RelationType.Call, RelationType.PropertyAccessor, RelationType.OptionalPropertyAccessor, @@ -235,7 +236,6 @@ export class InferenceTypeModelFactory extends TypeModelFactory { this._typeModel.addRelationScore(relationId, returnValueId); } - // TODO // couple function arguments with function parameters if (type && type.parameters.size > 0) { const smallest = Math.min(arguments_.length, type.parameters.size); @@ -515,7 +515,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { throw new Error(`Function definition has no involved elements`); } const functionId = relationId; - const [_identifierId, ...parameters] = involved; + const [identifierId, ...parameters] = involved; this.addFunctionParameters( elementMap, @@ -525,7 +525,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { ); // connect function to identifier - this._typeModel.addRelationScore(functionId, _identifierId); + this._typeModel.setEqual(functionId, identifierId); break; } diff --git a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts index 1402f6e49..940109027 100644 --- a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts +++ b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts @@ -100,6 +100,19 @@ export class TypeModel { }); } + setEqual(id1: string, id2: string) { + //TODO maybe merge + this._relationScoreMap.set(id2, this._relationScoreMap.get(id1)); + this._elementTypeScoreMap.set(id2, this._elementTypeScoreMap.get(id1)); + this._elementTypeProbabilityMap.set( + id2, + this._elementTypeProbabilityMap.get(id1) + ); + this._typeExecutionScoreMap.set(id2, this._typeExecutionScoreMap.get(id1)); + this._scoreHasChangedMap.set(id2, this._scoreHasChangedMap.get(id1)); + this._objectTypeDescription.set(id2, this._objectTypeDescription.get(id1)); + } + private _addRelationScore(id1: string, id2: string, score: number) { if (!this._relationScoreMap.has(id1)) { throw new Error(`Element ${id1} does not exist`); @@ -215,14 +228,15 @@ export class TypeModel { getRandomType( incorporateExecutionScore: boolean, randomTypeProbability: number, - id: string, - matchType?: TypeEnum + id: string ): string { const probabilities = this.calculateProbabilitiesForElement( incorporateExecutionScore, id ); + // console.log(id) + // console.log(probabilities) const genericTypes = [ TypeEnum.ARRAY, TypeEnum.BOOLEAN, @@ -249,17 +263,8 @@ export class TypeModel { ]); } - let matchingTypes = [...probabilities.entries()]; - let totalProbability = 1; - - if (matchType) { - matchingTypes = matchingTypes.filter(([type]) => - type.endsWith(matchType) - ); - totalProbability = this._sum( - matchingTypes.map(([, probability]) => probability) - ); - } + const matchingTypes = [...probabilities.entries()]; + const totalProbability = 1; const choice = prng.nextDouble(0, totalProbability); let index = 0; @@ -280,8 +285,7 @@ export class TypeModel { getHighestProbabilityType( incorporateExecutionScore: boolean, randomTypeProbability: number, - id: string, - matchType?: TypeEnum + id: string ): string { const probabilities = this.calculateProbabilitiesForElement( incorporateExecutionScore, @@ -311,15 +315,7 @@ export class TypeModel { ]); } - let matchingTypes = probabilities; - - if (matchType) { - matchingTypes = new Map( - [...matchingTypes.entries()].filter(([type]) => - type.endsWith(matchType) - ) - ); - } + const matchingTypes = probabilities; let best: string = matchingTypes.keys().next().value; diff --git a/libraries/analysis-javascript/package.json b/libraries/analysis-javascript/package.json index 24b775323..1bed9cd51 100644 --- a/libraries/analysis-javascript/package.json +++ b/libraries/analysis-javascript/package.json @@ -40,7 +40,7 @@ "format:check": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --check .", "lint": "eslint --config ../../.eslintrc.json --ignore-path ../../.eslintignore .", "lint:fix": "eslint --config ../../.eslintrc.json --ignore-path ../../.eslintignore . --fix", - "test": "mocha --config ../../.mocharc.json", + "test": "mocha --config ../../.mocharc.json -g 'InferenceTypeModelFactory test'", "test:coverage": "nyc --reporter=text --reporter=html --reporter=lcov mocha --config ../../.mocharc.json", "test:coverage:ci": "nyc --reporter=lcovonly mocha --config ../../.mocharc.json --reporter json --reporter-option output=test-results.json", "test:watch": "mocha --config ../../.mocharc.json --watch" diff --git a/libraries/analysis-javascript/test/type/InferenceTypeModelFactory.test.ts b/libraries/analysis-javascript/test/type/InferenceTypeModelFactory.test.ts new file mode 100644 index 000000000..5471eda1b --- /dev/null +++ b/libraries/analysis-javascript/test/type/InferenceTypeModelFactory.test.ts @@ -0,0 +1,63 @@ +/* + * Copyright 2020-2023 Delft University of Technology and SynTest contributors + * + * This file is part of SynTest Framework - SynTest JavaScript. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import traverse from "@babel/traverse"; +import { AbstractSyntaxTreeFactory } from "../../lib/ast/AbstractSyntaxTreeFactory"; +import { ElementVisitor } from "../../lib/type/discovery/element/ElementVisitor"; +import { InferenceTypeModelFactory } from "../../lib/type/resolving/InferenceTypeModelFactory"; +import { RelationVisitor } from "../../lib/type/discovery/relation/RelationVisitor"; + +function helper(source: string) { + const generator = new AbstractSyntaxTreeFactory(); + const ast = generator.convert("", source); + + const elementVisitor = new ElementVisitor(""); + traverse(ast, elementVisitor); + + const relationVisitor = new RelationVisitor(""); + traverse(ast, relationVisitor); + + const factory = new InferenceTypeModelFactory(); + const model = factory.resolveTypes( + new Map([["", elementVisitor.elementMap]]), + new Map([["", relationVisitor.relationMap]]) + ); + + return { + elements: elementVisitor.elementMap, + relations: relationVisitor.relationMap, + model, + }; +} + +describe("InferenceTypeModelFactory test", () => { + it("Identifiers: Block", () => { + const code = ` + const x = (a) => {} + x(0) + `; + + const { elements, relations, model } = helper(code); + console.log(elements); + console.log(relations); + console.log(); + + const x = [...elements.values()].find((v) => "name" in v && v.name === "x"); + + model.getObjectDescription(x.id); + }); +}); diff --git a/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts b/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts index b22b2ddaa..d821d6465 100644 --- a/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts +++ b/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts @@ -342,24 +342,4 @@ export class AbstractSyntaxTreeVisitor implements TraverseOptions { // return this._thisScopeStackNames[this._thisScopeStackNames.length - 1]; // } - - protected _getNameFromNode(node: t.Node): string { - if (node.type === "Identifier") { - return node.name; - } - - if ("name" in node) { - if (typeof node.name === "string") { - return node.name; - } else if (node.name.type === "JSXMemberExpression") { - return "anon"; - } else if (node.name.type === "JSXNamespacedName") { - return node.name.name.name; - } else { - return node.name.name; - } - } - - return "anon"; - } } diff --git a/libraries/search-javascript/lib/testcase/sampling/generators/action/CallGenerator.ts b/libraries/search-javascript/lib/testcase/sampling/generators/action/CallGenerator.ts index bd810d916..c6b5f9cae 100644 --- a/libraries/search-javascript/lib/testcase/sampling/generators/action/CallGenerator.ts +++ b/libraries/search-javascript/lib/testcase/sampling/generators/action/CallGenerator.ts @@ -45,12 +45,12 @@ export abstract class CallGenerator extends Generator { } } - for (let index = 0; index < 10; index++) { - if (prng.nextBoolean(0.05)) { - // TODO make this a config parameter - arguments_.push(this.sampler.sampleArgument(depth + 1, "anon", "anon")); - } - } + // for (let index = 0; index < 10; index++) { + // if (prng.nextBoolean(0.05)) { + // // TODO make this a config parameter + // arguments_.push(this.sampler.sampleArgument(depth + 1, "anon", "anon")); + // } + // } return arguments_; } From 9f6cd73c711bb7594ca9c0a8e5ab39169b45c407 Mon Sep 17 00:00:00 2001 From: Dimitri Stallenberg Date: Tue, 29 Aug 2023 10:18:48 +0200 Subject: [PATCH 04/14] fix: id bug --- .../lib/type/discovery/relation/RelationVisitor.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libraries/analysis-javascript/lib/type/discovery/relation/RelationVisitor.ts b/libraries/analysis-javascript/lib/type/discovery/relation/RelationVisitor.ts index 99c372639..31cd6699c 100644 --- a/libraries/analysis-javascript/lib/type/discovery/relation/RelationVisitor.ts +++ b/libraries/analysis-javascript/lib/type/discovery/relation/RelationVisitor.ts @@ -278,7 +278,8 @@ export class RelationVisitor extends AbstractSyntaxTreeVisitor { public FunctionExpression: (path: NodePath) => void = ( path ) => { - const involved = [path.get("id"), ...path.get("params")]; + const id = path.has("id") ? path.get("id") : path; + const involved = [id, ...path.get("params")]; if (path.node.generator && path.node.async) { this._createRelation( @@ -301,24 +302,25 @@ export class RelationVisitor extends AbstractSyntaxTreeVisitor { public FunctionDeclaration: (path: NodePath) => void = (path) => { + const id = path.has("id") ? path.get("id") : path; if (path.node.generator && path.node.async) { this._createRelation(path, RelationType.AsyncFunctionStarDefinition, [ - path.get("id"), + id, ...path.get("params"), ]); } else if (path.node.generator) { this._createRelation(path, RelationType.FunctionStarDefinition, [ - path.get("id"), + id, ...path.get("params"), ]); } else if (path.node.async) { this._createRelation(path, RelationType.AsyncFunctionDefinition, [ - path.get("id"), + id, ...path.get("params"), ]); } else { this._createRelation(path, RelationType.FunctionDefinition, [ - path.get("id"), + id, ...path.get("params"), ]); } From 63ef9dff462e2e9f9d9e80d46bb058669b9f84fe Mon Sep 17 00:00:00 2001 From: Dimitri Stallenberg Date: Tue, 29 Aug 2023 20:55:27 +0200 Subject: [PATCH 05/14] fix: type model --- .../resolving/InferenceTypeModelFactory.ts | 167 ++++++++++-------- .../lib/type/resolving/TypeModel.ts | 83 ++++++++- .../lib/criterion/BranchDistanceVisitor.ts | 2 +- .../sampling/JavaScriptRandomSampler.ts | 124 +++++-------- .../sampling/JavaScriptTestCaseSampler.ts | 35 ++-- .../action/ConstantObjectGenerator.ts | 2 - .../action/ConstructorCallGenerator.ts | 17 -- .../action/FunctionCallGenerator.ts | 2 - .../generators/action/GetterGenerator.ts | 2 - .../generators/action/MethodCallGenerator.ts | 2 - .../action/ObjectFunctionCallGenerator.ts | 2 - .../generators/action/SetterGenerator.ts | 2 - .../lib/testcase/statements/Statement.ts | 3 +- .../statements/action/ActionStatement.ts | 4 +- .../statements/action/ClassActionStatement.ts | 3 +- .../statements/action/ConstantObject.ts | 6 +- .../statements/action/ConstructorCall.ts | 7 +- .../statements/action/FunctionCall.ts | 7 +- .../lib/testcase/statements/action/Getter.ts | 8 +- .../testcase/statements/action/MethodCall.ts | 7 +- .../statements/action/ObjectFunctionCall.ts | 13 +- .../lib/testcase/statements/action/Setter.ts | 6 +- .../statements/complex/ArrayStatement.ts | 10 +- .../complex/ArrowFunctionStatement.ts | 16 +- .../statements/complex/ObjectStatement.ts | 11 +- .../statements/primitive/BoolStatement.ts | 13 +- .../statements/primitive/IntegerStatement.ts | 13 +- .../statements/primitive/NullStatement.ts | 15 +- .../statements/primitive/NumericStatement.ts | 20 ++- .../primitive/PrimitiveStatement.ts | 3 +- .../statements/primitive/StringStatement.ts | 22 ++- .../primitive/UndefinedStatement.ts | 6 +- tools/javascript/lib/JavaScriptLauncher.ts | 4 +- 33 files changed, 348 insertions(+), 289 deletions(-) diff --git a/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts b/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts index af1b12315..6e9c46b51 100644 --- a/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts +++ b/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts @@ -170,6 +170,8 @@ export class InferenceTypeModelFactory extends TypeModelFactory { RelationType.ObjectMethod, RelationType.ObjectProperty, + RelationType.Assignment, + RelationType.Return, RelationType.Call, @@ -215,7 +217,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { const argumentId = involved[1]; if (argumentId !== undefined) { - this._typeModel.addRelationScore(relationId, argumentId); + this._typeModel.addStrongRelation(relationId, argumentId); this._typeModel.addReturnType(functionId, argumentId); } @@ -233,7 +235,11 @@ export class InferenceTypeModelFactory extends TypeModelFactory { // relation result is equal to return type of functionId for (const returnValueId of type.return) { - this._typeModel.addRelationScore(relationId, returnValueId); + if (relationId === returnValueId) { + // recursive function call so we do not add a relation + continue; + } + this._typeModel.addStrongRelation(relationId, returnValueId); } // couple function arguments with function parameters @@ -243,7 +249,11 @@ export class InferenceTypeModelFactory extends TypeModelFactory { for (let index = 0; index < smallest; index++) { const argumentId = arguments_[index]; const parameterId = type.parameters.get(index); - this._typeModel.addRelationScore(parameterId, argumentId); + if (argumentId === parameterId) { + // recursive function call so we do not add a relation + continue; + } + this._typeModel.addStrongRelation(parameterId, argumentId); } } @@ -270,8 +280,8 @@ export class InferenceTypeModelFactory extends TypeModelFactory { } // connect property to value - if (valueId !== undefined) { - this._typeModel.addRelationScore(propertyId, valueId); + if (valueId !== undefined && valueId !== propertyId) { + this._typeModel.addStrongRelation(propertyId, valueId); } break; @@ -321,7 +331,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { // connect property to value if (valueId !== undefined) { - this._typeModel.addRelationScore(propertyId, valueId); + this._typeModel.addStrongRelation(propertyId, valueId); } break; @@ -388,7 +398,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { this._typeModel.addTypeScore(relationId, TypeEnum.ARRAY); // connect rest element to array - this._typeModel.addRelationScore(restElement, relationId); + this._typeModel.addStrongRelation(restElement, relationId); break; } @@ -424,7 +434,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { for (const id of typeOfArray.elements.values()) { // connect declarator to array element - this._typeModel.addRelationScore(declarator, id); + this._typeModel.addWeakRelation(declarator, id); } const typeOfObject = @@ -432,7 +442,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { for (const id of typeOfObject.properties.values()) { // connect declarator to object property - this._typeModel.addRelationScore(declarator, id); + this._typeModel.addWeakRelation(declarator, id); } break; @@ -447,7 +457,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { for (const id of typeOfArray.elements.values()) { // connect declarator to array element - this._typeModel.addRelationScore(declarator, id); + this._typeModel.addWeakRelation(declarator, id); } break; @@ -456,7 +466,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { const [discriminant, ...cases] = involved; for (const case_ of cases) { - this._typeModel.addRelationScore(discriminant, case_); + this._typeModel.addWeakRelation(discriminant, case_); } break; @@ -467,7 +477,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { const thisParent = involved[0]; // add this type to parent - this._typeModel.addRelationScore(thisParent, relationId); + this._typeModel.addStrongRelation(thisParent, relationId); // create object type this._typeModel.addTypeScore(relationId, TypeEnum.OBJECT); @@ -502,7 +512,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { this._typeModel.addTypeScore(classId, TypeEnum.OBJECT); // connect class to relation - this._typeModel.addRelationScore(classId, relationId); + this._typeModel.setEqual(classId, relationId); break; } @@ -549,41 +559,55 @@ export class InferenceTypeModelFactory extends TypeModelFactory { const propertyElement = elementMap.get(originalProperty); - // TODO - // we add these scores by default because it is likely a string/object/array - // however we should check if its one of the default properties of any of the primitives - // if that is the case we should not give it string object or array - this._typeModel.addTypeScore(objectId, TypeEnum.ARRAY); - this._typeModel.addTypeScore(objectId, TypeEnum.STRING); - this._typeModel.addTypeScore(objectId, TypeEnum.OBJECT); - if (propertyElement === undefined) { // e.g. object[b ? 1 : 0] // TODO what if the property is not an element - } else if (propertyElement.type === ElementType.NumericalLiteral) { - // e.g. object[0] - // add array type to object - this._typeModel.addTypeScore(objectId, TypeEnum.ARRAY); - this._typeModel.addElementType(objectId, relationId); - } else if (propertyElement.type === ElementType.StringLiteral) { - // e.g. object["abc"] - // add array type to object - this._typeModel.addTypeScore(objectId, TypeEnum.OBJECT); - this._typeModel.addPropertyType( - objectId, - propertyElement.value, - propertyId - ); - } else { - // const propertyName = - // "name" in propertyElement - // ? propertyElement.name - // : propertyElement.value; - // this._typeModel.addProperty(objectId, propertyName, propertyId); - } + } else + switch (propertyElement.type) { + case ElementType.NumericalLiteral: { + // e.g. object[0] + // add array type to object + this._typeModel.addElementType(objectId, relationId); + + break; + } + case ElementType.StringLiteral: { + // e.g. object["abc"] + // add array type to object + this._typeModel.addPropertyType( + objectId, + propertyElement.value, + propertyId + ); + + break; + } + case ElementType.Identifier: { + if (relation.computed) { + // e.g. object[abc] + // not allowed dynamic stuff happening + // or we can check wether abc is a number + + // add the defaults + this._typeModel.addTypeScore(objectId, TypeEnum.ARRAY); + this._typeModel.addTypeScore(objectId, TypeEnum.STRING); + this._typeModel.addTypeScore(objectId, TypeEnum.OBJECT); + } else { + // e.g. object.abc + this._typeModel.addPropertyType( + objectId, + propertyElement.name, + propertyId + ); + } + + break; + } + // No default + } // we don't have to connect the relationid to the propertyId since they are equal already - this._typeModel.addRelationScore(relationId, propertyId); + this._typeModel.addStrongRelation(relationId, propertyId); break; } @@ -594,7 +618,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { // type: TypeEnum.OBJECT, // properties: new Map() // }); - this._typeModel.addRelationScore(relationId, class_); + this._typeModel.addStrongRelation(relationId, class_); break; } @@ -606,7 +630,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { const argumentId = involved[0]; this._typeModel.addTypeScore(argumentId, TypeEnum.NUMERIC); - this._typeModel.addRelationScore(relationId, argumentId); + this._typeModel.addWeakRelation(relationId, argumentId); break; } @@ -649,7 +673,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { const type_ = this._typeModel.getObjectDescription(argumentId); for (const returnType of type_.return) { - this._typeModel.addRelationScore(relationId, returnType); + this._typeModel.addWeakRelation(relationId, returnType); } break; @@ -670,8 +694,8 @@ export class InferenceTypeModelFactory extends TypeModelFactory { this._typeModel.addTypeScore(leftId, TypeEnum.STRING); this._typeModel.addTypeScore(rightId, TypeEnum.STRING); - this._typeModel.addRelationScore(relationId, leftId); - this._typeModel.addRelationScore(relationId, rightId); + this._typeModel.addWeakRelation(relationId, leftId); + this._typeModel.addWeakRelation(relationId, rightId); // even though we add the relations we still add the number type directly since it is most likely this._typeModel.addTypeScore(relationId, TypeEnum.NUMERIC); @@ -692,8 +716,8 @@ export class InferenceTypeModelFactory extends TypeModelFactory { this._typeModel.addTypeScore(leftId, TypeEnum.NUMERIC); this._typeModel.addTypeScore(rightId, TypeEnum.NUMERIC); - this._typeModel.addRelationScore(relationId, leftId); - this._typeModel.addRelationScore(relationId, rightId); + this._typeModel.addWeakRelation(relationId, leftId); + this._typeModel.addWeakRelation(relationId, rightId); // even though we add the relations we still add the number type directly since it is most likely // in this case we are pretty sure the result is numeric so we give 2 score this._typeModel.addTypeScore(relationId, TypeEnum.NUMERIC, 2); @@ -748,7 +772,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { const [leftId, rightId] = involved; // both sides are likely the same type - this._typeModel.addRelationScore(leftId, rightId); + this._typeModel.addWeakRelation(leftId, rightId); this._typeModel.addTypeScore(relationId, TypeEnum.BOOLEAN); @@ -780,8 +804,8 @@ export class InferenceTypeModelFactory extends TypeModelFactory { this._typeModel.addTypeScore(rightId, TypeEnum.BOOLEAN); //can be the boolean or the type of the second one depending on if the first and second are not false/null/undefined - this._typeModel.addRelationScore(relationId, leftId); - this._typeModel.addRelationScore(relationId, rightId); + this._typeModel.addWeakRelation(relationId, leftId); + this._typeModel.addWeakRelation(relationId, rightId); this._typeModel.addTypeScore(relationId, TypeEnum.BOOLEAN); // TODO can we say that the leftId and rightId are the same type? @@ -796,10 +820,12 @@ export class InferenceTypeModelFactory extends TypeModelFactory { this._typeModel.addTypeScore(rightId, TypeEnum.BOOLEAN); // can be the type of the first or second one depending on if the first is not false/null/undefined - this._typeModel.addRelationScore(relationId, leftId); - this._typeModel.addRelationScore(relationId, rightId); + this._typeModel.addWeakRelation(relationId, leftId); + this._typeModel.addWeakRelation(relationId, rightId); this._typeModel.addTypeScore(relationId, TypeEnum.BOOLEAN); + this._typeModel.addWeakRelation(leftId, rightId); + // TODO can we say that the leftId and rightId are the same type? break; @@ -812,9 +838,10 @@ export class InferenceTypeModelFactory extends TypeModelFactory { this._typeModel.addTypeScore(leftId, TypeEnum.UNDEFINED); // returns the rightId if leftId is nullish - this._typeModel.addRelationScore(relationId, leftId); - this._typeModel.addRelationScore(relationId, rightId); + this._typeModel.addStrongRelation(relationId, leftId); + this._typeModel.addStrongRelation(relationId, rightId); // TODO can we say that the leftId and rightId are the same type? + this._typeModel.addWeakRelation(leftId, rightId); break; } @@ -826,10 +853,11 @@ export class InferenceTypeModelFactory extends TypeModelFactory { // returns the leftId if conditionId is true // returns the rightId if conditionId is false - this._typeModel.addRelationScore(relationId, leftId); - this._typeModel.addRelationScore(relationId, rightId); + this._typeModel.addStrongRelation(relationId, leftId); + this._typeModel.addStrongRelation(relationId, rightId); - // TODO can we say that the leftId and rightId are the same type? + // can we say that the leftId and rightId are the same type? + this._typeModel.addWeakRelation(leftId, rightId); break; } @@ -843,18 +871,14 @@ export class InferenceTypeModelFactory extends TypeModelFactory { } const [leftId, rightId] = involved; - this._typeModel.addRelationScore(leftId, rightId); - // TODO This is not the way to do this - // for now it is neccessary because variable declarations such as in lodash/at.js - // do not have the correct ids causing the relation to have the wrong - this._typeModel.addRelationScore(relationId, rightId); - this._typeModel.addRelationScore(leftId, relationId); - + this._typeModel.setEqual(leftId, relationId); // undefined should be the actual result // this._typeModel.addPrimitiveTypeScore(relationId, { // type: TypeEnum.UNDEFINED, // }); + this._typeModel.addStrongRelation(leftId, rightId); + break; } case RelationType.MultiplicationAssignment: // must be numeric @@ -875,7 +899,10 @@ export class InferenceTypeModelFactory extends TypeModelFactory { } const [leftId, rightId] = involved; - this._typeModel.addRelationScore(leftId, rightId); + // if they are equal we dont add a relation + if (leftId !== rightId) { + this._typeModel.addStrongRelation(leftId, rightId); + } // likely numeric this._typeModel.addTypeScore(leftId, TypeEnum.NUMERIC); this._typeModel.addTypeScore(rightId, TypeEnum.NUMERIC); @@ -892,7 +919,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { } const [leftId, rightId] = involved; - this._typeModel.addRelationScore(leftId, rightId); + this._typeModel.addWeakRelation(leftId, rightId); // likely numeric or string this._typeModel.addTypeScore(leftId, TypeEnum.NUMERIC); this._typeModel.addTypeScore(leftId, TypeEnum.STRING); @@ -914,7 +941,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { } const [leftId, rightId] = involved; - this._typeModel.addRelationScore(leftId, rightId); + this._typeModel.addWeakRelation(leftId, rightId); // likely boolean this._typeModel.addTypeScore(leftId, TypeEnum.BOOLEAN); this._typeModel.addTypeScore(rightId, TypeEnum.BOOLEAN); diff --git a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts index 940109027..b720cdde1 100644 --- a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts +++ b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts @@ -102,6 +102,36 @@ export class TypeModel { setEqual(id1: string, id2: string) { //TODO maybe merge + for (const [key, value] of this._relationScoreMap.get(id2).entries()) + this._relationScoreMap.get(id1).has(key) + ? this._relationScoreMap.get(id1).set(key, value) + : this._relationScoreMap + .get(id1) + .set(key, this._relationScoreMap.get(id1).get(key) + value); + for (const [key, value] of this._elementTypeScoreMap.get(id2).entries()) + this._elementTypeScoreMap.get(id1).has(key) + ? this._elementTypeScoreMap.get(id1).set(key, value) + : this._elementTypeScoreMap + .get(id1) + .set(key, this._elementTypeScoreMap.get(id1).get(key) + value); + for (const [key, value] of this._elementTypeProbabilityMap + .get(id2) + .entries()) + this._elementTypeProbabilityMap.get(id1).has(key) + ? this._elementTypeProbabilityMap.get(id1).set(key, value) + : this._elementTypeProbabilityMap + .get(id1) + .set( + key, + this._elementTypeProbabilityMap.get(id1).get(key) + value + ); + for (const [key, value] of this._typeExecutionScoreMap.get(id2).entries()) + this._typeExecutionScoreMap.get(id1).has(key) + ? this._typeExecutionScoreMap.get(id1).set(key, value) + : this._typeExecutionScoreMap + .get(id1) + .set(key, this._typeExecutionScoreMap.get(id1).get(key) + value); + this._relationScoreMap.set(id2, this._relationScoreMap.get(id1)); this._elementTypeScoreMap.set(id2, this._elementTypeScoreMap.get(id1)); this._elementTypeProbabilityMap.set( @@ -110,6 +140,8 @@ export class TypeModel { ); this._typeExecutionScoreMap.set(id2, this._typeExecutionScoreMap.get(id1)); this._scoreHasChangedMap.set(id2, this._scoreHasChangedMap.get(id1)); + // TODO maybe this should be merged too? + // or should we keep them separate? this._objectTypeDescription.set(id2, this._objectTypeDescription.get(id1)); } @@ -128,7 +160,19 @@ export class TypeModel { this._scoreHasChangedMap.set(id1, true); } - addRelationScore(id1: string, id2: string, score = 1) { + addWeakRelation(id1: string, id2: string) { + this.addRelationScore(id1, id2, 1); + } + + addStrongRelation(id1: string, id2: string) { + this.addRelationScore(id1, id2, 10); + } + + addRelationScore(id1: string, id2: string, score: number) { + if (id1 === id2) { + // no self loops + throw new Error(`ids should not be equal to add a relation id: ${id1}`); + } this._addRelationScore(id1, id2, score); this._addRelationScore(id2, id1, score); } @@ -235,8 +279,19 @@ export class TypeModel { id ); + // const x = new Map() + // for (const [type, probability] of probabilities.entries()) { + // const typeEnum = type.includes('<>') ? type.split('<>')[1] : type + + // if (!x.has(typeEnum)) { + // x.set(typeEnum, 0) + // } + + // x.set(typeEnum, x.get(typeEnum) + probability) + // } // console.log(id) - // console.log(probabilities) + // console.log(x) + const genericTypes = [ TypeEnum.ARRAY, TypeEnum.BOOLEAN, @@ -385,11 +440,21 @@ export class TypeModel { const usableRelations = new Set(); for (const [relation, score] of relationMap.entries()) { + if (relation === id) { + // ignore self references + continue; + } if (!relationPairsVisited.has(id)) { relationPairsVisited.set(id, new Set()); } + if (!relationPairsVisited.has(relation)) { + relationPairsVisited.set(relation, new Set()); + } - if (relationPairsVisited.get(id).has(relation)) { + if ( + relationPairsVisited.get(id).has(relation) || + relationPairsVisited.get(relation).has(id) + ) { // we have already visited this relation pair // this means that we have a cycle in the graph // we can safely ignore this relation @@ -416,6 +481,7 @@ export class TypeModel { } relationPairsVisited.get(id).add(relation); + relationPairsVisited.get(relation).add(id); const probabilityOfRelation = score / totalScore; @@ -428,17 +494,18 @@ export class TypeModel { for (const [type, probability] of probabilityMapOfRelation.entries()) { let finalType = type; - if ( - type === TypeEnum.FUNCTION || - type === TypeEnum.ARRAY || - type === TypeEnum.OBJECT - ) { + if (!type.includes("<>")) { // maybe should check for includes (or the inverse by checking for primitive types) // this will only add only the final relation id // the other method will add all relation id from the element to the final relation finalType = `${relation}<>${type}`; } + if (finalType.includes("<>") && finalType.split("<>")[0] === id) { + // skip this is a self loop + continue; + } + if (!probabilityMap.has(finalType)) { probabilityMap.set(finalType, 0); } diff --git a/libraries/search-javascript/lib/criterion/BranchDistanceVisitor.ts b/libraries/search-javascript/lib/criterion/BranchDistanceVisitor.ts index d51ce61fc..c2eb15052 100644 --- a/libraries/search-javascript/lib/criterion/BranchDistanceVisitor.ts +++ b/libraries/search-javascript/lib/criterion/BranchDistanceVisitor.ts @@ -139,7 +139,7 @@ export class BranchDistanceVisitor extends AbstractSyntaxTreeVisitor { const argumentValue = ( this._valueMap.get(argument.toString()) ); - + const endOfObject = objectValue.length > argumentValue.length ? objectValue.slice(-argumentValue.length) diff --git a/libraries/search-javascript/lib/testcase/sampling/JavaScriptRandomSampler.ts b/libraries/search-javascript/lib/testcase/sampling/JavaScriptRandomSampler.ts index 8dfa42b4d..d30ad39da 100644 --- a/libraries/search-javascript/lib/testcase/sampling/JavaScriptRandomSampler.ts +++ b/libraries/search-javascript/lib/testcase/sampling/JavaScriptRandomSampler.ts @@ -25,7 +25,6 @@ import { MethodTarget, ObjectFunctionTarget, ObjectTarget, - TypeEnum, } from "@syntest/analysis-javascript"; import { prng } from "@syntest/prng"; @@ -143,7 +142,6 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { method.id, method.typeId, method.name, - TypeEnum.FUNCTION, prng.uniqueId(), arguments_, constructor_ @@ -268,7 +266,6 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { class_.typeId, class_.id, class_.name, - TypeEnum.FUNCTION, prng.uniqueId(), [], export_ @@ -508,14 +505,6 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { } } - if (chosenType.endsWith("object")) { - return this.sampleObject(depth, id, name, chosenType); - } else if (chosenType.endsWith("array")) { - return this.sampleArray(depth, id, name, chosenType); - } else if (chosenType.endsWith("function")) { - return this.sampleArrowFunction(depth, id, name, chosenType); - } - // take from pool if (this.statementPoolEnabled) { const statementFromPool = @@ -529,37 +518,49 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { } } - switch (chosenType) { + const typeId = chosenType.includes("<>") ? chosenType.split("<>")[0] : id; + const type = chosenType.includes("<>") + ? chosenType.split("<>")[1] + : chosenType; + + switch (type) { case "boolean": { - return this.sampleBool(id, name); + return this.sampleBool(id, typeId, name); } case "string": { - return this.sampleString(id, name); + return this.sampleString(id, typeId, name); } case "numeric": { - return this.sampleNumber(id, name); + return this.sampleNumber(id, typeId, name); } case "integer": { - return this.sampleInteger(id, name); + return this.sampleInteger(id, typeId, name); } case "null": { - return this.sampleNull(id, name); + return this.sampleNull(id, typeId, name); } case "undefined": { - return this.sampleUndefined(id, name); + return this.sampleUndefined(id, typeId, name); + } + case "object": { + return this.sampleObject(depth, id, typeId, name); + } + case "array": { + return this.sampleArray(depth, id, typeId, name); + } + case "function": { + return this.sampleArrowFunction(depth, id, typeId, name); } case "regex": { // TODO REGEX - return this.sampleString(id, name); + return this.sampleString(id, typeId, name); } } throw new Error(`unknown type: ${chosenType}`); } - sampleObject(depth: number, id: string, name: string, type: string) { - const typeId = type.includes("<>") ? type.split("<>")[0] : id; - + sampleObject(depth: number, id: string, typeId: string, name: string) { const typeObject = this.rootContext .getTypeModel() .getObjectDescription(typeId); @@ -654,19 +655,10 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { object_[key] = this.sampleObjectArgument(depth + 1, typeId, key); } - return new ObjectStatement( - id, - typeId, - name, - type, - prng.uniqueId(), - object_ - ); + return new ObjectStatement(id, typeId, name, prng.uniqueId(), object_); } - sampleArray(depth: number, id: string, name: string, type: string) { - const typeId = type.includes("<>") ? type.split("<>")[0] : id; - + sampleArray(depth: number, id: string, typeId: string, name: string) { const children: Statement[] = []; for ( @@ -677,24 +669,15 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { children.push(this.sampleArrayArgument(depth + 1, typeId)); } - return new ArrayStatement( - id, - typeId, - name, - type, - prng.uniqueId(), - children - ); + return new ArrayStatement(id, typeId, name, prng.uniqueId(), children); } sampleArrowFunction( depth: number, id: string, - name: string, - type: string + typeId: string, + name: string ): ArrowFunctionStatement { - const typeId = type.includes("<>") ? type.split("<>")[0] : id; - const typeObject = this.rootContext .getTypeModel() .getObjectDescription(typeId); @@ -717,7 +700,6 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { id, typeId, name, - TypeEnum.FUNCTION, prng.uniqueId(), parameters, undefined // maybe something random? @@ -730,7 +712,6 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { id, typeId, name, - type, prng.uniqueId(), parameters, this.sampleArgument(depth + 1, chosenReturn, "return") @@ -739,6 +720,7 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { sampleString( id: string, + typeId: string, name: string, alphabet = this.stringAlphabet, maxlength = this.stringMaxLength @@ -762,9 +744,8 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { return new StringStatement( id, - id, + typeId, name, - TypeEnum.STRING, prng.uniqueId(), value, alphabet, @@ -773,22 +754,21 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { } // primitives - sampleBool(id: string, name: string): BoolStatement { + sampleBool(id: string, typeId: string, name: string): BoolStatement { return new BoolStatement( id, - id, + typeId, name, - TypeEnum.BOOLEAN, prng.uniqueId(), prng.nextBoolean() ); } - sampleNull(id: string, name: string): NullStatement { - return new NullStatement(id, id, name, TypeEnum.NULL, prng.uniqueId()); + sampleNull(id: string, typeId: string, name: string): NullStatement { + return new NullStatement(id, typeId, name, prng.uniqueId()); } - sampleNumber(id: string, name: string): NumericStatement { + sampleNumber(id: string, typeId: string, name: string): NumericStatement { // by default we create small numbers (do we need very large numbers?) const max = 1000; const min = -1000; @@ -802,17 +782,10 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { prng.nextDouble(min, max); } - return new NumericStatement( - id, - id, - name, - TypeEnum.NUMERIC, - prng.uniqueId(), - value - ); + return new NumericStatement(id, typeId, name, prng.uniqueId(), value); } - sampleInteger(id: string, name: string): IntegerStatement { + sampleInteger(id: string, typeId: string, name: string): IntegerStatement { // by default we create small numbers (do we need very large numbers?) const max = 1000; const min = -1000; @@ -826,23 +799,14 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler { prng.nextInt(min, max); } - return new IntegerStatement( - id, - id, - name, - TypeEnum.INTEGER, - prng.uniqueId(), - value - ); + return new IntegerStatement(id, typeId, name, prng.uniqueId(), value); } - sampleUndefined(id: string, name: string): UndefinedStatement { - return new UndefinedStatement( - id, - id, - name, - TypeEnum.UNDEFINED, - prng.uniqueId() - ); + sampleUndefined( + id: string, + typeId: string, + name: string + ): UndefinedStatement { + return new UndefinedStatement(id, typeId, name, prng.uniqueId()); } } diff --git a/libraries/search-javascript/lib/testcase/sampling/JavaScriptTestCaseSampler.ts b/libraries/search-javascript/lib/testcase/sampling/JavaScriptTestCaseSampler.ts index 03e7df840..ec91674df 100644 --- a/libraries/search-javascript/lib/testcase/sampling/JavaScriptTestCaseSampler.ts +++ b/libraries/search-javascript/lib/testcase/sampling/JavaScriptTestCaseSampler.ts @@ -253,40 +253,53 @@ export abstract class JavaScriptTestCaseSampler extends EncodingSampler { variableIdentifier, typeIdentifier, name, - TypeEnum.OBJECT, prng.uniqueId(), export_ ); diff --git a/libraries/search-javascript/lib/testcase/sampling/generators/action/ConstructorCallGenerator.ts b/libraries/search-javascript/lib/testcase/sampling/generators/action/ConstructorCallGenerator.ts index 495ad2c10..022c909fa 100644 --- a/libraries/search-javascript/lib/testcase/sampling/generators/action/ConstructorCallGenerator.ts +++ b/libraries/search-javascript/lib/testcase/sampling/generators/action/ConstructorCallGenerator.ts @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { TypeEnum } from "@syntest/analysis-javascript"; import { Statement } from "../../../statements/Statement"; import { prng } from "@syntest/prng"; import { CallGenerator } from "./CallGenerator"; @@ -35,21 +34,6 @@ export class ConstructorCallGenerator extends CallGenerator { .flat() .find((export_) => export_.id === exportIdentifier); - // console.log(exportIdentifier, typeIdentifier) - // if (exportIdentifier === typeIdentifier) { - // // default constructor with no type and no args - // return new ConstructorCall( - // variableIdentifier, - // typeIdentifier, - // exportIdentifier, - // name, - // TypeEnum.FUNCTION, - // prng.uniqueId(), - // [], - // export_ - // ); - // } - if (this.statementPoolEnabled) { const statementFromPool = statementPool.getRandomConstructor(exportIdentifier); @@ -73,7 +57,6 @@ export class ConstructorCallGenerator extends CallGenerator { typeIdentifier, exportIdentifier, name, - TypeEnum.FUNCTION, prng.uniqueId(), arguments_, export_ diff --git a/libraries/search-javascript/lib/testcase/sampling/generators/action/FunctionCallGenerator.ts b/libraries/search-javascript/lib/testcase/sampling/generators/action/FunctionCallGenerator.ts index a20151b87..a66d6496c 100644 --- a/libraries/search-javascript/lib/testcase/sampling/generators/action/FunctionCallGenerator.ts +++ b/libraries/search-javascript/lib/testcase/sampling/generators/action/FunctionCallGenerator.ts @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { TypeEnum } from "@syntest/analysis-javascript"; import { Statement } from "../../../statements/Statement"; import { prng } from "@syntest/prng"; import { FunctionCall } from "../../../statements/action/FunctionCall"; @@ -45,7 +44,6 @@ export class FunctionCallGenerator extends CallGenerator { variableIdentifier, typeIdentifier, name, - TypeEnum.FUNCTION, prng.uniqueId(), arguments_, export_ diff --git a/libraries/search-javascript/lib/testcase/sampling/generators/action/GetterGenerator.ts b/libraries/search-javascript/lib/testcase/sampling/generators/action/GetterGenerator.ts index ee3ae3eda..64cff15cd 100644 --- a/libraries/search-javascript/lib/testcase/sampling/generators/action/GetterGenerator.ts +++ b/libraries/search-javascript/lib/testcase/sampling/generators/action/GetterGenerator.ts @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { TypeEnum } from "@syntest/analysis-javascript"; import { prng } from "@syntest/prng"; import { CallGenerator } from "./CallGenerator"; import { Getter } from "../../../statements/action/Getter"; @@ -39,7 +38,6 @@ export class GetterGenerator extends CallGenerator { variableIdentifier, typeIdentifier, name, - TypeEnum.FUNCTION, prng.uniqueId(), constructor_ ); diff --git a/libraries/search-javascript/lib/testcase/sampling/generators/action/MethodCallGenerator.ts b/libraries/search-javascript/lib/testcase/sampling/generators/action/MethodCallGenerator.ts index dbe56c07b..4ebd86e66 100644 --- a/libraries/search-javascript/lib/testcase/sampling/generators/action/MethodCallGenerator.ts +++ b/libraries/search-javascript/lib/testcase/sampling/generators/action/MethodCallGenerator.ts @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { TypeEnum } from "@syntest/analysis-javascript"; import { Statement } from "../../../statements/Statement"; import { prng } from "@syntest/prng"; import { CallGenerator } from "./CallGenerator"; @@ -46,7 +45,6 @@ export class MethodCallGenerator extends CallGenerator { variableIdentifier, typeIdentifier, name, - TypeEnum.FUNCTION, prng.uniqueId(), arguments_, constructor_ diff --git a/libraries/search-javascript/lib/testcase/sampling/generators/action/ObjectFunctionCallGenerator.ts b/libraries/search-javascript/lib/testcase/sampling/generators/action/ObjectFunctionCallGenerator.ts index 117eb4132..ec3ecef32 100644 --- a/libraries/search-javascript/lib/testcase/sampling/generators/action/ObjectFunctionCallGenerator.ts +++ b/libraries/search-javascript/lib/testcase/sampling/generators/action/ObjectFunctionCallGenerator.ts @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { TypeEnum } from "@syntest/analysis-javascript"; import { Statement } from "../../../statements/Statement"; import { prng } from "@syntest/prng"; import { CallGenerator } from "./CallGenerator"; @@ -46,7 +45,6 @@ export class ObjectFunctionCallGenerator extends CallGenerator { variableIdentifier, typeIdentifier, name, - TypeEnum.FUNCTION, prng.uniqueId(), arguments_[0], constructor_ diff --git a/libraries/search-javascript/lib/testcase/statements/Statement.ts b/libraries/search-javascript/lib/testcase/statements/Statement.ts index 17062e8b1..be6207d3b 100644 --- a/libraries/search-javascript/lib/testcase/statements/Statement.ts +++ b/libraries/search-javascript/lib/testcase/statements/Statement.ts @@ -19,6 +19,7 @@ import { Encoding, EncodingSampler, shouldNeverHappen } from "@syntest/search"; import { JavaScriptDecoder } from "../../testbuilding/JavaScriptDecoder"; +import { TypeEnum } from "@syntest/analysis-javascript"; /** * @author Dimitri Stallenberg @@ -71,7 +72,7 @@ export abstract class Statement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, + type: TypeEnum, uniqueId: string ) { this._variableIdentifier = variableIdentifier; diff --git a/libraries/search-javascript/lib/testcase/statements/action/ActionStatement.ts b/libraries/search-javascript/lib/testcase/statements/action/ActionStatement.ts index ee75f1eeb..5d6135cab 100644 --- a/libraries/search-javascript/lib/testcase/statements/action/ActionStatement.ts +++ b/libraries/search-javascript/lib/testcase/statements/action/ActionStatement.ts @@ -19,7 +19,7 @@ import { Encoding, EncodingSampler, shouldNeverHappen } from "@syntest/search"; import { Statement } from "../Statement"; -import { Export } from "@syntest/analysis-javascript"; +import { Export, TypeEnum } from "@syntest/analysis-javascript"; /** * @author Dimitri Stallenberg @@ -32,7 +32,7 @@ export abstract class ActionStatement extends Statement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, + type: TypeEnum, uniqueId: string, arguments_: Statement[], export_?: Export diff --git a/libraries/search-javascript/lib/testcase/statements/action/ClassActionStatement.ts b/libraries/search-javascript/lib/testcase/statements/action/ClassActionStatement.ts index 2bc6896d3..a85f68255 100644 --- a/libraries/search-javascript/lib/testcase/statements/action/ClassActionStatement.ts +++ b/libraries/search-javascript/lib/testcase/statements/action/ClassActionStatement.ts @@ -19,6 +19,7 @@ import { shouldNeverHappen } from "@syntest/search"; import { Statement } from "../Statement"; import { ActionStatement } from "./ActionStatement"; import { ConstructorCall } from "./ConstructorCall"; +import { TypeEnum } from "@syntest/analysis-javascript"; export abstract class ClassActionStatement extends ActionStatement { private _constructor: ConstructorCall; @@ -35,7 +36,7 @@ export abstract class ClassActionStatement extends ActionStatement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, + type: TypeEnum, uniqueId: string, arguments_: Statement[], constructor_: ConstructorCall diff --git a/libraries/search-javascript/lib/testcase/statements/action/ConstantObject.ts b/libraries/search-javascript/lib/testcase/statements/action/ConstantObject.ts index f605c61a1..20280a32d 100644 --- a/libraries/search-javascript/lib/testcase/statements/action/ConstantObject.ts +++ b/libraries/search-javascript/lib/testcase/statements/action/ConstantObject.ts @@ -22,7 +22,7 @@ import { JavaScriptDecoder } from "../../../testbuilding/JavaScriptDecoder"; import { JavaScriptTestCaseSampler } from "../../sampling/JavaScriptTestCaseSampler"; import { Decoding } from "../Statement"; -import { Export } from "@syntest/analysis-javascript"; +import { Export, TypeEnum } from "@syntest/analysis-javascript"; import { ActionStatement } from "./ActionStatement"; /** @@ -33,7 +33,6 @@ export class ConstantObject extends ActionStatement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string, export_: Export ) { @@ -41,7 +40,7 @@ export class ConstantObject extends ActionStatement { variableIdentifier, typeIdentifier, name, - type, + TypeEnum.OBJECT, uniqueId, [], export_ @@ -68,7 +67,6 @@ export class ConstantObject extends ActionStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId, this.export ); diff --git a/libraries/search-javascript/lib/testcase/statements/action/ConstructorCall.ts b/libraries/search-javascript/lib/testcase/statements/action/ConstructorCall.ts index 7764af5c7..fded76662 100644 --- a/libraries/search-javascript/lib/testcase/statements/action/ConstructorCall.ts +++ b/libraries/search-javascript/lib/testcase/statements/action/ConstructorCall.ts @@ -23,7 +23,7 @@ import { JavaScriptTestCaseSampler } from "../../sampling/JavaScriptTestCaseSamp import { MethodCall } from "./MethodCall"; import { Decoding, Statement } from "../Statement"; -import { Export } from "@syntest/analysis-javascript"; +import { Export, TypeEnum } from "@syntest/analysis-javascript"; import { ActionStatement } from "./ActionStatement"; /** @@ -48,7 +48,6 @@ export class ConstructorCall extends ActionStatement { typeIdentifier: string, classIdentifier: string, name: string, - type: string, uniqueId: string, arguments_: Statement[], export_: Export @@ -57,7 +56,7 @@ export class ConstructorCall extends ActionStatement { variableIdentifier, typeIdentifier, name, - type, + TypeEnum.FUNCTION, uniqueId, arguments_, export_ @@ -88,7 +87,6 @@ export class ConstructorCall extends ActionStatement { this.typeIdentifier, this._classIdentifier, this.name, - this.type, prng.uniqueId(), arguments_, this.export @@ -113,7 +111,6 @@ export class ConstructorCall extends ActionStatement { this.typeIdentifier, this._classIdentifier, this.name, - this.type, this.uniqueId, deepCopyArguments, this.export diff --git a/libraries/search-javascript/lib/testcase/statements/action/FunctionCall.ts b/libraries/search-javascript/lib/testcase/statements/action/FunctionCall.ts index f9f1c38d0..d24ca3d01 100644 --- a/libraries/search-javascript/lib/testcase/statements/action/FunctionCall.ts +++ b/libraries/search-javascript/lib/testcase/statements/action/FunctionCall.ts @@ -22,7 +22,7 @@ import { JavaScriptDecoder } from "../../../testbuilding/JavaScriptDecoder"; import { JavaScriptTestCaseSampler } from "../../sampling/JavaScriptTestCaseSampler"; import { Decoding, Statement } from "../Statement"; -import { Export } from "@syntest/analysis-javascript"; +import { Export, TypeEnum } from "@syntest/analysis-javascript"; import { ActionStatement } from "./ActionStatement"; /** @@ -39,7 +39,6 @@ export class FunctionCall extends ActionStatement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string, arguments_: Statement[], export_: Export @@ -48,7 +47,7 @@ export class FunctionCall extends ActionStatement { variableIdentifier, typeIdentifier, name, - type, + TypeEnum.FUNCTION, uniqueId, arguments_, export_ @@ -69,7 +68,6 @@ export class FunctionCall extends ActionStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), arguments_, this.export @@ -83,7 +81,6 @@ export class FunctionCall extends ActionStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId, deepCopyArguments, this.export diff --git a/libraries/search-javascript/lib/testcase/statements/action/Getter.ts b/libraries/search-javascript/lib/testcase/statements/action/Getter.ts index e21630619..788a0ae07 100644 --- a/libraries/search-javascript/lib/testcase/statements/action/Getter.ts +++ b/libraries/search-javascript/lib/testcase/statements/action/Getter.ts @@ -24,6 +24,7 @@ import { Decoding } from "../Statement"; import { ClassActionStatement } from "./ClassActionStatement"; import { ConstructorCall } from "./ConstructorCall"; +import { TypeEnum } from "@syntest/analysis-javascript"; /** * @author Dimitri Stallenberg @@ -40,7 +41,6 @@ export class Getter extends ClassActionStatement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string, constructor_: ConstructorCall ) { @@ -48,7 +48,7 @@ export class Getter extends ClassActionStatement { variableIdentifier, typeIdentifier, name, - type, + TypeEnum.FUNCTION, uniqueId, [], constructor_ @@ -63,7 +63,6 @@ export class Getter extends ClassActionStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), constructor_ ); @@ -74,9 +73,8 @@ export class Getter extends ClassActionStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId, - this.constructor_ + this.constructor_.copy() ); } diff --git a/libraries/search-javascript/lib/testcase/statements/action/MethodCall.ts b/libraries/search-javascript/lib/testcase/statements/action/MethodCall.ts index 6aff30f6d..cf139fa7f 100644 --- a/libraries/search-javascript/lib/testcase/statements/action/MethodCall.ts +++ b/libraries/search-javascript/lib/testcase/statements/action/MethodCall.ts @@ -24,6 +24,7 @@ import { Decoding, Statement } from "../Statement"; import { ConstructorCall } from "./ConstructorCall"; import { ClassActionStatement } from "./ClassActionStatement"; +import { TypeEnum } from "@syntest/analysis-javascript"; /** * @author Dimitri Stallenberg @@ -32,7 +33,6 @@ export class MethodCall extends ClassActionStatement { /** * Constructor * @param identifierDescription the return type options of the function - * @param type the return type of the function * @param uniqueId id of the gene * @param methodName the name of the function * @param args the arguments of the function @@ -41,7 +41,6 @@ export class MethodCall extends ClassActionStatement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string, arguments_: Statement[], constructor_: ConstructorCall @@ -50,7 +49,7 @@ export class MethodCall extends ClassActionStatement { variableIdentifier, typeIdentifier, name, - type, + TypeEnum.FUNCTION, uniqueId, arguments_, constructor_ @@ -74,7 +73,6 @@ export class MethodCall extends ClassActionStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), arguments_, constructor_ @@ -88,7 +86,6 @@ export class MethodCall extends ClassActionStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId, deepCopyArguments, this.constructor_.copy() diff --git a/libraries/search-javascript/lib/testcase/statements/action/ObjectFunctionCall.ts b/libraries/search-javascript/lib/testcase/statements/action/ObjectFunctionCall.ts index 9afcfa100..ee22efdd4 100644 --- a/libraries/search-javascript/lib/testcase/statements/action/ObjectFunctionCall.ts +++ b/libraries/search-javascript/lib/testcase/statements/action/ObjectFunctionCall.ts @@ -25,6 +25,7 @@ import { Decoding, Statement } from "../Statement"; import { ActionStatement } from "./ActionStatement"; import { ConstantObject } from "./ConstantObject"; +import { TypeEnum } from "@syntest/analysis-javascript"; /** * @author Dimitri Stallenberg @@ -44,12 +45,18 @@ export class ObjectFunctionCall extends ActionStatement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string, arguments_: Statement[], object_: ConstantObject ) { - super(variableIdentifier, typeIdentifier, name, type, uniqueId, arguments_); + super( + variableIdentifier, + typeIdentifier, + name, + TypeEnum.FUNCTION, + uniqueId, + arguments_ + ); this._classType = "ObjectFunctionCall"; this._object = object_; } @@ -73,7 +80,6 @@ export class ObjectFunctionCall extends ActionStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), arguments_, object_ @@ -114,7 +120,6 @@ export class ObjectFunctionCall extends ActionStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId, deepCopyArguments, this._object.copy() diff --git a/libraries/search-javascript/lib/testcase/statements/action/Setter.ts b/libraries/search-javascript/lib/testcase/statements/action/Setter.ts index bdef00e40..9851bc2c9 100644 --- a/libraries/search-javascript/lib/testcase/statements/action/Setter.ts +++ b/libraries/search-javascript/lib/testcase/statements/action/Setter.ts @@ -26,6 +26,7 @@ import { Getter } from "./Getter"; import { MethodCall } from "./MethodCall"; import { ClassActionStatement } from "./ClassActionStatement"; import { ConstructorCall } from "./ConstructorCall"; +import { TypeEnum } from "@syntest/analysis-javascript"; /** * @author Dimitri Stallenberg @@ -43,7 +44,6 @@ export class Setter extends ClassActionStatement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string, argument: Statement, constructor_: ConstructorCall @@ -52,7 +52,7 @@ export class Setter extends ClassActionStatement { variableIdentifier, typeIdentifier, name, - type, + TypeEnum.FUNCTION, uniqueId, [argument], constructor_ @@ -77,7 +77,6 @@ export class Setter extends ClassActionStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), argument, constructor_ @@ -91,7 +90,6 @@ export class Setter extends ClassActionStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId, deepCopyArgument, this.constructor_.copy() diff --git a/libraries/search-javascript/lib/testcase/statements/complex/ArrayStatement.ts b/libraries/search-javascript/lib/testcase/statements/complex/ArrayStatement.ts index 28877cb57..3b413ca82 100644 --- a/libraries/search-javascript/lib/testcase/statements/complex/ArrayStatement.ts +++ b/libraries/search-javascript/lib/testcase/statements/complex/ArrayStatement.ts @@ -22,6 +22,7 @@ import { shouldNeverHappen } from "@syntest/search"; import { JavaScriptDecoder } from "../../../testbuilding/JavaScriptDecoder"; import { JavaScriptTestCaseSampler } from "../../sampling/JavaScriptTestCaseSampler"; import { Decoding, Statement } from "../Statement"; +import { TypeEnum } from "@syntest/analysis-javascript"; /** * @author Dimitri Stallenberg @@ -34,11 +35,10 @@ export class ArrayStatement extends Statement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string, children: Statement[] ) { - super(variableIdentifier, typeIdentifier, name, type, uniqueId); + super(variableIdentifier, typeIdentifier, name, TypeEnum.ARRAY, uniqueId); this._children = children; this._classType = "ArrayStatement"; @@ -89,7 +89,6 @@ export class ArrayStatement extends Statement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), children ); @@ -106,8 +105,8 @@ export class ArrayStatement extends Statement { return sampler.sampleArray( depth, this.variableIdentifier, - this.name, - this.type + this.typeIdentifier, + this.name ); } } @@ -118,7 +117,6 @@ export class ArrayStatement extends Statement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId, this._children .filter((a) => { diff --git a/libraries/search-javascript/lib/testcase/statements/complex/ArrowFunctionStatement.ts b/libraries/search-javascript/lib/testcase/statements/complex/ArrowFunctionStatement.ts index 32b1023e4..872704a36 100644 --- a/libraries/search-javascript/lib/testcase/statements/complex/ArrowFunctionStatement.ts +++ b/libraries/search-javascript/lib/testcase/statements/complex/ArrowFunctionStatement.ts @@ -22,6 +22,7 @@ import { shouldNeverHappen } from "@syntest/search"; import { JavaScriptDecoder } from "../../../testbuilding/JavaScriptDecoder"; import { JavaScriptTestCaseSampler } from "../../sampling/JavaScriptTestCaseSampler"; import { Decoding, Statement } from "../Statement"; +import { TypeEnum } from "@syntest/analysis-javascript"; /** * @author Dimitri Stallenberg @@ -34,12 +35,17 @@ export class ArrowFunctionStatement extends Statement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string, parameters: string[], returnValue: Statement | undefined ) { - super(variableIdentifier, typeIdentifier, name, type, uniqueId); + super( + variableIdentifier, + typeIdentifier, + name, + TypeEnum.FUNCTION, + uniqueId + ); this._parameters = parameters; this._returnValue = returnValue; this._classType = "ArrowFunctionStatement"; @@ -52,7 +58,6 @@ export class ArrowFunctionStatement extends Statement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), this._parameters, this.returnValue @@ -73,8 +78,8 @@ export class ArrowFunctionStatement extends Statement { return sampler.sampleArrowFunction( depth, this.variableIdentifier, - this.name, - this.type + this.typeIdentifier, + this.name ); } } @@ -85,7 +90,6 @@ export class ArrowFunctionStatement extends Statement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId, this._parameters, this._returnValue diff --git a/libraries/search-javascript/lib/testcase/statements/complex/ObjectStatement.ts b/libraries/search-javascript/lib/testcase/statements/complex/ObjectStatement.ts index 48b95b971..b9aac089a 100644 --- a/libraries/search-javascript/lib/testcase/statements/complex/ObjectStatement.ts +++ b/libraries/search-javascript/lib/testcase/statements/complex/ObjectStatement.ts @@ -22,6 +22,7 @@ import { shouldNeverHappen } from "@syntest/search"; import { JavaScriptDecoder } from "../../../testbuilding/JavaScriptDecoder"; import { JavaScriptTestCaseSampler } from "../../sampling/JavaScriptTestCaseSampler"; import { Decoding, Statement } from "../Statement"; +import { TypeEnum } from "@syntest/analysis-javascript"; /** * @author Dimitri Stallenberg @@ -36,11 +37,10 @@ export class ObjectStatement extends Statement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string, object: ObjectType ) { - super(variableIdentifier, typeIdentifier, name, type, uniqueId); + super(variableIdentifier, typeIdentifier, name, TypeEnum.OBJECT, uniqueId); this._object = object; this._classType = "ObjectStatement"; @@ -65,7 +65,6 @@ export class ObjectStatement extends Statement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), object ); @@ -117,7 +116,6 @@ export class ObjectStatement extends Statement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), object ); @@ -135,8 +133,8 @@ export class ObjectStatement extends Statement { return sampler.sampleObject( depth, this.variableIdentifier, - this.name, - this.type + this.typeIdentifier, + this.name ); } } @@ -162,7 +160,6 @@ export class ObjectStatement extends Statement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId, this._object ); diff --git a/libraries/search-javascript/lib/testcase/statements/primitive/BoolStatement.ts b/libraries/search-javascript/lib/testcase/statements/primitive/BoolStatement.ts index c16edc8e2..f7534d664 100644 --- a/libraries/search-javascript/lib/testcase/statements/primitive/BoolStatement.ts +++ b/libraries/search-javascript/lib/testcase/statements/primitive/BoolStatement.ts @@ -22,6 +22,7 @@ import { JavaScriptTestCaseSampler } from "../../sampling/JavaScriptTestCaseSamp import { PrimitiveStatement } from "./PrimitiveStatement"; import { Statement } from "../Statement"; +import { TypeEnum } from "@syntest/analysis-javascript"; /** * @author Dimitri Stallenberg @@ -31,11 +32,17 @@ export class BoolStatement extends PrimitiveStatement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string, value: boolean ) { - super(variableIdentifier, typeIdentifier, name, type, uniqueId, value); + super( + variableIdentifier, + typeIdentifier, + name, + TypeEnum.BOOLEAN, + uniqueId, + value + ); this._classType = "BoolStatement"; } @@ -46,7 +53,6 @@ export class BoolStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), !this.value ); @@ -65,7 +71,6 @@ export class BoolStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId, this.value ); diff --git a/libraries/search-javascript/lib/testcase/statements/primitive/IntegerStatement.ts b/libraries/search-javascript/lib/testcase/statements/primitive/IntegerStatement.ts index adc223158..3639c1b79 100644 --- a/libraries/search-javascript/lib/testcase/statements/primitive/IntegerStatement.ts +++ b/libraries/search-javascript/lib/testcase/statements/primitive/IntegerStatement.ts @@ -23,6 +23,7 @@ import { JavaScriptTestCaseSampler } from "../../sampling/JavaScriptTestCaseSamp import { PrimitiveStatement } from "./PrimitiveStatement"; import { Statement } from "../Statement"; import { NumericStatement } from "./NumericStatement"; +import { TypeEnum } from "@syntest/analysis-javascript"; /** * Generic number class @@ -34,7 +35,6 @@ export class IntegerStatement extends PrimitiveStatement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string, value: number ) { @@ -42,7 +42,7 @@ export class IntegerStatement extends PrimitiveStatement { variableIdentifier, typeIdentifier, name, - type, + TypeEnum.INTEGER, uniqueId, Math.round(value) ); @@ -58,7 +58,6 @@ export class IntegerStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), this.value ).deltaMutation(sampler); @@ -75,7 +74,11 @@ export class IntegerStatement extends PrimitiveStatement { ); } else { // 50% - return sampler.sampleInteger(this.variableIdentifier, this.name); + return sampler.sampleInteger( + this.variableIdentifier, + this.typeIdentifier, + this.name + ); } } } @@ -102,7 +105,6 @@ export class IntegerStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), newValue ); @@ -113,7 +115,6 @@ export class IntegerStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId, this.value ); diff --git a/libraries/search-javascript/lib/testcase/statements/primitive/NullStatement.ts b/libraries/search-javascript/lib/testcase/statements/primitive/NullStatement.ts index a84ef1655..988a20f5a 100644 --- a/libraries/search-javascript/lib/testcase/statements/primitive/NullStatement.ts +++ b/libraries/search-javascript/lib/testcase/statements/primitive/NullStatement.ts @@ -21,6 +21,7 @@ import { prng } from "@syntest/prng"; import { PrimitiveStatement } from "./PrimitiveStatement"; import { JavaScriptTestCaseSampler } from "../../sampling/JavaScriptTestCaseSampler"; import { Statement } from "../Statement"; +import { TypeEnum } from "@syntest/analysis-javascript"; /** * @author Dimitri Stallenberg @@ -30,11 +31,17 @@ export class NullStatement extends PrimitiveStatement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string ) { - // eslint-disable-next-line unicorn/no-null - super(variableIdentifier, typeIdentifier, name, type, uniqueId, null); + super( + variableIdentifier, + typeIdentifier, + name, + TypeEnum.NULL, + uniqueId, + // eslint-disable-next-line unicorn/no-null + null + ); this._classType = "NullStatement"; } @@ -45,7 +52,6 @@ export class NullStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId() ); } else { @@ -63,7 +69,6 @@ export class NullStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId ); } diff --git a/libraries/search-javascript/lib/testcase/statements/primitive/NumericStatement.ts b/libraries/search-javascript/lib/testcase/statements/primitive/NumericStatement.ts index 523e2827c..129f89736 100644 --- a/libraries/search-javascript/lib/testcase/statements/primitive/NumericStatement.ts +++ b/libraries/search-javascript/lib/testcase/statements/primitive/NumericStatement.ts @@ -23,6 +23,7 @@ import { JavaScriptTestCaseSampler } from "../../sampling/JavaScriptTestCaseSamp import { PrimitiveStatement } from "./PrimitiveStatement"; import { Statement } from "../Statement"; import { IntegerStatement } from "./IntegerStatement"; +import { TypeEnum } from "@syntest/analysis-javascript"; /** * Generic number class @@ -34,11 +35,17 @@ export class NumericStatement extends PrimitiveStatement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string, value: number ) { - super(variableIdentifier, typeIdentifier, name, type, uniqueId, value); + super( + variableIdentifier, + typeIdentifier, + name, + TypeEnum.NUMERIC, + uniqueId, + value + ); this._classType = "NumericStatement"; } @@ -51,7 +58,6 @@ export class NumericStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), this.value ).deltaMutation(sampler); @@ -68,7 +74,11 @@ export class NumericStatement extends PrimitiveStatement { ); } else { // 50% - return sampler.sampleNumber(this.variableIdentifier, this.name); + return sampler.sampleNumber( + this.variableIdentifier, + this.typeIdentifier, + this.name + ); } } } @@ -95,7 +105,6 @@ export class NumericStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), newValue ); @@ -106,7 +115,6 @@ export class NumericStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId, this.value ); diff --git a/libraries/search-javascript/lib/testcase/statements/primitive/PrimitiveStatement.ts b/libraries/search-javascript/lib/testcase/statements/primitive/PrimitiveStatement.ts index a5c2c6f89..4163a7097 100644 --- a/libraries/search-javascript/lib/testcase/statements/primitive/PrimitiveStatement.ts +++ b/libraries/search-javascript/lib/testcase/statements/primitive/PrimitiveStatement.ts @@ -16,6 +16,7 @@ * limitations under the License. */ +import { TypeEnum } from "@syntest/analysis-javascript"; import { JavaScriptTestCaseSampler } from "../../sampling/JavaScriptTestCaseSampler"; import { Decoding, Statement } from "../Statement"; @@ -32,7 +33,7 @@ export abstract class PrimitiveStatement extends Statement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, + type: TypeEnum, uniqueId: string, value: T ) { diff --git a/libraries/search-javascript/lib/testcase/statements/primitive/StringStatement.ts b/libraries/search-javascript/lib/testcase/statements/primitive/StringStatement.ts index a20e95e33..c865afdb6 100644 --- a/libraries/search-javascript/lib/testcase/statements/primitive/StringStatement.ts +++ b/libraries/search-javascript/lib/testcase/statements/primitive/StringStatement.ts @@ -22,6 +22,7 @@ import { JavaScriptTestCaseSampler } from "../../sampling/JavaScriptTestCaseSamp import { Decoding, Statement } from "../Statement"; import { PrimitiveStatement } from "./PrimitiveStatement"; +import { TypeEnum } from "@syntest/analysis-javascript"; /** * @author Dimitri Stallenberg @@ -34,13 +35,19 @@ export class StringStatement extends PrimitiveStatement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string, value: string, alphabet: string, maxlength: number ) { - super(variableIdentifier, typeIdentifier, name, type, uniqueId, value); + super( + variableIdentifier, + typeIdentifier, + name, + TypeEnum.STRING, + uniqueId, + value + ); this._classType = "StringStatement"; this.alphabet = alphabet; @@ -99,7 +106,11 @@ export class StringStatement extends PrimitiveStatement { ); } else { // 50% - return sampler.sampleString(this.variableIdentifier, this.name); + return sampler.sampleString( + this.variableIdentifier, + this.typeIdentifier, + this.name + ); } } } @@ -115,7 +126,6 @@ export class StringStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), newValue.join(""), this.alphabet, @@ -133,7 +143,6 @@ export class StringStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), newValue.join(""), this.alphabet, @@ -152,7 +161,6 @@ export class StringStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), newValue.join(""), this.alphabet, @@ -184,7 +192,6 @@ export class StringStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId(), newValue.join(""), this.alphabet, @@ -197,7 +204,6 @@ export class StringStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId, this.value, this.alphabet, diff --git a/libraries/search-javascript/lib/testcase/statements/primitive/UndefinedStatement.ts b/libraries/search-javascript/lib/testcase/statements/primitive/UndefinedStatement.ts index f853ef265..bee396ecd 100644 --- a/libraries/search-javascript/lib/testcase/statements/primitive/UndefinedStatement.ts +++ b/libraries/search-javascript/lib/testcase/statements/primitive/UndefinedStatement.ts @@ -21,6 +21,7 @@ import { prng } from "@syntest/prng"; import { PrimitiveStatement } from "./PrimitiveStatement"; import { Statement } from "../Statement"; import { JavaScriptTestCaseSampler } from "../../sampling/JavaScriptTestCaseSampler"; +import { TypeEnum } from "@syntest/analysis-javascript"; /** * @author Dimitri Stallenberg @@ -30,14 +31,13 @@ export class UndefinedStatement extends PrimitiveStatement { variableIdentifier: string, typeIdentifier: string, name: string, - type: string, uniqueId: string ) { super( variableIdentifier, typeIdentifier, name, - type, + TypeEnum.UNDEFINED, uniqueId, // eslint-disable-next-line unicorn/no-useless-undefined undefined @@ -52,7 +52,6 @@ export class UndefinedStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, prng.uniqueId() ); } else { @@ -70,7 +69,6 @@ export class UndefinedStatement extends PrimitiveStatement { this.variableIdentifier, this.typeIdentifier, this.name, - this.type, this.uniqueId ); } diff --git a/tools/javascript/lib/JavaScriptLauncher.ts b/tools/javascript/lib/JavaScriptLauncher.ts index 716885b1f..227f2aae1 100644 --- a/tools/javascript/lib/JavaScriptLauncher.ts +++ b/tools/javascript/lib/JavaScriptLauncher.ts @@ -830,7 +830,9 @@ export class JavaScriptLauncher extends Launcher { async exit(): Promise { JavaScriptLauncher.LOGGER.info("Exiting"); - this.runner.process.kill(); + if (this.runner && this.runner.process) { + this.runner.process.kill(); + } // TODO should be cleanup step in tool // Finish JavaScriptLauncher.LOGGER.info("Deleting temporary directories"); From 07df68c0103efb9b4086efa0038168a16d6ab7eb Mon Sep 17 00:00:00 2001 From: Dimitri Stallenberg Date: Tue, 29 Aug 2023 23:38:47 +0200 Subject: [PATCH 06/14] fix: type model --- .../lib/type/resolving/TypeModel.ts | 25 +++++++++++++------ .../lib/testcase/StatementPool.ts | 2 +- .../ExecutionInformationIntegrator.ts | 4 +-- .../lib/testcase/statements/Statement.ts | 4 +-- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts index b720cdde1..2aaae6210 100644 --- a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts +++ b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts @@ -234,25 +234,34 @@ export class TypeModel { this.getObjectDescription(element).elements.add(id); } - // TODO type should be TypeEnum? - addExecutionScore(id: string, type: string, score: number) { + // TODO should also add scores to the relations when relevant + addExecutionScore( + id: string, + typeId: string, + typeEnum: TypeEnum, + score = -1 + ) { if (!this._typeExecutionScoreMap.has(id)) { throw new Error(`Element ${id} does not exist`); } + let type: string = typeEnum; + + if (id !== typeId) { + type = `${typeId}<>${typeEnum}`; + } + if (!this._typeExecutionScoreMap.get(id).has(type)) { this._typeExecutionScoreMap.get(id).set(type, 0); } - const currentScore = this._typeExecutionScoreMap.get(id).get(type); - - this._typeExecutionScoreMap.get(id).set(type, currentScore + score); - - this._scoreHasChangedMap.set(id, true); - if (!this._elementTypeScoreMap.get(id).has(type)) { this._elementTypeScoreMap.get(id).set(type, 0); } + + const currentScore = this._typeExecutionScoreMap.get(id).get(type); + this._typeExecutionScoreMap.get(id).set(type, currentScore + score); + this._scoreHasChangedMap.set(id, true); } private _sum(iterable: Iterable) { diff --git a/libraries/search-javascript/lib/testcase/StatementPool.ts b/libraries/search-javascript/lib/testcase/StatementPool.ts index cd6da9a00..5ad441e3f 100644 --- a/libraries/search-javascript/lib/testcase/StatementPool.ts +++ b/libraries/search-javascript/lib/testcase/StatementPool.ts @@ -82,7 +82,7 @@ export class StatementPool { } // use type enum for primitives and arrays - let type = statement.type; + let type: string = statement.type; if (statement instanceof ConstantObject) { // use export identifier diff --git a/libraries/search-javascript/lib/testcase/execution/ExecutionInformationIntegrator.ts b/libraries/search-javascript/lib/testcase/execution/ExecutionInformationIntegrator.ts index 49be993c5..16ca056af 100644 --- a/libraries/search-javascript/lib/testcase/execution/ExecutionInformationIntegrator.ts +++ b/libraries/search-javascript/lib/testcase/execution/ExecutionInformationIntegrator.ts @@ -45,8 +45,8 @@ export class ExecutionInformationIntegrator { if (testResult.exception && testResult.exception.includes(child.name)) { this._typeModel.addExecutionScore( child.variableIdentifier, - child.type, - -1 + child.typeIdentifier, + child.type ); } queue.push(child); diff --git a/libraries/search-javascript/lib/testcase/statements/Statement.ts b/libraries/search-javascript/lib/testcase/statements/Statement.ts index be6207d3b..2ed269331 100644 --- a/libraries/search-javascript/lib/testcase/statements/Statement.ts +++ b/libraries/search-javascript/lib/testcase/statements/Statement.ts @@ -28,7 +28,7 @@ export abstract class Statement { private _variableIdentifier: string; private _typeIdentifier: string; private _name: string; - private _type: string; + private _type: TypeEnum; protected _uniqueId: string; protected _varName: string; @@ -46,7 +46,7 @@ export abstract class Statement { return this._name; } - get type(): string { + get type(): TypeEnum { return this._type; } From 6f2bddeff5644023ae8ca6d63327731138fde2f9 Mon Sep 17 00:00:00 2001 From: Dimitri Stallenberg Date: Tue, 29 Aug 2023 23:49:27 +0200 Subject: [PATCH 07/14] fix: type model --- libraries/analysis-javascript/lib/type/resolving/TypeModel.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts index 2aaae6210..d60f22057 100644 --- a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts +++ b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts @@ -171,7 +171,8 @@ export class TypeModel { addRelationScore(id1: string, id2: string, score: number) { if (id1 === id2) { // no self loops - throw new Error(`ids should not be equal to add a relation id: ${id1}`); + return; + // throw new Error(`ids should not be equal to add a relation id: ${id1}`); } this._addRelationScore(id1, id2, score); this._addRelationScore(id2, id1, score); From 05cf11cb9a479f8098670f7eed36ea9c8e7297cc Mon Sep 17 00:00:00 2001 From: Dimitri Stallenberg Date: Wed, 30 Aug 2023 16:05:49 +0200 Subject: [PATCH 08/14] fix: type model --- .../lib/type/discovery/element/Element.ts | 3 +- .../type/discovery/element/ElementVisitor.ts | 23 +++++++-- .../resolving/InferenceTypeModelFactory.ts | 15 ++++-- .../lib/type/resolving/TypeModel.ts | 47 +++++++++---------- .../lib/AbstractSyntaxTreeVisitor.ts | 22 +++++++-- 5 files changed, 73 insertions(+), 37 deletions(-) diff --git a/libraries/analysis-javascript/lib/type/discovery/element/Element.ts b/libraries/analysis-javascript/lib/type/discovery/element/Element.ts index 0868697b8..27f82867b 100644 --- a/libraries/analysis-javascript/lib/type/discovery/element/Element.ts +++ b/libraries/analysis-javascript/lib/type/discovery/element/Element.ts @@ -20,18 +20,19 @@ export type Element = Identifier | Literal; export interface Identifier { id: string; + bindingId: string; filePath: string; location: { startIndex: number; endIndex: number; }; type: ElementType.Identifier; - bindingId: string; name: string; } export interface Literal { id: string; + bindingId: string; filePath: string; location: { startIndex: number; diff --git a/libraries/analysis-javascript/lib/type/discovery/element/ElementVisitor.ts b/libraries/analysis-javascript/lib/type/discovery/element/ElementVisitor.ts index f318ab99c..d65322f1f 100644 --- a/libraries/analysis-javascript/lib/type/discovery/element/ElementVisitor.ts +++ b/libraries/analysis-javascript/lib/type/discovery/element/ElementVisitor.ts @@ -17,13 +17,27 @@ */ import { NodePath } from "@babel/core"; import * as t from "@babel/types"; -import { AbstractSyntaxTreeVisitor } from "@syntest/ast-visitor-javascript"; +import { + AbstractSyntaxTreeVisitor, + MemberSeparator, +} from "@syntest/ast-visitor-javascript"; import { Element, ElementType } from "../element/Element"; export class ElementVisitor extends AbstractSyntaxTreeVisitor { private _elementMap: Map; get elementMap(): Map { + for (const value of this._elementMap.values()) { + if ( + !this._elementMap.has(value.bindingId) && + value.bindingId.includes(MemberSeparator) + ) { + this._elementMap.set(value.bindingId, { + ...value, + id: value.bindingId, + }); + } + } return this._elementMap; } @@ -37,24 +51,25 @@ export class ElementVisitor extends AbstractSyntaxTreeVisitor { type: ElementType, value: string ) { - if (type === ElementType.Identifier) { - const bindingId = this._getBindingId(path); + const bindingId = this._getBindingId(path); + if (type === ElementType.Identifier) { const element: Element = { id: this._getNodeId(path), + bindingId, filePath: this._filePath, location: { startIndex: (<{ index: number }>(path.node.loc.start)).index, endIndex: (<{ index: number }>(path.node.loc.end)).index, }, type: ElementType.Identifier, - bindingId, name: value, }; this._elementMap.set(element.id, element); } else { const element: Element = { id: this._getNodeId(path), + bindingId, filePath: this._filePath, location: { startIndex: (<{ index: number }>(path.node.loc.start)).index, diff --git a/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts b/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts index 6e9c46b51..75684e330 100644 --- a/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts +++ b/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts @@ -98,9 +98,9 @@ export class InferenceTypeModelFactory extends TypeModelFactory { continue; } - this.createNewTypeProbability(element.id, element.id); + this.createNewTypeProbability(element.id, element.bindingId); this._typeModel.addTypeScore( - element.id, + element.bindingId, elementTypeToTypingType(element.type) ); } @@ -513,6 +513,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { // connect class to relation this._typeModel.setEqual(classId, relationId); + // this._typeModel.addStrongRelation(relationId, classId); break; } @@ -608,6 +609,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { // we don't have to connect the relationid to the propertyId since they are equal already this._typeModel.addStrongRelation(relationId, propertyId); + // this._typeModel.setEqual(relationId, propertyId) break; } @@ -871,13 +873,18 @@ export class InferenceTypeModelFactory extends TypeModelFactory { } const [leftId, rightId] = involved; - this._typeModel.setEqual(leftId, relationId); + if (leftId !== rightId) { + this._typeModel.addStrongRelation(leftId, rightId); + } // undefined should be the actual result // this._typeModel.addPrimitiveTypeScore(relationId, { // type: TypeEnum.UNDEFINED, // }); - this._typeModel.addStrongRelation(leftId, rightId); + // this._typeModel.setEqual(leftId, relationId); + // this._typeModel.addStrongRelation(relationId, leftId); + + this._typeModel.addTypeScore(relationId, TypeEnum.UNDEFINED); break; } diff --git a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts index d60f22057..bdac3cbc8 100644 --- a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts +++ b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts @@ -104,33 +104,30 @@ export class TypeModel { //TODO maybe merge for (const [key, value] of this._relationScoreMap.get(id2).entries()) this._relationScoreMap.get(id1).has(key) - ? this._relationScoreMap.get(id1).set(key, value) - : this._relationScoreMap + ? this._relationScoreMap .get(id1) - .set(key, this._relationScoreMap.get(id1).get(key) + value); + .set(key, this._relationScoreMap.get(id1).get(key) + value) + : this._relationScoreMap.get(id1).set(key, value); for (const [key, value] of this._elementTypeScoreMap.get(id2).entries()) this._elementTypeScoreMap.get(id1).has(key) - ? this._elementTypeScoreMap.get(id1).set(key, value) - : this._elementTypeScoreMap + ? this._elementTypeScoreMap .get(id1) - .set(key, this._elementTypeScoreMap.get(id1).get(key) + value); + .set(key, this._elementTypeScoreMap.get(id1).get(key) + value) + : this._elementTypeScoreMap.get(id1).set(key, value); for (const [key, value] of this._elementTypeProbabilityMap .get(id2) .entries()) this._elementTypeProbabilityMap.get(id1).has(key) - ? this._elementTypeProbabilityMap.get(id1).set(key, value) - : this._elementTypeProbabilityMap + ? this._elementTypeProbabilityMap .get(id1) - .set( - key, - this._elementTypeProbabilityMap.get(id1).get(key) + value - ); + .set(key, this._elementTypeProbabilityMap.get(id1).get(key) + value) + : this._elementTypeProbabilityMap.get(id1).set(key, value); for (const [key, value] of this._typeExecutionScoreMap.get(id2).entries()) this._typeExecutionScoreMap.get(id1).has(key) - ? this._typeExecutionScoreMap.get(id1).set(key, value) - : this._typeExecutionScoreMap + ? this._typeExecutionScoreMap .get(id1) - .set(key, this._typeExecutionScoreMap.get(id1).get(key) + value); + .set(key, this._typeExecutionScoreMap.get(id1).get(key) + value) + : this._typeExecutionScoreMap.get(id1).set(key, value); this._relationScoreMap.set(id2, this._relationScoreMap.get(id1)); this._elementTypeScoreMap.set(id2, this._elementTypeScoreMap.get(id1)); @@ -289,18 +286,18 @@ export class TypeModel { id ); - // const x = new Map() - // for (const [type, probability] of probabilities.entries()) { - // const typeEnum = type.includes('<>') ? type.split('<>')[1] : type + const x = new Map(); + for (const [type, probability] of probabilities.entries()) { + const typeEnum = type.includes("<>") ? type.split("<>")[1] : type; - // if (!x.has(typeEnum)) { - // x.set(typeEnum, 0) - // } + if (!x.has(typeEnum)) { + x.set(typeEnum, 0); + } - // x.set(typeEnum, x.get(typeEnum) + probability) - // } - // console.log(id) - // console.log(x) + x.set(typeEnum, x.get(typeEnum) + probability); + } + console.log(id); + console.log(x); const genericTypes = [ TypeEnum.ARRAY, diff --git a/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts b/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts index d821d6465..de97177e7 100644 --- a/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts +++ b/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts @@ -91,6 +91,9 @@ const reservedKeywords = new Set([ "with", "yield", ]); + +export const MemberSeparator = " <-> "; + export class AbstractSyntaxTreeVisitor implements TraverseOptions { protected static LOGGER: Logger; @@ -159,6 +162,11 @@ export class AbstractSyntaxTreeVisitor implements TraverseOptions { throw new Error("Cannot get binding for labeled statement"); } + // if (path.isThisExpression()) { + // // this expression refers to "thisParent" + // return this._getBindingId(this._getThisParent(path)) + // } + if ( path.parentPath.isMemberExpression() && path.parentPath.get("property") === path @@ -166,10 +174,18 @@ export class AbstractSyntaxTreeVisitor implements TraverseOptions { // we are the property of a member expression // so the binding id is equal to the object of the member expression relation + the id of the property // e.g. bar.foo + if ( + !path.isIdentifier() && + !path.isStringLiteral() && + !path.isNumericLiteral() + ) { + return this._getNodeId(path); + } return ( - // this._getBindingId(path.parentPath.get("object")) + - // " <-> " + - this._getNodeId(path) + this._getBindingId(path.parentPath.get("object")) + + MemberSeparator + + (path.isIdentifier() ? path.node.name : path.node.value) + // this._getNodeId(path) // bad ); } From d1d4e275146793e0f52f75bac2b85c9f94feca12 Mon Sep 17 00:00:00 2001 From: Dimitri Stallenberg Date: Wed, 30 Aug 2023 19:28:53 +0200 Subject: [PATCH 09/14] fix: update --- .../lib/type/resolving/InferenceTypeModelFactory.ts | 1 + .../lib/type/resolving/TypeModel.ts | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts b/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts index 75684e330..738e8ca1f 100644 --- a/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts +++ b/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts @@ -663,6 +663,7 @@ export class InferenceTypeModelFactory extends TypeModelFactory { } case RelationType.LogicalNotUnary: { // TODO can we say something about the argument? + //likely also boolean? this._typeModel.addTypeScore(relationId, TypeEnum.BOOLEAN); break; } diff --git a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts index bdac3cbc8..51ef542ae 100644 --- a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts +++ b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts @@ -162,7 +162,7 @@ export class TypeModel { } addStrongRelation(id1: string, id2: string) { - this.addRelationScore(id1, id2, 10); + this.addRelationScore(id1, id2, 5); } addRelationScore(id1: string, id2: string, score: number) { @@ -175,6 +175,10 @@ export class TypeModel { this._addRelationScore(id2, id1, score); } + addStrongTypeScore(id: string, type: TypeEnum) { + this.addTypeScore(id, type, 5); + } + addTypeScore(id: string, type: TypeEnum, score = 1) { if (!this._elementTypeScoreMap.has(id)) { throw new Error(`Element ${id} does not exist`); @@ -281,6 +285,9 @@ export class TypeModel { randomTypeProbability: number, id: string ): string { + if (id.includes("express/lib/response.js:539:59:::539:67:::13879:13887")) { + console.log(); + } const probabilities = this.calculateProbabilitiesForElement( incorporateExecutionScore, id @@ -575,7 +582,7 @@ export class TypeModel { totalProbability += probability; } - if (totalProbability !== 0) { + if (totalProbability !== 0 && totalProbability !== 1) { for (const [type, probability] of probabilityMap.entries()) { probabilityMap.set(type, probability / totalProbability); } From 5c15f781d8d8d92ec06d3482a2e20267ed05474b Mon Sep 17 00:00:00 2001 From: Dimitri Stallenberg Date: Fri, 1 Sep 2023 15:23:51 +0200 Subject: [PATCH 10/14] fix: computed element type scores --- .../lib/type/resolving/InferenceTypeModelFactory.ts | 9 ++++++--- .../analysis-javascript/lib/type/resolving/TypeModel.ts | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts b/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts index 738e8ca1f..1197a0f03 100644 --- a/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts +++ b/libraries/analysis-javascript/lib/type/resolving/InferenceTypeModelFactory.ts @@ -562,7 +562,10 @@ export class InferenceTypeModelFactory extends TypeModelFactory { if (propertyElement === undefined) { // e.g. object[b ? 1 : 0] - // TODO what if the property is not an element + // the property is not an element + this._typeModel.addTypeScore(objectId, TypeEnum.STRING); + this._typeModel.addTypeScore(objectId, TypeEnum.ARRAY); + this._typeModel.addTypeScore(objectId, TypeEnum.OBJECT, 2); } else switch (propertyElement.type) { case ElementType.NumericalLiteral: { @@ -590,9 +593,9 @@ export class InferenceTypeModelFactory extends TypeModelFactory { // or we can check wether abc is a number // add the defaults - this._typeModel.addTypeScore(objectId, TypeEnum.ARRAY); this._typeModel.addTypeScore(objectId, TypeEnum.STRING); - this._typeModel.addTypeScore(objectId, TypeEnum.OBJECT); + this._typeModel.addTypeScore(objectId, TypeEnum.ARRAY); + this._typeModel.addTypeScore(objectId, TypeEnum.OBJECT, 2); } else { // e.g. object.abc this._typeModel.addPropertyType( diff --git a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts index 51ef542ae..d55ad66ba 100644 --- a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts +++ b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts @@ -162,7 +162,7 @@ export class TypeModel { } addStrongRelation(id1: string, id2: string) { - this.addRelationScore(id1, id2, 5); + this.addRelationScore(id1, id2, 3); } addRelationScore(id1: string, id2: string, score: number) { From ea3673b92d17a1a39ac48f133315f2a33870c0ad Mon Sep 17 00:00:00 2001 From: Dimitri Stallenberg Date: Fri, 1 Sep 2023 15:24:30 +0200 Subject: [PATCH 11/14] fix: computed element type scores --- .../lib/type/resolving/TypeModel.ts | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts index d55ad66ba..07381ffe4 100644 --- a/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts +++ b/libraries/analysis-javascript/lib/type/resolving/TypeModel.ts @@ -285,26 +285,23 @@ export class TypeModel { randomTypeProbability: number, id: string ): string { - if (id.includes("express/lib/response.js:539:59:::539:67:::13879:13887")) { - console.log(); - } const probabilities = this.calculateProbabilitiesForElement( incorporateExecutionScore, id ); - const x = new Map(); - for (const [type, probability] of probabilities.entries()) { - const typeEnum = type.includes("<>") ? type.split("<>")[1] : type; + // const x = new Map(); + // for (const [type, probability] of probabilities.entries()) { + // const typeEnum = type.includes("<>") ? type.split("<>")[1] : type; - if (!x.has(typeEnum)) { - x.set(typeEnum, 0); - } + // if (!x.has(typeEnum)) { + // x.set(typeEnum, 0); + // } - x.set(typeEnum, x.get(typeEnum) + probability); - } - console.log(id); - console.log(x); + // x.set(typeEnum, x.get(typeEnum) + probability); + // } + // console.log(id); + // console.log(x); const genericTypes = [ TypeEnum.ARRAY, From 6fc160f488f37f1e6b6b99a405cf288c502641e7 Mon Sep 17 00:00:00 2001 From: Dimitri Stallenberg Date: Fri, 8 Sep 2023 13:36:54 +0200 Subject: [PATCH 12/14] fix: add multiple parameters back --- .../sampling/generators/action/CallGenerator.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/search-javascript/lib/testcase/sampling/generators/action/CallGenerator.ts b/libraries/search-javascript/lib/testcase/sampling/generators/action/CallGenerator.ts index c6b5f9cae..bd810d916 100644 --- a/libraries/search-javascript/lib/testcase/sampling/generators/action/CallGenerator.ts +++ b/libraries/search-javascript/lib/testcase/sampling/generators/action/CallGenerator.ts @@ -45,12 +45,12 @@ export abstract class CallGenerator extends Generator { } } - // for (let index = 0; index < 10; index++) { - // if (prng.nextBoolean(0.05)) { - // // TODO make this a config parameter - // arguments_.push(this.sampler.sampleArgument(depth + 1, "anon", "anon")); - // } - // } + for (let index = 0; index < 10; index++) { + if (prng.nextBoolean(0.05)) { + // TODO make this a config parameter + arguments_.push(this.sampler.sampleArgument(depth + 1, "anon", "anon")); + } + } return arguments_; } From a77b56b042562b758208a80fdf58586c84a67239 Mon Sep 17 00:00:00 2001 From: Dimitri Stallenberg Date: Fri, 8 Sep 2023 15:10:38 +0200 Subject: [PATCH 13/14] fix: sync package-lock.json and package.json --- package-lock.json | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 48db01460..70d4d389a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -133,7 +133,7 @@ }, "../syntest-core/libraries/metric": { "name": "@syntest/metric", - "version": "0.1.0-beta.6", + "version": "0.1.0-beta.7", "license": "Apache-2.0", "dependencies": { "@syntest/logging": "*", @@ -145,12 +145,12 @@ }, "../syntest-core/libraries/module": { "name": "@syntest/module", - "version": "0.1.0-beta.19", + "version": "0.1.0-beta.20", "license": "Apache-2.0", "dependencies": { "@syntest/cli-graphics": "^0.1.0-beta.3", "@syntest/logging": "*", - "@syntest/metric": "^0.1.0-beta.6", + "@syntest/metric": "^0.1.0-beta.7", "@syntest/storage": "^0.1.0-beta.0", "global-modules": "2.0.0", "yargs": "^17.7.1" @@ -177,7 +177,7 @@ }, "../syntest-core/libraries/search": { "name": "@syntest/search", - "version": "0.4.0-beta.45", + "version": "0.4.0-beta.46", "license": "Apache-2.0", "dependencies": { "@syntest/analysis": "^0.1.0-beta.9", @@ -195,15 +195,15 @@ }, "../syntest-core/tools/base-language": { "name": "@syntest/base-language", - "version": "0.2.0-beta.55", + "version": "0.2.0-beta.57", "license": "Apache-2.0", "dependencies": { "@syntest/analysis": "^0.1.0-beta.9", "@syntest/cli-graphics": "^0.1.0-beta.3", "@syntest/logging": "^0.1.0-beta.7", - "@syntest/metric": "^0.1.0-beta.6", - "@syntest/module": "^0.1.0-beta.19", - "@syntest/search": "^0.4.0-beta.45", + "@syntest/metric": "^0.1.0-beta.7", + "@syntest/module": "^0.1.0-beta.20", + "@syntest/search": "^0.4.0-beta.46", "@syntest/storage": "^0.1.0-beta.0", "globby": "11.0.4", "yargs": "^17.7.1" @@ -4473,6 +4473,10 @@ "resolved": "../syntest-core/libraries/module", "link": true }, + "node_modules/@syntest/plugin-javascript-event-listener-state-storage": { + "resolved": "plugins/plugin-javascript-event-listener-state-storage", + "link": true + }, "node_modules/@syntest/prng": { "resolved": "../syntest-core/libraries/prng", "link": true @@ -14250,6 +14254,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "plugins/plugin-javascript-event-listener-state-storage": { + "version": "0.0.1", + "license": "Apache-2.0", + "dependencies": { + "@syntest/analysis": "*", + "@syntest/analysis-javascript": "*", + "@syntest/base-language": "*", + "@syntest/cfg": "*", + "@syntest/logging": "*", + "@syntest/metric": "*", + "@syntest/module": "*", + "@syntest/search": "*" + }, + "engines": { + "node": ">=16" + } + }, "tools/javascript": { "name": "@syntest/javascript", "version": "0.1.0-beta.22", From d0ea54159bf1362d09194e6a6ed624a3ee2f9905 Mon Sep 17 00:00:00 2001 From: Dimitri Stallenberg Date: Fri, 8 Sep 2023 15:29:41 +0200 Subject: [PATCH 14/14] chore: remove commented code --- .../analysis-javascript/lib/RootContext.ts | 21 ------------------- .../lib/type/discovery/TypeExtractor.ts | 3 --- .../lib/AbstractSyntaxTreeVisitor.ts | 13 ------------ 3 files changed, 37 deletions(-) diff --git a/libraries/analysis-javascript/lib/RootContext.ts b/libraries/analysis-javascript/lib/RootContext.ts index e1dbfefbc..04dc8187c 100644 --- a/libraries/analysis-javascript/lib/RootContext.ts +++ b/libraries/analysis-javascript/lib/RootContext.ts @@ -317,25 +317,4 @@ export class RootContext extends CoreRootContext { return this._typePool; } - - // getElement(id: string): Element { - // if (!this._elementMap || !this._elementMap.has(id)) { - // this.extractTypes(); - // } - // return this._elementMap.get(id); - // } - - // getRelation(id: string): Relation { - // if (!this._relationMap || !this._relationMap.has(id)) { - // this.extractTypes(); - // } - // return this._relationMap.get(id); - // } - - // getObject(id: string): DiscoveredObjectType { - // if (!this._objectMap || !this._objectMap.has(id)) { - // this.extractTypes(); - // } - // return this._objectMap.get(id); - // } } diff --git a/libraries/analysis-javascript/lib/type/discovery/TypeExtractor.ts b/libraries/analysis-javascript/lib/type/discovery/TypeExtractor.ts index 710749d92..960fa6116 100644 --- a/libraries/analysis-javascript/lib/type/discovery/TypeExtractor.ts +++ b/libraries/analysis-javascript/lib/type/discovery/TypeExtractor.ts @@ -19,9 +19,6 @@ import { ObjectVisitor } from "./object/ObjectVisitor"; import traverse from "@babel/traverse"; import { ElementVisitor } from "./element/ElementVisitor"; import { RelationVisitor } from "./relation/RelationVisitor"; -// import { Element } from "./element/Element"; -// import { Relation } from "./relation/Relation"; -// import { DiscoveredObjectType } from "./object/DiscoveredType"; import * as t from "@babel/types"; export class TypeExtractor { diff --git a/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts b/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts index de97177e7..ca93bb732 100644 --- a/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts +++ b/libraries/ast-visitor-javascript/lib/AbstractSyntaxTreeVisitor.ts @@ -162,11 +162,6 @@ export class AbstractSyntaxTreeVisitor implements TraverseOptions { throw new Error("Cannot get binding for labeled statement"); } - // if (path.isThisExpression()) { - // // this expression refers to "thisParent" - // return this._getBindingId(this._getThisParent(path)) - // } - if ( path.parentPath.isMemberExpression() && path.parentPath.get("property") === path @@ -350,12 +345,4 @@ export class AbstractSyntaxTreeVisitor implements TraverseOptions { return this._thisScopeStack[this._thisScopeStack.length - 1]; } - - // protected _getCurrentThisScopeName() { - // if (this._thisScopeStackNames.length === 0) { - // throw new Error("Invalid scope stack!"); - // } - - // return this._thisScopeStackNames[this._thisScopeStackNames.length - 1]; - // } }