1 /*
<lambda>null2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 @file:Suppress("UnstableApiUsage")
18 
19 package androidx.work.lint
20 
21 import com.android.tools.lint.detector.api.Category
22 import com.android.tools.lint.detector.api.Detector
23 import com.android.tools.lint.detector.api.Implementation
24 import com.android.tools.lint.detector.api.Issue
25 import com.android.tools.lint.detector.api.JavaContext
26 import com.android.tools.lint.detector.api.Scope
27 import com.android.tools.lint.detector.api.Severity
28 import com.android.tools.lint.detector.api.SourceCodeScanner
29 import com.intellij.psi.PsiMethod
30 import org.jetbrains.uast.UCallExpression
31 
32 class PeriodicEnqueueIssueDetector : Detector(), SourceCodeScanner {
33     companion object {
34         val ISSUE =
35             Issue.create(
36                 id = "BadPeriodicWorkRequestEnqueue",
37                 briefDescription = "Use `enqueueUniquePeriodicWork()` instead of `enqueue()`",
38                 explanation =
39                     """
40                 When using `enqueue()` for `PeriodicWorkRequest`s, you might end up enqueuing
41                 duplicate requests unintentionally. You should be using
42                 `enqueueUniquePeriodicWork` with an `ExistingPeriodicWorkPolicy.KEEP` instead.
43             """,
44                 androidSpecific = true,
45                 category = Category.CORRECTNESS,
46                 severity = Severity.WARNING,
47                 implementation =
48                     Implementation(PeriodicEnqueueIssueDetector::class.java, Scope.JAVA_FILE_SCOPE)
49             )
50     }
51 
52     override fun getApplicableMethodNames(): List<String>? = listOf("enqueue")
53 
54     override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
55         if (context.evaluator.isMemberInClass(method, "androidx.work.WorkManager")) {
56             val periodic =
57                 node.valueArguments.filter { argument ->
58                     val type = argument.getExpressionType()?.canonicalText
59                     type == "androidx.work.PeriodicWorkRequest" ||
60                         type == "java.util.List<? extends androidx.work.PeriodicWorkRequest>" ||
61                         type == "java.util.List<? extends androidx.work.WorkRequest>"
62                 }
63             if (periodic.isNotEmpty()) {
64                 context.report(
65                     ISSUE,
66                     context.getLocation(method),
67                     message = "Use `enqueueUniquePeriodicWork()` instead of `enqueue()`"
68                 )
69             }
70         }
71     }
72 }
73