Eliminated use of compiler module

This commit is contained in:
Akash Yadav
2022-07-08 23:10:48 +05:30
parent 87875f6c84
commit 6e2853cfe0
18 changed files with 278 additions and 254 deletions
+6 -1
View File
@@ -19,7 +19,7 @@
<remote-repository>
<option name="id" value="MavenLocal" />
<option name="name" value="MavenLocal" />
<option name="url" value="file:/$PROJECT_DIR$/../../../Akash%20Yadav/.m2/repository/" />
<option name="url" value="file:/$USER_HOME$/Akash%20Yadav/.m2/repository/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven" />
@@ -66,5 +66,10 @@
<option name="name" value="MavenLocal" />
<option name="url" value="file:$USER_HOME$/.m2/repository" />
</remote-repository>
<remote-repository>
<option name="id" value="maven2" />
<option name="name" value="maven2" />
<option name="url" value="https://s01.oss.sonatype.org/content/repositories/snapshots/" />
</remote-repository>
</component>
</project>
Binary file not shown.
@@ -58,16 +58,12 @@ import androidx.lifecycle.ViewModelProvider;
import androidx.transition.Slide;
import androidx.transition.TransitionManager;
import com.blankj.utilcode.util.ClipboardUtils;
import com.blankj.utilcode.util.FileIOUtils;
import com.blankj.utilcode.util.FileUtils;
import com.blankj.utilcode.util.IntentUtils;
import com.blankj.utilcode.util.KeyboardUtils;
import com.blankj.utilcode.util.ResourceUtils;
import com.blankj.utilcode.util.SizeUtils;
import com.blankj.utilcode.util.ThreadUtils;
import com.blankj.utilcode.util.ThrowableUtils;
import com.blankj.utilcode.util.ZipUtils;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.navigation.NavigationView;
@@ -102,7 +98,6 @@ import com.itsaky.androidide.lsp.models.DiagnosticItem;
import com.itsaky.androidide.lsp.models.InitializeParams;
import com.itsaky.androidide.lsp.xml.XMLLanguageServer;
import com.itsaky.androidide.managers.PreferenceManager;
import com.itsaky.androidide.managers.ToolsManager;
import com.itsaky.androidide.models.ApkMetadata;
import com.itsaky.androidide.models.DiagnosticGroup;
import com.itsaky.androidide.models.LogLine;
@@ -148,7 +143,6 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -1134,7 +1128,6 @@ public class EditorActivity extends StudioActivity
EditorActivityActions.register(this);
try {
checkForCompilerModule();
dispatchOnResumeToEditors();
if (mFileTreeFragment != null) {
@@ -1166,77 +1159,7 @@ public class EditorActivity extends StudioActivity
ProjectManager.INSTANCE.unregister();
}
@SuppressWarnings("deprecation")
private void checkForCompilerModule() {
if (!Environment.isCompilerModuleInstalled()) {
final var pd =
ProgressDialog.show(
this,
getString(R.string.title_compiler_module_install),
getString(R.string.msg_compiler_module_install),
true,
false);
final CompletableFuture<Boolean> future =
CompletableFuture.supplyAsync(
() -> {
final var tmpModule = new File(Environment.TMP_DIR, "compiler-module.zip");
if (!ResourceUtils.copyFileFromAssets(
ToolsManager.getCommonAsset("compiler-module.zip"),
tmpModule.getAbsolutePath())) {
throw new CompletionException(
new RuntimeException("Unable to copy compiler-module.zip"));
}
try {
ZipUtils.unzipFile(tmpModule, Environment.COMPILER_MODULE);
} catch (Throwable e) {
throw new CompletionException(e);
}
if (!Environment.isCompilerModuleInstalled()) {
throw new CompletionException(new RuntimeException("Unknown error"));
}
try {
FileUtils.delete(tmpModule);
} catch (Exception e) {
// ignored
}
return true;
});
future.whenComplete(
(result, error) -> {
pd.dismiss();
if (error != null) {
showCompilerModuleInstallError(error);
return;
}
getApp().toast(getString(R.string.msg_compiler_module_installed), Toaster.Type.SUCCESS);
});
}
}
private void showCompilerModuleInstallError(Throwable error) {
final var stacktrace = ThrowableUtils.getFullStackTrace(error);
final var builder = DialogUtils.newMaterialDialogBuilder(this);
builder.setTitle(R.string.title_installation_failed);
builder.setMessage(getString(R.string.msg_compiler_module_install_failed, stacktrace));
builder.setCancelable(false);
builder.setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
builder.setNegativeButton(
R.string.copy,
(dialog, which) -> {
ClipboardUtils.copyText(stacktrace);
dialog.dismiss();
});
builder.show();
}
// TODO Replace with events
private void dispatchOnResumeToEditors() {
CompletableFuture.runAsync(
() -> {
@@ -179,6 +179,7 @@ public class JavaInputAstVisitor extends TreePathScanner<Void, Void> {
* items with length less than or equal to this threshold.
*/
private static final int MAX_ITEM_LENGTH_FOR_FILLING = 10;
private static final Pattern FORMAT_SPECIFIER = Pattern.compile("%|\\{[0-9]\\}");
static final ImmutableSet<String> LOG_METHODS =
ImmutableSet.of(
@@ -2777,7 +2778,6 @@ public class JavaInputAstVisitor extends TreePathScanner<Void, Void> {
}
/** Collapse chains of {@code .} operators, across multiple {@link ASTNode} types. */
private void formatAnnotationOrModifier(Deque<AnnotationOrModifier> modifiers) {
AnnotationOrModifier modifier = modifiers.removeFirst();
switch (modifier.getKind()) {
@@ -28,7 +28,8 @@ import com.itsaky.androidide.projects.builder.BuildService
import com.itsaky.androidide.projects.models.ActiveDocument
import com.itsaky.androidide.projects.util.ProjectTransformer
import com.itsaky.androidide.tooling.api.IProject
import com.itsaky.androidide.utils.BootstrapClassesProvider
import com.itsaky.androidide.utils.BootClasspathProvider
import com.itsaky.androidide.utils.Environment
import com.itsaky.androidide.utils.ILogger
import java.io.BufferedInputStream
import java.io.BufferedReader
@@ -38,6 +39,7 @@ import java.io.StringReader
import java.nio.file.Files
import java.nio.file.Path
import java.time.Instant
import java.util.*
import java.util.concurrent.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
@@ -226,12 +228,12 @@ object ProjectManager : EventReceiver {
if (!checkInit()) {
return createFileReader(file)
}
val document = getActiveDocument(file)
if (document != null) {
return BufferedReader(StringReader(document.content))
}
return createFileReader(file)
}
@@ -239,7 +241,7 @@ object ProjectManager : EventReceiver {
if (!checkInit()) {
return createFileInputStream(file)
}
val document = getActiveDocument(file)
if (document != null) {
BufferedInputStream(document.content.byteInputStream())
@@ -256,7 +258,11 @@ object ProjectManager : EventReceiver {
super.register()
// Make sure we list and store the bootstrap classes
CompletableFuture.runAsync { BootstrapClassesProvider.bootstrapClasses() }
CompletableFuture.runAsync {
BootClasspathProvider.update(
Collections.singleton(Environment.ANDROID_JAR.absolutePath)
)
}
}
@Subscribe(threadMode = BACKGROUND)
@@ -306,7 +312,7 @@ object ProjectManager : EventReceiver {
if (subModule !is ModuleProject) {
continue
}
if (subModule.onDocumentChanged(event)) {
break
}
@@ -18,7 +18,6 @@
package com.itsaky.androidide.projects.api
import android.text.TextUtils
import com.google.common.reflect.ClassPath
import com.itsaky.androidide.eventbus.events.editor.DocumentChangeEvent
import com.itsaky.androidide.eventbus.events.editor.DocumentCloseEvent
import com.itsaky.androidide.eventbus.events.editor.DocumentOpenEvent
@@ -29,12 +28,9 @@ import com.itsaky.androidide.projects.util.DocumentUtils
import com.itsaky.androidide.projects.util.SourceClassTrie
import com.itsaky.androidide.projects.util.SourceClassTrie.SourceNode
import com.itsaky.androidide.tooling.api.model.GradleTask
import com.itsaky.androidide.utils.ClasspathReader
import com.itsaky.androidide.utils.ILogger
import java.io.File
import java.io.IOException
import java.net.MalformedURLException
import java.net.URL
import java.net.URLClassLoader
import java.nio.file.Path
import java.time.Instant
import java.util.concurrent.*
@@ -163,6 +159,7 @@ abstract class ModuleProject(
}
/** Finds the source files and classes from source directories and classpaths and indexes them. */
@Suppress("UnstableApiUsage")
fun indexSourcesAndClasspaths() {
log.info("Indexing sources and classpaths for project:", path)
@@ -180,26 +177,11 @@ abstract class ModuleProject(
}
log.debug("Sources indexed for project: '$path'. Found $count source files.")
count = 0
val urls =
getCompileClasspaths().filter { it.exists() }.map { toUrl(it.toPath()) }.toTypedArray()
val loader = URLClassLoader(urls, null)
val scanner: ClassPath
try {
scanner = ClassPath.from(loader)
} catch (e: IOException) {
log.warn("Unable to read classpaths for project:", path)
throw RuntimeException(e)
}
log.debug("Classpaths indexed for project:", path)
scanner.topLevelClasses.forEach {
this.compileClasspathClasses.append(it.name)
count++
}
log.debug("Classpaths indexed for project: '$path'. Found $count classpaths.")
val paths = getCompileClasspaths().filter { it.exists() }.map { it.toPath() }
val topLevelClasses = ClasspathReader.listClasses(paths).filter { it.isTopLevel }
topLevelClasses.forEach { this.compileClasspathClasses.append(it.name) }
log.debug("Classpaths indexed for project: '$path'. Found ${topLevelClasses.size} classpaths.")
}
fun getSourceFilesInDir(dir: Path): List<SourceNode> =
@@ -278,12 +260,4 @@ abstract class ModuleProject(
modified = Instant.now()
)
}
private fun toUrl(path: Path): URL {
try {
return path.toUri().toURL()
} catch (e: MalformedURLException) {
throw RuntimeException(e)
}
}
}
+4 -1
View File
@@ -28,7 +28,7 @@ buildscript {
mavenLocal ()
mavenCentral ()
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots/'
url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
}
maven {
url 'https://jitpack.io'
@@ -116,6 +116,9 @@ allprojects {
maven {
url 'https://jitpack.io'
}
maven {
url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
}
}
}
+1
View File
@@ -32,6 +32,7 @@ dependencies {
implementation fileTree (dir: 'libs', include: ['*.jar'])
implementation common.utilcode
implementation common.lang3
implementation google.guava
implementation google.material
implementation androidx.appcompat
@@ -56,9 +56,9 @@ public class ToolsManager {
copyBusyboxIfNeeded();
extractLogsenderIfNeeded();
extractAapt2();
// extractLibHooks();
extractGradlePlugin();
extractToolingApi();
extractAndroidJar();
extractIdeEnv();
writeInitScript();
})
@@ -74,6 +74,13 @@ public class ToolsManager {
});
}
private static void extractAndroidJar() {
if (!Environment.ANDROID_JAR.exists()) {
ResourceUtils.copyFileFromAssets(
getCommonAsset("android.jar"), Environment.ANDROID_JAR.getAbsolutePath());
}
}
private static void extractIdeEnv() {
final var file = new File(Environment.BIN_DIR, "ideenv");
if (file.exists()) {
@@ -0,0 +1,115 @@
/*
* 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.utils;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.ClassPath;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
/**
* Provides class names from the boot classpath (i.e. android.jar).
*
* @author Akash Yadav
*/
@SuppressWarnings("UnstableApiUsage")
public class BootClasspathProvider {
private static final Map<String, ImmutableSet<ClassPath.ClassInfo>> bootClasspathClasses =
new ConcurrentHashMap<>();
private static final ILogger LOG = ILogger.newInstance("BootClassProvider");
/**
* Updates the boot classpath cache. If a classpath is already indexed, it is skipped.
*
* @param classpaths The full file paths of JAR files to index.
* @return <code>true</code> if the the classpath cache was updated. <code>false</code> otherwise.
* <p>This method <code>true</code> if and only if any new classpath classes are added into
* the cache.
*/
public static synchronized boolean update(Collection<String> classpaths) {
final var start = System.currentTimeMillis();
var count = 0;
for (final var classpath : classpaths) {
if (bootClasspathClasses.containsKey(classpath)) {
LOG.info("Skipping indexing for boot classpath as it is already indexed:", classpath);
continue;
}
LOG.debug("Indexing boot classpath:", classpath);
final var path = Paths.get(classpath);
final var classes = ClasspathReader.listClasses(Collections.singleton(path));
bootClasspathClasses.put(classpath, classes);
count += classes.size();
}
LOG.info(
"Indexed", count, "boot classpath classes in", System.currentTimeMillis() - start, "ms");
return count > 0;
}
/**
* Drops the entry for the given classpath from the cache.
*
* @param classpath The classpath to drop entry for.
*/
public static synchronized void drop(String classpath) {
bootClasspathClasses.remove(classpath);
}
/**
* Drops entries for all the given classpaths from the cache.
*
* @param classpaths The classpaths to drop entry for.
*/
public static synchronized void dropAll(Collection<String> classpaths) {
classpaths.forEach(BootClasspathProvider::drop);
}
/**
* Returns all cached <strong>top-level</strong> classes from all the given classpath locations.
*
* @param classpaths The classpaths to get class list from.
* @return The cached <strong>top-level</strong> classes from the given classpaths.
*/
public static synchronized Set<String> getTopLevelClasses(Collection<String> classpaths) {
final var result = new TreeSet<String>();
if (classpaths == null) {
return result;
}
for (final var classpath : classpaths) {
final var entry = bootClasspathClasses.get(classpath);
if (entry == null || entry.isEmpty()) {
continue;
}
entry.stream()
.filter(ClassPath.ClassInfo::isTopLevel)
.map(ClassPath.ClassInfo::getName)
.forEach(result::add);
}
return result;
}
}
@@ -1,107 +0,0 @@
/*
* 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.utils;
import androidx.annotation.Nullable;
import org.jetbrains.annotations.Contract;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Provides class names from the bootstrap classpath (i.e. android.jar).
*
* @author Akash Yadav
*/
public class BootstrapClassesProvider {
private static Set<String> sCachedClasses;
private static final ILogger LOG = ILogger.newInstance("BootstrapClassesProvider");
public static Set<String> bootstrapClasses() {
if (sCachedClasses != null && !sCachedClasses.isEmpty()) {
return sCachedClasses;
}
final var start = System.currentTimeMillis();
sCachedClasses = new HashSet<>();
try {
final var fs = getJRTFileSystem();
if (fs == null) {
LOG.error("Unable to create JRT FileSystem instance");
return sCachedClasses;
}
final var javaBase = fs.getPath("/modules/java.base/");
try (final var stream = Files.walk(javaBase)) {
final var it = stream.iterator();
while (it.hasNext()) {
final var classFile = it.next();
final String relative = javaBase.relativize(classFile).toString();
if (relative.endsWith(".class") && !relative.contains("$")) {
final String trim = relative.substring(0, relative.length() - ".class".length());
final String qualifiedName = trim.replace(File.separatorChar, '.');
sCachedClasses.add(qualifiedName);
}
}
LOG.info(
"Found",
sCachedClasses.size(),
"classes in bootstrap classpath in",
System.currentTimeMillis() - start,
"ms");
} catch (IOException io) {
LOG.error("An error occurred while listing classes from bootstrap classpath", io);
}
} catch (Throwable err) {
LOG.error("Unable to find classes from bootstrap classpath", err);
}
return sCachedClasses;
}
@Nullable
@Contract(" -> new")
private static FileSystem getJRTFileSystem() throws Exception {
final URI uri = URI.create("jrt:/");
try {
// Tests run on the JVM, so we cannot directly access JRTFileSystemProvider
// But this method will work
return FileSystems.getFileSystem(uri);
} catch (Throwable th) {
// When on ART, JRT file system is not available
// So we create an instance of the FS manually
final Class<?> klass = Class.forName("jdk.internal.jrtfs.JrtFileSystemProvider");
final Method newFs = klass.getMethod("newFileSystem", URI.class, Map.class);
newFs.setAccessible(true);
return (FileSystem) newFs.invoke(klass.newInstance(), uri, Collections.emptyMap());
}
}
}
@@ -0,0 +1,63 @@
/*
* 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.utils
import com.google.common.collect.ImmutableSet
import com.google.common.reflect.ClassPath
import java.io.IOException
import java.net.MalformedURLException
import java.net.URL
import java.net.URLClassLoader
import java.nio.file.Path
/**
* Lists all classes from classpath(s).
*
* @author Akash Yadav
*/
class ClasspathReader {
companion object {
private val log = ILogger.newInstance(ClasspathReader::class.java.simpleName)
@Suppress("UnstableApiUsage")
@JvmStatic
fun listClasses(paths: Collection<Path>): ImmutableSet<ClassPath.ClassInfo> {
val urls = paths.map { toUrl(it) }.toTypedArray()
val classLoader = URLClassLoader(urls, null)
val scanner: ClassPath
try {
scanner = ClassPath.from(classLoader)
} catch (e: IOException) {
log.warn("Unable to read classpaths for project:", paths)
throw RuntimeException(e)
}
return scanner.allClasses
}
private fun toUrl(path: Path): URL {
try {
return path.toUri().toURL()
} catch (e: MalformedURLException) {
throw RuntimeException(e)
}
}
}
}
@@ -58,11 +58,9 @@ public final class Environment {
public static File PROJECTS_DIR;
public static File IDE_PROPS_FILE;
public static File LIB_HOOK;
/**
* JDK modules used by the java language server for completions. This version of JDK modules
* contains only the classes included in android.jar
*/
public static File COMPILER_MODULE;
/** Used by Java LSP until the project is initialized. */
public static File ANDROID_JAR;
public static File TOOLING_API_JAR;
@@ -87,7 +85,7 @@ public final class Environment {
BIN_DIR = mkdirIfNotExits(new File(PREFIX, "bin"));
LIB_DIR = mkdirIfNotExits(new File(PREFIX, "lib"));
PROJECTS_DIR = mkdirIfNotExits(new File(FileUtil.getExternalStorageDir(), PROJECTS_FOLDER));
COMPILER_MODULE = mkdirIfNotExits(new File(ANDROIDIDE_HOME, "compiler-module"));
ANDROID_JAR = mkdirIfNotExits(new File(ANDROIDIDE_HOME, "android.jar"));
TOOLING_API_JAR =
new File(mkdirIfNotExits(new File(ANDROIDIDE_HOME, "tooling-api")), "tooling-api-all.jar");
AAPT2 = new File(ANDROIDIDE_HOME, "aapt2");
@@ -268,15 +266,7 @@ public final class Environment {
if (blacklist.isEmpty()) {
blacklist.add("HOME");
blacklist.add("SYSROOT");
blacklist.add("JLS_HOME");
}
return blacklist;
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public static boolean isCompilerModuleInstalled() {
final var modules = new File(COMPILER_MODULE, "lib/modules");
final var release = new File(COMPILER_MODULE, "release");
return modules.exists() && modules.isFile() && release.exists() && release.isFile();
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
ext {
androidide = [
javac: 'io.github.itsaky:nb-javac-android:17.0.0.1'
javac: 'io.github.itsaky:nb-javac-android:17.0.0.2'
]
common = [
@@ -17,17 +17,23 @@
package com.itsaky.androidide.lsp.java.compiler;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.core.util.Pair;
import com.itsaky.androidide.config.JavacConfigProvider;
import com.itsaky.androidide.javac.services.compiler.ReusableCompiler;
import com.itsaky.androidide.javac.services.partial.DiagnosticListenerImpl;
import com.itsaky.androidide.lsp.java.parser.Parser;
import com.itsaky.androidide.lsp.java.visitors.MethodRangeScanner;
import com.itsaky.androidide.models.Range;
import com.itsaky.androidide.projects.ProjectManager;
import com.itsaky.androidide.projects.api.AndroidModule;
import com.itsaky.androidide.projects.api.ModuleProject;
import com.itsaky.androidide.projects.util.SourceClassTrie;
import com.itsaky.androidide.tooling.api.IProject;
import com.itsaky.androidide.utils.BootClasspathProvider;
import com.itsaky.androidide.utils.Environment;
import com.itsaky.androidide.utils.ILogger;
import com.itsaky.androidide.utils.StopWatch;
@@ -50,6 +56,7 @@ import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Name;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
@@ -117,13 +124,25 @@ public class CompileBatch implements AutoCloseable {
parent.fileManager, diagnosticListener, options, Collections.emptyList(), sources);
}
@SuppressWarnings("Since15")
@NonNull
private static List<String> options(Set<Path> classPath) {
private List<String> options(Set<Path> classPath) {
List<String> list = new ArrayList<>();
// TODO Boot classpath must be different in java projects
// Also, java modules must be enabled in java projects
System.setProperty(
JavacConfigProvider.PROP_ANDROIDIDE_JAVA_HOME, Environment.JAVA_HOME.getAbsolutePath());
JavacConfigProvider.setLatestSourceVersion(SourceVersion.RELEASE_8);
JavacConfigProvider.setLatestSupportedSourceVersion(SourceVersion.RELEASE_11);
JavacConfigProvider.disableModules();
final List<String> bootClasspaths = getAndUpdateBootclasspaths();
Collections.addAll(list, "-bootclasspath", TextUtils.join(File.pathSeparator, bootClasspaths));
Collections.addAll(list, "-classpath", joinPath(classPath));
Collections.addAll(list, "-source", "11", "-target", "11");
Collections.addAll(list, "--system", Environment.COMPILER_MODULE.getAbsolutePath());
// Collections.addAll(list, "--system", Environment.COMPILER_MODULE.getAbsolutePath());
Collections.addAll(list, "-proc:none");
Collections.addAll(list, "-g");
@@ -139,9 +158,31 @@ public class CompileBatch implements AutoCloseable {
"-Xlint:varargs",
"-Xlint:static");
LOG.debug("Compiler options:", TextUtils.join(" ", list));
return list;
}
private List<String> getAndUpdateBootclasspaths() {
final List<String> bootClasspaths = new ArrayList<>(5);
if (parent.module == null) {
// Use default boot classpath if no module is available
bootClasspaths.add(Environment.ANDROID_JAR.getAbsolutePath());
} else if (parent.module.getType() == IProject.Type.Android) {
bootClasspaths.addAll(
((AndroidModule) parent.module)
.getBootClassPaths().stream().map(File::getAbsolutePath).collect(Collectors.toSet()));
}
if (BootClasspathProvider.update(bootClasspaths)) {
this.parent.bootClasspathClasses.clear();
this.parent.bootClasspathClasses.addAll(
BootClasspathProvider.getTopLevelClasses(bootClasspaths));
}
return bootClasspaths;
}
/**
* Combine source path or class path entries using the system separator, for example ':' in unix
*/
@@ -38,7 +38,8 @@ import com.itsaky.androidide.projects.api.ModuleProject;
import com.itsaky.androidide.projects.util.Cache;
import com.itsaky.androidide.projects.util.SourceClassTrie;
import com.itsaky.androidide.projects.util.StringSearch;
import com.itsaky.androidide.utils.BootstrapClassesProvider;
import com.itsaky.androidide.utils.BootClasspathProvider;
import com.itsaky.androidide.utils.Environment;
import com.itsaky.androidide.utils.ILogger;
import com.itsaky.androidide.utils.StopWatch;
import com.sun.source.tree.CompilationUnitTree;
@@ -79,7 +80,9 @@ public class JavaCompilerService implements CompilerProvider {
protected final Set<Path> classPath;
protected final Set<String> classPathClasses;
protected final Set<String> jdkClasses = BootstrapClassesProvider.bootstrapClasses();
protected final Set<String> bootClasspathClasses =
BootClasspathProvider.getTopLevelClasses(
Collections.singleton(Environment.ANDROID_JAR.getAbsolutePath()));
protected final List<Diagnostic<? extends JavaFileObject>> diagnostics = new ArrayList<>();
protected final Map<JavaFileObject, Long> cachedModified = new HashMap<>();
protected final Cache<Void, List<String>> cacheFileImports = new Cache<>();
@@ -160,7 +163,7 @@ public class JavaCompilerService implements CompilerProvider {
all.add(node.getQualifiedName());
}
all.addAll(classPathClasses);
all.addAll(jdkClasses);
all.addAll(bootClasspathClasses);
return all;
}
@@ -399,8 +402,7 @@ public class JavaCompilerService implements CompilerProvider {
final String newBody = partialRequest.contents.substring(start, end);
final boolean reparsed =
reparser.reparseMethod(
info, currentMethod.second, newBody, partialRequest.contents);
reparser.reparseMethod(info, currentMethod.second, newBody, partialRequest.contents);
if (!reparsed) {
LOG.error("Failed to reparse");
recompile(request);
@@ -32,11 +32,12 @@ abstract class LanguageServerProvider {
fun server(): ILanguageServer {
if (Environment.COMPILER_MODULE == null) {
val javaHome = System.getProperty("java.home")
assertThat(javaHome).isNotEmpty()
Environment.COMPILER_MODULE = File(javaHome)
}
// TODO replace with android.jar
// if (Environment.COMPILER_MODULE == null) {
// val javaHome = System.getProperty("java.home")
// assertThat(javaHome).isNotEmpty()
// Environment.COMPILER_MODULE = File(javaHome)
// }
initIfNecessary()