Status Update
Comments
ey...@gmail.com <ey...@gmail.com> #2
I'm trying to repro this in a clean project, but I'm unable to
In my actual project, the only thing that changed since lint completed successfully is:
Ran the "nonTransitiveRClass" migration from Android Studio, which:
- Added
android.nonTransitiveRClass=true
togradle.properties
- Fully qualified any
R
that came from another module
I then manually:
- created import aliases for any of the fully qualified
R
from step 2 - added the missing project dependency for any module that was relying on transitive R
I tried keeping everything else and changing android.nonTransitiveRClass=true
to android.nonTransitiveRClass=false
, but the false positive still occurs.
Looking at what's triggering the false positives, two of the modules are used by almost every other module in the app. They both have lots of resources, but only 13 resources between the two of them are triggering the false positive.
There are three other modules that are triggering the false positive (6 resources between all of them causing it).
vi...@google.com <vi...@google.com>
gh...@google.com <gh...@google.com>
ai...@gmail.com <ai...@gmail.com> #3
I can confirm that we have the same issue, and it's reproducible with AGP 7.0.0-beta03, the same case, android.nonTransitiveRClass=true and type alias. Removing type alias helps and the resource is not marked as unused anymore. It looks that this is the case only for complex module structure (when :app:lintDebug run with checkDependencies=true and one of libraries modules references another library module resource with typealias, maybe it also somehow related when all dependencies are implementation
, so it not exposed directly to app)
Also we had no issue before updating to AGP 7.0.0 from 4.0 and android.namespacedRClass=true
tn...@google.com <tn...@google.com> #4
I was finally able to reproduce this (repro project attached).
The root problem seems to be that we don't have the R.jar files for upstream modules provided in the lint model as part of libraries. As a result, attempts to resolve references into that R class will fail. Lint has some heuristics for dealing with incomplete class paths so it will recognize a reference to R.type.name even if it does not resolve to an actual field, but that does not work with import aliases where any identifier could reference an R class -- lint does look at every reference to see if this is the case, but that requires resolve to work and there is nothing about the name that suggests it's a resource.
In the test example, a string resource is defined in lib2 (@string/lib2), which is referenced from code in lib1 (imported as String_lib2), and app depends on lib1. (I actually created a bunch of permutations to try to reproduce this bug, but there was only one scenario which failed and I've pruned things down to just this.) When you run ./gradlew :app:lint it will complain that @string/lib2 is unused, which is not the case.
I think the root problem here is that the library passed in the lint model for the dependency does not include its R.jar, only the classes.jar. It's nowhere under the library definition folder:
./out/jars/classes.jar
./out/res/values/values.xml
./out/AndroidManifest.xml
./out/META-INF/com/android/build/gradle/aar-metadata.properties
./out/META-INF/com/android/build/gradle/lint-model-metadata.properties
./out/proguard.txt
./out/R.txt
I could probably load the lint model for the dependency myself and locate the R.jar in the classes/ folder, but that seems hacky. Shouldn't the AndroidLibrary model provide the R.jar instead of (or in addition to) the R.txt file when using namespaced R classes?
(Note: Lint is currently skipping anything not a LintModelExternalLibrary from the classpath so we'll need to tweak that too, but as I was debugging this and thinking to fix it by pulling in the jars for local dependencies, which is necessary with partial analysis, I realized that even adding that wouldn't help since the R.jar's aren't there.)
Repro project: ./gradlew :app:lint -- will list R.string.lib2 as unused, though it's referenced from Lib1.kt.
tn...@google.com <tn...@google.com> #5
I have created a workaround in lint for this: if resolving a symbol fails, then it will check the imports to see if it matches an alias that itself looks like a resource reference (.R.type.name) then it will visit the resource reference that way. This fixes this bug.
HOWEVER -- having unresolved symbols is bad; there are potentially other things broken. For example when I invoke Go To Declaration on the aliased resource identifier, it doesn't in fact go to declaration. Therefore, we need to make sure that the way android.nonTransitiveRClass
is implemented preserves the old semantics in the tools. Over to AGP.
cm...@google.com <cm...@google.com> #6
Ah I think this is a regression from us adding runtime dependencies as well as compile, the code in CheckDependenciesLintModelArtifactHandler
means we prefer runtime artifacts when we should prefer compile artifacts, which have the additional R class baked in. i.e. just reversing the order of the maps would mean the compile dependencies will show through
cm...@google.com <cm...@google.com> #7
I just realize I might have sent you in the wrong direction with making the R classes resolve - We might need to have a separate exploded AAR for lint that has the R.jar merged in - the problem currently is that even the lint aar artifact on the compile classpath doesn't have the R classes for lint In normal compilation they're present in the compile classpath R jar
tn...@google.com <tn...@google.com> #8
Why does it have to be a separate AAR? In the project tree I see all the R.jar files:
lib1/build/intermediates/compile_r_class_jar/debug/R.jar
lib2/build/intermediates/compile_r_class_jar/debug/R.jar
app/build/intermediates/compile_and_runtime_not_namespaced_r_class_jar/debug/R.jar
When the lint model is fed to the lib2 analysis task, I would think that the LintModelModuleLibrary for lib1 should include the lib2 R.jar. (Right now LintModelModuleLibrary only takes a single lintJar:File; we probably need to switch to List<File> as is done for some other library types, like LintModelExternalLibrary.
cm...@google.com <cm...@google.com> #9
For lint to be up-to-date it needs to actually depend on the things it reads, so adding it to the model without also creating the dependency isn't correct. We could handle it separately, but either way we need to change what we export from libraries to include it.
ai...@gmail.com <ai...@gmail.com> #10
Issue still exists in AGP 7.0.1
ai...@gmail.com <ai...@gmail.com> #12
I updated dependencies on #4 comment project and it fixed for original code, but to reproduce it enough to change import alias from the resource itself to alias for R file (which arguably the much more common use case):
- import com.android.tools.test.lib2.R.string.lib2 as String_lib2
+ import com.android.tools.test.lib2.R as Lib2R
- println(String_lib2)
+ println(Lib2R.string.lib2)
Attached updated project
ga...@freeletics.com <ga...@freeletics.com> #13
Issue still exists in 7.1.0 for us
ga...@gmail.com <ga...@gmail.com> #14
The reproducer from
sp...@google.com <sp...@google.com> #15
This has been fixed. The fix will be in AGP 7.3.0-alpha09 and/or 7.3.0-beta01.
Change-Id: Ia15bd84ffc0ed963b431f6fe1d89f19f5ca27cbe
de...@google.com <de...@google.com> #16
Thank you for your patience while our engineering team worked to resolve this issue. A fix for this issue is now available in:
- Android Studio Dolphin Canary 9 (2021.3.1.9)
- Android Gradle Plugin 7.3.0-alpha09
We encourage you to try the latest update.
If you notice further issues or have questions, please file a new bug report.
Thank you for taking the time to submit feedback — we really appreciate it!
ai...@gmail.com <ai...@gmail.com> #17
I checked test project and my own project and it looks that bug was fixed in 7.3.0-alpha09
Description
I set
android.nonTransitiveRClass=true
which led to a lot of fully qualifiedR
references throughout my project.I solved that by using a lot of import aliases for the different
R
classes, e.g.:However, Lint marks them as unused.