mirror of
https://github.com/adelphes/android-dev-ext.git
synced 2025-12-22 09:29:38 +00:00
* initial working language server * first hacky version of source parsing and type checking * first iteration of method body parser * add support for prefix/postfix inc expressions * add basic support for parsing new expressions * different attempt to parse using collapsable text ranges * fix parsing of binary operstors following a bracket expression * updated validation to use new JavaTypes module instead of MTIs * add support for array-literal expressions * fix || and && not being tokenized as operators allow float literals starting with dot * add new method body parser to use direct linear parsing * add super as an object literal * fix interface constructors check constructor type modifiers * fix assignment operator types * Fix resolving of enclosed type identifiers * add default constructor for class types with no explicit constructors * add missing constructor validator * add constructor parameters to list of resolvable types * update SourceMethod to pass name in super constructor * add Any* classes to reduce cascading errors * update method call parameter checking use isTypeAssignable instead of getParameterCompatibleTypeSignatures * tidy up isTypeAssignable allow class equivilents for primitives * add more info when methods/ctrs cannot be matched * allow interfaces to be cast to class instances * use isTypeAssignable for checking branch test expressions * allow AnyValue to be a constant value * split shift operators from bitwise operators * add support for literal numbers to be assignable to multiple primtive types * clear diagnostics when document is closed * update check for cast expression * casting only applies to qualified term not a whole expression * allow all primitive-number-type casts * add support for synchronized statement * update primitive type compatibility * allow null to be cast to any non-primitve * use better regex for string literals * allow character literals to be assigned to number types * add support for array qualifiers after a variable name * make sure any long specifier is stripped from a bigint value * improve invalid array expression message add AnyType array element to prevent cascading errors * make default a modifer keyword for interface default method support * initial support for wildcard type arguments * fix parse issue with nested generic types * allow generic types to be assigned to inherited types with compatible type arguments * allow unicode characters, $ and _ in identifiers * map primitive types to their boxed versions for class member * support assert statement * allow unicode char literals * make type parser and body parser use same tokenizer * reuse parsed tokens instead of tokenizing each method body * re-add throws as a keyword * treat default and synchronized as modifiers * add SourceInitialiser support * refactor to prepare for merging with type parsing * add support for array qualifiers in type identifiers * pass scoped type instead of method to typeIdent * update ResolvableType to use same type resolving as method body parsing * add support for post-name array qualifiers in fields and parameters * post-name array qualifiers in method decls * add type variables to SourceMethod * initial attempt to support type variable arguments in methods * specialise methods with type variables * don't require default interface methods to be implemented * make variable arity parameters an array type * tidy array constructors and fix some warnings * update isCallCompatible to handle variable arity calls * improve assert statement support * parse labels and break/continue targets * refactor new term qualifiers * add support for generic inferred-type arguments * improve modifier checks for interface types * improve reporting of unresolved type errors * fix type checking of field and method declarations * add missng strictfp modifier * refactor in preparation for parsing local types * replace Locals with scopeable MethodDeclarations to allow labels and types to be stored * initial changes to support local type declarations * update to use new set of SourceX classes * refactor to allow expressions to have a type scope * replace regex parsing with linear parsing * generate source types before parsing * fix support for resolving type variables in method declarations * fix checking of array literal compatability * report errors from unit parsing * remove local modifier validation during parse add parameter modifier checking to validation * allow trailing comma for array literals * start separating validation from parsing * add support for parsing enum values * allow uppercase 0X in hex literals * include enclosing types in identifier search * add support for parsing parameterless lambdas * ignore unresolved types in extends/implements * implement specialisation of SourceType * allow super as a member qualifier * allow empty enums * don't report missing constructors if superclass has none * update typemap declarations to use CEIType instead of JavaType * fix resolving of class type variables * fix bad imports when resolving annotations * allow null scope in findIdentifier * add support for static member imports * import types from same package * remove this qualifier from isCastExpression * add hex exponent support * parse try-with-resources * fix resolving imported enclosed types * extract expression types into separate files * extract statement types into separate files * fix type warnings * extract literals into separate files * remove Value class, add NewExpression and separate out Any classes * rename source types module * remove some parse checks that should be in verify * support token extraction in expressions * implement resolveExpression * add type cast checking * check for valid type in class member expressions * allow assigns for assignable type arguments * improve reporting of unresolved identifiers * add new array validation * validate array literals * validate array indexes * improve validation of binary operators * rename ResolvedType to ResolvedValue * improve checking of number literals * support package name as a resolved value * implement method body and ststement validation * improve method call resolving * add support for this() and super() constructor calls * remove return type for source constructors * add checks for unary operators * ensure tokens are assigned for qualified expressions * check castability using type assignments * add implicit enum methods values() and valueOf() * add basic type checking of lambda expressions * fix return type check * fix assert statement checks * improve support for ternary operators in assignments and method invocations * perform more detailed search of implemented methods * initial test of context-dependant code completion * support package, type and static field import completion * support for member expressions * use exact type signatures for locating types for completion items * add support for field and method docs * add support for docs in source types * support member completion for array types improve comment formatting * ensure Object is always last in the list of inherited types * add owning method to statements create common keyword statement class * improve code completion list add method parameters order list items by scope * add source types to list hide this and super for non-methods * fix bad member resolution at end of block fix missing method and type docs * add support for editing multiple files * allow multiple source files to be used in parsing * load and parse files at startup * add support for displaying method signatures * add single trace function with timestamps * implement shceduleReparse to reduce parsing load while typing * remove parsed type list logging * wait for reparsing before returning method signatures * resolve new object contructors * improve extraction of parameter docs * update @types/vscode * cache decoded android library in globalStoragePath * load single android library cache from local folder * android-29 library cache * allow configurable app root setting * set configurable trace logging and update section names * description updates * handle null token passed to ParseProblem * refactoring * Rename language client extension to Android * ignore unnamed type declarations * handle java file change notifications * make sure we only try and parse java files * add option to allow language server to be shutdown * simplify handling of this and class member qualifiers * relocate java-mti package into project * get main node install to install langserver dependencies * remove debugging pause * rename body-parser3 to body-parser * clean up import resolving code * remove unused field from ResolvedImport * remove validation modules that used old parser types * remove old parser files * remove redundant types and functions used by old parser * move addproblem into TokenList * remove unused ResolvedType class * validate more statements * add support for parsing and validating anonymous types * hide some method modifiers which aren't useful to show * code comments and minor improvements * fix some type warnings * improve support for completion of enum values * add type name to parameter completion labels * ignore synthetic members in completion list * use a specialised map for handling case-insenstive file uris * add basic build script * reference java-mti package from GitHub * revert @types/vscode * update initial file loading to use URIs passed from the client changes to the appSourceRoot now require an extension restart * add support for loading filtered androidx libraries for code completion * update version of java-mti * add mixpanel package * add basic analytics * fix dependency versions * fix dependency versions * set empty cache file markers * add language server debug config * add file to build script * add unqualified type members when inside a method * apply statics filter to enum values * add basic debugger analytics * include current time in startup event * add terminate reason to debugger * update changelog and readme
757 lines
22 KiB
JavaScript
757 lines
22 KiB
JavaScript
const { CEIType, JavaType, PrimitiveType, ArrayType, TypeVariableType, Field, Method, MethodBase, Constructor, Parameter, TypeVariable, TypeArgument } = require('java-mti');
|
|
const { AnyType } = require('./anys');
|
|
const { Token } = require('./tokenizer');
|
|
|
|
/**
|
|
* @typedef {import('./body-types').ResolvedIdent} ResolvedIdent
|
|
*/
|
|
|
|
/**
|
|
* @param {SourceType|SourceMethod|SourceConstructor|SourceInitialiser|string} scope_or_package_name
|
|
* @param {string} name
|
|
*/
|
|
function generateShortSignature(scope_or_package_name, name) {
|
|
if (scope_or_package_name instanceof SourceType) {
|
|
const type = scope_or_package_name;
|
|
return `${type._rawShortSignature}$${name}`;
|
|
}
|
|
if (scope_or_package_name instanceof SourceMethod
|
|
|| scope_or_package_name instanceof SourceConstructor
|
|
|| scope_or_package_name instanceof SourceInitialiser) {
|
|
const method = scope_or_package_name;
|
|
return `${method.owner._rawShortSignature}$${method.owner.localTypeCount += 1}${name}`;
|
|
}
|
|
const pkgname = scope_or_package_name;
|
|
return pkgname ?`${pkgname.replace(/\./g, '/')}/${name}` : name;
|
|
}
|
|
|
|
/**
|
|
* @param {SourceType} enum_type
|
|
* @param {Map<string,CEIType>} typemap
|
|
*/
|
|
function createImplicitEnumMethods(enum_type, typemap) {
|
|
return [
|
|
new class extends Method {
|
|
constructor() {
|
|
super(enum_type, 'values', ['public','static'], '');
|
|
this._returnType = new ArrayType(enum_type, 1);
|
|
}
|
|
get returnType() {
|
|
return this._returnType;
|
|
}
|
|
},
|
|
new class extends Method {
|
|
constructor() {
|
|
super(enum_type, 'valueOf', ['public','static'], '');
|
|
this._parameters = [
|
|
new Parameter('name', typemap.get('java/lang/String'), false)
|
|
]
|
|
this._returnType = enum_type;
|
|
}
|
|
get parameters() {
|
|
return this._parameters;
|
|
}
|
|
get returnType() {
|
|
return this._returnType;
|
|
}
|
|
}
|
|
];
|
|
}
|
|
|
|
class SourceType extends CEIType {
|
|
/**
|
|
* @param {string} rawShortSignature
|
|
* @param {'class'|'interface'|'enum'|'@interface'} typeKind
|
|
* @param {string[]|number} modifiers
|
|
* @param {string} docs
|
|
* @param {Map<string,CEIType>} typemap
|
|
*/
|
|
constructor(rawShortSignature, typeKind, modifiers, docs, typemap) {
|
|
super(rawShortSignature, typeKind, modifiers, docs);
|
|
/**
|
|
* Number of local/anonymous types declared in the scope of this type
|
|
* The number is used when naming them.
|
|
*/
|
|
this.localTypeCount = 0;
|
|
/** @type {SourceTypeIdent[]} */
|
|
this.extends_types = [];
|
|
/** @type {SourceTypeIdent[]} */
|
|
this.implements_types = [];
|
|
/** @type {SourceConstructor[]} */
|
|
this.constructors = [];
|
|
/** @type {Method[]} */
|
|
this.methods = typeKind === 'enum'
|
|
? createImplicitEnumMethods(this, typemap)
|
|
: [];
|
|
/** @type {SourceField[]} */
|
|
this.fields = [];
|
|
/** @type {SourceInitialiser[]} */
|
|
this.initers = [];
|
|
/** @type {SourceEnumValue[]} */
|
|
this.enumValues = [];
|
|
this.typemap = typemap;
|
|
}
|
|
|
|
/**
|
|
* @param {string} docs
|
|
* @param {Token} ident
|
|
* @param {ResolvedIdent[]} ctr_args
|
|
* @param {SourceType} anonymousType
|
|
*/
|
|
addEnumValue(docs, ident, ctr_args, anonymousType) {
|
|
this.enumValues.push(new SourceEnumValue(this, docs, ident, ctr_args, anonymousType));
|
|
}
|
|
|
|
/**
|
|
* @returns {SourceMethod[]}
|
|
*/
|
|
get sourceMethods() {
|
|
// @ts-ignore
|
|
return this.methods.filter(m => m instanceof SourceMethod);// [...this.implicitMethods, ...this.sourceMethods];
|
|
}
|
|
|
|
}
|
|
|
|
class AnonymousSourceType extends SourceType {
|
|
|
|
/**
|
|
* @param {SourceType|SourceMethod|SourceConstructor|SourceInitialiser} scope
|
|
*/
|
|
static genSignature(scope) {
|
|
const type = scope instanceof SourceType ? scope : scope.owner;
|
|
return `${type._rawShortSignature}$${type.localTypeCount += 1}`;
|
|
}
|
|
|
|
/**
|
|
* @param {SourceTypeIdent} typeident
|
|
* @param {SourceType|SourceMethod|SourceConstructor|SourceInitialiser} outer_scope
|
|
* @param {Map<string,CEIType>} typemap
|
|
*/
|
|
constructor(typeident, outer_scope, typemap) {
|
|
super(AnonymousSourceType.genSignature(outer_scope), 'class', [], '', typemap);
|
|
this.simpleTypeName = typeident.resolved.simpleTypeName;
|
|
this.typeIdent = typeident;
|
|
}
|
|
|
|
get dottedTypeName() {
|
|
return this.typeIdent.resolved.dottedTypeName;
|
|
}
|
|
|
|
get fullyDottedRawName() {
|
|
return this.dottedTypeName;
|
|
}
|
|
|
|
get fullyDottedTypeName() {
|
|
return this.dottedTypeName;
|
|
}
|
|
|
|
get label() {
|
|
return `new ${this.dottedTypeName}`;
|
|
}
|
|
|
|
/** @type {JavaType[]} */
|
|
get supers() {
|
|
if (this.typeIdent.resolved instanceof AnyType || this.typeIdent.resolved.typeKind !== 'class') {
|
|
return [this.typemap.get('java/lang/Object')]
|
|
}
|
|
return [this.typeIdent.resolved];
|
|
}
|
|
|
|
get shortSignature() {
|
|
return this._rawShortSignature;
|
|
}
|
|
|
|
get rawTypeSignature() {
|
|
return `L${this._rawShortSignature};`;
|
|
}
|
|
|
|
get typeSignature() {
|
|
return this.rawTypeSignature;
|
|
}
|
|
}
|
|
|
|
class NamedSourceType extends SourceType {
|
|
/**
|
|
* @param {string} packageName
|
|
* @param {SourceType|SourceMethod|SourceConstructor|SourceInitialiser} outer_scope
|
|
* @param {string} docs
|
|
* @param {Token[]} modifiers
|
|
* @param {string} typeKind
|
|
* @param {Token} kind_token
|
|
* @param {Token} name_token
|
|
* @param {Map<string,CEIType>} typemap
|
|
*/
|
|
constructor(packageName, outer_scope, docs, modifiers, typeKind, kind_token, name_token, typemap) {
|
|
// @ts-ignore
|
|
super(generateShortSignature(outer_scope || packageName, name_token.value), typeKind, modifiers.map(m => m.source), docs, typemap);
|
|
super.packageName = packageName;
|
|
this.modifierTokens = modifiers;
|
|
this.kind_token = kind_token;
|
|
this.nameToken = name_token;
|
|
this.scope = outer_scope;
|
|
}
|
|
|
|
/**
|
|
* @param {string} package_name
|
|
* @param {SourceType|SourceMethod|SourceConstructor|SourceInitialiser} outer_scope
|
|
* @param {string} name
|
|
*/
|
|
static getShortSignature(package_name, outer_scope, name) {
|
|
return generateShortSignature(outer_scope || package_name || '', name);
|
|
}
|
|
|
|
/**
|
|
* @param {Token[]} mods
|
|
*/
|
|
setModifierTokens(mods) {
|
|
this.modifierTokens = mods;
|
|
this.modifiers = mods.map(m => m.source);
|
|
}
|
|
|
|
/**
|
|
* @param {JavaType[]} types
|
|
* @returns {CEIType}
|
|
*/
|
|
specialise(types) {
|
|
const short_sig = `${this.shortSignature}<${types.map(t => t.typeSignature).join('')}>`;
|
|
if (this.typemap.has(short_sig)) {
|
|
// @ts-ignore
|
|
return this.typemap.get(short_sig);
|
|
}
|
|
/** @type {'class'|'enum'|'interface'|'@interface'} */
|
|
// @ts-ignore
|
|
const typeKind = this.typeKind;
|
|
const specialised_type = new SpecialisedSourceType(this, typeKind, this._rawShortSignature, types);
|
|
this.typemap.set(short_sig, specialised_type);
|
|
return specialised_type;
|
|
}
|
|
|
|
get supers() {
|
|
const supertypes = [...this.extends_types, ...this.implements_types].map(x => x.resolved);
|
|
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 SpecialisedSourceType extends CEIType {
|
|
/**
|
|
*
|
|
* @param {SourceType} source_type
|
|
* @param {'class'|'enum'|'interface'|'@interface'} typeKind
|
|
* @param {string} raw_short_signature
|
|
* @param {JavaType[]} types
|
|
*/
|
|
constructor(source_type, typeKind, raw_short_signature, types) {
|
|
super(raw_short_signature, typeKind, source_type.modifiers, source_type.docs);
|
|
this.source_type = source_type;
|
|
this.typemap = source_type.typemap;
|
|
/** @type {TypeArgument[]} */
|
|
// @ts-ignore
|
|
const type_args = source_type.typeVariables.map((tv, idx) => new TypeArgument(this, tv, types[idx] || this.typemap.get('java/lang/Object')));
|
|
this.typeVariables = type_args;
|
|
|
|
function resolveType(type, typevars = []) {
|
|
if (type instanceof ArrayType) {
|
|
return new ArrayType(resolveType(type.base, typevars), type.arrdims);
|
|
}
|
|
if (!(type instanceof TypeVariableType)) {
|
|
return type;
|
|
}
|
|
if (typevars.includes(type.typeVariable)) {
|
|
return type;
|
|
}
|
|
const specialised_type = type_args.find(ta => ta.name === type.typeVariable.name);
|
|
return specialised_type.type;
|
|
}
|
|
|
|
this.fields = source_type.fields.map(f => {
|
|
const type = this;
|
|
return new class extends Field {
|
|
constructor() {
|
|
super(f.modifiers, f.docs);
|
|
this.owner = type;
|
|
this.source = f;
|
|
this.fieldType = resolveType(f.fieldTypeIdent.resolved);
|
|
}
|
|
get name() { return this.source.name }
|
|
get type() { return this.fieldType }
|
|
};
|
|
});
|
|
|
|
this.constructors = source_type.constructors.map(c => {
|
|
const type = this;
|
|
return new class extends Constructor {
|
|
constructor() {
|
|
super(type, c.modifiers, c.docs);
|
|
this.owner = type;
|
|
this.source = c;
|
|
this._parameters = c.sourceParameters.map(p => new Parameter(p.name, resolveType(p.paramTypeIdent.resolved, c.typeVariables), p.varargs));
|
|
}
|
|
get hasImplementation() {
|
|
return !!this.source.body;
|
|
}
|
|
get parameters() {
|
|
return this._parameters;
|
|
}
|
|
get typeVariables() {
|
|
return this.source.typeVars;
|
|
}
|
|
|
|
};
|
|
});
|
|
this.methods = source_type.methods.map(method => {
|
|
if (!(method instanceof SourceMethod)) {
|
|
return method;
|
|
}
|
|
const m = method;
|
|
const type = this;
|
|
return new class extends Method {
|
|
constructor() {
|
|
super(type, m.name, m.modifiers, m.docs);
|
|
this.owner = type;
|
|
this.source = m;
|
|
this._returnType = resolveType(m.returnType, m.typeVars)
|
|
this._parameters = m.sourceParameters.map(p => new Parameter(p.name, resolveType(p.type, m.typeVars), p.varargs));
|
|
}
|
|
get hasImplementation() {
|
|
return !!this.source.body;
|
|
}
|
|
get parameters() {
|
|
return this._parameters;
|
|
}
|
|
get returnType() {
|
|
return this._returnType;
|
|
}
|
|
get typeVariables() {
|
|
return this.source.typeVars;
|
|
}
|
|
};
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param {JavaType[]} types
|
|
* @returns {CEIType}
|
|
*/
|
|
specialise(types) {
|
|
const short_sig = `${this._rawShortSignature}<${types.map(t => t.typeSignature).join('')}>`;
|
|
if (this.typemap.has(short_sig)) {
|
|
// @ts-ignore
|
|
return this.typemap.get(short_sig);
|
|
}
|
|
/** @type {'class'|'enum'|'interface'|'@interface'} */
|
|
// @ts-ignore
|
|
const typeKind = this.typeKind;
|
|
const specialised_type = new SpecialisedSourceType(this.source_type, typeKind, this._rawShortSignature, types);
|
|
this.typemap.set(short_sig, specialised_type);
|
|
return specialised_type;
|
|
}
|
|
|
|
}
|
|
|
|
class SourceEnumValue extends Field {
|
|
/**
|
|
* @param {SourceType} owner
|
|
* @param {string} docs
|
|
* @param {Token} ident
|
|
* @param {ResolvedIdent[]} ctr_args
|
|
* @param {SourceType} anonymousType
|
|
*/
|
|
constructor(owner, docs, ident, ctr_args, anonymousType) {
|
|
super(['public','static','final'], docs);
|
|
this.owner = owner;
|
|
this.ident = ident;
|
|
this.value = ctr_args;
|
|
this.anonymousType = anonymousType;
|
|
}
|
|
|
|
get label() {
|
|
// don't include the implicit modifiers in the label
|
|
return `${this.owner.simpleTypeName} ${this.name}`;
|
|
}
|
|
|
|
get name() {
|
|
return this.ident.value;
|
|
}
|
|
|
|
get type() {
|
|
return this.owner;
|
|
}
|
|
}
|
|
|
|
class SourceTypeIdent {
|
|
/**
|
|
* @param {Token[]} tokens
|
|
* @param {JavaType} type
|
|
*/
|
|
constructor(tokens, type) {
|
|
this.tokens = tokens;
|
|
this.resolved = type;
|
|
}
|
|
}
|
|
|
|
class SourceField extends Field {
|
|
/**
|
|
* @param {SourceType} owner
|
|
* @param {string} docs
|
|
* @param {Token[]} modifiers
|
|
* @param {SourceTypeIdent} field_type_ident
|
|
* @param {Token} name_token
|
|
* @param {ResolvedIdent} init
|
|
*/
|
|
constructor(owner, docs, modifiers, field_type_ident, name_token, init) {
|
|
super(modifiers.map(m => m.value), docs);
|
|
this.owner = owner;
|
|
this.modifierTokens = modifiers;
|
|
this.fieldTypeIdent = field_type_ident;
|
|
this.nameToken = name_token;
|
|
this.init = init;
|
|
}
|
|
|
|
get name() {
|
|
return this.nameToken ? this.nameToken.value : '';
|
|
}
|
|
|
|
get type() {
|
|
return this.fieldTypeIdent.resolved;
|
|
}
|
|
}
|
|
|
|
class SourceConstructor extends Constructor {
|
|
/**
|
|
* @param {SourceType} owner
|
|
* @param {string} docs
|
|
* @param {TypeVariable[]} type_vars
|
|
* @param {Token[]} modifiers
|
|
* @param {SourceParameter[]} parameters
|
|
* @param {JavaType[]} throws
|
|
* @param {Token[]} body_tokens
|
|
*/
|
|
constructor(owner, docs, type_vars, modifiers, parameters, throws, body_tokens) {
|
|
super(owner, modifiers.map(m => m.value), docs);
|
|
this.owner = owner;
|
|
this.typeVars = type_vars;
|
|
this.modifierTokens = modifiers;
|
|
this.sourceParameters = parameters;
|
|
this.throws = throws;
|
|
this.body = {
|
|
tokens: body_tokens,
|
|
/** @type {import('./body-types').Local[]} */
|
|
locals: [],
|
|
/** @type {import('./statementtypes/Block').Block} */
|
|
block: null,
|
|
}
|
|
this.parsed = null;
|
|
}
|
|
|
|
get hasImplementation() {
|
|
return !!this.body;
|
|
}
|
|
|
|
get parameterCount() {
|
|
return this.sourceParameters.length;
|
|
}
|
|
|
|
/**
|
|
* @returns {SourceParameter[]}
|
|
*/
|
|
get parameters() {
|
|
return this.sourceParameters;
|
|
}
|
|
|
|
get typeVariables() {
|
|
return this.typeVars;
|
|
}
|
|
}
|
|
|
|
class SourceMethod extends Method {
|
|
/**
|
|
* @param {SourceType} owner
|
|
* @param {string} docs
|
|
* @param {TypeVariable[]} type_vars
|
|
* @param {Token[]} modifiers
|
|
* @param {SourceAnnotation[]} annotations
|
|
* @param {SourceTypeIdent} method_type_ident
|
|
* @param {Token} name_token
|
|
* @param {SourceParameter[]} parameters
|
|
* @param {JavaType[]} throws
|
|
* @param {Token[]} body_tokens
|
|
*/
|
|
constructor(owner, docs, type_vars, modifiers, annotations, method_type_ident, name_token, parameters, throws, body_tokens) {
|
|
super(owner, name_token ? name_token.value : '', modifiers.map(m => m.value), docs);
|
|
this.annotations = annotations;
|
|
this.owner = owner;
|
|
this.typeVars = type_vars;
|
|
this.modifierTokens = modifiers;
|
|
this.returnTypeIdent = method_type_ident;
|
|
this.nameToken = name_token;
|
|
this.sourceParameters = parameters;
|
|
this.throws = throws;
|
|
this.body = {
|
|
tokens: body_tokens,
|
|
/** @type {import('./body-types').Local[]} */
|
|
locals: [],
|
|
/** @type {import('./statementtypes/Block').Block} */
|
|
block: null,
|
|
}
|
|
this.parsed = null;
|
|
}
|
|
|
|
get hasImplementation() {
|
|
return !!this.body;
|
|
}
|
|
|
|
get parameterCount() {
|
|
return this.sourceParameters.length;
|
|
}
|
|
|
|
/**
|
|
* @returns {SourceParameter[]}
|
|
*/
|
|
get parameters() {
|
|
return this.sourceParameters;
|
|
}
|
|
|
|
get returnType() {
|
|
return this.returnTypeIdent.resolved;
|
|
}
|
|
|
|
get typeVariables() {
|
|
return this.typeVars;
|
|
}
|
|
}
|
|
|
|
class SourceInitialiser extends MethodBase {
|
|
/**
|
|
* @param {SourceType} owner
|
|
* @param {string} docs
|
|
* @param {Token[]} modifiers
|
|
* @param {Token[]} body_tokens
|
|
*/
|
|
constructor(owner, docs, modifiers, body_tokens) {
|
|
super(owner, modifiers.map(m => m.value), docs);
|
|
/** @type {SourceType} */
|
|
this.owner = owner;
|
|
this.modifierTokens = modifiers;
|
|
this.body = {
|
|
tokens: body_tokens,
|
|
/** @type {import('./body-types').Local[]} */
|
|
locals: [],
|
|
/** @type {import('./statementtypes/Block').Block} */
|
|
block: null,
|
|
}
|
|
this.parsed = null;
|
|
}
|
|
|
|
/**
|
|
* @returns {SourceParameter[]}
|
|
*/
|
|
get parameters() {
|
|
return [];
|
|
}
|
|
|
|
get returnType() {
|
|
return PrimitiveType.map.V;
|
|
}
|
|
}
|
|
|
|
class SourceParameter extends Parameter {
|
|
/**
|
|
* @param {Token[]} modifiers
|
|
* @param {SourceTypeIdent} typeident
|
|
* @param {boolean} varargs
|
|
* @param {Token} name_token
|
|
*/
|
|
constructor(modifiers, typeident, varargs, name_token) {
|
|
super(name_token ? name_token.value : '', typeident.resolved, varargs);
|
|
this.nameToken = name_token;
|
|
this.modifierTokens = modifiers;
|
|
this.paramTypeIdent = typeident;
|
|
}
|
|
|
|
get type() {
|
|
return this.paramTypeIdent.resolved;
|
|
}
|
|
}
|
|
|
|
class SourceAnnotation {
|
|
/**
|
|
* @param {SourceTypeIdent} typeident
|
|
*/
|
|
constructor(typeident) {
|
|
this.annotationTypeIdent = typeident;
|
|
}
|
|
|
|
get type() {
|
|
return this.annotationTypeIdent.resolved;
|
|
}
|
|
}
|
|
|
|
class SourcePackage {
|
|
/**
|
|
* @param {Token[]} tokens
|
|
* @param {string} name
|
|
*/
|
|
constructor(tokens, name) {
|
|
this.tokens = tokens;
|
|
this.name = name;
|
|
}
|
|
}
|
|
|
|
class SourceImport {
|
|
|
|
/**
|
|
* @param {Token[]} tokens
|
|
* @param {Token[]} name_tokens
|
|
* @param {string} pkg_name
|
|
* @param {Token} static_token
|
|
* @param {Token} asterisk_token
|
|
* @param {import('./parsetypes/resolved-import')} resolved
|
|
*/
|
|
constructor(tokens, name_tokens, pkg_name, static_token, asterisk_token, resolved) {
|
|
this.tokens = tokens;
|
|
this.nameTokens = name_tokens;
|
|
this.package_name = pkg_name;
|
|
this.staticToken = static_token;
|
|
this.asteriskToken = asterisk_token;
|
|
this.resolved = resolved;
|
|
}
|
|
|
|
get isDemandLoad() {
|
|
return !!this.asteriskToken;
|
|
}
|
|
|
|
get isStatic() {
|
|
return !!this.staticToken;
|
|
}
|
|
}
|
|
|
|
class SourceUnit {
|
|
/** @type {string} */
|
|
uri = '';
|
|
/** @type {Token[]} */
|
|
tokens = [];
|
|
/** @type {SourcePackage} */
|
|
package_ = null;
|
|
/** @type {SourceImport[]} */
|
|
imports = [];
|
|
/** @type {SourceType[]} */
|
|
types = [];
|
|
|
|
/**
|
|
* @param {Token} token
|
|
*/
|
|
getSourceMethodAtToken(token) {
|
|
if (!token) {
|
|
return null;
|
|
}
|
|
for (let type of this.types) {
|
|
for (let method of [...type.sourceMethods, ...type.constructors, ...type.initers]) {
|
|
if (method.body && method.body.tokens && method.body.tokens.includes(token)) {
|
|
return method;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @param {number} char_index
|
|
*/
|
|
getTokenAt(char_index) {
|
|
let i = 0;
|
|
for (let tok of this.tokens) {
|
|
if (char_index > tok.range.start + tok.range.length) {
|
|
i++;
|
|
continue;
|
|
}
|
|
while (i > 0 && tok.kind === 'wsc') {
|
|
tok = this.tokens[--i];
|
|
}
|
|
return tok;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {number} char_index
|
|
*/
|
|
getCompletionOptionsAt(char_index) {
|
|
const token = this.getTokenAt(char_index);
|
|
const method = this.getSourceMethodAtToken(token);
|
|
// we should also include local variables here, but
|
|
// it's currently difficult to map an individual token to a scope
|
|
return {
|
|
index: char_index,
|
|
loc: token && token.loc,
|
|
method,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Return the name of the package this unit belongs to
|
|
*/
|
|
get packageName() {
|
|
return (this.package_ && this.package_.name) || '';
|
|
}
|
|
}
|
|
|
|
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}]`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @typedef {SourceMethod|SourceConstructor|SourceInitialiser} SourceMethodLike
|
|
*/
|
|
|
|
exports.SourceType = SourceType;
|
|
exports.SourceTypeIdent = SourceTypeIdent;
|
|
exports.SourceField = SourceField;
|
|
exports.SourceMethod = SourceMethod;
|
|
exports.SourceParameter = SourceParameter;
|
|
exports.SourceConstructor = SourceConstructor;
|
|
exports.SourceInitialiser = SourceInitialiser;
|
|
exports.SourceAnnotation = SourceAnnotation;
|
|
exports.SourceUnit = SourceUnit;
|
|
exports.SourcePackage = SourcePackage;
|
|
exports.SourceImport = SourceImport;
|
|
exports.SourceEnumValue = SourceEnumValue;
|
|
exports.SourceArrayType = SourceArrayType;
|
|
exports.FixedLengthArrayType = FixedLengthArrayType;
|
|
exports.NamedSourceType = NamedSourceType;
|
|
exports.AnonymousSourceType = AnonymousSourceType;
|