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 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 85x 85x 85x 85x 85x 85x 16x 16x 16x 16x 13x 13x 13x 1x 1x 1x 1x 16x 3x 3x 3x 3x 3x 16x 81x 81x 85x 81x 85x 81x 81x 81x 81x 81x 81x 10x 81x 5x 5x 5x 71x 66x 66x 66x 66x 2x 2x 2x 66x 56x 56x 56x 2x 2x 2x 56x 54x 54x 54x 47x 47x 56x 2x 2x 2x 2x 56x 70x 81x 1x 1x 81x 70x 85x 8x 8x 70x 85x 85x 8x 8x 70x 85x 85x 85x 85x 8x 8x 8x 8x 62x 85x 54x 54x 1x 1x 1x 54x 61x 61x 61x 1x 1x 104x 104x 97x 97x 7x 104x 1x 1x 1x 104x 1x 1x 5x 5x 5x 104x 104x 1x 1x 69x 16x 16x 4x 4x 16x 16x 53x 53x 69x 69x 69x 69x 69x 69x 13x 13x 13x 13x 13x 13x 13x 13x 3x 3x 3x 13x 2x 2x 2x 2x 8x 8x 8x 48x 69x 2x 2x 2x 2x 46x 1x | import * as Expressions from "../../2_statements/expressions";
import {StatementNode} from "../../nodes";
import {Source} from "../expressions/source";
import {Target} from "../expressions/target";
import {Dynamic} from "../expressions/dynamic";
import {ReferenceType} from "../_reference";
import {AnyType, DataType, GenericObjectReferenceType, ObjectReferenceType, UnknownType, VoidType} from "../../types/basic";
import {ClassDefinition, InterfaceDefinition} from "../../types";
import {StatementSyntax} from "../_statement_syntax";
import {IClassDefinition} from "../../types/_class_definition";
import {ObjectOriented} from "../_object_oriented";
import {TypeUtils} from "../_type_utils";
import {SyntaxInput, syntaxIssue} from "../_syntax_input";
import {Visibility} from "../../4_file_information/visibility";
export class CreateObject implements StatementSyntax {
public runSyntax(node: StatementNode, input: SyntaxInput): void {
let cdef: IClassDefinition | undefined = undefined;
// CREATE OBJECT, TYPE
const type = node.findExpressionAfterToken("TYPE");
if (type && type.get() instanceof Expressions.ClassName) {
const token = type.getFirstToken();
const name = token.getStr();
cdef = input.scope.findClassDefinition(name);
if (cdef) {
input.scope.addReference(token, cdef, ReferenceType.ObjectOrientedReference, input.filename);
input.scope.addReference(token, cdef, ReferenceType.ConstructorReference, input.filename, {ooName: cdef.getName()});
if (cdef.isAbstract() === true) {
const message = cdef.getName() + " is abstract, cannot be instantiated";
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
}
} else if (input.scope.getDDIC().inErrorNamespace(name) === false) {
input.scope.addReference(token, undefined, ReferenceType.ObjectOrientedVoidReference, input.filename, {ooName: name, ooType: "CLAS"});
} else {
const message = "TYPE \"" + name + "\" not found";
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
}
}
// just recurse
for (const s of node.findDirectExpressions(Expressions.Source)) {
Source.runSyntax(s, input);
}
for (const t of node.findDirectExpression(Expressions.ParameterListExceptions)?.findAllExpressions(Expressions.Target) || []) {
Target.runSyntax(t, input);
}
const t = node.findDirectExpression(Expressions.Target);
let found = undefined;
if (t) {
found = Target.runSyntax(t, input);
if (found instanceof VoidType) {
// do nothing
} else if (found instanceof UnknownType) {
const message = "Target type unknown, " + t.concatTokens();
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
} else if (!(found instanceof ObjectReferenceType)
&& !(found instanceof AnyType)
&& !(found instanceof DataType)
&& !(found instanceof GenericObjectReferenceType)) {
const message = "Target must be an object reference, " + t.concatTokens();
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
} else if (found instanceof GenericObjectReferenceType && type === undefined) {
const message = "Generic type, cannot be instantiated";
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
} else if (found instanceof ObjectReferenceType) {
const identifier = found.getIdentifier();
const idFound = input.scope.findObjectDefinition(identifier.getName());
if (idFound instanceof InterfaceDefinition && type === undefined) {
const message = "Interface reference, cannot be instantiated";
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
} else if (found instanceof ObjectReferenceType
&& type === undefined
&& input.scope.findInterfaceDefinition(found.getQualifiedName())) {
const message = "Interface reference, cannot be instantiated";
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
} else if (idFound instanceof ClassDefinition && cdef === undefined) {
cdef = idFound;
}
if (type === undefined && idFound instanceof ClassDefinition && idFound.isAbstract() === true) {
const message = identifier.getName() + " is abstract, cannot be instantiated";
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
}
}
if (found instanceof ObjectReferenceType && cdef === undefined) {
cdef = input.scope.findClassDefinition(found.getQualifiedName());
}
}
for (const t of node.findDirectExpressions(Expressions.Dynamic)) {
Dynamic.runSyntax(t, input);
}
let ooName = cdef?.getName();
if (ooName === undefined && found instanceof VoidType) {
ooName = found.getVoided();
}
input.scope.addReference(t?.getFirstToken(), cdef, ReferenceType.ConstructorReference, input.filename,
{ooName: ooName});
if (type && type.get() instanceof Expressions.Dynamic) {
// the class is only known at runtime, cdef is the static type of the target
this.validateParameters(undefined, node, input);
return;
}
if (cdef !== undefined) {
const err = CreateObject.checkInstantiationAllowed(cdef, input);
if (err) {
input.issues.push(syntaxIssue(input, node.getFirstToken(), err));
return;
}
}
this.validateParameters(cdef, node, input);
}
public static checkInstantiationAllowed(cdef: IClassDefinition, input: SyntaxInput): string | undefined {
const createVis = cdef.getCreateVisibility();
if (createVis === Visibility.Public) {
return undefined;
}
const enclosingClass = input.scope.getEnclosingClassName();
if (enclosingClass === undefined) {
return cdef.getName() + " cannot be instantiated, class is defined as " +
(createVis === Visibility.Private ? "private" : "protected");
}
if (enclosingClass.toUpperCase() === cdef.getName().toUpperCase()) {
return undefined;
}
if (new ObjectOriented(input.scope).hasFriendship(cdef, enclosingClass)) {
return undefined;
}
if (createVis === Visibility.Protected) {
// subclasses are also allowed
let sup = input.scope.findClassDefinition(enclosingClass)?.getSuperClass();
while (sup !== undefined) {
if (sup.toUpperCase() === cdef.getName().toUpperCase()) {
return undefined;
}
sup = input.scope.findClassDefinition(sup)?.getSuperClass();
}
}
return cdef.getName() + " cannot be instantiated, class is defined as " +
(createVis === Visibility.Private ? "private" : "protected");
}
private validateParameters(cdef: IClassDefinition | undefined, node: StatementNode, input: SyntaxInput): void {
if (cdef === undefined) {
const sources = node.findDirectExpression(Expressions.ParameterListS)?.findAllExpressions(Expressions.Source);
for (const s of sources || []) {
Source.runSyntax(s, input);
}
return;
}
const methodDef = new ObjectOriented(input.scope).searchMethodName(cdef, "CONSTRUCTOR");
const methodParameters = methodDef.method?.getParameters();
const allImporting = methodParameters?.getImporting() || [];
const requiredImporting = new Set(methodParameters?.getRequiredParameters().map(i => i.getName().toUpperCase()));
for (const p of node.findDirectExpression(Expressions.ParameterListS)?.findAllExpressions(Expressions.ParameterS) || []) {
const name = p.findDirectExpression(Expressions.ParameterName)?.concatTokens().toUpperCase();
if (name === undefined) {
continue;
}
const found = allImporting?.find(p => p.getName().toUpperCase() === name);
const source = p.findDirectExpression(Expressions.Source);
const sourceType = Source.runSyntax(source, input, found?.getType());
if (found === undefined) {
const message = `constructor parameter "${name}" does not exist`;
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
} else if (new TypeUtils(input.scope).isAssignableStrict(sourceType, found.getType(), source) === false) {
const message = `constructor parameter "${name}" type not compatible`;
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
}
requiredImporting.delete(name);
}
for (const r of requiredImporting.values()) {
const message = `constructor parameter "${r}" must be supplied`;
input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
return;
}
}
}
|