aboutsummaryrefslogtreecommitdiffstats
path: root/javaparser-core/src/main/java/com/github/javaparser/ast/validator
diff options
context:
space:
mode:
Diffstat (limited to 'javaparser-core/src/main/java/com/github/javaparser/ast/validator')
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java10Validator.java19
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java11Validator.java16
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_0Validator.java121
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_1Validator.java22
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_2Validator.java17
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_3Validator.java10
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_4Validator.java11
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java5Validator.java52
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java6Validator.java10
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java7Validator.java39
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java8Validator.java32
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java9Validator.java30
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/NoProblemsValidator.java16
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/ProblemReporter.java34
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/ReservedKeywordValidator.java36
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/SimpleValidator.java20
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/SingleNodeTypeValidator.java24
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/TreeVisitorValidator.java22
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/TypedValidator.java24
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/Validator.java15
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/Validators.java45
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/VisitorValidator.java16
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/CommonValidators.java70
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/ModifierValidator.java211
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/NoBinaryIntegerLiteralsValidator.java27
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/NoUnderscoresInIntegerLiteralsValidator.java27
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/UnderscoreKeywordValidator.java27
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/VarValidator.java93
28 files changed, 1086 insertions, 0 deletions
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java10Validator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java10Validator.java
new file mode 100644
index 000000000..c7fda2f46
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java10Validator.java
@@ -0,0 +1,19 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.type.VarType;
+import com.github.javaparser.ast.validator.chunks.VarValidator;
+
+/**
+ * This validator validates according to Java 10 syntax rules.
+ */
+public class Java10Validator extends Java9Validator {
+
+ protected final Validator varOnlyOnLocalVariableDefinitionAndFor = new SingleNodeTypeValidator<>(VarType.class, new VarValidator(false));
+
+ public Java10Validator() {
+ super();
+ add(varOnlyOnLocalVariableDefinitionAndFor);
+ /* There is no validator that validates that "var" is not used in Java 9 and lower, since the parser will never create a VarType node,
+ because that is done by the Java10 postprocessor. You can add it by hand, but that is obscure enough to ignore. */
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java11Validator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java11Validator.java
new file mode 100644
index 000000000..0eb879aa0
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java11Validator.java
@@ -0,0 +1,16 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.type.VarType;
+import com.github.javaparser.ast.validator.chunks.VarValidator;
+
+/**
+ * This validator validates according to Java 11 syntax rules.
+ */
+public class Java11Validator extends Java10Validator {
+ protected final Validator varAlsoInLambdaParameters = new SingleNodeTypeValidator<>(VarType.class, new VarValidator(true));
+
+ public Java11Validator() {
+ super();
+ replace(varOnlyOnLocalVariableDefinitionAndFor, varAlsoInLambdaParameters);
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_0Validator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_0Validator.java
new file mode 100644
index 000000000..0d1051d67
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_0Validator.java
@@ -0,0 +1,121 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.ImportDeclaration;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.body.*;
+import com.github.javaparser.ast.expr.AnnotationExpr;
+import com.github.javaparser.ast.expr.ClassExpr;
+import com.github.javaparser.ast.expr.LambdaExpr;
+import com.github.javaparser.ast.expr.StringLiteralExpr;
+import com.github.javaparser.ast.modules.ModuleDeclaration;
+import com.github.javaparser.ast.nodeTypes.NodeWithTypeArguments;
+import com.github.javaparser.ast.nodeTypes.NodeWithTypeParameters;
+import com.github.javaparser.ast.stmt.AssertStmt;
+import com.github.javaparser.ast.stmt.ForeachStmt;
+import com.github.javaparser.ast.stmt.SwitchEntryStmt;
+import com.github.javaparser.ast.stmt.TryStmt;
+import com.github.javaparser.ast.type.UnionType;
+import com.github.javaparser.ast.validator.chunks.CommonValidators;
+import com.github.javaparser.ast.validator.chunks.ModifierValidator;
+import com.github.javaparser.ast.validator.chunks.NoBinaryIntegerLiteralsValidator;
+import com.github.javaparser.ast.validator.chunks.NoUnderscoresInIntegerLiteralsValidator;
+
+/**
+ * This validator validates according to Java 1.0 syntax rules.
+ */
+public class Java1_0Validator extends Validators {
+ protected final Validator modifiersWithoutStrictfpAndDefaultAndStaticInterfaceMethodsAndPrivateInterfaceMethods
+ = new ModifierValidator(false, false, false);
+ protected final Validator noAssertKeyword = new SimpleValidator<>(AssertStmt.class,
+ n -> true,
+ (n, reporter) -> reporter.report(n, "'assert' keyword is not supported.")
+ );
+ protected final Validator noInnerClasses = new SimpleValidator<>(ClassOrInterfaceDeclaration.class,
+ n -> !n.isTopLevelType(),
+ (n, reporter) -> reporter.report(n, "inner classes or interfaces are not supported.")
+ );
+ protected final Validator noReflection = new SimpleValidator<>(ClassExpr.class,
+ n -> true,
+ (n, reporter) -> reporter.report(n, "Reflection is not supported.")
+ );
+ protected final Validator noGenerics = new TreeVisitorValidator((node, reporter) -> {
+ if (node instanceof NodeWithTypeArguments) {
+ if (((NodeWithTypeArguments<? extends Node>) node).getTypeArguments().isPresent()) {
+ reporter.report(node, "Generics are not supported.");
+ }
+ }
+ if (node instanceof NodeWithTypeParameters) {
+ if (((NodeWithTypeParameters<? extends Node>) node).getTypeParameters().isNonEmpty()) {
+ reporter.report(node, "Generics are not supported.");
+ }
+ }
+ });
+ protected final SingleNodeTypeValidator<TryStmt> tryWithoutResources = new SingleNodeTypeValidator<>(TryStmt.class, (n, reporter) -> {
+ if (n.getCatchClauses().isEmpty() && !n.getFinallyBlock().isPresent()) {
+ reporter.report(n, "Try has no finally and no catch.");
+ }
+ if (n.getResources().isNonEmpty()) {
+ reporter.report(n, "Catch with resource is not supported.");
+ }
+ });
+ protected final Validator noAnnotations = new TreeVisitorValidator((node, reporter) -> {
+ if (node instanceof AnnotationExpr || node instanceof AnnotationDeclaration) {
+ reporter.report(node, "Annotations are not supported.");
+ }
+ });
+ protected final Validator noEnums = new SimpleValidator<>(EnumDeclaration.class,
+ n -> true,
+ (n, reporter) -> reporter.report(n, "Enumerations are not supported.")
+ );
+ protected final Validator noVarargs = new SimpleValidator<>(Parameter.class,
+ Parameter::isVarArgs,
+ (n, reporter) -> reporter.report(n, "Varargs are not supported.")
+ );
+ protected final Validator noForEach = new SimpleValidator<>(ForeachStmt.class,
+ n -> true,
+ (n, reporter) -> reporter.report(n, "For-each loops are not supported.")
+ );
+ protected final Validator noStaticImports = new SimpleValidator<>(ImportDeclaration.class,
+ ImportDeclaration::isStatic,
+ (n, reporter) -> reporter.report(n, "Static imports are not supported.")
+ );
+ protected final Validator noStringsInSwitch = new SimpleValidator<>(SwitchEntryStmt.class,
+ n -> n.getLabel().map(l -> l instanceof StringLiteralExpr).orElse(false),
+ (n, reporter) -> reporter.report(n.getLabel().get(), "Strings in switch statements are not supported.")
+ );
+ protected final Validator noBinaryIntegerLiterals = new NoBinaryIntegerLiteralsValidator();
+ protected final Validator noUnderscoresInIntegerLiterals = new NoUnderscoresInIntegerLiteralsValidator();
+ protected final Validator noMultiCatch = new SimpleValidator<>(UnionType.class,
+ n -> true,
+ (n, reporter) -> reporter.report(n, "Multi-catch is not supported.")
+ );
+ protected final Validator noLambdas = new SimpleValidator<>(LambdaExpr.class,
+ n -> true,
+ (n, reporter) -> reporter.report(n, "Lambdas are not supported.")
+ );
+ protected final Validator noModules = new SimpleValidator<>(ModuleDeclaration.class,
+ n -> true,
+ (n, reporter) -> reporter.report(n, "Modules are not supported.")
+ );
+
+ public Java1_0Validator() {
+ super(new CommonValidators());
+ add(modifiersWithoutStrictfpAndDefaultAndStaticInterfaceMethodsAndPrivateInterfaceMethods);
+ add(noAssertKeyword);
+ add(noInnerClasses);
+ add(noReflection);
+ add(noGenerics);
+ add(tryWithoutResources);
+ add(noAnnotations);
+ add(noEnums);
+ add(noVarargs);
+ add(noForEach);
+ add(noStaticImports);
+ add(noStringsInSwitch);
+ add(noBinaryIntegerLiterals);
+ add(noUnderscoresInIntegerLiterals);
+ add(noMultiCatch);
+ add(noLambdas);
+ add(noModules);
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_1Validator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_1Validator.java
new file mode 100644
index 000000000..5279b7f95
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_1Validator.java
@@ -0,0 +1,22 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.stmt.LocalClassDeclarationStmt;
+
+/**
+ * This validator validates according to Java 1.1 syntax rules.
+ */
+public class Java1_1Validator extends Java1_0Validator {
+ protected final Validator innerClasses = new SingleNodeTypeValidator<>(ClassOrInterfaceDeclaration.class,
+ (n, reporter) -> n.getParentNode().ifPresent(p -> {
+ if (p instanceof LocalClassDeclarationStmt && n.isInterface())
+ reporter.report(n, "There is no such thing as a local interface.");
+ })
+ );
+
+ public Java1_1Validator() {
+ super();
+ replace(noInnerClasses, innerClasses);
+ remove(noReflection);
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_2Validator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_2Validator.java
new file mode 100644
index 000000000..4ac7565b2
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_2Validator.java
@@ -0,0 +1,17 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.validator.chunks.ModifierValidator;
+
+/**
+ * This validator validates according to Java 1.2 syntax rules.
+ */
+public class Java1_2Validator extends Java1_1Validator {
+ protected final Validator modifiersWithoutDefaultAndStaticInterfaceMethodsAndPrivateInterfaceMethods = new ModifierValidator(true, false, false);
+ protected final Validator strictfpNotAllowed = new ReservedKeywordValidator("strictfp");
+
+ public Java1_2Validator() {
+ super();
+ replace(modifiersWithoutStrictfpAndDefaultAndStaticInterfaceMethodsAndPrivateInterfaceMethods, modifiersWithoutDefaultAndStaticInterfaceMethodsAndPrivateInterfaceMethods);
+ add(strictfpNotAllowed);
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_3Validator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_3Validator.java
new file mode 100644
index 000000000..72830a117
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_3Validator.java
@@ -0,0 +1,10 @@
+package com.github.javaparser.ast.validator;
+
+/**
+ * This validator validates according to Java 1.3 syntax rules.
+ */
+public class Java1_3Validator extends Java1_2Validator {
+ public Java1_3Validator() {
+ super();
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_4Validator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_4Validator.java
new file mode 100644
index 000000000..2d4ad5e86
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java1_4Validator.java
@@ -0,0 +1,11 @@
+package com.github.javaparser.ast.validator;
+
+/**
+ * This validator validates according to Java 1.4 syntax rules.
+ */
+public class Java1_4Validator extends Java1_3Validator {
+ public Java1_4Validator() {
+ super();
+ remove(noAssertKeyword);
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java5Validator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java5Validator.java
new file mode 100644
index 000000000..d8b1aab1b
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java5Validator.java
@@ -0,0 +1,52 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.nodeTypes.NodeWithTypeArguments;
+import com.github.javaparser.ast.type.PrimitiveType;
+import com.github.javaparser.ast.type.Type;
+
+import java.util.Optional;
+
+/**
+ * This validator validates according to Java 5 syntax rules.
+ */
+public class Java5Validator extends Java1_4Validator {
+ Validator genericsWithoutDiamondOperator = new TreeVisitorValidator((node, reporter) -> {
+ if (node instanceof NodeWithTypeArguments) {
+ Optional<NodeList<Type>> typeArguments = ((NodeWithTypeArguments<? extends Node>) node).getTypeArguments();
+ if (typeArguments.isPresent() && typeArguments.get().isEmpty()) {
+ reporter.report(node, "The diamond operator is not supported.");
+ }
+ }
+ });
+
+ protected Validator noPrimitiveGenericArguments = new TreeVisitorValidator((node, reporter) -> {
+ if (node instanceof NodeWithTypeArguments) {
+ Optional<NodeList<Type>> typeArguments = ((NodeWithTypeArguments<? extends Node>) node).getTypeArguments();
+ typeArguments.ifPresent(types -> types.forEach(ty -> {
+ if (ty instanceof PrimitiveType) {
+ reporter.report(node, "Type arguments may not be primitive.");
+ }
+ }));
+ }
+ });
+
+ protected final Validator enumNotAllowed = new ReservedKeywordValidator("enum");
+
+ public Java5Validator() {
+ super();
+ replace(noGenerics, genericsWithoutDiamondOperator);
+ add(noPrimitiveGenericArguments);
+ add(enumNotAllowed);
+
+ // TODO validate annotations on classes, fields and methods but nowhere else
+ // The following is probably too simple.
+ remove(noAnnotations);
+
+ remove(noEnums);
+ remove(noVarargs);
+ remove(noForEach);
+ remove(noStaticImports);
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java6Validator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java6Validator.java
new file mode 100644
index 000000000..705400318
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java6Validator.java
@@ -0,0 +1,10 @@
+package com.github.javaparser.ast.validator;
+
+/**
+ * This validator validates according to Java 6 syntax rules.
+ */
+public class Java6Validator extends Java5Validator{
+ public Java6Validator() {
+ super();
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java7Validator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java7Validator.java
new file mode 100644
index 000000000..995e83620
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java7Validator.java
@@ -0,0 +1,39 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.stmt.TryStmt;
+import com.github.javaparser.ast.type.UnionType;
+
+/**
+ * This validator validates according to Java 7 syntax rules.
+ */
+public class Java7Validator extends Java6Validator {
+ protected final SingleNodeTypeValidator<TryStmt> tryWithLimitedResources = new SingleNodeTypeValidator<>(TryStmt.class, (n, reporter) -> {
+ if (n.getCatchClauses().isEmpty()
+ && n.getResources().isEmpty()
+ && !n.getFinallyBlock().isPresent()) {
+ reporter.report(n, "Try has no finally, no catch, and no resources.");
+ }
+ for (Expression resource : n.getResources()) {
+ if (!resource.isVariableDeclarationExpr()) {
+ reporter.report(n, "Try with resources only supports variable declarations.");
+ }
+ }
+ });
+ protected final SingleNodeTypeValidator<UnionType> multiCatch = new SingleNodeTypeValidator<>(UnionType.class, (n, reporter) -> {
+ // Case "0 elements" is caught elsewhere.
+ if (n.getElements().size() == 1) {
+ reporter.report(n, "Union type (multi catch) must have at least two elements.");
+ }
+ });
+
+ public Java7Validator() {
+ super();
+ remove(genericsWithoutDiamondOperator);
+ replace(tryWithoutResources, tryWithLimitedResources);
+ remove(noStringsInSwitch);
+ remove(noBinaryIntegerLiterals);
+ remove(noUnderscoresInIntegerLiterals);
+ replace(noMultiCatch, multiCatch);
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java8Validator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java8Validator.java
new file mode 100644
index 000000000..e6aca92d0
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java8Validator.java
@@ -0,0 +1,32 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.validator.chunks.ModifierValidator;
+
+/**
+ * This validator validates according to Java 7 syntax rules.
+ */
+public class Java8Validator extends Java7Validator {
+ protected final Validator modifiersWithoutPrivateInterfaceMethods = new ModifierValidator(true, true, false);
+ protected final Validator defaultMethodsInInterface = new SingleNodeTypeValidator<>(ClassOrInterfaceDeclaration.class,
+ (n, reporter) -> {
+ if (n.isInterface()) {
+ n.getMethods().forEach(m -> {
+ if (m.isDefault() && !m.getBody().isPresent()) {
+ reporter.report(m, "'default' methods must have a body.");
+ }
+ });
+ }
+ }
+ );
+
+ public Java8Validator() {
+ super();
+ replace(modifiersWithoutDefaultAndStaticInterfaceMethodsAndPrivateInterfaceMethods, modifiersWithoutPrivateInterfaceMethods);
+ add(defaultMethodsInInterface);
+ remove(noLambdas);
+
+ // TODO validate more annotation locations http://openjdk.java.net/jeps/104
+ // TODO validate repeating annotations http://openjdk.java.net/jeps/120
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java9Validator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java9Validator.java
new file mode 100644
index 000000000..2175c9af3
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Java9Validator.java
@@ -0,0 +1,30 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.VariableDeclarationExpr;
+import com.github.javaparser.ast.stmt.TryStmt;
+import com.github.javaparser.ast.validator.chunks.ModifierValidator;
+import com.github.javaparser.ast.validator.chunks.UnderscoreKeywordValidator;
+
+/**
+ * This validator validates according to Java 9 syntax rules.
+ */
+public class Java9Validator extends Java8Validator {
+ protected final Validator underscoreKeywordValidator = new UnderscoreKeywordValidator();
+ protected final Validator modifiers = new ModifierValidator(true, true, true);
+ protected final SingleNodeTypeValidator<TryStmt> tryWithResources = new SingleNodeTypeValidator<>(TryStmt.class, (n, reporter) -> {
+ if (n.getCatchClauses().isEmpty()
+ && n.getResources().isEmpty()
+ && !n.getFinallyBlock().isPresent()) {
+ reporter.report(n, "Try has no finally, no catch, and no resources.");
+ }
+ });
+
+ public Java9Validator() {
+ super();
+ add(underscoreKeywordValidator);
+ remove(noModules);
+ replace(modifiersWithoutPrivateInterfaceMethods, modifiers);
+ replace(tryWithLimitedResources, tryWithResources);
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/NoProblemsValidator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/NoProblemsValidator.java
new file mode 100644
index 000000000..002668892
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/NoProblemsValidator.java
@@ -0,0 +1,16 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ParserConfiguration;
+import com.github.javaparser.ast.Node;
+
+/**
+ * Stub validator for when no validation is wanted.
+ *
+ * @deprecated when setting a language validator, try {@link com.github.javaparser.ParserConfiguration#setLanguageLevel(ParserConfiguration.LanguageLevel)} with RAW.
+ */
+@Deprecated
+public final class NoProblemsValidator implements Validator {
+ @Override
+ public void accept(Node node, ProblemReporter problemReporter) {
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/ProblemReporter.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/ProblemReporter.java
new file mode 100644
index 000000000..eb54810c1
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/ProblemReporter.java
@@ -0,0 +1,34 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.Problem;
+import com.github.javaparser.TokenRange;
+import com.github.javaparser.ast.nodeTypes.NodeWithTokenRange;
+
+import java.util.function.Consumer;
+
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+
+/**
+ * A simple interface where validators can report found problems.
+ */
+public class ProblemReporter {
+ private final Consumer<Problem> problemConsumer;
+
+ public ProblemReporter(Consumer<Problem> problemConsumer) {
+ this.problemConsumer = problemConsumer;
+ }
+
+ /**
+ * Report a problem.
+ *
+ * @param message description of the problem
+ * @param node the node in which the problem occurred, used to find the Range of the problem.
+ */
+ public void report(NodeWithTokenRange<?> node, String message, Object... args) {
+ report(node.getTokenRange().orElse(null), message, args);
+ }
+
+ public void report(TokenRange range, String message, Object... args) {
+ problemConsumer.accept(new Problem(f(message, args), range, null));
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/ReservedKeywordValidator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/ReservedKeywordValidator.java
new file mode 100644
index 000000000..51a08bdca
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/ReservedKeywordValidator.java
@@ -0,0 +1,36 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.expr.Name;
+import com.github.javaparser.ast.expr.SimpleName;
+
+import static com.github.javaparser.utils.CodeGenerationUtils.f;
+
+/**
+ * Validates that identifiers are not keywords - this for the few keywords that the parser
+ * accepts because they were added after Java 1.0.
+ */
+public class ReservedKeywordValidator extends VisitorValidator {
+ private final String keyword;
+ private final String error;
+
+ public ReservedKeywordValidator(String keyword) {
+ this.keyword = keyword;
+ error = f("'%s' cannot be used as an identifier as it is a keyword.", keyword);
+ }
+
+ @Override
+ public void visit(Name n, ProblemReporter arg) {
+ if (n.getIdentifier().equals(keyword)) {
+ arg.report(n, error);
+ }
+ super.visit(n, arg);
+ }
+
+ @Override
+ public void visit(SimpleName n, ProblemReporter arg) {
+ if (n.getIdentifier().equals(keyword)) {
+ arg.report(n, error);
+ }
+ super.visit(n, arg);
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/SimpleValidator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/SimpleValidator.java
new file mode 100644
index 000000000..b705b9146
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/SimpleValidator.java
@@ -0,0 +1,20 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.Node;
+
+import java.util.function.BiConsumer;
+import java.util.function.Predicate;
+
+/**
+ * Runs a validator on all nodes of a certain type,
+ * and adds a problem for all nodes that pass a condition.
+ */
+public class SimpleValidator<N extends Node> extends SingleNodeTypeValidator<N> {
+ public SimpleValidator(Class<N> type, Predicate<N> condition, BiConsumer<N, ProblemReporter> problemSupplier) {
+ super(type, (node, problemReporter) -> {
+ if (condition.test(node)) {
+ problemSupplier.accept(node, problemReporter);
+ }
+ });
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/SingleNodeTypeValidator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/SingleNodeTypeValidator.java
new file mode 100644
index 000000000..169849489
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/SingleNodeTypeValidator.java
@@ -0,0 +1,24 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.Node;
+
+/**
+ * Runs a validator on all nodes of a certain type.
+ */
+public class SingleNodeTypeValidator<N extends Node> implements Validator {
+ private final Class<N> type;
+ private final TypedValidator<N> validator;
+
+ public SingleNodeTypeValidator(Class<N> type, TypedValidator<N> validator) {
+ this.type = type;
+ this.validator = validator;
+ }
+
+ @Override
+ public void accept(Node node, ProblemReporter problemReporter) {
+ if (type.isInstance(node)) {
+ validator.accept(type.cast(node), problemReporter);
+ }
+ node.findAll(type).forEach(n -> validator.accept(n, problemReporter));
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/TreeVisitorValidator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/TreeVisitorValidator.java
new file mode 100644
index 000000000..ae8e049e0
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/TreeVisitorValidator.java
@@ -0,0 +1,22 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.Node;
+
+/**
+ * A validator that walks the whole tree, visiting every node.
+ */
+public class TreeVisitorValidator implements Validator {
+ private final Validator validator;
+
+ public TreeVisitorValidator(Validator validator) {
+ this.validator = validator;
+ }
+
+ @Override
+ public final void accept(Node node, ProblemReporter reporter) {
+ validator.accept(node, reporter);
+ for (Node child : node.getChildNodes()) {
+ accept(child, reporter);
+ }
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/TypedValidator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/TypedValidator.java
new file mode 100644
index 000000000..588c53f11
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/TypedValidator.java
@@ -0,0 +1,24 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ParseResult;
+import com.github.javaparser.ast.Node;
+
+import java.util.function.BiConsumer;
+
+/**
+ * A validator that validates a known node type.
+ */
+public interface TypedValidator<N extends Node> extends BiConsumer<N, ProblemReporter> {
+ /**
+ * @param node the node that wants to be validated
+ * @param problemReporter when found, validation errors can be reported here
+ */
+ void accept(N node, ProblemReporter problemReporter);
+
+ @SuppressWarnings("unchecked")
+ default ParseResult.PostProcessor postProcessor() {
+ return (result, configuration) ->
+ result.getResult().ifPresent(node ->
+ accept((N) node, new ProblemReporter(problem -> result.getProblems().add(problem))));
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Validator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Validator.java
new file mode 100644
index 000000000..0d5752a03
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Validator.java
@@ -0,0 +1,15 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.Node;
+
+/**
+ * A validator that can be run on a node to check for semantic errors.
+ * It is fully up to the implementor how to do this.
+ */
+public interface Validator extends TypedValidator<Node> {
+ /**
+ * @param node the node that wants to be validated
+ * @param problemReporter when found, validation errors can be reported here
+ */
+ void accept(Node node, ProblemReporter problemReporter);
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Validators.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Validators.java
new file mode 100644
index 000000000..dd6926ab7
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/Validators.java
@@ -0,0 +1,45 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.Node;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A validator that will call a collection of validators.
+ */
+public class Validators implements Validator {
+ private final List<Validator> validators = new ArrayList<>();
+
+ public Validators(Validator... validators) {
+ this.validators.addAll(Arrays.asList(validators));
+ }
+
+ public List<Validator> getValidators() {
+ return validators;
+ }
+
+ public Validators remove(Validator validator) {
+ if (!validators.remove(validator)) {
+ throw new AssertionError("Trying to remove a validator that isn't there.");
+ }
+ return this;
+ }
+
+ public Validators replace(Validator oldValidator, Validator newValidator) {
+ remove(oldValidator);
+ add(newValidator);
+ return this;
+ }
+
+ public Validators add(Validator newValidator) {
+ validators.add(newValidator);
+ return this;
+ }
+
+ @Override
+ public void accept(Node node, ProblemReporter problemReporter) {
+ validators.forEach(v -> v.accept(node, problemReporter));
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/VisitorValidator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/VisitorValidator.java
new file mode 100644
index 000000000..547092d67
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/VisitorValidator.java
@@ -0,0 +1,16 @@
+package com.github.javaparser.ast.validator;
+
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
+
+/**
+ * A validator that uses a visitor for validation.
+ * This class is the visitor too.
+ * Implement the "visit" methods you want to use for validation.
+ */
+public abstract class VisitorValidator extends VoidVisitorAdapter<ProblemReporter> implements Validator {
+ @Override
+ public void accept(Node node, ProblemReporter problemReporter) {
+ node.accept(this, problemReporter);
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/CommonValidators.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/CommonValidators.java
new file mode 100644
index 000000000..5e5b7919e
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/CommonValidators.java
@@ -0,0 +1,70 @@
+package com.github.javaparser.ast.validator.chunks;
+
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.InitializerDeclaration;
+import com.github.javaparser.ast.expr.*;
+import com.github.javaparser.ast.validator.SimpleValidator;
+import com.github.javaparser.ast.validator.SingleNodeTypeValidator;
+import com.github.javaparser.ast.validator.TreeVisitorValidator;
+import com.github.javaparser.ast.validator.Validators;
+import com.github.javaparser.metamodel.NodeMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+
+import java.util.Optional;
+
+/**
+ * Contains validations that are valid for every Java version.
+ */
+public class CommonValidators extends Validators {
+ public CommonValidators() {
+ super(
+ new SimpleValidator<>(ClassOrInterfaceDeclaration.class,
+ n -> !n.isInterface() && n.getExtendedTypes().size() > 1,
+ (n, reporter) -> reporter.report(n.getExtendedTypes(1), "A class cannot extend more than one other class.")
+ ),
+ new SimpleValidator<>(ClassOrInterfaceDeclaration.class,
+ n -> n.isInterface() && !n.getImplementedTypes().isEmpty(),
+ (n, reporter) -> reporter.report(n.getImplementedTypes(0), "An interface cannot implement other interfaces.")
+ ),
+ new SingleNodeTypeValidator<>(ClassOrInterfaceDeclaration.class, (n, reporter) -> {
+ if (n.isInterface()) {
+ n.getMembers().forEach(mem -> {
+ if (mem instanceof InitializerDeclaration) {
+ reporter.report(mem, "An interface cannot have initializers.");
+ }
+ });
+ }
+ }
+ ),
+ new SingleNodeTypeValidator<>(AssignExpr.class, (n, reporter) -> {
+ // https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26
+ Expression target = n.getTarget();
+ while (target instanceof EnclosedExpr) {
+ target = ((EnclosedExpr) target).getInner();
+ }
+ if (target instanceof NameExpr
+ || target instanceof ArrayAccessExpr
+ || target instanceof FieldAccessExpr) {
+ return;
+ }
+ reporter.report(n.getTarget(), "Illegal left hand side of an assignment.");
+ }
+ ),
+ new TreeVisitorValidator((node, problemReporter) -> {
+ NodeMetaModel mm = node.getMetaModel();
+ for (PropertyMetaModel ppm : mm.getAllPropertyMetaModels()) {
+ if (ppm.isNonEmpty()) {
+ if (ppm.isNodeList()) {
+ NodeList value = (NodeList) ppm.getValue(node);
+ if (value.isEmpty()) {
+ problemReporter.report(node, "%s.%s can not be empty.", mm.getTypeName(), ppm.getName());
+ }
+ }
+ // No need to check empty strings, it should be impossible to set them to ""
+ }
+ }
+ })
+ );
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/ModifierValidator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/ModifierValidator.java
new file mode 100644
index 000000000..0a01c3349
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/ModifierValidator.java
@@ -0,0 +1,211 @@
+package com.github.javaparser.ast.validator.chunks;
+
+import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.body.*;
+import com.github.javaparser.ast.expr.LambdaExpr;
+import com.github.javaparser.ast.expr.VariableDeclarationExpr;
+import com.github.javaparser.ast.modules.ModuleRequiresStmt;
+import com.github.javaparser.ast.nodeTypes.NodeWithModifiers;
+import com.github.javaparser.ast.nodeTypes.NodeWithTokenRange;
+import com.github.javaparser.ast.stmt.CatchClause;
+import com.github.javaparser.ast.validator.ProblemReporter;
+import com.github.javaparser.ast.validator.VisitorValidator;
+import com.github.javaparser.utils.SeparatedItemStringBuilder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.github.javaparser.ast.Modifier.*;
+import static java.util.Arrays.asList;
+
+
+/**
+ * Verifies that only allowed modifiers are used where modifiers are expected.
+ */
+public class ModifierValidator extends VisitorValidator {
+ private final Modifier[] interfaceWithNothingSpecial = new Modifier[]{PUBLIC, PROTECTED, ABSTRACT, FINAL, SYNCHRONIZED, NATIVE, STRICTFP};
+ private final Modifier[] interfaceWithStaticAndDefault = new Modifier[]{PUBLIC, PROTECTED, ABSTRACT, STATIC, FINAL, SYNCHRONIZED, NATIVE, STRICTFP, DEFAULT};
+ private final Modifier[] interfaceWithStaticAndDefaultAndPrivate = new Modifier[]{PUBLIC, PROTECTED, PRIVATE, ABSTRACT, STATIC, FINAL, SYNCHRONIZED, NATIVE, STRICTFP, DEFAULT};
+
+ private final boolean hasStrictfp;
+ private final boolean hasDefaultAndStaticInterfaceMethods;
+ private final boolean hasPrivateInterfaceMethods;
+
+ public ModifierValidator(boolean hasStrictfp, boolean hasDefaultAndStaticInterfaceMethods, boolean hasPrivateInterfaceMethods) {
+ this.hasStrictfp = hasStrictfp;
+ this.hasDefaultAndStaticInterfaceMethods = hasDefaultAndStaticInterfaceMethods;
+ this.hasPrivateInterfaceMethods = hasPrivateInterfaceMethods;
+ }
+
+ @Override
+ public void visit(ClassOrInterfaceDeclaration n, ProblemReporter reporter) {
+ if (n.isInterface()) {
+ validateInterfaceModifiers(n, reporter);
+ } else {
+ validateClassModifiers(n, reporter);
+ }
+ super.visit(n, reporter);
+ }
+
+ private void validateClassModifiers(ClassOrInterfaceDeclaration n, ProblemReporter reporter) {
+ if (n.isTopLevelType()) {
+ validateModifiers(n, reporter, PUBLIC, ABSTRACT, FINAL, STRICTFP);
+ } else if (n.isNestedType()) {
+ validateModifiers(n, reporter, PUBLIC, PROTECTED, PRIVATE, ABSTRACT, STATIC, FINAL, STRICTFP);
+ } else if (n.isLocalClassDeclaration()) {
+ validateModifiers(n, reporter, ABSTRACT, FINAL, STRICTFP);
+ }
+ }
+
+ private void validateInterfaceModifiers(TypeDeclaration<?> n, ProblemReporter reporter) {
+ if (n.isTopLevelType()) {
+ validateModifiers(n, reporter, PUBLIC, ABSTRACT, STRICTFP);
+ } else if (n.isNestedType()) {
+ validateModifiers(n, reporter, PUBLIC, PROTECTED, PRIVATE, ABSTRACT, STATIC, STRICTFP);
+ }
+ }
+
+ @Override
+ public void visit(EnumDeclaration n, ProblemReporter reporter) {
+ if (n.isTopLevelType()) {
+ validateModifiers(n, reporter, PUBLIC, STRICTFP);
+ } else if (n.isNestedType()) {
+ validateModifiers(n, reporter, PUBLIC, PROTECTED, PRIVATE, STATIC, STRICTFP);
+ }
+ super.visit(n, reporter);
+ }
+
+ @Override
+ public void visit(AnnotationDeclaration n, ProblemReporter reporter) {
+ validateInterfaceModifiers(n, reporter);
+ super.visit(n, reporter);
+ }
+
+ @Override
+ public void visit(AnnotationMemberDeclaration n, ProblemReporter reporter) {
+ validateModifiers(n, reporter, PUBLIC, ABSTRACT);
+ super.visit(n, reporter);
+ }
+
+ @Override
+ public void visit(ConstructorDeclaration n, ProblemReporter reporter) {
+ validateModifiers(n, reporter, PUBLIC, PROTECTED, PRIVATE);
+ n.getParameters().forEach(p -> validateModifiers(p, reporter, FINAL));
+ super.visit(n, reporter);
+ }
+
+ @Override
+ public void visit(FieldDeclaration n, ProblemReporter reporter) {
+ validateModifiers(n, reporter, PUBLIC, PROTECTED, PRIVATE, STATIC, FINAL, TRANSIENT, VOLATILE);
+ super.visit(n, reporter);
+ }
+
+ @Override
+ public void visit(MethodDeclaration n, ProblemReporter reporter) {
+ if (n.isAbstract()) {
+ final SeparatedItemStringBuilder builder = new SeparatedItemStringBuilder("Cannot be 'abstract' and also '", "', '", "'.");
+ for (Modifier m : asList(PRIVATE, STATIC, FINAL, NATIVE, STRICTFP, SYNCHRONIZED)) {
+ if (n.getModifiers().contains(m)) {
+ builder.append(m.asString());
+ }
+ }
+ if (builder.hasItems()) {
+ reporter.report(n, builder.toString());
+ }
+ }
+ if (n.getParentNode().isPresent()) {
+ if (n.getParentNode().get() instanceof ClassOrInterfaceDeclaration) {
+ if (((ClassOrInterfaceDeclaration) n.getParentNode().get()).isInterface()) {
+ if (hasDefaultAndStaticInterfaceMethods) {
+ if (hasPrivateInterfaceMethods) {
+ validateModifiers(n, reporter, interfaceWithStaticAndDefaultAndPrivate);
+ } else {
+ validateModifiers(n, reporter, interfaceWithStaticAndDefault);
+ }
+ } else {
+ validateModifiers(n, reporter, interfaceWithNothingSpecial);
+ }
+ } else {
+ validateModifiers(n, reporter, PUBLIC, PROTECTED, PRIVATE, ABSTRACT, STATIC, FINAL, SYNCHRONIZED, NATIVE, STRICTFP);
+ }
+ }
+ }
+ n.getParameters().forEach(p -> validateModifiers(p, reporter, FINAL));
+ super.visit(n, reporter);
+ }
+
+ @Override
+ public void visit(LambdaExpr n, ProblemReporter reporter) {
+ n.getParameters().forEach(p -> {
+ // Final is not allowed on inferred parameters, but those get caught by the parser.
+ validateModifiers(p, reporter, FINAL);
+ });
+ super.visit(n, reporter);
+ }
+
+ @Override
+ public void visit(CatchClause n, ProblemReporter reporter) {
+ validateModifiers(n.getParameter(), reporter, FINAL);
+ super.visit(n, reporter);
+ }
+
+ @Override
+ public void visit(VariableDeclarationExpr n, ProblemReporter reporter) {
+ validateModifiers(n, reporter, FINAL);
+ super.visit(n, reporter);
+ }
+
+ @Override
+ public void visit(ModuleRequiresStmt n, ProblemReporter reporter) {
+ validateModifiers(n, reporter, TRANSITIVE, STATIC);
+ super.visit(n, reporter);
+ }
+
+ private <T extends NodeWithModifiers<?> & NodeWithTokenRange<?>> void validateModifiers(T n, ProblemReporter reporter, Modifier... allowedModifiers) {
+ validateAtMostOneOf(n, reporter, PUBLIC, PROTECTED, PRIVATE);
+ validateAtMostOneOf(n, reporter, FINAL, ABSTRACT);
+ if (hasStrictfp) {
+ validateAtMostOneOf(n, reporter, NATIVE, STRICTFP);
+ } else {
+ allowedModifiers = removeModifierFromArray(STRICTFP, allowedModifiers);
+ }
+ for (Modifier m : n.getModifiers()) {
+ if (!arrayContains(allowedModifiers, m)) {
+ reporter.report(n, "'%s' is not allowed here.", m.asString());
+ }
+ }
+ }
+
+ private Modifier[] removeModifierFromArray(Modifier m, Modifier[] allowedModifiers) {
+ final List<Modifier> newModifiers = new ArrayList<>(asList(allowedModifiers));
+ newModifiers.remove(m);
+ allowedModifiers = newModifiers.toArray(new Modifier[0]);
+ return allowedModifiers;
+ }
+
+ private boolean arrayContains(Object[] items, Object searchItem) {
+ for (Object o : items) {
+ if (o == searchItem) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private <T extends NodeWithModifiers<?> & NodeWithTokenRange<?>> void validateAtMostOneOf(T t, ProblemReporter reporter, Modifier... modifiers) {
+ List<Modifier> foundModifiers = new ArrayList<>();
+ for (Modifier m : modifiers) {
+ if (t.getModifiers().contains(m)) {
+ foundModifiers.add(m);
+ }
+ }
+ if (foundModifiers.size() > 1) {
+ SeparatedItemStringBuilder builder = new SeparatedItemStringBuilder("Can have only one of '", "', '", "'.");
+ for (Modifier m : foundModifiers) {
+ builder.append(m.asString());
+ }
+ reporter.report(t, builder.toString());
+ }
+ }
+
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/NoBinaryIntegerLiteralsValidator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/NoBinaryIntegerLiteralsValidator.java
new file mode 100644
index 000000000..82e8dd7cc
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/NoBinaryIntegerLiteralsValidator.java
@@ -0,0 +1,27 @@
+package com.github.javaparser.ast.validator.chunks;
+
+import com.github.javaparser.ast.expr.IntegerLiteralExpr;
+import com.github.javaparser.ast.expr.LiteralStringValueExpr;
+import com.github.javaparser.ast.expr.LongLiteralExpr;
+import com.github.javaparser.ast.validator.ProblemReporter;
+import com.github.javaparser.ast.validator.VisitorValidator;
+
+public class NoBinaryIntegerLiteralsValidator extends VisitorValidator {
+ @Override
+ public void visit(IntegerLiteralExpr n, ProblemReporter arg) {
+ validate(n, arg);
+ super.visit(n, arg);
+ }
+
+ @Override
+ public void visit(LongLiteralExpr n, ProblemReporter arg) {
+ validate(n, arg);
+ super.visit(n, arg);
+ }
+
+ private static void validate(LiteralStringValueExpr n, ProblemReporter arg) {
+ if (n.getValue().toUpperCase().startsWith("0B")) {
+ arg.report(n, "Binary literal values are not supported.");
+ }
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/NoUnderscoresInIntegerLiteralsValidator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/NoUnderscoresInIntegerLiteralsValidator.java
new file mode 100644
index 000000000..901b7348f
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/NoUnderscoresInIntegerLiteralsValidator.java
@@ -0,0 +1,27 @@
+package com.github.javaparser.ast.validator.chunks;
+
+import com.github.javaparser.ast.expr.IntegerLiteralExpr;
+import com.github.javaparser.ast.expr.LiteralStringValueExpr;
+import com.github.javaparser.ast.expr.LongLiteralExpr;
+import com.github.javaparser.ast.validator.ProblemReporter;
+import com.github.javaparser.ast.validator.VisitorValidator;
+
+public class NoUnderscoresInIntegerLiteralsValidator extends VisitorValidator {
+ @Override
+ public void visit(IntegerLiteralExpr n, ProblemReporter arg) {
+ validate(n, arg);
+ super.visit(n, arg);
+ }
+
+ @Override
+ public void visit(LongLiteralExpr n, ProblemReporter arg) {
+ validate(n, arg);
+ super.visit(n, arg);
+ }
+
+ private static void validate(LiteralStringValueExpr n, ProblemReporter arg) {
+ if (n.getValue().contains("_")) {
+ arg.report(n, "Underscores in literal values are not supported.");
+ }
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/UnderscoreKeywordValidator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/UnderscoreKeywordValidator.java
new file mode 100644
index 000000000..e812597bb
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/UnderscoreKeywordValidator.java
@@ -0,0 +1,27 @@
+package com.github.javaparser.ast.validator.chunks;
+
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.expr.Name;
+import com.github.javaparser.ast.expr.SimpleName;
+import com.github.javaparser.ast.validator.ProblemReporter;
+import com.github.javaparser.ast.validator.VisitorValidator;
+
+public class UnderscoreKeywordValidator extends VisitorValidator {
+ @Override
+ public void visit(Name n, ProblemReporter arg) {
+ validateIdentifier(n, n.getIdentifier(), arg);
+ super.visit(n, arg);
+ }
+
+ @Override
+ public void visit(SimpleName n, ProblemReporter arg) {
+ validateIdentifier(n, n.getIdentifier(), arg);
+ super.visit(n, arg);
+ }
+
+ private static void validateIdentifier(Node n, String id, ProblemReporter arg) {
+ if (id.equals("_")) {
+ arg.report(n, "'_' is a reserved keyword.");
+ }
+ }
+}
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/VarValidator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/VarValidator.java
new file mode 100644
index 000000000..19357e83c
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/chunks/VarValidator.java
@@ -0,0 +1,93 @@
+package com.github.javaparser.ast.validator.chunks;
+
+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.ArrayCreationExpr;
+import com.github.javaparser.ast.expr.LambdaExpr;
+import com.github.javaparser.ast.expr.NullLiteralExpr;
+import com.github.javaparser.ast.expr.VariableDeclarationExpr;
+import com.github.javaparser.ast.stmt.ExpressionStmt;
+import com.github.javaparser.ast.stmt.ForStmt;
+import com.github.javaparser.ast.stmt.ForeachStmt;
+import com.github.javaparser.ast.type.VarType;
+import com.github.javaparser.ast.validator.ProblemReporter;
+import com.github.javaparser.ast.validator.TypedValidator;
+
+import java.util.Optional;
+
+public class VarValidator implements TypedValidator<VarType> {
+ private boolean varAllowedInLambdaParameters;
+
+ public VarValidator(boolean varAllowedInLambdaParameters) {
+ this.varAllowedInLambdaParameters = varAllowedInLambdaParameters;
+ }
+
+ @Override
+ public void accept(VarType node, ProblemReporter reporter) {
+ // All allowed locations are within a VariableDeclaration inside a VariableDeclarationExpr inside something else.
+ Optional<VariableDeclarator> variableDeclarator = node.findParent(VariableDeclarator.class);
+ if (!variableDeclarator.isPresent()) {
+ // Java 11's var in lambda's
+ if (varAllowedInLambdaParameters) {
+ boolean valid = node
+ .findParent(Parameter.class)
+ .flatMap(Node::getParentNode)
+ .map((Node p) -> p instanceof LambdaExpr).orElse(false);
+ if (valid) {
+ return;
+ }
+ }
+ reportIllegalPosition(node, reporter);
+ return;
+ }
+ variableDeclarator.ifPresent(vd -> {
+ Optional<Node> variableDeclarationExpr = vd.getParentNode();
+ if (!variableDeclarationExpr.isPresent()) {
+ reportIllegalPosition(node, reporter);
+ return;
+ }
+ variableDeclarationExpr.ifPresent(vdeNode -> {
+ if (!(vdeNode instanceof VariableDeclarationExpr)) {
+ reportIllegalPosition(node, reporter);
+ return;
+ }
+ VariableDeclarationExpr vde = (VariableDeclarationExpr) vdeNode;
+ if (vde.getVariables().size() > 1) {
+ reporter.report(vde, "\"var\" only takes a single variable.");
+ }
+ Optional<Node> container = vdeNode.getParentNode();
+ if (!container.isPresent()) {
+ reportIllegalPosition(node, reporter);
+ return;
+ }
+ container.ifPresent(c -> {
+ boolean positionIsFine = c instanceof ForStmt || c instanceof ForeachStmt || c instanceof ExpressionStmt;
+ if (!positionIsFine) {
+ reportIllegalPosition(node, reporter);
+ }
+ // A local variable declaration ends up inside an ExpressionStmt.
+ if (c instanceof ExpressionStmt) {
+ if (!vd.getInitializer().isPresent()) {
+ reporter.report(node, "\"var\" needs an initializer.");
+ }
+ vd.getInitializer().ifPresent(initializer -> {
+ if (initializer instanceof NullLiteralExpr) {
+ reporter.report(node, "\"var\" cannot infer type from just null.");
+ }
+ if (initializer instanceof ArrayCreationExpr) {
+ reporter.report(node, "\"var\" cannot infer array types.");
+ }
+ });
+
+ }
+ });
+ });
+ });
+
+ }
+
+ private void reportIllegalPosition(VarType n, ProblemReporter reporter) {
+ reporter.report(n, "\"var\" is not allowed here.");
+ }
+}