mirror of
https://github.com/adelphes/android-dev-ext.git
synced 2025-12-23 01:48:18 +00:00
fix support for resolving type variables in method declarations
This commit is contained in:
@@ -554,19 +554,19 @@ function typeBody(type, tokens, owner, imports, typemap) {
|
|||||||
/**
|
/**
|
||||||
* @param {Token[]} modifiers
|
* @param {Token[]} modifiers
|
||||||
* @param {SourceAnnotation[]} annotations
|
* @param {SourceAnnotation[]} annotations
|
||||||
* @param {TypeVariable[]} type_variables
|
* @param {TypeVariable[]} type_vars
|
||||||
* @param {SourceType} type
|
* @param {SourceType} type
|
||||||
* @param {TokenList} tokens
|
* @param {TokenList} tokens
|
||||||
* @param {ResolvedImport[]} imports
|
* @param {ResolvedImport[]} imports
|
||||||
* @param {Map<string,JavaType>} typemap
|
* @param {Map<string,JavaType>} typemap
|
||||||
*/
|
*/
|
||||||
function fmc(modifiers, annotations, type_variables, type, tokens, imports, typemap) {
|
function fmc(modifiers, annotations, type_vars, type, tokens, imports, typemap) {
|
||||||
let decl_type_ident = typeIdent(tokens, type, imports, typemap);
|
let decl_type_ident = typeIdent(tokens, type, imports, typemap, { no_array_qualifiers: false, type_vars });
|
||||||
if (decl_type_ident.resolved.rawTypeSignature === type.rawTypeSignature) {
|
if (decl_type_ident.resolved.rawTypeSignature === type.rawTypeSignature) {
|
||||||
if (tokens.current.value === '(') {
|
if (tokens.current.value === '(') {
|
||||||
// constructor
|
// constructor
|
||||||
const { parameters, throws, body } = methodDeclaration(type, tokens, imports, typemap);
|
const { parameters, throws, body } = methodDeclaration(type_vars, type, tokens, imports, typemap);
|
||||||
const ctr = new SourceConstructor(type, modifiers, parameters, throws, body);
|
const ctr = new SourceConstructor(type, type_vars, modifiers, parameters, throws, body);
|
||||||
type.constructors.push(ctr);
|
type.constructors.push(ctr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -577,15 +577,15 @@ function fmc(modifiers, annotations, type_variables, type, tokens, imports, type
|
|||||||
addproblem(tokens, ParseProblem.Error(tokens.current, `Identifier expected`))
|
addproblem(tokens, ParseProblem.Error(tokens.current, `Identifier expected`))
|
||||||
}
|
}
|
||||||
if (tokens.current.value === '(') {
|
if (tokens.current.value === '(') {
|
||||||
const { postnamearrdims, parameters, throws, body } = methodDeclaration(type, tokens, imports, typemap);
|
const { postnamearrdims, parameters, throws, body } = methodDeclaration(type_vars, type, tokens, imports, typemap);
|
||||||
if (postnamearrdims > 0) {
|
if (postnamearrdims > 0) {
|
||||||
decl_type_ident.resolved = new ArrayType(decl_type_ident.resolved, postnamearrdims);
|
decl_type_ident.resolved = new ArrayType(decl_type_ident.resolved, postnamearrdims);
|
||||||
}
|
}
|
||||||
const method = new SourceMethod(type, modifiers, annotations, decl_type_ident, name, parameters, throws, body);
|
const method = new SourceMethod(type, type_vars, modifiers, annotations, decl_type_ident, name, parameters, throws, body);
|
||||||
type.methods.push(method);
|
type.methods.push(method);
|
||||||
} else {
|
} else {
|
||||||
if (name) {
|
if (name) {
|
||||||
if (type_variables.length) {
|
if (type_vars.length) {
|
||||||
addproblem(tokens, ParseProblem.Error(tokens.current, `Fields cannot declare type variables`));
|
addproblem(tokens, ParseProblem.Error(tokens.current, `Fields cannot declare type variables`));
|
||||||
}
|
}
|
||||||
const locals = var_ident_list(modifiers, decl_type_ident, name, tokens, new MethodDeclarations(), type, imports, typemap);
|
const locals = var_ident_list(modifiers, decl_type_ident, name, tokens, new MethodDeclarations(), type, imports, typemap);
|
||||||
@@ -641,7 +641,7 @@ function annotation(tokens, scope, imports, typemap) {
|
|||||||
addproblem(tokens, ParseProblem.Error(tokens.current, `Type identifier expected`));
|
addproblem(tokens, ParseProblem.Error(tokens.current, `Type identifier expected`));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let annotation_type = typeIdent(tokens, scope, imports, typemap, false);
|
let annotation_type = typeIdent(tokens, scope, imports, typemap, {no_array_qualifiers: true, type_vars:[]});
|
||||||
if (tokens.isValue('(')) {
|
if (tokens.isValue('(')) {
|
||||||
if (!tokens.isValue(')')) {
|
if (!tokens.isValue(')')) {
|
||||||
expressionList(tokens, new MethodDeclarations(), scope, imports, typemap);
|
expressionList(tokens, new MethodDeclarations(), scope, imports, typemap);
|
||||||
@@ -729,17 +729,18 @@ function typeVariableList(owner, tokens, scope, imports, typemap) {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param {TypeVariable[]} type_vars
|
||||||
* @param {SourceType} owner
|
* @param {SourceType} owner
|
||||||
* @param {TokenList} tokens
|
* @param {TokenList} tokens
|
||||||
* @param {ResolvedImport[]} imports
|
* @param {ResolvedImport[]} imports
|
||||||
* @param {Map<string,JavaType>} typemap
|
* @param {Map<string,JavaType>} typemap
|
||||||
*/
|
*/
|
||||||
function methodDeclaration(owner, tokens, imports, typemap) {
|
function methodDeclaration(type_vars, owner, tokens, imports, typemap) {
|
||||||
tokens.expectValue('(');
|
tokens.expectValue('(');
|
||||||
let parameters = [], throws = [], postnamearrdims = 0, body = null;
|
let parameters = [], throws = [], postnamearrdims = 0, body = null;
|
||||||
if (!tokens.isValue(')')) {
|
if (!tokens.isValue(')')) {
|
||||||
for(;;) {
|
for(;;) {
|
||||||
const p = parameterDeclaration(owner, tokens, imports, typemap);
|
const p = parameterDeclaration(type_vars, owner, tokens, imports, typemap);
|
||||||
parameters.push(p);
|
parameters.push(p);
|
||||||
if (tokens.isValue(',')) {
|
if (tokens.isValue(',')) {
|
||||||
continue;
|
continue;
|
||||||
@@ -767,19 +768,20 @@ function methodDeclaration(owner, tokens, imports, typemap) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param {TypeVariable[]} type_vars
|
||||||
* @param {SourceType} owner
|
* @param {SourceType} owner
|
||||||
* @param {TokenList} tokens
|
* @param {TokenList} tokens
|
||||||
* @param {ResolvedImport[]} imports
|
* @param {ResolvedImport[]} imports
|
||||||
* @param {Map<string,JavaType>} typemap
|
* @param {Map<string,JavaType>} typemap
|
||||||
*/
|
*/
|
||||||
function parameterDeclaration(owner, tokens, imports, typemap) {
|
function parameterDeclaration(type_vars, owner, tokens, imports, typemap) {
|
||||||
const modifiers = [];
|
const modifiers = [];
|
||||||
while (tokens.current.kind === 'modifier') {
|
while (tokens.current.kind === 'modifier') {
|
||||||
modifiers.push(tokens.current);
|
modifiers.push(tokens.current);
|
||||||
tokens.inc();
|
tokens.inc();
|
||||||
}
|
}
|
||||||
checkLocalModifiers(tokens, modifiers);
|
checkLocalModifiers(tokens, modifiers);
|
||||||
let type_ident = typeIdent(tokens, owner, imports, typemap);
|
let type_ident = typeIdent(tokens, owner, imports, typemap, { no_array_qualifiers: false, type_vars });
|
||||||
const varargs = tokens.isValue('...');
|
const varargs = tokens.isValue('...');
|
||||||
let name_token = tokens.current;
|
let name_token = tokens.current;
|
||||||
if (!tokens.isKind('ident')) {
|
if (!tokens.isKind('ident')) {
|
||||||
@@ -2353,7 +2355,7 @@ function rootTerm(tokens, mdecls, scope, imports, typemap) {
|
|||||||
function newTerm(tokens, mdecls, scope, imports, typemap) {
|
function newTerm(tokens, mdecls, scope, imports, typemap) {
|
||||||
tokens.expectValue('new');
|
tokens.expectValue('new');
|
||||||
const type_start_token = tokens.idx;
|
const type_start_token = tokens.idx;
|
||||||
const { resolved: ctr_type } = typeIdent(tokens, scope, imports, typemap, false);
|
const { resolved: ctr_type } = typeIdent(tokens, scope, imports, typemap, {no_array_qualifiers:true, type_vars:[]});
|
||||||
if (ctr_type instanceof AnyType) {
|
if (ctr_type instanceof AnyType) {
|
||||||
const toks = tokens.tokens.slice(type_start_token, tokens.idx);
|
const toks = tokens.tokens.slice(type_start_token, tokens.idx);
|
||||||
addproblem(tokens, ParseProblem.Error(toks, `Unresolved type: '${toks.map(t => t.source).join('')}'`));
|
addproblem(tokens, ParseProblem.Error(toks, `Unresolved type: '${toks.map(t => t.source).join('')}'`));
|
||||||
@@ -2843,7 +2845,7 @@ function findIdentifier(ident, mdecls, scope, imports, typemap) {
|
|||||||
if (type) {
|
if (type) {
|
||||||
matches.types = [type];
|
matches.types = [type];
|
||||||
} else {
|
} else {
|
||||||
const { types, package_name } = resolveTypeOrPackage(ident, scope, imports, typemap);
|
const { types, package_name } = resolveTypeOrPackage(ident, [], scope, imports, typemap);
|
||||||
matches.types = types;
|
matches.types = types;
|
||||||
matches.package_name = package_name;
|
matches.package_name = package_name;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const { CEIType, JavaType, PrimitiveType, Field, Method, MethodBase, Constructor, Parameter } = require('java-mti');
|
const { CEIType, JavaType, PrimitiveType, Field, Method, MethodBase, Constructor, Parameter, TypeVariable } = require('java-mti');
|
||||||
const { Token } = require('./tokenizer');
|
const { Token } = require('./tokenizer');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,14 +127,16 @@ class SourceField extends Field {
|
|||||||
class SourceConstructor extends Constructor {
|
class SourceConstructor extends Constructor {
|
||||||
/**
|
/**
|
||||||
* @param {SourceType} owner
|
* @param {SourceType} owner
|
||||||
|
* @param {TypeVariable[]} type_vars
|
||||||
* @param {Token[]} modifiers
|
* @param {Token[]} modifiers
|
||||||
* @param {SourceParameter[]} parameters
|
* @param {SourceParameter[]} parameters
|
||||||
* @param {JavaType[]} throws
|
* @param {JavaType[]} throws
|
||||||
* @param {Token[]} body
|
* @param {Token[]} body
|
||||||
*/
|
*/
|
||||||
constructor(owner, modifiers, parameters, throws, body) {
|
constructor(owner, type_vars, modifiers, parameters, throws, body) {
|
||||||
super(owner, modifiers.map(m => m.value), '');
|
super(owner, modifiers.map(m => m.value), '');
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
|
this.typeVars = type_vars;
|
||||||
this.modifierTokens = modifiers;
|
this.modifierTokens = modifiers;
|
||||||
this.sourceParameters = parameters;
|
this.sourceParameters = parameters;
|
||||||
this.throws = throws;
|
this.throws = throws;
|
||||||
@@ -162,11 +164,16 @@ class SourceConstructor extends Constructor {
|
|||||||
get returnType() {
|
get returnType() {
|
||||||
return this.owner;
|
return this.owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get typeVariables() {
|
||||||
|
return this.typeVars;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SourceMethod extends Method {
|
class SourceMethod extends Method {
|
||||||
/**
|
/**
|
||||||
* @param {SourceType} owner
|
* @param {SourceType} owner
|
||||||
|
* @param {TypeVariable[]} type_vars
|
||||||
* @param {Token[]} modifiers
|
* @param {Token[]} modifiers
|
||||||
* @param {SourceAnnotation[]} annotations
|
* @param {SourceAnnotation[]} annotations
|
||||||
* @param {SourceTypeIdent} method_type_ident
|
* @param {SourceTypeIdent} method_type_ident
|
||||||
@@ -175,10 +182,11 @@ class SourceMethod extends Method {
|
|||||||
* @param {JavaType[]} throws
|
* @param {JavaType[]} throws
|
||||||
* @param {Token[]} body
|
* @param {Token[]} body
|
||||||
*/
|
*/
|
||||||
constructor(owner, modifiers, annotations, method_type_ident, name_token, parameters, throws, body) {
|
constructor(owner, type_vars, modifiers, annotations, method_type_ident, name_token, parameters, throws, body) {
|
||||||
super(owner, name_token ? name_token.value : '', modifiers.map(m => m.value), '');
|
super(owner, name_token ? name_token.value : '', modifiers.map(m => m.value), '');
|
||||||
this.annotations = annotations;
|
this.annotations = annotations;
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
|
this.typeVars = type_vars;
|
||||||
this.modifierTokens = modifiers;
|
this.modifierTokens = modifiers;
|
||||||
this.returnTypeIdent = method_type_ident;
|
this.returnTypeIdent = method_type_ident;
|
||||||
this.nameToken = name_token;
|
this.nameToken = name_token;
|
||||||
@@ -202,12 +210,13 @@ class SourceMethod extends Method {
|
|||||||
return this.sourceParameters;
|
return this.sourceParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {JavaType}
|
|
||||||
*/
|
|
||||||
get returnType() {
|
get returnType() {
|
||||||
return this.returnTypeIdent.resolved;
|
return this.returnTypeIdent.resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get typeVariables() {
|
||||||
|
return this.typeVars;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SourceInitialiser extends MethodBase {
|
class SourceInitialiser extends MethodBase {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @typedef {Map<string,JavaType>} TypeMap
|
* @typedef {Map<string,JavaType>} TypeMap
|
||||||
*/
|
*/
|
||||||
const { JavaType, PrimitiveType, ArrayType, CEIType, MethodBase } = require('java-mti');
|
const { JavaType, PrimitiveType, ArrayType, CEIType, MethodBase, TypeVariable } = require('java-mti');
|
||||||
const { ResolvedImport } = require('./import-resolver');
|
const { ResolvedImport } = require('./import-resolver');
|
||||||
const ResolvedType = require('./parsetypes/resolved-type');
|
const ResolvedType = require('./parsetypes/resolved-type');
|
||||||
|
|
||||||
@@ -260,15 +260,21 @@ function resolveTypeIdents(types, fully_qualified_scope, resolved_imports, typem
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} ident
|
* @param {string} ident
|
||||||
|
* @param {TypeVariable[]} type_variables
|
||||||
* @param {CEIType|MethodBase} scope
|
* @param {CEIType|MethodBase} scope
|
||||||
* @param {ResolvedImport[]} imports
|
* @param {ResolvedImport[]} imports
|
||||||
* @param {Map<string,JavaType>} typemap
|
* @param {Map<string,JavaType>} typemap
|
||||||
*/
|
*/
|
||||||
function resolveTypeOrPackage(ident, scope, imports, typemap) {
|
function resolveTypeOrPackage(ident, type_variables, scope, imports, typemap) {
|
||||||
const types = [];
|
const types = [];
|
||||||
let package_name = '';
|
let package_name = '';
|
||||||
|
|
||||||
if (scope instanceof MethodBase) {
|
const tv = type_variables.find(tv => tv.name === ident);
|
||||||
|
if (tv) {
|
||||||
|
types.push(tv.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!types[0] && scope instanceof MethodBase) {
|
||||||
// is it a type variable in the current scope
|
// is it a type variable in the current scope
|
||||||
const tv = scope.typeVariables.find(tv => tv.name === ident);
|
const tv = scope.typeVariables.find(tv => tv.name === ident);
|
||||||
if (tv) {
|
if (tv) {
|
||||||
@@ -276,7 +282,7 @@ function resolveTypeOrPackage(ident, scope, imports, typemap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope) {
|
if (!types[0] && scope) {
|
||||||
// is it an enclosed type of the currently scoped type or any outer type
|
// is it an enclosed type of the currently scoped type or any outer type
|
||||||
const scoped_type = scope instanceof CEIType ? scope : scope.owner;
|
const scoped_type = scope instanceof CEIType ? scope : scope.owner;
|
||||||
const scopes = scoped_type.shortSignature.split('$');
|
const scopes = scoped_type.shortSignature.split('$');
|
||||||
@@ -293,7 +299,7 @@ function resolveTypeOrPackage(ident, scope, imports, typemap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope instanceof CEIType) {
|
if (!types[0] && scope instanceof CEIType) {
|
||||||
// is it a type variable of the currently scoped type
|
// is it a type variable of the currently scoped type
|
||||||
const tv = scope.typeVariables.find(tv => tv.name === ident);
|
const tv = scope.typeVariables.find(tv => tv.name === ident);
|
||||||
if (tv) {
|
if (tv) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const { ArrayType, CEIType, JavaType, PrimitiveType, MethodBase, WildcardType } = require('java-mti');
|
const { ArrayType, CEIType, JavaType, PrimitiveType, MethodBase, WildcardType, TypeVariable } = require('java-mti');
|
||||||
const { SourceTypeIdent, SourceMethod, SourceConstructor, SourceInitialiser } = require('./source-type');
|
const { SourceTypeIdent, SourceMethod, SourceConstructor, SourceInitialiser } = require('./source-type');
|
||||||
const ResolvedImport = require('./parsetypes/resolved-import');
|
const ResolvedImport = require('./parsetypes/resolved-import');
|
||||||
const { resolveTypeOrPackage, resolveNextTypeOrPackage } = require('./type-resolver');
|
const { resolveTypeOrPackage, resolveNextTypeOrPackage } = require('./type-resolver');
|
||||||
@@ -32,11 +32,11 @@ function typeIdentList(tokens, scope, imports, typemap) {
|
|||||||
* @param {CEIType|MethodBase} scope
|
* @param {CEIType|MethodBase} scope
|
||||||
* @param {ResolvedImport[]} imports
|
* @param {ResolvedImport[]} imports
|
||||||
* @param {Map<string,JavaType>} typemap
|
* @param {Map<string,JavaType>} typemap
|
||||||
* @param {boolean} allow_array_qualifiers
|
* @param {{no_array_qualifiers:boolean, type_vars:TypeVariable[]}} [opts]
|
||||||
*/
|
*/
|
||||||
function typeIdent(tokens, scope, imports, typemap, allow_array_qualifiers = true) {
|
function typeIdent(tokens, scope, imports, typemap, opts) {
|
||||||
tokens.mark();
|
tokens.mark();
|
||||||
const type = singleTypeIdent(tokens, scope, imports, typemap, allow_array_qualifiers);
|
const type = singleTypeIdent(tokens, scope, imports, typemap, opts);
|
||||||
return new SourceTypeIdent(tokens.markEnd(), type);
|
return new SourceTypeIdent(tokens.markEnd(), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,15 +45,15 @@ function typeIdent(tokens, scope, imports, typemap, allow_array_qualifiers = tru
|
|||||||
* @param {CEIType|MethodBase} scope
|
* @param {CEIType|MethodBase} scope
|
||||||
* @param {ResolvedImport[]} imports
|
* @param {ResolvedImport[]} imports
|
||||||
* @param {Map<string,JavaType>} typemap
|
* @param {Map<string,JavaType>} typemap
|
||||||
* @param {boolean} allow_array_qualifiers
|
* @param {{no_array_qualifiers:boolean, type_vars: TypeVariable[]}} [opts]
|
||||||
*/
|
*/
|
||||||
function singleTypeIdent(tokens, scope, imports, typemap, allow_array_qualifiers = true) {
|
function singleTypeIdent(tokens, scope, imports, typemap, opts) {
|
||||||
/** @type {JavaType[]} */
|
/** @type {JavaType[]} */
|
||||||
let types = [], package_name = '';
|
let types = [], package_name = '';
|
||||||
tokens.mark();
|
tokens.mark();
|
||||||
switch(tokens.current.kind) {
|
switch(tokens.current.kind) {
|
||||||
case 'ident':
|
case 'ident':
|
||||||
({ types, package_name } = resolveTypeOrPackage(tokens.current.value, scope, imports, typemap));
|
({ types, package_name } = resolveTypeOrPackage(tokens.current.value, opts ? opts.type_vars : [], scope, imports, typemap));
|
||||||
break;
|
break;
|
||||||
case 'primitive-type':
|
case 'primitive-type':
|
||||||
types.push(PrimitiveType.fromName(tokens.current.value));
|
types.push(PrimitiveType.fromName(tokens.current.value));
|
||||||
@@ -84,6 +84,8 @@ function singleTypeIdent(tokens, scope, imports, typemap, allow_array_qualifiers
|
|||||||
types.push(anytype);
|
types.push(anytype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// allow array qualifiers unless specifically disabled
|
||||||
|
const allow_array_qualifiers = !opts || !opts.no_array_qualifiers;
|
||||||
if ( allow_array_qualifiers && tokens.isValue('[')) {
|
if ( allow_array_qualifiers && tokens.isValue('[')) {
|
||||||
let arrdims = 0;
|
let arrdims = 0;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
|||||||
Reference in New Issue
Block a user