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 216x 216x 216x 216x 216x 216x 31x 31x 31x 31x 28x 28x 28x 1x 1x 1x 1x 31x 3x 3x 3x 3x 3x 31x 212x 212x 216x 212x 216x 212x 212x 212x 212x 212x 212x 10x 212x 5x 5x 5x 202x 197x 197x 197x 197x 3x 3x 3x 197x 185x 185x 185x 2x 2x 2x 185x 183x 183x 183x 162x 162x 185x 2x 2x 2x 2x 185x 200x 212x 1x 1x 212x 200x 216x 10x 10x 200x 216x 216x 8x 8x 200x 216x 216x 216x 216x 10x 10x 10x 10x 190x 216x 182x 182x 1x 1x 1x 182x 189x 189x 189x 1x 1x 480x 480x 473x 473x 7x 480x 1x 1x 1x 480x 1x 1x 5x 5x 5x 480x 480x 1x 1x 199x 18x 18x 4x 4x 18x 18x 181x 181x 199x 199x 199x 199x 199x 199x 37x 37x 37x 37x 37x 37x 37x 37x 3x 3x 3x 37x 2x 2x 2x 2x 32x 32x 32x 176x 199x 2x 2x 2x 2x 174x 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;
}
}
}
|