Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 355x 355x 355x 355x 355x 355x 355x 355x 355x 355x 355x 355x 355x 158x 158x 343x 355x 434x 434x 434x 434x 295x 295x 295x 295x 295x 295x 295x 295x 75x 75x 71x 71x 295x 220x 220x 220x 220x 220x 295x 8x 8x 8x 8x 8x 8x 295x 295x 2x 295x 7x 293x 256x 256x 256x 288x 288x 295x 256x 295x 30x 30x 434x 139x 1x 1x 434x 288x 288x 288x 1x 1x 1x 1x 355x 88x 88x 88x 88x 18x 18x 18x 88x 3x 3x 67x 67x 355x 38x 267x 64x 229x 7x 165x 158x 158x 86x 86x 158x 72x 72x 1x 1x | import {ExpressionNode} from "../../nodes"; import {CurrentScope} from "../_current_scope"; import * as Expressions from "../../2_statements/expressions"; import {AbstractType} from "../../types/basic/_abstract_type"; import {VoidType, ObjectReferenceType} from "../../types/basic"; import {FieldChain} from "./field_chain"; import {INode} from "../../nodes/_inode"; import {ObjectOriented} from "../_object_oriented"; import {NewObject} from "./new_object"; import {Cast} from "./cast"; import {BuiltIn} from "../_builtin"; import {MethodCallParam} from "./method_call_param"; import {IReferenceExtras, ReferenceType} from "../_reference"; import {ComponentName} from "./component_name"; import {AttributeName} from "./attribute_name"; import {ClassDefinition} from "../../types/class_definition"; export class MethodCallChain { public runSyntax( node: ExpressionNode, scope: CurrentScope, filename: string, targetType?: AbstractType): AbstractType | undefined { const helper = new ObjectOriented(scope); const children = node.getChildren().slice(); const first = children.shift(); if (first === undefined) { throw new Error("MethodCallChain, first child expected"); } let context: AbstractType | undefined = this.findTop(first, scope, targetType, filename); if (first.get() instanceof Expressions.MethodCall) { children.unshift(first); } while (children.length > 0) { const current = children.shift(); if (current === undefined) { break; } if (current instanceof ExpressionNode && current.get() instanceof Expressions.MethodCall) { // for built-in methods set className to undefined const className = context instanceof ObjectReferenceType ? context.getIdentifierName() : undefined; const methodToken = current.findDirectExpression(Expressions.MethodName)?.getFirstToken(); const methodName = methodToken?.getStr(); const def = scope.findObjectDefinition(className); // eslint-disable-next-line prefer-const let {method, def: foundDef} = helper.searchMethodName(def, methodName); if (method === undefined && current === first) { method = new BuiltIn().searchBuiltin(methodName?.toUpperCase()); if (method) { scope.addReference(methodToken, method, ReferenceType.BuiltinMethodReference, filename); } } else { const extra: IReferenceExtras = { ooName: foundDef?.getName(), ooType: foundDef instanceof ClassDefinition ? "CLAS" : "INTF"}; scope.addReference(methodToken, method, ReferenceType.MethodReference, filename, extra); } if (methodName?.includes("~")) { const name = methodName.split("~")[0]; const idef = scope.findInterfaceDefinition(name); if (idef) { scope.addReference(methodToken, idef, ReferenceType.ObjectOrientedReference, filename); } } if (method === undefined && methodName?.toUpperCase() === "CONSTRUCTOR") { context = undefined; // todo, this is a workaround, constructors always exists } else if (method === undefined && !(context instanceof VoidType)) { throw new Error("Method \"" + methodName + "\" not found, methodCallChain"); } else if (method) { const ret = method.getParameters().getReturning()?.getType(); context = ret; } const param = current.findDirectExpression(Expressions.MethodCallParam); if (param && method) { new MethodCallParam().runSyntax(param, scope, method, filename); } else if (param && context instanceof VoidType) { new MethodCallParam().runSyntax(param, scope, context, filename); } } else if (current instanceof ExpressionNode && current.get() instanceof Expressions.ComponentName) { context = new ComponentName().runSyntax(context, current); } else if (current instanceof ExpressionNode && current.get() instanceof Expressions.AttributeName) { context = new AttributeName().runSyntax(context, current, scope, filename); } } return context; } ////////////////////////////////////// private findTop(first: INode, scope: CurrentScope, targetType: AbstractType | undefined, filename: string): AbstractType | undefined { if (first.get() instanceof Expressions.ClassName) { const token = first.getFirstToken(); const className = token.getStr(); const classDefinition = scope.findObjectDefinition(className); if (classDefinition === undefined && scope.getDDIC().inErrorNamespace(className) === false) { const extra: IReferenceExtras = {ooName: className, ooType: "Void"}; scope.addReference(token, undefined, ReferenceType.ObjectOrientedVoidReference, filename, extra); return new VoidType(className); } else if (classDefinition === undefined) { throw new Error("Class " + className + " not found"); } scope.addReference(first.getFirstToken(), classDefinition, ReferenceType.ObjectOrientedReference, filename); return new ObjectReferenceType(classDefinition); } else if (first instanceof ExpressionNode && first.get() instanceof Expressions.FieldChain) { return new FieldChain().runSyntax(first, scope, filename, ReferenceType.DataReadReference); } else if (first instanceof ExpressionNode && first.get() instanceof Expressions.NewObject) { return new NewObject().runSyntax(first, scope, targetType, filename); } else if (first instanceof ExpressionNode && first.get() instanceof Expressions.Cast) { return new Cast().runSyntax(first, scope, targetType, filename); } else { const meType = scope.findVariable("me")?.getType(); if (meType) { return meType; } } return undefined; } } |