mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
feat: use custom JavaCompiler implementation for Java LSP
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.lsp.java.compiler
|
||||
|
||||
import com.itsaky.androidide.javac.services.compiler.ReusableCompiler
|
||||
import com.itsaky.androidide.javac.services.compiler.ReusableContext
|
||||
|
||||
/**
|
||||
* Implementation of the [ReusableCompiler] which replaces necessary components from the
|
||||
* [ReusableContext].
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class JCReusableCompiler : ReusableCompiler() {
|
||||
|
||||
override fun onCreateContext(): ReusableContext {
|
||||
return super.onCreateContext().also {
|
||||
JavaCompilerImpl.preRegister(context = it, replace = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.lsp.java.compiler
|
||||
|
||||
import com.itsaky.androidide.javac.services.compiler.ReusableContext
|
||||
import com.itsaky.androidide.javac.services.compiler.ReusableJavaCompiler
|
||||
import jdkx.tools.JavaFileObject
|
||||
import openjdk.tools.javac.tree.JCTree.JCCompilationUnit
|
||||
import openjdk.tools.javac.util.Context
|
||||
|
||||
class JavaCompilerImpl(context: Context?) : ReusableJavaCompiler(context) {
|
||||
|
||||
override fun parse(filename: JavaFileObject?, content: CharSequence?): JCCompilationUnit {
|
||||
// TODO Prune unnecessary methods to speed up compilation
|
||||
return super.parse(filename, content)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun preRegister(context: ReusableContext, replace: Boolean = false) {
|
||||
if (replace) {
|
||||
context.drop(compilerKey)
|
||||
}
|
||||
context.put(compilerKey, Context.Factory { JavaCompilerImpl(it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -86,7 +86,7 @@ public class JavaCompilerService implements CompilerProvider {
|
||||
protected final SynchronizedTask synchronizedTask = new SynchronizedTask();
|
||||
protected final SourceFileManager fileManager;
|
||||
protected final ModuleProject module;
|
||||
public ReusableCompiler compiler = new ReusableCompiler();
|
||||
public ReusableCompiler compiler = new JCReusableCompiler();
|
||||
protected Set<String> bootClasspathClasses =
|
||||
BootClasspathProvider.getTopLevelClasses(
|
||||
Collections.singleton(Environment.ANDROID_JAR.getAbsolutePath()));
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ public class CompletionProvider extends AbstractServiceProvider implements IComp
|
||||
final var sourceObject = new SourceFileObject(file);
|
||||
final var contentBuilder = new StringBuilder(sourceObject.getCharContent(true));
|
||||
|
||||
if (!VMUtils.isJvm()) {
|
||||
if (false && !VMUtils.isJvm()) {
|
||||
// Cannot use tree sitter in tests
|
||||
// TODO(itsaky): Should we use the legacy method pruner for tests?
|
||||
final StopWatch watch = new StopWatch("Prune method bodies");
|
||||
|
||||
+3
-3
@@ -59,9 +59,9 @@ import openjdk.tools.javac.util.Position;
|
||||
*/
|
||||
public class NBParserFactory extends ParserFactory {
|
||||
|
||||
private final ScannerFactory scannerFactory;
|
||||
private final Names names;
|
||||
private final CancelService cancelService;
|
||||
protected final ScannerFactory scannerFactory;
|
||||
protected final Names names;
|
||||
protected final CancelService cancelService;
|
||||
|
||||
public static void preRegister(Context context) {
|
||||
context.put(parserFactoryKey, (Context.Factory<ParserFactory>) NBParserFactory::new);
|
||||
|
||||
+30
-31
@@ -31,6 +31,10 @@ import com.itsaky.androidide.javac.services.fs.CacheFSInfoSingleton
|
||||
import com.itsaky.androidide.javac.services.fs.JarPackageProviderImpl
|
||||
import com.itsaky.androidide.utils.VMUtils
|
||||
import com.itsaky.androidide.zipfs2.JarPackageProvider
|
||||
import java.net.URI
|
||||
import jdkx.tools.DiagnosticListener
|
||||
import jdkx.tools.JavaFileManager
|
||||
import jdkx.tools.JavaFileObject
|
||||
import openjdk.source.util.JavacTask
|
||||
import openjdk.source.util.TaskEvent
|
||||
import openjdk.source.util.TaskEvent.Kind.ANALYZE
|
||||
@@ -53,35 +57,41 @@ import openjdk.tools.javac.util.Context
|
||||
import openjdk.tools.javac.util.DefinedBy
|
||||
import openjdk.tools.javac.util.DefinedBy.Api.COMPILER_TREE
|
||||
import openjdk.tools.javac.util.Log
|
||||
import java.io.PrintWriter
|
||||
import java.net.URI
|
||||
import jdkx.tools.DiagnosticListener
|
||||
import jdkx.tools.JavaFileManager
|
||||
import jdkx.tools.JavaFileObject
|
||||
|
||||
/**
|
||||
* Reusable [Context] for [ReusableCompiler].
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class ReusableContext(cancelService: CancelService) : Context(), TaskListener {
|
||||
|
||||
|
||||
private val flowCompleted = mutableSetOf<URI>()
|
||||
|
||||
|
||||
init {
|
||||
put(Log.logKey, ReusableLog.factory)
|
||||
put(FSInfo::class.java, if (VMUtils.isJvm()) CacheFSInfo() else CacheFSInfoSingleton)
|
||||
put(JavaCompiler.compilerKey, ReusableJavaCompiler.factory)
|
||||
put(JavacFlowListener.flowListenerKey, JavacFlowListener { this.hasFlowCompleted(it) })
|
||||
put(JarPackageProvider::class.java, JarPackageProviderImpl)
|
||||
registerNBServices(cancelService)
|
||||
|
||||
NBAttr.preRegister(this)
|
||||
NBParserFactory.preRegister(this)
|
||||
NBTreeMaker.preRegister(this)
|
||||
NBJavacTrees.preRegister(this)
|
||||
NBResolve.preRegister(this)
|
||||
NBEnter.preRegister(this)
|
||||
NBMemberEnter.preRegister(this, false)
|
||||
NBClassFinder.preRegister(this)
|
||||
NBClassReader.preRegister(this)
|
||||
CancelService.preRegister(this, cancelService)
|
||||
}
|
||||
|
||||
|
||||
@DefinedBy(COMPILER_TREE)
|
||||
override fun started(e: TaskEvent) {
|
||||
// log.debug("Started: $e")
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
|
||||
@DefinedBy(COMPILER_TREE)
|
||||
override fun finished(e: TaskEvent) {
|
||||
if (e.kind == ANALYZE) {
|
||||
@@ -91,7 +101,7 @@ class ReusableContext(cancelService: CancelService) : Context(), TaskListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun clear() {
|
||||
drop(Arguments.argsKey)
|
||||
drop(DiagnosticListener::class.java)
|
||||
@@ -101,7 +111,7 @@ class ReusableContext(cancelService: CancelService) : Context(), TaskListener {
|
||||
drop(JavacTask::class.java)
|
||||
drop(JavacTrees::class.java)
|
||||
drop(JavacElements::class.java)
|
||||
|
||||
|
||||
if (ht[Log.logKey] is ReusableLog) {
|
||||
// log already init-ed - not first round
|
||||
(Log.instance(this) as ReusableLog).clear()
|
||||
@@ -115,15 +125,17 @@ class ReusableContext(cancelService: CancelService) : Context(), TaskListener {
|
||||
MultiTaskListener.instance(this).clear()
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> drop(k: Key<T>?) {
|
||||
|
||||
/** **FOR INTERNAL USE ONLY!** */
|
||||
fun <T> drop(k: Key<T>?) {
|
||||
ht.remove(k)
|
||||
}
|
||||
|
||||
private fun <T> drop(c: Class<T>?) {
|
||||
ht.remove(key(c))
|
||||
|
||||
/** **FOR INTERNAL USE ONLY!** */
|
||||
fun <T> drop(c: Class<T>?) {
|
||||
drop(key(c))
|
||||
}
|
||||
|
||||
|
||||
private fun hasFlowCompleted(fo: JavaFileObject?): Boolean {
|
||||
return if (fo == null) {
|
||||
false
|
||||
@@ -135,17 +147,4 @@ class ReusableContext(cancelService: CancelService) : Context(), TaskListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerNBServices(cancelService: CancelService) {
|
||||
NBAttr.preRegister(this)
|
||||
NBParserFactory.preRegister(this)
|
||||
NBTreeMaker.preRegister(this)
|
||||
NBJavacTrees.preRegister(this)
|
||||
NBResolve.preRegister(this)
|
||||
NBEnter.preRegister(this)
|
||||
NBMemberEnter.preRegister(this, false)
|
||||
NBClassFinder.preRegister(this)
|
||||
NBClassReader.preRegister(this)
|
||||
CancelService.preRegister(this, cancelService)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import openjdk.tools.javac.util.Context
|
||||
* Reusable JavaCompiler; exposes a method to clean up the component from leftovers associated
|
||||
* with previous compilations.
|
||||
*/
|
||||
internal class ReusableJavaCompiler(context: Context?) : NBJavaCompiler(context) {
|
||||
open class ReusableJavaCompiler(context: Context?) : NBJavaCompiler(context) {
|
||||
|
||||
companion object {
|
||||
val factory = Context.Factory<JavaCompiler> { ReusableJavaCompiler(it) }
|
||||
|
||||
Reference in New Issue
Block a user