Fixed #441: No java.lang error in non-android module projects

This commit is contained in:
Akash Yadav
2022-10-07 12:06:02 +05:30
parent 438080e20b
commit 162c65d6e9
8 changed files with 57 additions and 84 deletions
Binary file not shown.
@@ -108,17 +108,16 @@ public class NBClassFinder extends ClassFinder {
throw constr.newInstance(
sym,
(Supplier<JCDiagnostic>)
() -> {
return diagFactory.create(
log.currentSource(),
new SimpleDiagnosticPosition(0),
DiagnosticInfo.of(
DiagnosticType.ERROR,
"compiler",
"cant.resolve",
"package",
"java.lang"));
},
() ->
diagFactory.create(
log.currentSource(),
new SimpleDiagnosticPosition(0),
DiagnosticInfo.of(
DiagnosticType.ERROR,
"compiler",
"cant.resolve",
"package",
"java.lang")),
dcfh);
} catch (ClassNotFoundException
| NoSuchMethodException
+2 -2
View File
@@ -3,6 +3,6 @@ plugins {
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = rootProject.ext.javaSourceVersion
targetCompatibility = rootProject.ext.javaTargetVersion
}
@@ -23,6 +23,7 @@ import com.itsaky.androidide.tooling.api.IProject.Type.Java
import com.itsaky.androidide.tooling.api.model.GradleTask
import com.itsaky.androidide.tooling.api.model.JavaContentRoot
import com.itsaky.androidide.tooling.api.model.JavaModuleDependency
import com.itsaky.androidide.tooling.api.model.JavaModuleExternalDependency
import com.itsaky.androidide.tooling.api.model.JavaModuleProjectDependency
import java.io.File
@@ -112,13 +113,10 @@ class JavaModule(
override fun getCompileClasspaths(): Set<File> {
val classpaths = getModuleClasspaths().toMutableSet()
getCompileModuleProjects().forEach { classpaths.addAll(it.getCompileClasspaths()) }
classpaths.addAll(getDependencyClasspaths())
return classpaths
}
// TODO IdeaDependency.getExported() always returns false
// Find out its cause and handle exported dependencies here.
//
// Currently transitive dependencies are not included in this.
override fun getCompileModuleProjects(): List<ModuleProject> {
val root = ProjectManager.rootProject ?: return emptyList()
return this.dependencies
@@ -127,4 +125,8 @@ class JavaModule(
.mapNotNull { root.findByPath(it.projectPath) }
.filterIsInstance(ModuleProject::class.java)
}
fun getDependencyClasspaths(): Set<File> {
return this.dependencies.filterIsInstance<JavaModuleExternalDependency>().mapNotNull { it.jarFile }.toHashSet()
}
}
@@ -21,8 +21,7 @@ import com.android.builder.model.v2.ide.LibraryType.PROJECT
import com.android.builder.model.v2.ide.ProjectType.APPLICATION
import com.google.common.truth.Truth.assertThat
import com.google.gson.GsonBuilder
import com.itsaky.androidide.tooling.api.IProject
import com.itsaky.androidide.tooling.api.IToolingApiServer
import com.itsaky.androidide.tooling.api.IProject.Type.Gradle
import com.itsaky.androidide.tooling.api.messages.InitializeProjectMessage
import com.itsaky.androidide.tooling.api.model.AndroidModule
import com.itsaky.androidide.tooling.api.model.JavaModule
@@ -37,55 +36,42 @@ import org.junit.runners.JUnit4
/** @author Akash Yadav */
@RunWith(JUnit4::class)
class ToolingApiImplTest {
class MultiModuleAndroidProjectTest {
@Test
fun testProjectInit() {
val (server, project) = ToolingApiTestLauncher().launchServer()
server.initialize(InitializeProjectMessage(File("../../tests/test-project").absolutePath)).get()
verifyProjectProps(project, server)
}
private fun verifyProjectProps(project: IProject, server: IToolingApiServer) {
assertThat(project).isNotNull()
assertThat(project.type.get()).isEqualTo(IProject.Type.Gradle)
assertThat(project.type.get()).isEqualTo(Gradle)
// As the returned project is just a proxy,
// project instanceOf IdeGradleProject will always return false
val isInitialized = server.isServerInitialized().get()
assertThat(isInitialized).isTrue()
val app = project.findByPath(":app").get()
assertThat(app).isNotNull()
assertThat(app).isInstanceOf(AndroidModule::class.java)
GsonBuilder().apply {
ToolingApiLauncher.configureGson(this)
println(create().toJson(app))
}
assertThat((app as AndroidModule).javaCompileOptions).isNotNull()
assertThat(app.javaCompileOptions.sourceCompatibility).isEqualTo("11")
assertThat(app.javaCompileOptions.targetCompatibility).isEqualTo("11")
assertThat(app.javaCompileOptions.javaSourceVersion).isEqualTo("11")
assertThat(app.javaCompileOptions.javaBytecodeVersion).isEqualTo("11")
assertThat(app.javaCompileOptions.isCoreLibraryDesugaringEnabled).isFalse()
assertThat(app.projectType).isEqualTo(APPLICATION)
assertThat(app.packageName).isEqualTo("com.itsaky.test.app")
assertThat(app.viewBindingOptions).isNotNull()
assertThat(app.viewBindingOptions!!.isEnabled).isTrue()
// There are always more than 100 tasks in an android module
// Also, the tasks must contain the user defined tasks
assertThat(app.tasks.size).isAtLeast(100)
assertThat(app.tasks.first { it.path == "${app.projectPath}:thisIsATestTask" }).isNotNull()
assertThat(app.libraries).isNotEmpty()
// At least one project library
assertThat(app.libraryMap.values.filter { it.type == PROJECT }).isNotEmpty()
// :app module includes :java-library as a dependency. But it is not transitive
assertThat(
app.libraryMap.values.firstOrNull {
@@ -95,7 +81,6 @@ class ToolingApiImplTest {
}
)
.isNull()
val androidLib = project.findByPath(":android-library").get()
assertThat(androidLib).isNotNull()
assertThat(androidLib).isInstanceOf(AndroidModule::class.java)
@@ -110,16 +95,13 @@ class ToolingApiImplTest {
}
)
.isNotNull()
assertThat(androidLib.javaCompileOptions.javaSourceVersion).isEqualTo("11")
assertThat(androidLib.javaCompileOptions.javaBytecodeVersion).isEqualTo("11")
val javaLibrary = project.findByPath(":java-library").get()
assertThat(javaLibrary).isNotNull()
assertThat(javaLibrary).isInstanceOf(JavaModule::class.java)
assertThat((javaLibrary as JavaModule).compilerSettings.javaSourceVersion).isEqualTo("11")
assertThat(javaLibrary.compilerSettings.javaBytecodeVersion).isEqualTo("11")
assertThat(
javaLibrary.javaDependencies.firstOrNull {
it is JavaModuleExternalDependency &&
@@ -132,14 +114,12 @@ class ToolingApiImplTest {
}
)
.isNotNull()
assertThat(
javaLibrary.javaDependencies.firstOrNull {
it is JavaModuleProjectDependency && it.moduleName == "another-java-library"
}
)
.isNotNull()
// In case we have multiple dependencies with same name but different path
val nested =
javaLibrary.javaDependencies
@@ -147,13 +127,13 @@ class ToolingApiImplTest {
.filter { it.moduleName.endsWith("nested-java-library") }
assertThat(nested).hasSize(2)
assertThat(nested[0].projectPath).isNotEqualTo(nested[1].projectPath)
assertThat(project.findByPath(":does-not-exist").get()).isNull()
val anotherJavaLib = project.findByPath(":another-java-library").get()
assertThat(anotherJavaLib).isNotNull()
assertThat(anotherJavaLib).isInstanceOf(JavaModule::class.java)
assertThat((anotherJavaLib as JavaModule).compilerSettings.javaSourceVersion).isEqualTo("1.8")
assertThat(anotherJavaLib.compilerSettings.javaBytecodeVersion).isEqualTo("1.8")
server.shutdown().get()
}
}
@@ -17,6 +17,13 @@
package com.itsaky.androidide.lsp.java.compiler;
import static com.itsaky.androidide.config.JavacConfigProvider.PROP_ANDROIDIDE_JAVA_HOME;
import static com.itsaky.androidide.config.JavacConfigProvider.disableModules;
import static com.itsaky.androidide.config.JavacConfigProvider.enableModules;
import static com.itsaky.androidide.config.JavacConfigProvider.setLatestSourceVersion;
import static com.itsaky.androidide.config.JavacConfigProvider.setLatestSupportedSourceVersion;
import static com.itsaky.androidide.utils.Environment.JAVA_HOME;
import androidx.annotation.NonNull;
import androidx.core.util.Pair;
@@ -26,10 +33,11 @@ import com.itsaky.androidide.javac.services.compiler.ReusableBorrow;
import com.itsaky.androidide.javac.services.partial.DiagnosticListenerImpl;
import com.itsaky.androidide.lsp.java.visitors.MethodRangeScanner;
import com.itsaky.androidide.models.Range;
import com.itsaky.androidide.projects.api.AndroidModule;
import com.itsaky.androidide.projects.api.ModuleProject;
import com.itsaky.androidide.projects.util.StringSearch;
import com.itsaky.androidide.tooling.api.IProject;
import com.itsaky.androidide.utils.ClassTrie;
import com.itsaky.androidide.utils.Environment;
import com.itsaky.androidide.utils.ILogger;
import com.itsaky.androidide.utils.SourceClassTrie;
import com.itsaky.androidide.utils.StopWatch;
@@ -133,21 +141,18 @@ public class CompileBatch implements AutoCloseable {
@NonNull
private List<String> options() {
List<String> options = 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();
LOG.debug(
JavacConfigProvider.getJavaHome(),
JavacConfigProvider.isModulesEnabled(),
SourceVersion.latest(),
SourceVersion.latestSupported());
// This won't be used if the current module is Android module project
System.setProperty(PROP_ANDROIDIDE_JAVA_HOME, JAVA_HOME.getAbsolutePath());
if (this.parent.module != null && this.parent.module.getType() == IProject.Type.Android) {
setLatestSourceVersion(SourceVersion.RELEASE_8);
setLatestSupportedSourceVersion(SourceVersion.RELEASE_11);
disableModules();
} else {
setLatestSourceVersion(SourceVersion.RELEASE_11);
setLatestSupportedSourceVersion(SourceVersion.RELEASE_11);
enableModules();
}
setupCompileOptions(parent.module, options);
Collections.addAll(options, "-proc:none", "-g");
@@ -20,15 +20,15 @@ package com.itsaky.androidide.lsp.java.compiler;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import com.blankj.utilcode.util.CloseUtils;
import com.itsaky.androidide.config.JavacConfigProvider;
import com.itsaky.androidide.javac.services.fs.AndroidFsProviderImpl;
import com.itsaky.androidide.projects.api.AndroidModule;
import com.itsaky.androidide.projects.api.ModuleProject;
import com.itsaky.androidide.projects.util.StringSearch;
import com.itsaky.androidide.tooling.api.IProject;
import com.itsaky.androidide.utils.ClassTrie;
import com.itsaky.androidide.utils.Environment;
import com.itsaky.androidide.utils.ILogger;
@@ -80,36 +80,29 @@ public class SourceFileManager extends ForwardingJavaFileManager<JavacFileManage
AndroidFsProviderImpl.INSTANCE.init();
if (module == null) {
setFallbackPlatformClasspath();
return;
}
// Must be set before setting classpaths
System.setProperty(JavacConfigProvider.PROP_ANDROIDIDE_JAVA_HOME, Environment.JAVA_HOME.getAbsolutePath());
setLocationLogError(StandardLocation.SOURCE_PATH, module.getCompileSourceDirectories());
final Set<File> classpaths = configureClasspaths(module);
setLocationLogError(StandardLocation.CLASS_PATH, classpaths);
setLocationLogError(StandardLocation.CLASS_PATH, configureClasspaths(module));
listLocations(EnumSet.of(StandardLocation.CLASS_PATH, StandardLocation.PLATFORM_CLASS_PATH));
}
@NonNull
private Set<File> configureClasspaths(final ModuleProject module) {
if (module == null) {
setFallbackPlatformClasspath();
return emptySet();
}
final Set<File> classpaths = module.getCompileClasspaths();
if (!(module instanceof AndroidModule)) {
setFallbackPlatformClasspath();
return emptySet();
}
final AndroidModule androidModule = (AndroidModule) module;
classpaths.addAll(androidModule.getBootClassPaths());
setLocationLogError(StandardLocation.PLATFORM_CLASS_PATH, androidModule.getBootClassPaths());
return classpaths;
if (module instanceof AndroidModule) {
final AndroidModule androidModule = (AndroidModule) module;
setLocationLogError(StandardLocation.PLATFORM_CLASS_PATH, androidModule.getBootClassPaths());
}
return module.getCompileClasspaths();
}
private static JavacFileManager createDelegateFileManager() {
@@ -117,12 +110,6 @@ public class SourceFileManager extends ForwardingJavaFileManager<JavacFileManage
.getStandardFileManager(LOG::debug, Locale.getDefault(), StandardCharsets.UTF_8);
}
protected void setFallbackPlatformClasspath() {
// TODO Module system must be enabled for Java modules instead of setting Platform Classpath
setLocationLogError(
StandardLocation.PLATFORM_CLASS_PATH, Collections.singleton(Environment.ANDROID_JAR));
}
public void setLocationLogError(Location location, Iterable<File> searchPath) {
try {
fileManager.setLocation(location, searchPath);
Binary file not shown.