Java22Validator.java
/*
* Copyright (C) 2011, 2013-2025 The JavaParser Team.
*
* This file is part of JavaParser.
*
* JavaParser can be used either under the terms of
* a) the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* b) the terms of the Apache License
*
* You should have received a copy of both licenses in LICENCE.LGPL and
* LICENCE.APACHE. Please refer to those files for details.
*
* JavaParser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
package com.github.javaparser.ast.validator.language_level_validations;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.Parameter;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.CatchClause;
import com.github.javaparser.ast.stmt.ForStmt;
import com.github.javaparser.ast.validator.ProblemReporter;
import com.github.javaparser.ast.validator.SingleNodeTypeValidator;
import com.github.javaparser.ast.validator.Validator;
import com.github.javaparser.resolution.Navigator;
/**
* This validator validates according to Java 22 syntax rules.
*
* @see <a href="https://openjdk.java.net/projects/jdk/22/">https://openjdk.java.net/projects/jdk/22/</a>
*/
public class Java22Validator extends Java21Validator {
final Validator unnamedVarOnlyWhereAllowedByJep456 =
new SingleNodeTypeValidator<>(SimpleName.class, (name, reporter) -> {
if (!name.getIdentifier().equals("_")) {
return;
}
if (reportNoParent(name, reporter)) {
return;
}
Node parentNode = name.getParentNode().get();
if (parentNode instanceof VariableDeclarator || parentNode instanceof TypePatternExpr) {
return;
}
if (parentNode instanceof Parameter) {
Parameter parameter = (Parameter) parentNode;
if (reportNoParent(parameter, reporter)) {
return;
}
Node grandParent = parameter.getParentNode().get();
if (grandParent instanceof CatchClause || grandParent instanceof LambdaExpr) {
return;
}
}
try {
ForStmt enclosingFor =
(ForStmt) Navigator.demandParentNode(name, ancestor -> ancestor instanceof ForStmt);
if (enclosingFor.getCompare().isPresent()
&& enclosingFor.getCompare().get().containsWithinRange(name)) {
// In a for compare, so now check that it's the LHS of an assignment
AssignExpr enclosingAssign = (AssignExpr)
Navigator.demandParentNode(name, ancestor -> ancestor instanceof AssignExpr);
if (enclosingAssign.getTarget().containsWithinRange(name)) {
return;
}
}
} catch (IllegalStateException e) {
// Didn't find a ForStmt ancestor, so the "_" identifier should not be allowed here.
}
reporter.report(name, "Unnamed variables only supported in cases described by JEP456");
});
final Validator matchAllPatternNotTopLevel =
new SingleNodeTypeValidator<>(MatchAllPatternExpr.class, (patternExpr, reporter) -> {
if (!patternExpr.getParentNode().isPresent()
|| !(patternExpr.getParentNode().get() instanceof PatternExpr)) {
reporter.report(patternExpr, "MatchAllPatternExpr cannot be used as a top-level pattern");
}
});
private boolean reportNoParent(Node node, ProblemReporter reporter) {
if (node.getParentNode().isPresent()) {
return false;
}
String className = node.getClass().getCanonicalName();
reporter.report(node, "Node of type " + className + " must have an AST parent");
return true;
}
public Java22Validator() {
super();
remove(underscoreKeywordValidator);
add(unnamedVarOnlyWhereAllowedByJep456);
add(matchAllPatternNotTopLevel);
}
}