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 128 129 130 131 132 133 134 135 136 137 138 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 399x 399x 399x 399x 399x 399x 399x 399x 399x 399x 399x 399x 175x 175x 399x 399x 399x 491x 491x 491x 491x 332x 332x 332x 332x 332x 332x 332x 332x 80x 80x 75x 75x 332x 252x 1x 1x 1x 1x 252x 252x 252x 252x 332x 8x 8x 8x 8x 8x 8x 331x 332x 2x 332x 8x 8x 8x 329x 280x 280x 280x 323x 323x 332x 280x 332x 41x 41x 491x 159x 1x 1x 482x 482x 482x 390x 390x 390x 1x 1x 1x 1x 399x 99x 99x 99x 99x 21x 21x 21x 99x 3x 3x 3x 3x 75x 75x 399x 41x 300x 74x 259x 10x 185x 175x 175x 98x 98x 175x 77x 77x 1x 1x | import {ExpressionNode, TokenNode} from "../../nodes"; 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 {CheckSyntaxKey, SyntaxInput, syntaxIssue} from "../_syntax_input"; export class MethodCallChain { public runSyntax( node: ExpressionNode, input: SyntaxInput, targetType?: AbstractType): AbstractType | undefined { const helper = new ObjectOriented(input.scope); const children = node.getChildren().slice(); const first = children.shift(); if (first === undefined) { const message = "MethodCallChain, first child expected"; input.issues.push(syntaxIssue(input, node.getFirstToken(), message)); return new VoidType(CheckSyntaxKey); } let context: AbstractType | undefined = this.findTop(first, input, targetType); if (first.get() instanceof Expressions.MethodCall) { children.unshift(first); } let previous: ExpressionNode | TokenNode | undefined = undefined; 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 = input.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) { input.scope.addReference(methodToken, method, ReferenceType.BuiltinMethodReference, input.filename); } } else { if (previous && previous.getFirstToken().getStr() === "=>" && method?.isStatic() === false) { const message = "Method \"" + methodName + "\" not static"; input.issues.push(syntaxIssue(input, methodToken!, message)); return new VoidType(CheckSyntaxKey); } const voidedName = context instanceof VoidType ? context.getVoided() : undefined; const extra = helper.methodReferenceExtras(foundDef, className || voidedName); input.scope.addReference(methodToken, method, ReferenceType.MethodReference, input.filename, extra); } if (methodName?.includes("~")) { const name = methodName.split("~")[0]; const idef = input.scope.findInterfaceDefinition(name); if (idef) { input.scope.addReference(methodToken, idef, ReferenceType.ObjectOrientedReference, input.filename); } } if (method === undefined && methodName?.toUpperCase() === "CONSTRUCTOR") { context = undefined; // todo, this is a workaround, constructors always exists } else if (method === undefined && !(context instanceof VoidType)) { const message = "Method \"" + methodName + "\" not found, methodCallChain"; input.issues.push(syntaxIssue(input, methodToken!, message)); return new VoidType(CheckSyntaxKey); } else if (method) { const ret = method.getParameters().getReturning()?.getType(); context = ret; } const param = current.findDirectExpression(Expressions.MethodCallParam); if (param && method) { new MethodCallParam().runSyntax(param, input, method); } else if (param && context instanceof VoidType) { new MethodCallParam().runSyntax(param, input, context); } } else if (current instanceof ExpressionNode && current.get() instanceof Expressions.ComponentName) { context = new ComponentName().runSyntax(context, current, input); } else if (current instanceof ExpressionNode && current.get() instanceof Expressions.AttributeName) { context = new AttributeName().runSyntax(context, current, input); } previous = current; } return context; } ////////////////////////////////////// private findTop(first: INode, input: SyntaxInput, targetType: AbstractType | undefined): AbstractType | undefined { if (first.get() instanceof Expressions.ClassName) { const token = first.getFirstToken(); const className = token.getStr(); const classDefinition = input.scope.findObjectDefinition(className); if (classDefinition === undefined && input.scope.getDDIC().inErrorNamespace(className) === false) { const extra: IReferenceExtras = {ooName: className, ooType: "Void"}; input.scope.addReference(token, undefined, ReferenceType.ObjectOrientedVoidReference, input.filename, extra); return new VoidType(className); } else if (classDefinition === undefined) { const message = "Class " + className + " not found"; input.issues.push(syntaxIssue(input, first.getFirstToken(), message)); return new VoidType(CheckSyntaxKey); } input.scope.addReference(first.getFirstToken(), classDefinition, ReferenceType.ObjectOrientedReference, input.filename); return new ObjectReferenceType(classDefinition); } else if (first instanceof ExpressionNode && first.get() instanceof Expressions.FieldChain) { return new FieldChain().runSyntax(first, input, ReferenceType.DataReadReference); } else if (first instanceof ExpressionNode && first.get() instanceof Expressions.NewObject) { return new NewObject().runSyntax(first, input, targetType); } else if (first instanceof ExpressionNode && first.get() instanceof Expressions.Cast) { return new Cast().runSyntax(first, input, targetType); } else { const meType = input.scope.findVariable("me")?.getType(); if (meType) { return meType; } } return undefined; } } |