From f05b34171c6d92a6b38657a35712ffd2d6977e18 Mon Sep 17 00:00:00 2001 From: Dave Holoway Date: Thu, 18 Jun 2020 14:54:12 +0100 Subject: [PATCH] add new array validation --- langserver/java/anys.js | 2 +- langserver/java/body-parser3.js | 7 ++-- .../java/expressiontypes/NewExpression.js | 37 +++++++++++++++++-- langserver/java/source-types.js | 32 ++++++++++++++++ 4 files changed, 70 insertions(+), 8 deletions(-) diff --git a/langserver/java/anys.js b/langserver/java/anys.js index f2b4218..ca40fd3 100644 --- a/langserver/java/anys.js +++ b/langserver/java/anys.js @@ -130,7 +130,7 @@ class MultiValueType { * @typedef {JavaType|MethodType|LambdaType|ArrayValueType|TypeIdentType|MultiValueType} ResolvedType **/ - exports.AnyMethod = AnyMethod; +exports.AnyMethod = AnyMethod; exports.AnyType = AnyType; exports.AnyValue = AnyValue; exports.ArrayValueType = ArrayValueType; diff --git a/langserver/java/body-parser3.js b/langserver/java/body-parser3.js index b4e0647..320197c 100644 --- a/langserver/java/body-parser3.js +++ b/langserver/java/body-parser3.js @@ -6,7 +6,7 @@ */ const { JavaType, CEIType, PrimitiveType, ArrayType, UnresolvedType, TypeVariable, Field, Method } = require('java-mti'); const { SourceType, SourceTypeIdent, SourceField, SourceMethod, SourceConstructor, SourceInitialiser, SourceParameter, SourceAnnotation, - SourceUnit, SourcePackage, SourceImport } = require('./source-types'); + SourceUnit, SourcePackage, SourceImport, SourceArrayType, FixedLengthArrayType } = require('./source-types'); const ResolvedImport = require('./parsetypes/resolved-import'); const ParseProblem = require('./parsetypes/parse-problem'); const { tokenize, Token } = require('./tokenizer'); @@ -1641,7 +1641,8 @@ function expressionList(tokens, mdecls, scope, imports, typemap, opts) { */ function arrayElementOrConstructor(tokens, open_array, instance, index) { const ident = `${instance.source}[${index.source}]`; - return new ResolvedIdent(ident, [new ArrayIndexExpression(instance, index)]); + const types = instance.types.map(t => new FixedLengthArrayType(t, index)); + return new ResolvedIdent(ident, [new ArrayIndexExpression(instance, index)], [], types, '', index.tokens.slice()); } /** @@ -1765,7 +1766,7 @@ function methodCallQualifier(matches, tokens, mdecls, scope, imports, typemap) { * @param {ResolvedIdent} matches */ function arrayTypeExpression(matches) { - const types = matches.types.map(t => new ArrayType(t, 1)); + const types = matches.types.map(t => new SourceArrayType(t)); return new ResolvedIdent(`${matches.source}[]`, [], [], types); } diff --git a/langserver/java/expressiontypes/NewExpression.js b/langserver/java/expressiontypes/NewExpression.js index 242212e..d7cb952 100644 --- a/langserver/java/expressiontypes/NewExpression.js +++ b/langserver/java/expressiontypes/NewExpression.js @@ -6,7 +6,9 @@ * @typedef {import('java-mti').JavaType} JavaType */ const { Expression } = require("./Expression"); -const { ArrayType } = require('java-mti'); +const { ArrayType, PrimitiveType } = require('java-mti'); +const { FixedLengthArrayType, SourceArrayType } = require('../source-types'); +const ParseProblem = require('../parsetypes/parse-problem'); class NewArray extends Expression { /** @@ -19,18 +21,45 @@ class NewArray extends Expression { this.new_token = new_token; this.element_type = element_type; this.dimensions = dimensions; - this.array_type = new ArrayType(element_type.resolved, 1); } /** * @param {ResolveInfo} ri */ resolveExpression(ri) { - return this.array_type; + /** @type {ResolvedIdent[]} */ + const fixed_dimensions = []; + const type = this.dimensions.types[0]; + for (let x = type; ;) { + if (x instanceof FixedLengthArrayType) { + fixed_dimensions.unshift(x.length); + x = x.parent_type; + continue; + } + if (x instanceof SourceArrayType) { + x = x.parent_type; + continue; + } + break; + } + const arrdims = type instanceof ArrayType ? type.arrdims : 1; + const array_type = new ArrayType(this.element_type.resolved, arrdims); + + fixed_dimensions.forEach(d => { + const idx = d.resolveExpression(ri); + if (idx instanceof PrimitiveType) { + if (!/^[BSI]$/.test(idx.typeSignature)) { + ri.problems.push(ParseProblem.Error(d.tokens, `Expression of type '${idx.label}' is not valid as an array dimension`)); + } + return; + } + ri.problems.push(ParseProblem.Error(d.tokens, `Integer value expected`)); + }) + return array_type; } tokens() { - return [this.new_token, ...this.element_type.tokens, ...this.dimensions.tokens]; + return [this.new_token, ...this.dimensions.tokens]; } } diff --git a/langserver/java/source-types.js b/langserver/java/source-types.js index f19caf9..94098bb 100644 --- a/langserver/java/source-types.js +++ b/langserver/java/source-types.js @@ -487,6 +487,36 @@ class SourceUnit { types = []; } +class SourceArrayType extends ArrayType { + /** + * + * @param {JavaType} element_type + */ + constructor(element_type) { + super(element_type, 1); + this.parent_type = element_type; + } + get label() { + return `${this.parent_type.label}[]`; + } +} + +class FixedLengthArrayType extends SourceArrayType { + /** + * + * @param {JavaType} element_type + * @param {ResolvedIdent} length + */ + constructor(element_type, length) { + super(element_type); + this.length = length; + } + + get label() { + return `${this.parent_type.label}[${this.length.source}]`; + } +} + exports.SourceType = SourceType; exports.SourceTypeIdent = SourceTypeIdent; exports.SourceField = SourceField; @@ -499,3 +529,5 @@ exports.SourceUnit = SourceUnit; exports.SourcePackage = SourcePackage; exports.SourceImport = SourceImport; exports.SourceEnumValue = SourceEnumValue; +exports.SourceArrayType = SourceArrayType; +exports.FixedLengthArrayType = FixedLengthArrayType;