kotlin-language-server
kotlin-language-server copied to clipboard
Unresolved reference: R
VSC shows in the Problems tab this error for any R use :
"code": "UNRESOLVED_REFERENCE",
"severity": 8,
"message": "Unresolved reference: R",
"source": "kotlin",
Steps to reproduce the behavior: my code example:
mChannel.description = getString(R.string.notif_channel_desc)
Expected behavior No errors or warnings.
Extension version 0.2.10
This seems to be a duplicate of #164, which is hopefully resolved by #186
This is still happening
This line appears to be missing pr #186
File.separator + "javac" +
Hrm, we might need something a bit more flexible to handle the various directory structures that Android uses to store those compiled class files
Right now, we're coupled to a particular version of the Android build plugin and that's no good.
I'll look into it and see if I can figure something out 😉
@DonnieWest is there any news for this?
@NICHTJ3 Nope, I've not had time to really look into it. It basically boils down to two approaches though:
- Code in all possible Android class paths. This should be only one or two currently and might need to be updated as the Android Build Plugin is updated
- Exhaustively search for all class paths. We did this before and it was slow, but it did ensure that everything worked without needing to update manually
I'm leaning toward 1. since it changes infrequently and could be found by just running a simple Android project through all current Android Build Plugin versions.
If you want to put in the footwork and create a PR, that'd likely get accepted faster than waiting on me :wink:
@DonnieWest I'll have a look if I have some free time
@DonnieWest can you point to a source file specifically? I'm trying to follow your suggestion, but no clue where to start from.
I've created a sample Android Studio project and, the build.gradle file, from what I've seen, has no "applicationVariants" (thus #186 would have no effect for me).
I've also seem some examples where "R" is imported into the source code directly
import com.example.android.autofill.app.R;
but I'm not able to do the same.
Exhaustively search for all class paths. We did this before and it was slow, but it did ensure that everything worked without needing to update manually
I'm interested to see where this was. I've looked into the history for server/src/main/resources/projectClassPathFinder.gradle but couldn't figure out. Can you point to which MR or commit changed this?
Thank you in advance!
@resolritter the PR you referenced ( #186 ) is what I'd point you to. Instead of having one path to search for classes, I'd change that to an array of paths to search.
Once it's changed to an array, take your Android project and switch out Android Studio and Android build plugin versions and check your project build directory for how these class files change. Those are the paths you'll need to add to that array
This is just me spitballing though - if there's a better approach, feel free to take it. I'd just avoid exhaustively having Gradle search for those paths itself. That can take a non-trivial amount of time
I'm not knowledgeable in Kotlin or JVM languages in general, but I've tried to dig a bit into this
Since Android Gradle Plugin 3.6, the R.java files are not generated anymore [1]
I've searched in the source on Jetbrain's Android plug-in repository [2] and those are the findings I'd guess are relevant
- updateRoots
- ResourceClassGenerator generator = buildGenerator(appResources)
- generator.generate(className)
There's also a brief writing on how those Resource modules work [3]
[1] https://stackoverflow.com/a/61079734/8401696 [2] https://github.com/JetBrains/android [3] https://github.com/JetBrains/android/blob/master/android/src/com/android/tools/idea/res/README.md
As said in the beginning, I don't code in Java so I wouldn't know how to bring a similar functionality into this project. Is it possible to use their packages instead? I've seen a few places in this project where the import org.jetbrains.kotlin.idea package is used (for instance, Compiler.kt).
FWIW, while poking at the code from my last comment, I've also found out that the R class can be used directly, even without importing, for projects using Android Gradle Plugin 3.6+.
Therefore downgrading the plug-in locally is not an option. Even disregarding regressions and inconveniences that repeating this process over and over would bring, there'd need to be some way to automatically inject the generated R class file in the resolution context (similar to what's done in this line).
On another news, I was able to make the R class be resolved (on AGP 3.2.1) with the following change:
classpath 'com.android.tools.build:gradle:3.2.1'
R classes are placed in <root>/app/build/generated (see this answer).
diff --git a/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt b/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt
index 36ce322..e11c90c 100644
--- a/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt
+++ b/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt
@@ -5,6 +5,7 @@ import java.io.Closeable
import java.nio.file.Files
import java.nio.file.FileSystems
import java.nio.file.Path
+import java.io.File
/**
* Manages the class path (compiled JARs, etc), the Java source path
@@ -128,10 +129,27 @@ class CompilerClassPath(private val config: CompilerConfiguration) : Closeable {
private fun findJavaSourceFiles(root: Path): Set<Path> {
val sourceMatcher = FileSystems.getDefault().getPathMatcher("glob:*.java")
+ val generatedResources = root.toAbsolutePath().toString() + File.separator + "build" + File.separator + "generated"
+
return SourceExclusions(root)
.walkIncluded()
.filter { sourceMatcher.matches(it.fileName) }
.toSet()
+ .union(
+ File(generatedResources)
+ .walk()
+ .filter { file: File ->
+ file.path.endsWith(".java")
+ }
+ .map {
+ it.toPath()
+ }
+ .toSet()
+ )
}
Oh, this might be a much better solution overall anyway. It'll also pull in generated files from Dagger and Jetpack Navigation.
Out of curiosity, does this also update if the project is built? ie: I change a file in xml, build the project, are those changes reflected?
@DonnieWest
Out of curiosity, does this also update if the project is built? ie: I change a file in xml, build the project, are those changes reflected?
From what I've seen, no.
In the IntelliJ plug-in, they have this concept of "FileObserver" which could be related to that.
https://github.com/JetBrains/android/blob/16e242a9cd5978bef7d95a7d34cd6c5af9c87f1c/android/src/com/android/tools/idea/res/ResourceNotificationManager.java#L88
And also
https://github.com/JetBrains/android/blob/01abd96ef2058598e1d45112f5152b600024f3fc/android/src/com/android/tools/idea/res/PsiProjectListener.java#L57
From cursory search, I could not find out if addJavaSourceRoot (called in Compiler.kt in this project) activates any sort of "listeners" under the hood. If someone's interested in digging deeper, I'll be linking the source below.
https://github.com/JetBrains/kotlin/blob/b574917314dec125db78922aafbd505231342993/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/config/JvmContentRoots.kt#L53
My gut feeling is that those "addRoot" type of calls do not care about file changes. For instance, in one of the tests they are set up upfront:
https://github.com/JetBrains/intellij-community/blob/8a97e03c834199b597f5d8f8a8324190ac43da27/java/java-tests/testSrc/com/intellij/java/psi/impl/file/impl/PsiEventsTest.java#L71
And the "listeners" are only added later.
https://github.com/JetBrains/intellij-community/blob/8a97e03c834199b597f5d8f8a8324190ac43da27/java/java-tests/testSrc/com/intellij/java/psi/impl/file/impl/PsiEventsTest.java#L81