GH-1219: preparing the AST parsing for environment cleanup activities after bulk parsing to close zip files and free up memory

This commit is contained in:
Martin Lippert
2024-04-04 14:49:19 +02:00
parent e89adc6a94
commit 9c30e6c87e
3 changed files with 168 additions and 19 deletions

View File

@@ -0,0 +1,88 @@
/*******************************************************************************
* Copyright (c) 2024 Broadcom
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Broadcom - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.utils;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.FileASTRequestor;
/**
* Wrapper around a JDT AST parser to enable cleanup functionality on the lookup environment,
* which is otherwise hidden and not accessible from the outside
*/
public class ASTParserCleanupEnabled {
private final ASTParser parser;
// private final INameEnvironmentWithProgress environment;
private final Map<String, String> options;
// private final int flags;
// private final int apiLevel;
public ASTParserCleanupEnabled(String[] classpathEntries, String[] sourceEntries, boolean ignoreMethodBodies) {
parser = ASTParser.newParser(AST.JLS21);
options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_21, options);
parser.setCompilerOptions(options);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setStatementsRecovery(true);
parser.setBindingsRecovery(true);
parser.setResolveBindings(true);
parser.setIgnoreMethodBodies(ignoreMethodBodies);
parser.setEnvironment(classpathEntries, sourceEntries, null, false);
// List<Classpath> classpaths = CUResolver.getClasspath(parser);
// environment = CUResolver.createLookupEnvironment(classpaths.toArray(new Classpath[classpaths.size()]));
//
// apiLevel = AST.JLS21;
//
// int flags = 0;
// flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY;
// flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY;
//
// if (ignoreMethodBodies) {
// flags |= ICompilationUnit.IGNORE_METHOD_BODIES;
// }
//
// this.flags = flags;
}
public void setUnitName(String unitName) {
this.parser.setUnitName(unitName);
}
public void setSource(char[] source) {
this.parser.setSource(source);
}
public ASTNode createAST(IProgressMonitor monitor) {
return this.parser.createAST(monitor);
}
public void createASTs(String[] sourceFilePaths, String[] encodings, String[] bindingKeys,
FileASTRequestor requestor, IProgressMonitor monitor) {
// CUResolver.resolve(sourceFilePaths, encodings, bindingKeys, requestor, apiLevel, options, flags, environment);
this.parser.createASTs(sourceFilePaths, encodings, bindingKeys, requestor, monitor);
}
public void cleanup() {
// environment.cleanup();
}
}

View File

