Status Update
Comments
gr...@google.com <gr...@google.com>
gr...@google.com <gr...@google.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).
gr...@google.com <gr...@google.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
gr...@google.com <gr...@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.
gr...@google.com <gr...@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.
gr...@google.com <gr...@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
pa...@partners.mbank.pl <pa...@partners.mbank.pl> #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
pa...@partners.mbank.pl <pa...@partners.mbank.pl> #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.
gr...@google.com <gr...@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.
ap...@google.com <ap...@google.com> #10
Issue still exists in AGP 7.0.1
gr...@google.com <gr...@google.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
gr...@google.com <gr...@google.com> #13
Issue still exists in 7.1.0 for us
er...@gmail.com <er...@gmail.com> #14
The reproducer from
gr...@google.com <gr...@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
Description
Jetpack Compose version: BOM 2024.12.01
Jetpack Compose component(s) used: Text in Material3
Android Studio Build: Meerkat Canary 9
Kotlin version: 2.1.0
Problem:
Since bumping target SDK to 35 we notice that some strings on some devices receive unintended line breaks even when the Text Composable is allowed to be as wide as it wants. Trying to force single line does not work either as setting
maxLines=1
clip the string rather than join to one line.Examples of problematic strings:
Steps to Reproduce or Code Sample to Reproduce:
Code: Attached minimal reproduction repo including our custom font
Device: Reproduced on Pixel 9 Pro XL real device and emulator using the font/display settings in attached screenshot. Also reported on but not verified: Pixel 8 Pro, Pixel Tablet
Summary of the reprod sample: Activity with the following XML:
...and the following sample code:
This will produce the result in attached screenshots.
Some findings from debugging the issue: