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 @file:Suppress("UnstableApiUsage") 18 19 package androidx.navigation.common.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.UBlockExpression 31 import org.jetbrains.uast.UCallExpression 32 import org.jetbrains.uast.ULambdaExpression 33 34 /** 35 * Lint for checking for empty construction of NavDeepLink in the Kotlin DSL, i.e. navDeepLink { } 36 */ 37 class EmptyNavDeepLinkDetector : Detector(), SourceCodeScanner { 38 companion object { 39 val EmptyNavDeepLink = 40 Issue.create( 41 id = "EmptyNavDeepLink", 42 briefDescription = 43 "NavDeepLink must define an uri, action, and/or mimetype to be " + "valid.", 44 explanation = 45 "Attempting to create an empty NavDeepLink will result in an " + 46 "IllegalStateException at runtime. You may set these arguments within the lambda " + 47 "of the call to navDeepLink.", 48 category = Category.CORRECTNESS, 49 severity = Severity.ERROR, 50 implementation = 51 Implementation(EmptyNavDeepLinkDetector::class.java, Scope.JAVA_FILE_SCOPE) 52 ) 53 } 54 getApplicableMethodNamesnull55 override fun getApplicableMethodNames(): List<String> = listOf("navDeepLink") 56 57 override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) { 58 // valueArgumentCount should be 1 when navDeepLink is called 59 // safe args version of navDeepLink (reified T) can have no lambda, as the base uriPattern 60 // is passed in as param 61 if (node.valueArgumentCount > 0 && node.typeArgumentCount == 0) { 62 val lam = node.valueArguments[0] as ULambdaExpression 63 val body = lam.body as UBlockExpression 64 if (body.expressions.isEmpty()) { 65 context.report( 66 EmptyNavDeepLink, 67 node, 68 context.getNameLocation(node), 69 "Creation of empty NavDeepLink" 70 ) 71 } 72 } 73 } 74 } 75