@@ -24,6 +24,7 @@ import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.FileASTRequestor;
import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
import org.eclipse.jdt.internal.compiler.IProblemFactory;
@@ -217,6 +218,27 @@ class CUResolver {
return null;
};
private static final Supplier<Method> RESOLVE_SOURCE_FILES_METHOD = () -> {
try {
Class<?> clazz = COMPILATION_UNIT_RESOLVER_CLASS.get();
if (clazz != null) {
Method resolveMethod = clazz.getDeclaredMethod("resolve",
String[].class, // sourceCompilationUnits
String[].class, // encodings
String[].class, //bindingKeys
FileASTRequestor.class, // astRequestor
int.class, // apiLevel
Map.class, // compilerOptions
int.class); // flags
resolveMethod.setAccessible(true);
return resolveMethod;
}
} catch (NoSuchMethodException | SecurityException e) {
log.error("{}", e);
}
return null;
};
private static final Supplier<Method> CONVERT_METHOD = () -> {
try {
Class<?> clazz = COMPILATION_UNIT_RESOLVER_CLASS.get();
@@ -300,6 +322,57 @@ class CUResolver {
return null;
}
static void resolve(
String[] sourceUnits,
String[] encodings,
String[] bindingKeys,
FileASTRequestor requestor,
int apiLevel,
Map<String, String> options,
int flags,
INameEnvironmentWithProgress environment) {
CancelableProblemFactory problemFactory = null;
try {
problemFactory = new CancelableProblemFactory(new NullProgressMonitor());
CompilerOptions compilerOptions = (CompilerOptions) GET_COMPILER_OPTIONS_METHOD.get().invoke(null, options,
(flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0);
compilerOptions.ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0;
Object resolver = COMPILATION_UNIT_RESOLVER_CONSTRUCTOR.get().newInstance(environment,
GET_HANDLER_POLICY_METHOD.get().invoke(null), compilerOptions,
GET_REQUESTOR_METHOD.get().invoke(null), problemFactory, new NullProgressMonitor(), false);
// CompilationUnitResolver resolver =
// new CompilationUnitResolver(
// environment,
// getHandlingPolicy(),
// compilerOptions,
// getRequestor(),
// problemFactory,
// subMonitor,
// false);
RESOLVE_SOURCE_FILES_METHOD.get().invoke(resolver,
sourceUnits, encodings, bindingKeys, requestor, apiLevel, options, flags);
// resolver.resolve(sourceUnits, encodings, bindingKeys, requestor, apiLevel, options, flags);
}
catch (Exception e) {
log.error("{}", e);
}
finally {
if (environment != null) {
environment.setMonitor(null); // don't hold a reference to this external object
}
if (problemFactory != null) {
problemFactory.monitor = null; // don't hold a reference to this external object
}
}
}
static CompilationUnitDeclaration parse(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, Map<String, String> options, int flags) {
try {
return (CompilationUnitDeclaration) PARSE_METHOD.get()

View File

@@ -34,9 +34,6 @@ import java.util.stream.Stream;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.CompilationUnit;
@@ -264,7 +261,7 @@ public class SpringIndexerJava implements SpringIndexer {
private void scanFile(IJavaProject project, DocumentDescriptor updatedDoc, String content) throws Exception {
final boolean ignoreMethodBodies = false;
ASTParser parser = createParser(project, ignoreMethodBodies);
ASTParserCleanupEnabled parser = createParser(project, ignoreMethodBodies);
String docURI = updatedDoc.getDocURI();
long lastModified = updatedDoc.getLastModified();
@@ -420,8 +417,9 @@ public class SpringIndexerJava implements SpringIndexer {
List<String[]> chunks = createChunks(javaFiles, this.scanChunkSize);
for(int i = 0; i < chunks.size(); i++) {
ASTParser parser = createParser(project, ignoreMethodBodies);
ASTParserCleanupEnabled parser = createParser(project, ignoreMethodBodies);
parser.createASTs(chunks.get(i), null, new String[0], requestor, null);
parser.cleanup();
}
EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
@@ -572,8 +570,9 @@ public class SpringIndexerJava implements SpringIndexer {
}
};
ASTParser parser = createParser(project, ignoreMethodBodies);
ASTParserCleanupEnabled parser = createParser(project, ignoreMethodBodies);
parser.createASTs(javaFiles, null, new String[0], requestor, null);
parser.cleanup();
return (String[]) nextPassFiles.toArray(new String[nextPassFiles.size()]);
}
@@ -768,22 +767,11 @@ public class SpringIndexerJava implements SpringIndexer {
return null;
}
public static ASTParser createParser(IJavaProject project, boolean ignoreMethodBodies) throws Exception {
public static ASTParserCleanupEnabled createParser(IJavaProject project, boolean ignoreMethodBodies) throws Exception {
String[] classpathEntries = getClasspathEntries(project);
String[] sourceEntries = getSourceEntries(project);
ASTParser parser = ASTParser.newParser(AST.JLS21);
Map<String, String> options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_21, options);
parser.setCompilerOptions(options);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setStatementsRecovery(true);
parser.setBindingsRecovery(true);
parser.setResolveBindings(true);
parser.setIgnoreMethodBodies(ignoreMethodBodies);
parser.setEnvironment(classpathEntries, sourceEntries, null, false);
return parser;
return new ASTParserCleanupEnabled(classpathEntries, sourceEntries, ignoreMethodBodies);
}
private static String[] getClasspathEntries(IJavaProject project) throws Exception {