diff --git a/langserver/java/body-parser3.js b/langserver/java/body-parser3.js index 9316d6a..96f8794 100644 --- a/langserver/java/body-parser3.js +++ b/langserver/java/body-parser3.js @@ -352,7 +352,8 @@ function statement(tokens, mdecls, method, imports, typemap) { } // modifiers are only allowed on local variable decls if (modifiers.length) { - s = var_decl(modifiers, tokens, mdecls, method, imports, typemap); + const type = typeIdent(tokens, method, imports, typemap); + s = var_ident_list(modifiers, type, null, tokens, mdecls, method, imports, typemap) addLocals(tokens, mdecls, s); semicolon(tokens); return s; @@ -789,7 +790,6 @@ function parameterDeclaration(type_vars, owner, tokens, imports, typemap) { modifiers.push(tokens.current); tokens.inc(); } - checkLocalModifiers(tokens, modifiers); let type_ident = typeIdent(tokens, owner, imports, typemap, { no_array_qualifiers: false, type_vars }); const varargs = tokens.isValue('...'); let name_token = tokens.current; @@ -1148,7 +1148,6 @@ function catchFinallyBlocks(s, tokens, mdecls, method, imports, typemap) { mdecls.pushScope(); let exceptionVar; if (catchinfo.types[0] && catchinfo.name) { - checkLocalModifiers(tokens, mods); exceptionVar = new Local(mods, catchinfo.name.value, catchinfo.name, catchinfo.types[0], 0); mdecls.locals.push(exceptionVar); } @@ -1360,19 +1359,6 @@ function checkThrowExpression(tokens, throw_expression, typemap) { } } -/** - * @param {TokenList} tokens - * @param {MethodDeclarations} mdecls - * @param {Scope} scope - * @param {ResolvedImport[]} imports - * @param {Map} typemap - * @returns {Local[]} - */ -function var_decl(mods, tokens, mdecls, scope, imports, typemap) { - const type = typeIdent(tokens, scope, imports, typemap); - return var_ident_list(mods, type, null, tokens, mdecls, scope, imports, typemap) -} - /** * * @param {Token[]} mods @@ -1385,7 +1371,6 @@ function var_decl(mods, tokens, mdecls, scope, imports, typemap) { * @param {Map} typemap */ function var_ident_list(mods, type, first_ident, tokens, mdecls, scope, imports, typemap) { - checkLocalModifiers(tokens, mods); const new_locals = []; for (;;) { let name; @@ -1467,20 +1452,6 @@ function expression_list_or_var_decl(tokens, mdecls, scope, imports, typemap) { return expressions; } - -/** - * @param {Token[]} mods - */ -function checkLocalModifiers(tokens, mods) { - for (let i=0; i < mods.length; i++) { - if (mods[i].value !== 'final') { - addproblem(tokens, ParseProblem.Error(mods[i], `Modifier '${mods[i].source}' cannot be applied to local variable declarations.`)); - } else if (mods.findIndex(m => m.source === 'final') < i) { - addproblem(tokens, ParseProblem.Error(mods[i], `Repeated 'final' modifier.`)); - } - } -} - /** * Operator precedence levels. * Lower number = higher precedence. diff --git a/langserver/java/validation/modifier-errors.js b/langserver/java/validation/modifier-errors.js index dd82e21..a3f91f3 100644 --- a/langserver/java/validation/modifier-errors.js +++ b/langserver/java/validation/modifier-errors.js @@ -1,4 +1,4 @@ -const { SourceType, SourceMethod, SourceField, SourceConstructor, SourceInitialiser } = require('../source-type'); +const { SourceType, SourceMethod, SourceParameter, SourceField, SourceConstructor, SourceInitialiser } = require('../source-type'); const { Token } = require('../tokenizer'); const ParseProblem = require('../parsetypes/parse-problem'); @@ -68,6 +68,25 @@ function checkFieldModifiers(field, probs) { } } +/** + * @param {SourceParameter} param + * @param {ParseProblem[]} probs + */ +function checkParameterModifiers(param, probs) { + // the only permitted modifier is final + let has_final = false; + param.modifierTokens.forEach(mod => { + if (mod.value === 'final') { + if (has_final) { + probs.push(ParseProblem.Error(mod, `Repeated modifier: final`)); + } + has_final = true; + return; + } + probs.push(ParseProblem.Error(mod, `Parameter declarations cannot be ${mod.value}`)); + }); +} + /** * @param {SourceType} type * @param {Map} ownertypemods @@ -78,6 +97,8 @@ function checkMethodModifiers(type, ownertypemods, method, probs) { checkDuplicate(method.modifierTokens, probs); checkConflictingAccess(method.modifierTokens, probs); + method.parameters.forEach(p => checkParameterModifiers(p, probs)); + const allmods = new Map(method.modifierTokens.map(m => [m.source, m])); const is_interface_kind = /@?interface/.test(type.typeKind); const has_body = method.hasImplementation;