Skip to content

Commit 2fbe7bd

Browse files
committed
Fix warnings in the linter.
1 parent 89ee79b commit 2fbe7bd

File tree

8 files changed

+74
-42
lines changed

8 files changed

+74
-42
lines changed

firebase-messaging/src/main/java/com/google/firebase/messaging/FcmExecutors.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ static ExecutorService newFileExecutor() {
100100
return Executors.newSingleThreadExecutor(new NamedThreadFactory(THREAD_FILE));
101101
}
102102

103+
// TODO(b/258424124): Migrate to go/firebase-android-executors
104+
@SuppressLint("ThreadPoolCreation")
103105
static ExecutorService newIntentHandleExecutor() {
104106
return PoolableExecutors.factory()
105107
.newSingleThreadExecutor(

tools/lint/src/main/kotlin/CheckRegistry.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package com.google.firebase.lint.checks
1616

1717
import com.android.tools.lint.client.api.IssueRegistry
18+
import com.android.tools.lint.client.api.Vendor
1819
import com.android.tools.lint.detector.api.CURRENT_API
1920
import com.android.tools.lint.detector.api.Issue
2021

@@ -37,4 +38,12 @@ class CheckRegistry : IssueRegistry() {
3738
get() = CURRENT_API
3839
override val minApi: Int
3940
get() = 2
41+
42+
override val vendor: Vendor
43+
get() =
44+
Vendor(
45+
"firebase",
46+
identifier = "firebase",
47+
feedbackUrl = "https://github.com/firebase/firebase-android-sdk/issues"
48+
)
4049
}

tools/lint/src/main/kotlin/DeferredApiDetector.kt

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414

1515
package com.google.firebase.lint.checks
1616

17+
import com.android.tools.lint.detector.api.AnnotationInfo
18+
import com.android.tools.lint.detector.api.AnnotationOrigin
19+
import com.android.tools.lint.detector.api.AnnotationUsageInfo
1720
import com.android.tools.lint.detector.api.AnnotationUsageType
1821
import com.android.tools.lint.detector.api.Category
1922
import com.android.tools.lint.detector.api.Detector
@@ -24,27 +27,24 @@ import com.android.tools.lint.detector.api.Scope
2427
import com.android.tools.lint.detector.api.Severity
2528
import com.android.tools.lint.detector.api.SourceCodeScanner
2629
import com.intellij.psi.PsiMethod
27-
import org.jetbrains.uast.UAnnotation
2830
import org.jetbrains.uast.UCallExpression
2931
import org.jetbrains.uast.UElement
3032

33+
@Suppress("DetectorIsMissingAnnotations")
3134
class DeferredApiDetector : Detector(), SourceCodeScanner {
3235
override fun applicableAnnotations(): List<String> = listOf(ANNOTATION)
3336

3437
override fun visitAnnotationUsage(
3538
context: JavaContext,
36-
usage: UElement,
37-
type: AnnotationUsageType,
38-
annotation: UAnnotation,
39-
qualifiedName: String,
40-
method: PsiMethod?,
41-
annotations: List<UAnnotation>,
42-
allMemberAnnotations: List<UAnnotation>,
43-
allClassAnnotations: List<UAnnotation>,
44-
allPackageAnnotations: List<UAnnotation>
39+
element: UElement,
40+
annotationInfo: AnnotationInfo,
41+
usageInfo: AnnotationUsageInfo
4542
) {
46-
if (method != null && type == AnnotationUsageType.METHOD_CALL) {
47-
check(context, usage as UCallExpression, method)
43+
if (
44+
usageInfo.type == AnnotationUsageType.METHOD_CALL &&
45+
annotationInfo.origin == AnnotationOrigin.METHOD
46+
) {
47+
check(context, usageInfo.usage as UCallExpression, annotationInfo.annotated as PsiMethod)
4848
}
4949
}
5050

@@ -59,7 +59,7 @@ class DeferredApiDetector : Detector(), SourceCodeScanner {
5959
INVALID_DEFERRED_API_USE,
6060
usage,
6161
context.getCallLocation(usage, includeReceiver = false, includeArguments = true),
62-
"${method.name} is only safe to call in the context of a Deferred<T> dependency."
62+
"${method.name} is only safe to call in the context of a Deferred`<T>` dependency"
6363
)
6464
}
6565

@@ -75,9 +75,9 @@ class DeferredApiDetector : Detector(), SourceCodeScanner {
7575
briefDescription = "Invalid use of @DeferredApi",
7676
explanation =
7777
"""
78-
Ensures that a method which expects to be called in the context of
79-
Deferred#whenAvailable(), is actually called this way. This is important for
80-
supporting dynamically loaded modules, where certain dependencies become available
78+
Ensures that a method which expects to be called in the context of \
79+
`Deferred#whenAvailable()`, is actually called this way. This is important for \
80+
supporting dynamically loaded modules, where certain dependencies become available \
8181
during app's runtime and not available upon app launch.
8282
""",
8383
category = Category.CORRECTNESS,

tools/lint/src/main/kotlin/KotlinInteropDetector.kt

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import org.jetbrains.uast.getContainingUClass
5252
import org.jetbrains.uast.getContainingUMethod
5353
import org.jetbrains.uast.getParentOfType
5454

55+
@Suppress("DetectorIsMissingAnnotations")
5556
class KotlinInteropDetector : Detector(), SourceCodeScanner {
5657
companion object Issues {
5758
private val IMPLEMENTATION =
@@ -66,13 +67,13 @@ class KotlinInteropDetector : Detector(), SourceCodeScanner {
6667
briefDescription = "No Hard Kotlin Keywords",
6768
explanation =
6869
"""
69-
Do not use Kotlin’s hard keywords as the name of methods or fields.
70-
These require the use of backticks to escape when calling from Kotlin.
70+
Do not use Kotlin’s hard keywords as the name of methods or fields. \
71+
These require the use of backticks to escape when calling from Kotlin. \
7172
Soft keywords, modifier keywords, and special identifiers are allowed.
7273
7374
For example, Mockito’s `when` function requires backticks when used from Kotlin:
7475
75-
val callable = Mockito.mock(Callable::class.java)
76+
val callable = Mockito.mock(Callable::class.java) \
7677
Mockito.\`when\`(callable.call()).thenReturn(/* … */)
7778
""",
7879
category = Category.INTEROPERABILITY_KOTLIN,
@@ -88,7 +89,7 @@ class KotlinInteropDetector : Detector(), SourceCodeScanner {
8889
briefDescription = "Lambda Parameters Last",
8990
explanation =
9091
"""
91-
To improve calling this code from Kotlin,
92+
To improve calling this code from Kotlin, \
9293
parameter types eligible for SAM conversion should be last.
9394
""",
9495
category = Category.INTEROPERABILITY_KOTLIN,
@@ -104,7 +105,7 @@ class KotlinInteropDetector : Detector(), SourceCodeScanner {
104105
briefDescription = "Unknown nullness",
105106
explanation =
106107
"""
107-
To improve referencing this code from Kotlin, consider adding
108+
To improve referencing this code from Kotlin, consider adding \
108109
explicit nullness information here with either `@NonNull` or `@Nullable`.
109110
""",
110111
category = Category.INTEROPERABILITY_KOTLIN,
@@ -312,7 +313,7 @@ class KotlinInteropDetector : Detector(), SourceCodeScanner {
312313

313314
if (getter == null) {
314315
// Look for inherited methods
315-
cls.superClass?.let { superClass ->
316+
cls.javaPsi.superClass?.let { superClass ->
316317
for (inherited in superClass.findMethodsByName(getterName1, true)) {
317318
if (inherited.parameterList.parametersCount == 0) {
318319
getter = inherited
@@ -435,7 +436,7 @@ class KotlinInteropDetector : Detector(), SourceCodeScanner {
435436
) {
436437
val name1 = badGetter!!.name
437438
if (name1.startsWith("is") && methodName.startsWith("setIs") && name1[2].isUpperCase()) {
438-
val newProperty = name1[2].toLowerCase() + name1.substring(3)
439+
val newProperty = name1[2].lowercaseChar() + name1.substring(3)
439440
val message =
440441
"This method should be called `set${newProperty.capitalize()}` such " +
441442
"that (along with the `$name1` getter) Kotlin code can access it " +
@@ -463,6 +464,10 @@ class KotlinInteropDetector : Detector(), SourceCodeScanner {
463464
}
464465
}
465466

467+
private fun String.capitalize() = replaceFirstChar { it.uppercase() }
468+
469+
private fun String.decapitalize() = replaceFirstChar { it.lowercase() }
470+
466471
/** Returns true if the given class has a (possibly inherited) setter of the given type */
467472
private fun hasSetter(cls: UClass, type: PsiType?, setterName: String): Boolean {
468473
for (method in cls.findMethodsByName(setterName, true)) {
@@ -570,7 +575,7 @@ class KotlinInteropDetector : Detector(), SourceCodeScanner {
570575
val replaceLocation =
571576
if (node is UParameter) {
572577
location
573-
} else if (node is UMethod && node.modifierList != null) {
578+
} else if (node is UMethod) {
574579
// Place the insertion point at the modifiers such that we don't
575580
// insert the annotation for example after the "public" keyword.
576581
// We also don't want to place it on the method range itself since

tools/lint/src/main/kotlin/ManifestElementHasNoExportedAttributeDetector.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.android.tools.lint.detector.api.XmlContext
2525
import com.android.tools.lint.detector.api.XmlScanner
2626
import org.w3c.dom.Element
2727

28+
@Suppress("DetectorIsMissingAnnotations")
2829
class ManifestElementHasNoExportedAttributeDetector : Detector(), XmlScanner {
2930

3031
enum class Component(val xmlName: String) {

tools/lint/src/main/kotlin/NonAndroidxNullabilityDetector.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ private val ANDROIDX_ANNOTATIONS =
4343
"android.support.annotation.NonNull"
4444
)
4545

46+
@Suppress("DetectorIsMissingAnnotations")
4647
class NonAndroidxNullabilityDetector : Detector(), SourceCodeScanner {
4748
companion object Issues {
4849
private val IMPLEMENTATION =
@@ -52,7 +53,7 @@ class NonAndroidxNullabilityDetector : Detector(), SourceCodeScanner {
5253
val NON_ANDROIDX_NULLABILITY =
5354
Issue.create(
5455
id = "FirebaseNonAndroidxNullability",
55-
briefDescription = "Use androidx nullability annotations.",
56+
briefDescription = "Use androidx nullability annotations",
5657
explanation = "Use androidx nullability annotations instead.",
5758
category = Category.COMPLIANCE,
5859
priority = 1,
@@ -124,7 +125,7 @@ class NonAndroidxNullabilityDetector : Detector(), SourceCodeScanner {
124125
context.report(
125126
NON_ANDROIDX_NULLABILITY,
126127
context.getLocation(annotation),
127-
"Use androidx nullability annotations.",
128+
"Use androidx nullability annotations",
128129
fix
129130
)
130131
}

tools/lint/src/main/kotlin/ProviderAssignmentDetector.kt

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,32 +25,34 @@ import com.android.tools.lint.detector.api.SourceCodeScanner
2525
import com.intellij.psi.PsiClass
2626
import com.intellij.psi.PsiField
2727
import com.intellij.psi.PsiMethod
28+
import org.jetbrains.uast.UBinaryExpression
2829
import org.jetbrains.uast.UCallExpression
2930
import org.jetbrains.uast.UReferenceExpression
3031
import org.jetbrains.uast.getParentOfType
31-
import org.jetbrains.uast.java.JavaUAssignmentExpression
3232

3333
private const val PROVIDER = "com.google.firebase.inject.Provider"
3434

35+
@Suppress("DetectorIsMissingAnnotations")
3536
class ProviderAssignmentDetector : Detector(), SourceCodeScanner {
3637
override fun getApplicableMethodNames() = listOf("get")
3738

3839
override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
3940
if (!isProviderGet(method)) {
4041
return
4142
}
42-
val assignmentExpression =
43-
node.getParentOfType<JavaUAssignmentExpression>(JavaUAssignmentExpression::class.java, true)
44-
val assignmentTarget = assignmentExpression?.leftOperand as? UReferenceExpression ?: return
43+
val binaryOperation = node.getParentOfType<UBinaryExpression>(true) ?: return
44+
if (binaryOperation.operatorIdentifier?.name != "=") return
45+
46+
val assignmentTarget = binaryOperation.leftOperand as? UReferenceExpression ?: return
4547

4648
// This would only be true if assigning the result of get(),
4749
// in cases like foo = p.get().someMethod() there would be an intermediate parent
4850
// and we don't want to trigger in such cases.
49-
if (assignmentExpression != node.uastParent?.uastParent) {
51+
if (binaryOperation != node.uastParent?.uastParent) {
5052
return
5153
}
5254

53-
if (hasDeferredApiAnnotation(context, assignmentExpression)) {
55+
if (hasDeferredApiAnnotation(context, binaryOperation)) {
5456
return
5557
}
5658

@@ -59,7 +61,7 @@ class ProviderAssignmentDetector : Detector(), SourceCodeScanner {
5961
context.report(
6062
INVALID_PROVIDER_ASSIGNMENT,
6163
context.getCallLocation(node, includeReceiver = false, includeArguments = true),
62-
"Provider.get() assignment to a field detected."
64+
"`Provider.get()` assignment to a field detected"
6365
)
6466
}
6567
}
@@ -87,9 +89,9 @@ class ProviderAssignmentDetector : Detector(), SourceCodeScanner {
8789
briefDescription = "Invalid use of Provider<T>",
8890
explanation =
8991
"""
90-
Ensures that results of Provider.get() are not stored in class fields. Doing
91-
so may lead to bugs in the context of dynamic feature loading. Namely, optional
92-
provider dependencies can become available during the execution of the app, so
92+
Ensures that results of `Provider.get()` are not stored in class fields. Doing \
93+
so may lead to bugs in the context of dynamic feature loading. Namely, optional \
94+
provider dependencies can become available during the execution of the app, so \
9395
dependents must be ready to handle this situation.
9496
""",
9597
category = Category.CORRECTNESS,

tools/lint/src/main/kotlin/ThreadPoolDetector.kt

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import com.intellij.psi.PsiClass
1212
import com.intellij.psi.PsiMethod
1313
import org.jetbrains.uast.UCallExpression
1414

15+
@Suppress("DetectorIsMissingAnnotations")
1516
class ThreadPoolDetector : Detector(), SourceCodeScanner {
1617
override fun getApplicableMethodNames(): List<String> =
1718
listOf(
@@ -20,7 +21,8 @@ class ThreadPoolDetector : Detector(), SourceCodeScanner {
2021
"newScheduledThreadPool",
2122
"newSingleThreadExecutor",
2223
"newSingleThreadScheduledExecutor",
23-
"newWorkStealingPool"
24+
"newWorkStealingPool",
25+
"factory"
2426
)
2527

2628
override fun getApplicableConstructorTypes(): List<String> =
@@ -32,14 +34,14 @@ class ThreadPoolDetector : Detector(), SourceCodeScanner {
3234
)
3335

3436
override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
35-
if (!isExecutorMethod(method)) {
37+
if (!isExecutorMethod(method) && !isPoolableFactory(method)) {
3638
return
3739
}
3840

3941
context.report(
4042
THREAD_POOL_CREATION,
4143
context.getCallLocation(node, includeReceiver = false, includeArguments = true),
42-
"Creating thread pools is not allowed."
44+
"Creating thread pools is not allowed"
4345
)
4446
}
4547

@@ -51,7 +53,7 @@ class ThreadPoolDetector : Detector(), SourceCodeScanner {
5153
context.report(
5254
THREAD_POOL_CREATION,
5355
context.getCallLocation(node, includeReceiver = false, includeArguments = true),
54-
"Creating threads or thread pools is not allowed."
56+
"Creating threads or thread pools is not allowed"
5557
)
5658
}
5759

@@ -62,6 +64,14 @@ class ThreadPoolDetector : Detector(), SourceCodeScanner {
6264
return false
6365
}
6466

67+
private fun isPoolableFactory(method: PsiMethod): Boolean {
68+
if (method.name != "factory") return false
69+
(method.parent as? PsiClass)?.let {
70+
return it.name == "PoolableExecutors"
71+
}
72+
return false
73+
}
74+
6575
companion object {
6676
private val IMPLEMENTATION =
6777
Implementation(ThreadPoolDetector::class.java, Scope.JAVA_FILE_SCOPE)
@@ -71,10 +81,12 @@ class ThreadPoolDetector : Detector(), SourceCodeScanner {
7181
val THREAD_POOL_CREATION =
7282
Issue.create(
7383
id = "ThreadPoolCreation",
74-
briefDescription = "Creating thread pools is not allowed.",
84+
briefDescription = "Creating thread pools is not allowed",
7585
explanation =
7686
"""
77-
Please use one of the executors provided by firebase-common
87+
Please use one of the executors provided by firebase-common.
88+
89+
See: https://github.com/firebase/firebase-android-sdk/blob/master/docs/executors.md
7890
""",
7991
category = Category.CORRECTNESS,
8092
priority = 6,

0 commit comments

Comments
 (0)