1 /*
2  * Copyright 2022 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 package androidx.build.lint
18 
19 import com.android.tools.lint.client.api.UElementHandler
20 import com.android.tools.lint.detector.api.Category
21 import com.android.tools.lint.detector.api.Detector
22 import com.android.tools.lint.detector.api.Implementation
23 import com.android.tools.lint.detector.api.Incident
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 org.jetbrains.uast.UClass
29 
30 /**
31  * Detector to apply lint rules for CameraX quirks. The rule is to enforce a javadoc template to
32  * describe the bug id, issue description and device info. This detector is disabled by default.
33  * Only CameraX modules will enable the detector.
34  */
35 class CameraXQuirksClassDetector : Detector(), Detector.UastScanner {
36 
getApplicableUastTypesnull37     override fun getApplicableUastTypes() = listOf(UClass::class.java)
38 
39     override fun createUastHandler(context: JavaContext) =
40         object : UElementHandler() {
41 
42             override fun visitClass(node: UClass) {
43                 val isQuirk =
44                     node.implementsList?.referenceElements?.find {
45                         it.referenceName!!.endsWith("Quirk")
46                     } != null
47 
48                 if (isQuirk) {
49                     val comments = node.comments
50                     val sb = StringBuilder()
51                     comments.forEach { sb.append(it.text) }
52                     val comment = sb.append("\n").toString()
53 
54                     if (
55                         !comment.contains("<p>QuirkSummary") ||
56                             !comment.contains("Bug Id:") ||
57                             !comment.contains("Description:") ||
58                             !comment.contains("Device(s):")
59                     ) {
60                         val implForInsertion =
61                             """
62                          * <p>QuirkSummary
63                          *     Bug Id:
64                          *     Description:
65                          *     Device(s):
66                         """
67                                 .trimIndent()
68 
69                         val incident =
70                             Incident(context)
71                                 .issue(ISSUE)
72                                 .message(
73                                     "CameraX quirks should include this template in the javadoc:" +
74                                         "\n\n$implForInsertion\n\n"
75                                 )
76                                 .location(context.getNameLocation(node))
77                                 .scope(node)
78                         context.report(incident)
79                     }
80                 }
81             }
82         }
83 
84     companion object {
85         val ISSUE =
86             Issue.create(
87                 id = "CameraXQuirksClassDetector",
88                 briefDescription = "CameraQuirks include @QuirkSummary in the javadoc",
89                 explanation = "CameraX quirks should include @QuirkSummary in the javadoc.",
90                 category = Category.CORRECTNESS,
91                 priority = 5,
92                 severity = Severity.ERROR,
93                 enabledByDefault = false,
94                 implementation =
95                     Implementation(CameraXQuirksClassDetector::class.java, Scope.JAVA_FILE_SCOPE)
96             )
97     }
98 }
99