diff --git a/langserver/java/validater.js b/langserver/java/validater.js index 0d3b376..d241d04 100644 --- a/langserver/java/validater.js +++ b/langserver/java/validater.js @@ -89,6 +89,7 @@ function validate(mod, androidLibrary) { require('./validation/bad-implements'), require('./validation/non-implemented-interfaces'), require('./validation/bad-overrides'), + require('./validation/missing-constructor'), ]; let problems = [ module_validaters.map(v => v(mod, imports, source_types)), diff --git a/langserver/java/validation/missing-constructor.js b/langserver/java/validation/missing-constructor.js new file mode 100644 index 0000000..4bb3920 --- /dev/null +++ b/langserver/java/validation/missing-constructor.js @@ -0,0 +1,41 @@ +const { ModuleBlock, TypeDeclBlock } = require('../parser9'); +const ParseProblem = require('../parsetypes/parse-problem'); +const {SourceType, SourceConstructor} = require('../source-type'); + +/** + * @param {SourceType} source_type + * @param {ParseProblem[]} probs + */ +function checkConstructor(source_type, probs) { + if (source_type.typeKind !== 'class') { + return; + } + if (source_type.constructors[0] instanceof SourceConstructor) { + return; + } + const superclass = source_type.supers.find(s => s.typeKind === 'class'); + if (!superclass) { + // if there's no superclass, the class must inherit from an interface + // - which means the inherited class is Object (and a default constructor exists) + return; + } + 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.`)); + } +} + +/** + * @param {ModuleBlock} mod + * @param {*} imports + * @param {SourceType[]} source_types + */ +module.exports = function(mod, imports, source_types) { + /** @type {ParseProblem[]} */ + const probs = []; + + source_types.forEach(type => checkConstructor(type, probs)); + + return probs; +}