summaryrefslogtreecommitdiff
path: root/SafetyCenter
diff options
context:
space:
mode:
authorGiulio Fiscella <fiscella@google.com>2023-04-23 20:10:09 +0000
committerGiulio Fiscella <fiscella@google.com>2023-04-23 20:34:16 +0000
commit47364de5c70175ca7b569cb354e79bc3aa82905e (patch)
tree043610301faf965ba817969d324319d51a71b1ce /SafetyCenter
parent7e0363366c1ea30301cf7d298083d976af097419 (diff)
downloadPermission-47364de5c70175ca7b569cb354e79bc3aa82905e.tar.gz
Only use EN-US strings to lint config
When we delete strings, we tend to delete only the EN-US version and we then rely on the translation pipeline to delete all translations. The linter would have reported a false positive if a string is deleted without deleting the reference in the config, because it would fallback on a translation. (Note that the actual code on the device would not fallback if the device is set to EN-US). Also, improve the string checks by taking into consideration which SDK a string is available from. Bug: 257974388 Test: m out/soong/.intermediates/packages/modules/Permission/SafetyCenter/Resources/SafetyCenterResources/android_common/lint/lint-report.html Test: atest ConfigLintCheckerTest Change-Id: I7b8bfa432c77f06fd24b16d271d7c8a4a008d021
Diffstat (limited to 'SafetyCenter')
-rw-r--r--SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/FileSdk.kt23
-rw-r--r--SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ParserExceptionDetector.kt32
-rw-r--r--SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ParserExceptionDetectorTest.kt51
3 files changed, 85 insertions, 21 deletions
diff --git a/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/FileSdk.kt b/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/FileSdk.kt
index f93d4ecab..2d095967b 100644
--- a/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/FileSdk.kt
+++ b/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/FileSdk.kt
@@ -50,11 +50,26 @@ object FileSdk {
if (lastQualifier.isEmpty() || lastQualifier[0] != 'v') {
return TIRAMISU
}
- return try {
- lastQualifier.substring(1).toInt()
- } catch (nfe: NumberFormatException) {
- TIRAMISU
+ return lastQualifier.substring(1).toIntOrNull() ?: TIRAMISU
+ }
+
+ /**
+ * Returns whether the file belongs to a basic configuration. By basic, we mean either the
+ * default configuration that has no qualifier, or a configuration that is defined only by an
+ * SDK level version.
+ */
+ fun belongsToABasicConfiguration(file: File): Boolean {
+ val directParentName = file.parentFile.name
+ val qualifierCount = directParentName.count { it == '-' }
+ val lastQualifier = directParentName.substringAfterLast("-", "")
+ if (
+ lastQualifier.isNotEmpty() &&
+ lastQualifier[0] == 'v' &&
+ lastQualifier.substring(1).toIntOrNull() != null
+ ) {
+ return qualifierCount == 1
}
+ return qualifierCount == 0
}
/** Returns the schema for the specific SDK level provided or null if it doesn't exist. */
diff --git a/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ParserExceptionDetector.kt b/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ParserExceptionDetector.kt
index d8656f889..c05b5404c 100644
--- a/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ParserExceptionDetector.kt
+++ b/SafetyCenter/ConfigLintChecker/java/android/safetycenter/lint/ParserExceptionDetector.kt
@@ -35,6 +35,7 @@ import com.android.tools.lint.detector.api.Severity
import com.android.tools.lint.detector.api.XmlContext
import com.android.tools.lint.detector.api.XmlScanner
import java.util.EnumSet
+import kotlin.math.min
import org.w3c.dom.Element
import org.w3c.dom.Node
@@ -60,8 +61,8 @@ class ParserExceptionDetector : Detector(), OtherFileScanner, XmlScanner {
androidSpecific = true
)
- val STRING_MAP_BUILD_PHASE = 1
- val CONFIG_PARSE_PHASE = 2
+ const val STRING_MAP_BUILD_PHASE = 1
+ const val CONFIG_PARSE_PHASE = 2
}
override fun appliesTo(folderType: ResourceFolderType): Boolean {
@@ -73,9 +74,10 @@ class ParserExceptionDetector : Detector(), OtherFileScanner, XmlScanner {
}
/** Implements XmlScanner and builds a map of string resources in the first phase */
- val mNameToIndex: MutableMap<String, Int> = mutableMapOf()
- val mIndexToValue: MutableMap<Int, String> = mutableMapOf()
- var mIndex = 1000
+ private val mNameToIndex: MutableMap<String, Int> = mutableMapOf()
+ private val mIndexToValue: MutableMap<Int, String> = mutableMapOf()
+ private val mIndexToMinSdk: MutableMap<Int, Int> = mutableMapOf()
+ private var mIndex = 1000
override fun getApplicableElements(): Collection<String>? {
return listOf(TAG_STRING)
@@ -84,14 +86,21 @@ class ParserExceptionDetector : Detector(), OtherFileScanner, XmlScanner {
override fun visitElement(context: XmlContext, element: Element) {
if (
context.driver.phase != STRING_MAP_BUILD_PHASE ||
- context.resourceFolderType != ResourceFolderType.VALUES
+ context.resourceFolderType != ResourceFolderType.VALUES ||
+ !FileSdk.belongsToABasicConfiguration(context.file)
) {
return
}
+ val minSdk = FileSdk.getSdkQualifier(context.file)
val name = element.getAttribute(ATTR_NAME)
+ val index = mNameToIndex[name]
+ if (index != null) {
+ mIndexToMinSdk[index] = min(mIndexToMinSdk[index]!!, minSdk)
+ return
+ }
var value = ""
- for (index in 0 until element.childNodes.length) {
- val child = element.childNodes.item(index)
+ for (childIndex in 0 until element.childNodes.length) {
+ val child = element.childNodes.item(childIndex)
if (child.nodeType == Node.TEXT_NODE) {
value = child.nodeValue
break
@@ -99,6 +108,7 @@ class ParserExceptionDetector : Detector(), OtherFileScanner, XmlScanner {
}
mNameToIndex[name] = mIndex
mIndexToValue[mIndex] = value
+ mIndexToMinSdk[mIndex] = minSdk
mIndex++
}
@@ -129,7 +139,11 @@ class ParserExceptionDetector : Detector(), OtherFileScanner, XmlScanner {
// the target package or on packages that refer to Android global resources.
// However, we cannot use a custom linter with the default soong overlay
// build rule regardless.
- Resources(context.project.`package`, mNameToIndex, mIndexToValue)
+ Resources(
+ context.project.`package`,
+ mNameToIndex.filterValues { sdk >= mIndexToMinSdk[it]!! },
+ mIndexToValue.filterKeys { sdk >= mIndexToMinSdk[it]!! }
+ )
)
} catch (e: ParseException) {
context.report(
diff --git a/SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ParserExceptionDetectorTest.kt b/SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ParserExceptionDetectorTest.kt
index 869780eea..1cd693ef6 100644
--- a/SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ParserExceptionDetectorTest.kt
+++ b/SafetyCenter/ConfigLintChecker/tests/java/android/safetycenter/lint/test/ParserExceptionDetectorTest.kt
@@ -16,6 +16,7 @@
package android.safetycenter.lint.test
+import android.os.Build.VERSION_CODES.TIRAMISU
import android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE
import android.safetycenter.lint.FileSdk
import android.safetycenter.lint.ParserExceptionDetector
@@ -48,7 +49,7 @@ class ParserExceptionDetectorTest : LintDetectorTest() {
lint()
.files(
xml("res/raw/safety_center_config.xml", VALID_TIRAMISU_CONFIG),
- STRINGS_WITH_REFERENCE_XML
+ STRINGS_WITH_REFERENCE_XML_DEFAULT
)
.run()
.expectClean()
@@ -59,7 +60,7 @@ class ParserExceptionDetectorTest : LintDetectorTest() {
lint()
.files(
xml("res/raw-99/safety_center_config.xml", VALID_TIRAMISU_CONFIG),
- STRINGS_WITH_REFERENCE_XML
+ STRINGS_WITH_REFERENCE_XML_DEFAULT
)
.run()
.expectClean()
@@ -100,7 +101,7 @@ class ParserExceptionDetectorTest : LintDetectorTest() {
lint()
.files(
xml("res/raw/safety_center_config.xml", VALID_UDC_CONFIG),
- STRINGS_WITH_REFERENCE_XML
+ STRINGS_WITH_REFERENCE_XML_DEFAULT
)
.run()
.expect(
@@ -111,6 +112,40 @@ class ParserExceptionDetectorTest : LintDetectorTest() {
}
@Test
+ fun validTConfigWithUReference_throwsInT() {
+ FileSdk.maxVersionOverride = TIRAMISU
+ lint()
+ .files(
+ xml("res/raw/safety_center_config.xml", VALID_TIRAMISU_CONFIG),
+ xml("res/values-v34/strings.xml", STRINGS_WITH_REFERENCE_XML),
+ )
+ .run()
+ .expect(
+ "res/raw/safety_center_config.xml: Error: Parser exception at sdk=33: " +
+ "\"Resource name \"@lint.test.pkg:string/reference\" in " +
+ "safety-sources-group.title missing or invalid\", cause: \"null\" " +
+ "[InvalidSafetyCenterConfig]\n1 errors, 0 warnings"
+ )
+ }
+
+ @Test
+ fun validTConfigWithOtherLanguageReference_throwsInT() {
+ FileSdk.maxVersionOverride = TIRAMISU
+ lint()
+ .files(
+ xml("res/raw/safety_center_config.xml", VALID_TIRAMISU_CONFIG),
+ xml("res/values-ar/strings.xml", STRINGS_WITH_REFERENCE_XML),
+ )
+ .run()
+ .expect(
+ "res/raw/safety_center_config.xml: Error: Parser exception at sdk=33: " +
+ "\"Resource name \"@lint.test.pkg:string/reference\" in " +
+ "safety-sources-group.title missing or invalid\", cause: \"null\" " +
+ "[InvalidSafetyCenterConfig]\n1 errors, 0 warnings"
+ )
+ }
+
+ @Test
fun unrelatedFile_doesNotThrow() {
lint().files(xml("res/raw/some_other_config.xml", "<some-other-root/>")).run().expectClean()
}
@@ -121,15 +156,15 @@ class ParserExceptionDetectorTest : LintDetectorTest() {
}
private companion object {
- val STRINGS_WITH_REFERENCE_XML: TestFile =
- xml(
- "res/values/strings.xml",
- """
+ const val STRINGS_WITH_REFERENCE_XML =
+ """
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="reference" translatable="false">Reference</string>
</resources>
"""
- )
+
+ val STRINGS_WITH_REFERENCE_XML_DEFAULT: TestFile =
+ xml("res/values/strings.xml", STRINGS_WITH_REFERENCE_XML)
const val VALID_TIRAMISU_CONFIG =
"""