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 139 140 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 408x 408x 408x 408x 408x 408x 408x 408x 408x 408x 408x 408x 408x 178x 178x 408x 408x 408x 898x 898x 398x 398x 500x 500x 898x 338x 338x 338x 338x 338x 338x 338x 338x 81x 81x 76x 76x 338x 256x 1x 1x 1x 1x 256x 256x 256x 256x 338x 8x 8x 8x 8x 8x 8x 336x 338x 2x 338x 8x 8x 8x 334x 285x 285x 285x 328x 328x 338x 285x 338x 41x 41x 898x 162x 1x 1x 490x 490x 490x 398x 398x 398x 1x 1x 1x 1x 408x 101x 101x 101x 101x 21x 21x 21x 101x 3x 3x 3x 3x 77x 77x 408x 42x 307x 77x 265x 10x 188x 178x 178x 100x 100x 178x 78x 78x 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 static runSyntax( node: ExpressionNode, input: SyntaxInput, targetType?: AbstractType): AbstractType | undefined { const helper = new ObjectOriented(input.scope); const children = node.getChildren(); const first = children[0]; if (first === undefined) { const message = "MethodCallChain, first child expected"; input.issues.push(syntaxIssue(input, node.getFirstToken(), message)); return VoidType.get(CheckSyntaxKey); } let currentIndex = 1; let context: AbstractType | undefined = this.findTop(first, input, targetType); if (first.get() instanceof Expressions.MethodCall) { currentIndex--; } let previous: ExpressionNode | TokenNode | undefined = undefined; while (currentIndex <= children.length) { const current = children[currentIndex]; if (current === undefined) { break; } currentIndex++; 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 VoidType.get(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 VoidType.get(CheckSyntaxKey); } else if (method) { const ret = method.getParameters().getReturning()?.getType(); context = ret; } const param = current.findDirectExpression(Expressions.MethodCallParam); if (param && method) { MethodCallParam.runSyntax(param, input, method); } else if (param && context instanceof VoidType) { MethodCallParam.runSyntax(param, input, context); } } else if (current instanceof ExpressionNode && current.get() instanceof Expressions.ComponentName) { context = ComponentName.runSyntax(context, current, input); } else if (current instanceof ExpressionNode && current.get() instanceof Expressions.AttributeName) { context = AttributeName.runSyntax(context, current, input); } previous = current; } return context; } ////////////////////////////////////// private static 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 VoidType.get(className); } else if (classDefinition === undefined) { const message = "Class " + className + " not found"; input.issues.push(syntaxIssue(input, first.getFirstToken(), message)); return VoidType.get(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 FieldChain.runSyntax(first, input, ReferenceType.DataReadReference); } else if (first instanceof ExpressionNode && first.get() instanceof Expressions.NewObject) { return NewObject.runSyntax(first, input, targetType); } else if (first instanceof ExpressionNode && first.get() instanceof Expressions.Cast) { return Cast.runSyntax(first, input, targetType); } else { const meType = input.scope.findVariable("me")?.getType(); if (meType) { return meType; } } return undefined; } } |