diff --git a/langserver/java/body-parser3.js b/langserver/java/body-parser3.js index 9c383c7..fd79e1c 100644 --- a/langserver/java/body-parser3.js +++ b/langserver/java/body-parser3.js @@ -6,15 +6,15 @@ */ const { JavaType, CEIType, PrimitiveType, ArrayType, UnresolvedType, NullType, WildcardType, TypeVariableType, TypeVariable, InferredTypeArgument, Field, Method, ReifiedMethod, Parameter, Constructor, signatureToType } = require('java-mti'); -const { SourceMethod, SourceConstructor, SourceInitialiser } = require('./source-type'); +const { SourceType, SourceTypeIdent, SourceField, SourceMethod, SourceConstructor, SourceInitialiser, SourceParameter, SourceAnnotation } = require('./source-types2'); const ResolvedImport = require('./parsetypes/resolved-import'); const ParseProblem = require('./parsetypes/parse-problem'); const { getOperatorType, Token } = require('./tokenizer'); const { resolveTypeOrPackage, resolveNextTypeOrPackage } = require('./type-resolver'); const { genericTypeArgs, typeIdent, typeIdentList } = require('./typeident'); const { TokenList } = require("./TokenList"); -const { AnyMethod, AnyType, AnyValue, ArrayElement, ArrayLiteral, ConstructorCall, Label, LiteralNumber, LiteralValue, Local, MethodCall, MethodDeclarations, ResolvedIdent, TernaryValue, Value } = require("./body-types"); -const { SourceType, SourceField2, SourceMethod2, SourceConstructor2, SourceParameter2 } = require('./source-types2'); +const { AnyMethod, AnyType, AnyValue, ArrayElement, ArrayLiteral, ConstructorCall, Label, LiteralNumber, LiteralValue, Local, + MethodCall, MethodDeclarations, ResolvedIdent, TernaryValue, Value } = require("./body-types"); /** * @typedef {SourceMethod|SourceConstructor|SourceInitialiser} SourceMC @@ -47,11 +47,11 @@ function flattenBlocks(blocks, isMethod) { * @param {Map} typemap */ function parseBody(method, imports, typemap) { - const body = method._decl.body().blockArray(); - if (!body || body.blocks[0].value !== '{') { + const body = method.body; + if (!body || body[0].value !== '{') { return null; } - const tokenlist = new TokenList(flattenBlocks(body.blocks, true)); + const tokenlist = new TokenList(flattenBlocks(body, true)); let block = null; let mdecls = new MethodDeclarations(); try { @@ -245,7 +245,7 @@ class AssertStatement extends Statement { */ function localType(modifiers, tokens, mdecls, method, imports, typemap) { // local types are inner types with number-prefixed names, eg. Type$1Inner - const type = typeDeclaration(method, modifiers, tokens.current, tokens, imports, typemap); + const type = typeDeclaration(method.owner.packageName, method, modifiers, tokens.current, tokens, imports, typemap); mdecls.types.push(type); if (tokens.isValue('extends')) { const extends_types = typeIdentList(tokens, type, imports, typemap); @@ -268,7 +268,7 @@ function localType(modifiers, tokens, mdecls, method, imports, typemap) { */ function typeBody(type, tokens, method, imports, typemap) { while (!tokens.isValue('}')) { - let modifiers = []; + let modifiers = [], annotations = []; while (tokens.current.kind === 'modifier') { modifiers.push(tokens.current); tokens.inc(); @@ -276,7 +276,7 @@ function typeBody(type, tokens, method, imports, typemap) { switch(tokens.current.kind) { case 'ident': case 'primitive-type': - fmc(modifiers, [], type, tokens, imports, typemap); + fmc(modifiers, annotations, [], type, tokens, imports, typemap); continue; case 'type-kw': localType(modifiers, tokens, new MethodDeclarations(), method, imports, typemap); @@ -285,11 +285,11 @@ function typeBody(type, tokens, method, imports, typemap) { switch(tokens.current.value) { case '<': const type_variables = typeVariableList(type, tokens, type, imports, typemap); - fmc(modifiers, type_variables, type, tokens, imports, typemap); + fmc(modifiers, annotations, type_variables, type, tokens, imports, typemap); continue; case '@': tokens.inc().value === 'interface' - ? annotationTypeDeclaration(type, modifiers.splice(0,1e9), tokens, imports, typemap) + ? annotationTypeDeclaration(type.packageName, type, modifiers.splice(0,1e9), tokens, imports, typemap) : annotation(tokens, type, imports, typemap); continue; case ';': @@ -304,19 +304,20 @@ function typeBody(type, tokens, method, imports, typemap) { /** * @param {Token[]} modifiers + * @param {SourceAnnotation[]} annotations * @param {TypeVariable[]} type_variables * @param {SourceType} type * @param {TokenList} tokens * @param {ResolvedImport[]} imports * @param {Map} typemap */ -function fmc(modifiers, type_variables, type, tokens, imports, typemap) { +function fmc(modifiers, annotations, type_variables, type, tokens, imports, typemap) { const decl_type = typeIdent(tokens, type, imports, typemap); if (decl_type.rawTypeSignature === type.rawTypeSignature) { if (tokens.current.value === '(') { // constructor const { parameters, throws, body } = methodDeclaration(type, tokens, imports, typemap); - const ctr = new SourceConstructor2(type, modifiers, parameters, throws, body); + const ctr = new SourceConstructor(type, modifiers, parameters, throws, body); type.constructors.push(ctr); return; } @@ -328,7 +329,7 @@ function fmc(modifiers, type_variables, type, tokens, imports, typemap) { } if (tokens.current.value === '(') { const { parameters, throws, body } = methodDeclaration(type, tokens, imports, typemap); - const method = new SourceMethod2(type, modifiers, decl_type, name, parameters, throws, body); + const method = new SourceMethod(type, modifiers, annotations, new SourceTypeIdent([], decl_type), name, parameters, throws, body); type.methods.push(method); } else { if (name) { @@ -336,7 +337,7 @@ function fmc(modifiers, type_variables, type, tokens, imports, typemap) { addproblem(tokens, ParseProblem.Error(tokens.current, `Fields cannot declare type variables`)); } const locals = var_ident_list(modifiers, decl_type, name, tokens, new MethodDeclarations(), type, imports, typemap); - const fields = locals.map(l => new SourceField2(type, modifiers, l.type, l.decltoken)); + const fields = locals.map(l => new SourceField(type, modifiers, new SourceTypeIdent([], l.type), l.decltoken)); type.fields.push(...fields); } semicolon(tokens); @@ -362,6 +363,7 @@ function annotation(tokens, scope, imports, typemap) { } /** + * @param {string} package_name * @param {SourceType | SourceMC} scope * @param {Token[]} modifiers * @param {TokenList} tokens @@ -369,11 +371,12 @@ function annotation(tokens, scope, imports, typemap) { * @param {ResolvedImport[]} imports * @param {Map} typemap */ -function annotationTypeDeclaration(scope, modifiers, tokens, imports, typemap) { - const type = typeDeclaration(scope, modifiers, tokens.current, tokens, imports, typemap); +function annotationTypeDeclaration(package_name, scope, modifiers, tokens, imports, typemap) { + const type = typeDeclaration(package_name, scope, modifiers, tokens.current, tokens, imports, typemap); } /** + * @param {string} package_name * @param {SourceType | SourceMC} scope * @param {Token[]} modifiers * @param {Token} kind_token @@ -381,14 +384,14 @@ function annotationTypeDeclaration(scope, modifiers, tokens, imports, typemap) { * @param {ResolvedImport[]} imports * @param {Map} typemap */ -function typeDeclaration(scope, modifiers, kind_token, tokens, imports, typemap) { +function typeDeclaration(package_name, scope, modifiers, kind_token, tokens, imports, typemap) { let name = tokens.inc(); if (!tokens.isKind('ident')) { name = null; addproblem(tokens, ParseProblem.Error(tokens.current, `Type identifier expected`)); return; } - const type = new SourceType('', scope, '', modifiers.map(m => m.source), kind_token, name); + const type = new SourceType(package_name, scope, '', modifiers.map(m => m.source), kind_token, name, typemap); type.typeVariables = tokens.current.value === '<' ? typeVariableList(type, tokens, scope, imports, typemap) : []; @@ -516,7 +519,7 @@ function parameterDeclaration(owner, tokens, imports, typemap) { if (varargs) { type = new ArrayType(type, 1); } - return new SourceParameter2(modifiers, type, varargs, name_token); + return new SourceParameter(modifiers, new SourceTypeIdent([], type), varargs, name_token); } /** diff --git a/langserver/java/parser9.js b/langserver/java/parser9.js index 4709db5..c6a30f2 100644 --- a/langserver/java/parser9.js +++ b/langserver/java/parser9.js @@ -331,6 +331,10 @@ class DeclaredVariableBlock extends DeclarationBlock { return this.varBlock ? this.varBlock.name : ''; } + get name_token() { + return this.varBlock ? this.varBlock.name_token : null; + } + get type() { return this.varBlock ? this.varBlock.type : ''; } @@ -475,6 +479,10 @@ class MethodBlock extends MCBlock { return this.varBlock.name; } + get name_token() { + return this.varBlock.name_token; + } + get type() { return this.varBlock.type + (this.postNameArrToken ? this.postNameArrToken.source : ''); } diff --git a/langserver/java/source-type.js b/langserver/java/source-type.js index 834dafa..e1fb8cc 100644 --- a/langserver/java/source-type.js +++ b/langserver/java/source-type.js @@ -298,11 +298,14 @@ class ResolvableType extends UnresolvedType { } } -exports.SourceType = SourceType; -exports.SourceField = SourceField; -exports.SourceMethod = SourceMethod; -exports.SourceParameter = SourceParameter; -exports.SourceConstructor = SourceConstructor; +const source_types = require('./source-types2'); +exports.SourceType = source_types.SourceType; +exports.SourceTypeIdent = source_types.SourceTypeIdent; +exports.SourceField = source_types.SourceField; +exports.SourceMethod = source_types.SourceMethod; +exports.SourceParameter = source_types.SourceParameter; +exports.SourceConstructor = source_types.SourceConstructor; exports.DefaultConstructor = DefaultConstructor; -exports.SourceInitialiser = SourceInitialiser; +exports.SourceInitialiser = source_types.SourceInitialiser; +exports.SourceAnnotation = source_types.SourceAnnotation; exports.ResolvableType = ResolvableType; diff --git a/langserver/java/source-types2.js b/langserver/java/source-types2.js index e248d31..044b24b 100644 --- a/langserver/java/source-types2.js +++ b/langserver/java/source-types2.js @@ -1,5 +1,4 @@ -const { CEIType, JavaType, Field, Method, Constructor, Parameter } = require('java-mti'); -const { SourceMethod, SourceConstructor, SourceInitialiser } = require('./source-type'); +const { CEIType, JavaType, PrimitiveType, Field, Method, MethodBase, Constructor, Parameter } = require('java-mti'); const { Token } = require('./tokenizer'); /** @@ -24,39 +23,69 @@ function generateShortSignature(scope_or_package_name, name) { class SourceType extends CEIType { /** * @param {string} packageName - * @param {SourceType|SourceMethod2|SourceConstructor|SourceInitialiser} outer_scope + * @param {SourceType|SourceMethod|SourceConstructor|SourceInitialiser} outer_scope * @param {string} docs * @param {string[]} modifiers * @param {Token} kind_token * @param {Token} name_token */ - constructor(packageName, outer_scope, docs, modifiers, kind_token, name_token) { + constructor(packageName, outer_scope, docs, modifiers, kind_token, name_token, typemap) { // @ts-ignore super(generateShortSignature(outer_scope || packageName, name_token), kind_token.source, modifiers, docs); super.packageName = packageName; this.kind_token = kind_token; this.name_token = name_token; this.scope = outer_scope; + this.typemap = typemap; /** * Number of local/anonymous types declared in the scope of this type * The number is used when naming them. */ this.localTypeCount = 0; - /** @type {SourceConstructor2[]} */ + /** @type {SourceTypeIdent[]} */ + this.extends_types = []; + /** @type {SourceTypeIdent[]} */ + this.implements_types = []; + /** @type {SourceConstructor[]} */ this.constructors = []; - /** @type {SourceMethod2[]} */ + /** @type {SourceMethod[]} */ this.methods = []; - /** @type {SourceField2[]} */ + /** @type {SourceField[]} */ this.fields = []; + /** @type {SourceInitialiser[]} */ + this.initers = []; } + get supers() { + const supertypes = [...this.extends_types, ...this.implements_types].map(x => x.type); + if (this.typeKind === 'enum') { + /** @type {CEIType} */ + const enumtype = this.typemap.get('java/lang/Enum'); + supertypes.unshift(enumtype.specialise([this])); + } + else if (!supertypes.find(type => type.typeKind === 'class')) { + supertypes.unshift(this.typemap.get('java/lang/Object')); + } + return supertypes; + } } -class SourceField2 extends Field { +class SourceTypeIdent { + /** + * @param {Token[]} tokens + * @param {JavaType} type + */ + constructor(tokens, type) { + this.typeTokens = tokens; + this.type = type; + } +} + +class SourceField extends Field { /** * @param {SourceType} owner * @param {Token[]} modifiers - * @param {JavaType} field_type + * @param {SourceTypeIdent} field_type * @param {Token} name_token */ constructor(owner, modifiers, field_type, name_token) { @@ -71,15 +100,15 @@ class SourceField2 extends Field { } get type() { - return this.fieldType; + return this.fieldType.type; } } -class SourceConstructor2 extends Constructor { +class SourceConstructor extends Constructor { /** * @param {SourceType} owner * @param {Token[]} modifiers - * @param {SourceParameter2[]} parameters + * @param {SourceParameter[]} parameters * @param {JavaType[]} throws * @param {Token[]} body */ @@ -88,11 +117,11 @@ class SourceConstructor2 extends Constructor { this.owner = owner; this.sourceParameters = parameters; this.throws = throws; - this.body_tokens = body; + this.body = body; } get hasImplementation() { - return !!this.body_tokens; + return !!this.body; } get parameterCount() { @@ -100,7 +129,7 @@ class SourceConstructor2 extends Constructor { } /** - * @returns {SourceParameter2[]} + * @returns {SourceParameter[]} */ get parameters() { return this.sourceParameters; @@ -114,27 +143,29 @@ class SourceConstructor2 extends Constructor { } } -class SourceMethod2 extends Method { +class SourceMethod extends Method { /** * @param {SourceType} owner * @param {Token[]} modifiers - * @param {JavaType} method_type + * @param {SourceAnnotation[]} annotations + * @param {SourceTypeIdent} method_type_ident * @param {Token} name_token - * @param {SourceParameter2[]} parameters + * @param {SourceParameter[]} parameters * @param {JavaType[]} throws * @param {Token[]} body */ - constructor(owner, modifiers, method_type, name_token, parameters, throws, body) { + constructor(owner, modifiers, annotations, method_type_ident, name_token, parameters, throws, body) { super(owner, name_token ? name_token.value : '', modifiers.map(m => m.value), ''); + this.annotations = annotations; this.owner = owner; - this.methodType = method_type; + this.methodTypeIdent = method_type_ident; this.sourceParameters = parameters; this.throws = throws; - this.body_tokens = body; + this.body = body; } get hasImplementation() { - return !!this.body_tokens; + return !!this.body; } get parameterCount() { @@ -142,7 +173,7 @@ class SourceMethod2 extends Method { } /** - * @returns {SourceParameter2[]} + * @returns {SourceParameter[]} */ get parameters() { return this.sourceParameters; @@ -152,26 +183,64 @@ class SourceMethod2 extends Method { * @returns {JavaType} */ get returnType() { - return this.methodType; + return this.methodTypeIdent.type; } } -class SourceParameter2 extends Parameter { +class SourceInitialiser extends MethodBase { + /** + * @param {SourceType} owner + * @param {Token[]} modifiers + * @param {Token[]} body + */ + constructor(owner, modifiers, body) { + super(owner, modifiers.map(m => m.value), ''); + /** @type {SourceType} */ + this.owner = owner; + this.body = body; + } + + /** + * @returns {SourceParameter[]} + */ + get parameters() { + return []; + } + + get returnType() { + return PrimitiveType.map.V; + } +} + +class SourceParameter extends Parameter { /** * @param {Token[]} modifiers - * @param {JavaType} type + * @param {SourceTypeIdent} typeident * @param {boolean} varargs * @param {Token} name_token */ - constructor(modifiers, type, varargs, name_token) { - super(name_token ? name_token.value : '', type, varargs); + constructor(modifiers, typeident, varargs, name_token) { + super(name_token ? name_token.value : '', typeident.type, varargs); this.name_token = name_token; this.modifiers = modifiers; + this.paramTypeIdent = typeident; + } +} + +class SourceAnnotation { + /** + * @param {SourceTypeIdent} typeident + */ + constructor(typeident) { + this.annotationTypeIdent = typeident; } } exports.SourceType = SourceType; -exports.SourceField2 = SourceField2; -exports.SourceMethod2 = SourceMethod2; -exports.SourceParameter2 = SourceParameter2; -exports.SourceConstructor2 = SourceConstructor2; +exports.SourceTypeIdent = SourceTypeIdent; +exports.SourceField = SourceField; +exports.SourceMethod = SourceMethod; +exports.SourceParameter = SourceParameter; +exports.SourceConstructor = SourceConstructor; +exports.SourceInitialiser = SourceInitialiser; +exports.SourceAnnotation = SourceAnnotation; diff --git a/langserver/java/validater.js b/langserver/java/validater.js index a65bf4c..79eaaf3 100644 --- a/langserver/java/validater.js +++ b/langserver/java/validater.js @@ -1,8 +1,8 @@ -const { JavaType } = require('java-mti'); +const { ArrayType, JavaType, TypeVariable } = require('java-mti'); const { ModuleBlock, TypeDeclBlock } = require('./parser9'); const { resolveImports } = require('../java/import-resolver'); const ResolvedImport = require('../java/parsetypes/resolved-import'); -const { SourceType, SourceMethod, SourceConstructor, ResolvableType } = require('./source-type'); +const { SourceType, SourceTypeIdent, SourceField, SourceMethod, SourceConstructor, SourceInitialiser, SourceParameter, SourceAnnotation } = require('./source-type'); const { parseBody, flattenBlocks } = require('./body-parser3'); const { TokenList } = require('./TokenList'); const { typeIdent } = require('./typeident'); @@ -10,57 +10,102 @@ const { typeIdent } = require('./typeident'); /** * @param {ModuleBlock} mod - * @param {string} owner_typename + * @param {SourceType} outer_type * @param {ModuleBlock|TypeDeclBlock} parent * @param {SourceType[]} source_types * @param {Map} typemap */ -function getSourceTypes(mod, owner_typename, parent, source_types, typemap) { +function getSourceTypes(mod, outer_type, parent, source_types, typemap) { parent.types.forEach(type => { - const qualifiedTypeName = `${owner_typename}${type.simpleName}`; - // we add the names of type variables here, but we resolve any bounds later - //const typevar_names = type.typevars.map(tv => tv.name); - //const mti = new MTI().addType(package_name, '', mods, type.kind(), qualifiedTypeName, typevar_names); - const t = new SourceType(mod, type, qualifiedTypeName, typemap); + const t = new SourceType(mod.packageName, outer_type, '', type.modifiers.map(m => m.value), type.kindToken, type.name_token, typemap); + t.typeVariables = type.typevars.map(tv => new TypeVariable(t, tv.name, [new TypeVariable.Bound(t, 'Ljava/lang/Object;', false)])); source_types.push(t); - getSourceTypes(mod, `${qualifiedTypeName}$`, type, source_types, typemap); + getSourceTypes(mod, t, type, source_types, typemap); }); } /** - * @param {ResolvableType} rt - * @param {SourceType|SourceMethod|SourceConstructor} scope - * @param {ResolvedImport[]} resolved_imports - * @param {Map} typemap + * @param {TokenList} tokens + * @param {ModuleBlock|TypeDeclBlock} parent + * @param {ResolvedImport[]} imports + * @param {Map} typemap */ -function resolveResolvableType(rt, scope, resolved_imports, typemap) { - const tokens = new TokenList(flattenBlocks(rt.typeTokens, false)); - rt._resolved = typeIdent(tokens, scope, resolved_imports, typemap); -} +function populateTypes(tokens, parent, imports, typemap) { -/** - * - * @param {SourceType} source_type - * @param {ResolvedImport[]} resolved_imports - * @param {Map} typemap - */ -function resolveResolvableTypes(source_type, resolved_imports, typemap) { - source_type.extends_types.forEach(rt => resolveResolvableType(rt, source_type, resolved_imports, typemap)); - source_type.implements_types.forEach(rt => resolveResolvableType(rt, source_type, resolved_imports, typemap)); - - source_type.fields.forEach(f => resolveResolvableType(f._type, source_type, resolved_imports, typemap)); - - // methods and constructors can have parameterized types - source_type.methods.forEach(m => { - resolveResolvableType(m._returnType, m, resolved_imports, typemap); - m.parameters.forEach(p => resolveResolvableType(p._paramType, m, resolved_imports, typemap)); + parent.types.forEach(type => { + const source_type = typemap.get(type.shortSignature); + if (source_type instanceof SourceType) { + if (type.extends_decl) + source_type.extends_types = resolveTypeList(source_type, type.extends_decl); + if (type.implements_decl) + source_type.implements_types = resolveTypeList(source_type, type.implements_decl); + + // fields + source_type.fields = type.fields.map(f => { + const field_type = resolveTypeFromTokens(source_type, f); + return new SourceField(source_type, f.modifiers, field_type, f.name_token); + }); + // methods + source_type.methods = type.methods.map(m => { + const method_type = resolveTypeFromTokens(source_type, m); + const params = m.parameters.map(p => { + let param_type = resolveTypeFromTokens(source_type, p); + return new SourceParameter(p.modifiers, param_type, p.isVarArgs, p.name_token); + }) + const annotations = m.annotations.map(a => new SourceAnnotation(resolveTypeFromTokens(source_type, {typeTokens: [a.blockArray().blocks.slice().pop()]}))) + return new SourceMethod(source_type, m.modifiers, annotations, method_type, m.name_token, params, [], flattenBlocks([m.body()], true)); + }) + // constructors + source_type.constructors = type.constructors.map(c => { + const params = c.parameters.map(p => { + const param_type = resolveTypeFromTokens(source_type, p); + return new SourceParameter(p.modifiers, param_type, p.isVarArgs, p.name_token); + }) + return new SourceConstructor(source_type, c.modifiers, params, [], flattenBlocks([c.body()], true)); + }) + // initialisers + source_type.initers = type.initialisers.map(i => { + return new SourceInitialiser(source_type, i.modifiers, flattenBlocks([i.body()], true)); + }) + } + populateTypes(tokens, type, imports, typemap); }); - source_type.declaredConstructors.forEach(c => { - c.parameters.forEach(p => resolveResolvableType(p._paramType, c, resolved_imports, typemap)); - }); + function resolveTypeFromTokens(scope, decl) { + const typetokens = flattenBlocks([decl.typeTokens[0]], false); + tokens.current = tokens.tokens[tokens.idx = tokens.tokens.indexOf(typetokens[0])]; + let type = typeIdent(tokens, scope, imports, typemap); + if (decl.varBlock && decl.varBlock.post_name_arr_token) { + type = new ArrayType(type, decl.varBlock.post_name_arr_token.source.replace(/[^\[]/g,'').length); + } + if (decl.isVarArgs) { + type = new ArrayType(type, 1); + } + return new SourceTypeIdent(typetokens, type); + } + + function resolveTypeList(scope, eit_decl) { + const types = []; + const eit_tokens = flattenBlocks([eit_decl], false); + tokens.current = tokens.tokens[tokens.idx = tokens.tokens.indexOf(eit_tokens[0])]; + tokens.inc(); // bypass extends/implements/throws keyword + for (;;) { + const start = tokens.idx; + const type = typeIdent(tokens, scope, imports, typemap); + let end = tokens.idx - 1; + while (tokens.tokens[end].kind === 'wsc') { + end -= 1; + } + types.push(new SourceTypeIdent(tokens.tokens.slice(start, end + 1), type)); + if (!tokens.isValue(',')) { + break; + } + } + return types; + } } + /** * @param {ModuleBlock} mod * @param {Map} androidLibrary @@ -70,30 +115,25 @@ function validate(mod, androidLibrary) { /** @type {SourceType[]} */ const source_types = []; - getSourceTypes(mod, '', mod, source_types, androidLibrary); + getSourceTypes(mod, null, mod, source_types, androidLibrary); const imports = resolveImports(androidLibrary, source_types, mod.imports, mod.packageName); - source_types.forEach(t => { - resolveResolvableTypes(t, imports.resolved, imports.typemap); - }); + populateTypes(new TokenList(flattenBlocks(mod.blocks, false)), mod, imports.resolved, imports.typemap); let probs = []; source_types.forEach(t => { t.initers.forEach(i => { - console.log('()'); const parsed = parseBody(i, imports.resolved, imports.typemap); if (parsed) probs = probs.concat(parsed.problems) }) - t.declaredConstructors.forEach(c => { - console.log(c.label); + t.constructors.forEach(c => { const parsed = parseBody(c, imports.resolved, imports.typemap); if (parsed) probs = probs.concat(parsed.problems) }) t.methods.forEach(m => { - console.log(m.label); const parsed = parseBody(m, imports.resolved, imports.typemap); if (parsed) probs = probs.concat(parsed.problems) @@ -107,7 +147,6 @@ function validate(mod, androidLibrary) { require('./validation/parse-errors'), require('./validation/modifier-errors'), require('./validation/unresolved-imports'), - require('./validation/unresolved-types'), require('./validation/invalid-types'), require('./validation/bad-extends'), require('./validation/bad-implements'), diff --git a/langserver/java/validation/bad-extends.js b/langserver/java/validation/bad-extends.js index d3132bf..793e1d7 100644 --- a/langserver/java/validation/bad-extends.js +++ b/langserver/java/validation/bad-extends.js @@ -10,7 +10,7 @@ function checkExtends(source_type, probs) { if (source_type.extends_types.length === 0) { return; } - const supertypes = source_type.extends_types.map(st => st.resolved); + const supertypes = source_type.extends_types.map(st => st.type); const supertype = supertypes[0]; if (source_type.typeKind === 'enum') { probs.push(ParseProblem.Error(source_type.extends_types[0].typeTokens, `Enum types cannot declare a superclass`)); diff --git a/langserver/java/validation/bad-implements.js b/langserver/java/validation/bad-implements.js index 99c8b68..34cf8af 100644 --- a/langserver/java/validation/bad-implements.js +++ b/langserver/java/validation/bad-implements.js @@ -11,7 +11,7 @@ function checkImplements(source_type, probs) { if (source_type.implements_types.length === 0) { return; } - const interfaces = source_type.implements_types.map(it => it.resolved); + const interfaces = source_type.implements_types.map(it => it.type); if (source_type.typeKind === 'interface') { probs.push(ParseProblem.Error(source_type.implements_types[0].typeTokens, `Interface types cannot declare an implements section`)); } diff --git a/langserver/java/validation/bad-overrides.js b/langserver/java/validation/bad-overrides.js index 4d02dcb..68c1b78 100644 --- a/langserver/java/validation/bad-overrides.js +++ b/langserver/java/validation/bad-overrides.js @@ -1,6 +1,6 @@ -const { ModuleBlock, TextBlock } = require('../parser9'); +const { ModuleBlock } = require('../parser9'); const ParseProblem = require('../parsetypes/parse-problem'); -const {SourceType} = require('../source-type'); +const {SourceType, SourceAnnotation} = require('../source-type'); const {CEIType, Method} = require('java-mti'); function nonAbstractLabel(label) { @@ -19,10 +19,10 @@ function checkOverrides(source_type, probs) { return; } - /** @type {{ann:TextBlock, method:Method, method_id:string}[]} */ + /** @type {{ann:SourceAnnotation, method:Method, method_id:string}[]} */ const overriden_methods = []; source_type.methods.reduce((arr, method) => { - const ann = method._decl.annotations.find(a => /^@\s*Override$/.test(a.source)); + const ann = method.annotations.find(a => /^Override$/.test(a.annotationTypeIdent.type.simpleTypeName)); if (ann) { arr.push({ ann, @@ -52,7 +52,7 @@ function checkOverrides(source_type, probs) { overriden_methods.forEach(x => { if (!methods.has(x.method_id)) { - probs.push(ParseProblem.Error(x.ann, `${x.method.label} does not override a matching method in any inherited type or interface`)); + probs.push(ParseProblem.Error(x.ann.annotationTypeIdent.typeTokens, `${x.method.label} does not override a matching method in any inherited type or interface`)); } }) } diff --git a/langserver/java/validation/invalid-types.js b/langserver/java/validation/invalid-types.js index 64e0d85..5720645 100644 --- a/langserver/java/validation/invalid-types.js +++ b/langserver/java/validation/invalid-types.js @@ -1,11 +1,14 @@ -const { ModuleBlock, TypeDeclBlock } = require('../parser9'); +const { ModuleBlock } = require('../parser9'); const ParseProblem = require('../parsetypes/parse-problem'); const {SourceType} = require('../source-type'); -const {JavaType, ArrayType, CEIType, TypeArgument, UnresolvedType} = require('java-mti'); -const { AnyType } = require('../body-types'); +const {Token} = require('../tokenizer'); +const {JavaType} = require('java-mti'); /** * @param {JavaType} type + * @param {boolean} is_return_type + * @param {Token[]} typeTokens + * @param {ParseProblem[]} probs */ function checkType(type, is_return_type, typeTokens, probs) { const typesig = type.typeSignature; @@ -26,11 +29,11 @@ function checkType(type, is_return_type, typeTokens, probs) { * @param {*} probs */ function checkInvalidTypes(type, probs) { - type.fields.forEach(f => checkType(f.type, false, f._decl.typeTokens, probs)); + type.fields.forEach(f => checkType(f.type, false, f.fieldType.typeTokens, probs)); type.methods.forEach(m => { - checkType(m.returnType, true, m._decl.typeTokens, probs); + checkType(m.returnType, true, m.methodTypeIdent.typeTokens, probs); m.parameters.forEach(p => { - checkType(p.type, false, p._decl.typeTokens, probs); + checkType(p.type, false, p.paramTypeIdent.typeTokens, probs); }) }) } diff --git a/langserver/java/validation/missing-constructor.js b/langserver/java/validation/missing-constructor.js index 4bb3920..e99833a 100644 --- a/langserver/java/validation/missing-constructor.js +++ b/langserver/java/validation/missing-constructor.js @@ -22,7 +22,7 @@ function checkConstructor(source_type, probs) { if (!superclass.constructors.find(c => c.parameterCount === 0)) { // the source type has no declared constructors, but the superclass // does not include a default (parameterless) constructor - probs.push(ParseProblem.Error(source_type._decl.name_token, `Type ${superclass.fullyDottedRawName} requires a constructor to be declared because the inherited class '${superclass.fullyDottedRawName}' does not define a default constructor.`)); + probs.push(ParseProblem.Error(source_type.name_token, `Class '${source_type.fullyDottedRawName}' requires a constructor to be declared because the inherited class '${superclass.fullyDottedRawName}' does not define a default constructor.`)); } } diff --git a/langserver/java/validation/non-implemented-interfaces.js b/langserver/java/validation/non-implemented-interfaces.js index 29fff02..c741081 100644 --- a/langserver/java/validation/non-implemented-interfaces.js +++ b/langserver/java/validation/non-implemented-interfaces.js @@ -49,7 +49,7 @@ function checkImplementedInterfaces(source_type, probs) { } }) if (missing_methods.length) { - probs.push(ParseProblem.Error(source_type._decl.kindToken, `Non-abstract ${source_type.typeKind} '${source_type.fullyDottedRawName}' does not implement the following methods from interface '${intf.fullyDottedRawName}':\n${missing_methods.join('\n')}`)); + probs.push(ParseProblem.Error(source_type.kind_token, `Non-abstract ${source_type.typeKind} '${source_type.fullyDottedRawName}' does not implement the following methods from interface '${intf.fullyDottedRawName}':\n${missing_methods.join('\n')}`)); } }); } diff --git a/langserver/java/validation/unresolved-types.js b/langserver/java/validation/unresolved-types.js deleted file mode 100644 index 8165402..0000000 --- a/langserver/java/validation/unresolved-types.js +++ /dev/null @@ -1,52 +0,0 @@ -const { ModuleBlock, TypeDeclBlock } = require('../parser9'); -const ParseProblem = require('../parsetypes/parse-problem'); -const {SourceType} = require('../source-type'); -const {JavaType, CEIType, TypeArgument, UnresolvedType} = require('java-mti') - -/** - * @param {JavaType} type - */ -function checkType(type, typeTokens, probs) { - if (type instanceof UnresolvedType) { - probs.push(ParseProblem.Error(typeTokens, `Unknown type: ${type.label}`)); - return; - } - if (type instanceof CEIType) { - type.typeVariables.forEach(tv => { - if (tv instanceof TypeArgument) { - checkType(tv.type, typeTokens, probs); - } - }) - } -} - -/** - * @param {SourceType} type - * @param {*} probs - */ -function checkUnresolvedTypes(type, probs) { - type.extends_types.forEach(superclass => checkType(superclass.resolved, superclass.typeTokens, probs)); - type.implements_types.forEach(superintf => checkType(superintf.resolved, superintf.typeTokens, probs)); - type.fields.forEach(f => checkType(f.type, f._decl.typeTokens, probs)); - type.methods.forEach(m => { - checkType(m.returnType, m._decl.typeTokens, probs); - m.parameters.forEach(p => { - checkType(p.type, p._decl.typeTokens, probs); - }) - }) -} - - -/** - * @param {ModuleBlock} mod - * @param {*} imports - * @param {SourceType[]} source_types - */ -module.exports = function(mod, imports, source_types) { - /** @type {ParseProblem[]} */ - const probs = []; - - source_types.forEach(type => checkUnresolvedTypes(type, probs)); - - return probs; -}