From a4889843e966f11e1e2bd6047b2abd802187a710 Mon Sep 17 00:00:00 2001
From: Patrick Ziegler <ziegler.patrick@hotmail.de>
Date: Wed, 15 Jan 2025 20:46:13 +0100
Subject: [PATCH] Restrict system library check to require Java nature

The validation of the project classpath introduced with
74d062b38d3003638127127cc5358dd9f79df0f4 always fails, if the project
doesn't have a Java nature (and thus usually no .classpath file).

This causes issues when e.g. trying to open a source file with the Java
editor or simply when trying to use the AST parser outside of a Java
project. With this change, the check becomes more conservative and only
fails, if both the Java nature exists and no system library is
configured.

Note that one can avoid this exception by disabling the binding
resolution. But given that this requires changes in user code, it is
more prudent to only fail in cases where this is the desired behavior.

Resolves https://github.com/eclipse-jdt/eclipse.jdt.core/issues/3298
---
 .../core/tests/dom/ASTConverterBugsTest.java  | 37 +++++++++++++++++++
 .../org/eclipse/jdt/core/dom/ASTParser.java   |  7 +++-
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterBugsTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterBugsTest.java
index df440d9bd3c..75936c063bc 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterBugsTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterBugsTest.java
@@ -13,6 +13,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.core.tests.dom;
 
+import static org.junit.Assert.assertThrows;
+
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -21,6 +23,7 @@
 import java.util.Map;
 import java.util.Set;
 import junit.framework.Test;
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.jdt.core.IClassFile;
 import org.eclipse.jdt.core.ICompilationUnit;
@@ -1445,4 +1448,38 @@ public void acceptAST(String sourceFilePath, CompilationUnit cu) {
 	parser.createASTs(paths, null, new String[] {}, new MyFileASTRequestor() {}, null);
 	assertEquals(expectedProblems, actualProblems);
 }
+public void testGH3298() throws Exception {
+	Hashtable<String, String> options = JavaCore.getDefaultOptions();
+	options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_9);
+	options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_9);
+	options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_9);
+
+	createProject("P");
+	IFile javaFile = createFile("P/Test.java", "public class Test{}");
+	ICompilationUnit javaElement = JavaCore.createCompilationUnitFrom(javaFile);
+
+	try {
+		ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
+		parser.setSource(javaElement);
+		parser.setCompilerOptions(options);
+		parser.setResolveBindings(true);
+		parser.setKind(ASTParser.K_COMPILATION_UNIT);
+		assertNotNull(parser.createAST(null));
+
+		addJavaNature("P");
+		parser.setSource(javaElement);
+		parser.setCompilerOptions(options);
+		parser.setResolveBindings(true);
+		parser.setKind(ASTParser.K_COMPILATION_UNIT);
+		assertThrows(IllegalStateException.class, () -> parser.createAST(null));
+
+		parser.setSource(javaElement);
+		parser.setCompilerOptions(options);
+		parser.setResolveBindings(false);
+		parser.setKind(ASTParser.K_COMPILATION_UNIT);
+		assertNotNull(parser.createAST(null));
+	} finally {
+		deleteProject("P");
+	}
+}
 }
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
index 6223e6f1aaa..3252700db18 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
@@ -44,6 +44,7 @@
 import org.eclipse.jdt.internal.core.ClassFileWorkingCopy;
 import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner;
 import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.JavaProject;
 import org.eclipse.jdt.internal.core.PackageFragment;
 import org.eclipse.jdt.internal.core.dom.ICompilationUnitResolver;
 import org.eclipse.jdt.internal.core.dom.util.DOMASTUtil;
@@ -306,7 +307,7 @@ private void checkForSystemLibrary(List<Classpath> allClasspaths) {
 					}
 				}
 			}
-			if (!hasSystemLibrary)
+			if (!hasSystemLibrary && hasJavaNature())
 				throw new IllegalStateException("Missing system library", exception); //$NON-NLS-1$
 		}
 	}
@@ -1562,4 +1563,8 @@ private void rootNodeToCompilationUnit(AST ast, CompilationUnit compilationUnit,
 				}
 		}
 	}
+
+	private boolean hasJavaNature() {
+		return this.project != null && JavaProject.hasJavaNature(this.project.getProject());
+	}
 }