blob: 5afcc74428eb6693c2f765d5b09c682a6fcf5e98 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tools.lint.detector.api
import com.android.tools.lint.client.api.GradleVisitor
import com.android.tools.lint.client.api.LintDriver
import java.io.File
import java.util.regex.Pattern
/** Context for analyzing a particular file */
class GradleContext(
/** Visitor to use to analyze the file */
val gradleVisitor: GradleVisitor,
/** the driver running through the checks */
driver: LintDriver,
/** the project to run lint on which contains the given file */
project: Project,
/**
* The main project if this project is a library project, or
* null if this is not a library project. The main project is
* the root project of all library projects, not necessarily the
* directly including project.
*/
main: Project?,
/** the file to be analyzed */
file: File
) : Context(driver, project, main, file) {
/** Returns a location for the given range */
fun getLocation(cookie: Any): Location = gradleVisitor.createLocation(this, cookie)
fun isSuppressedWithComment(cookie: Any, issue: Issue): Boolean {
val startOffset = gradleVisitor.getStartOffset(this, cookie)
return startOffset >= 0 && isSuppressedWithComment(startOffset, issue)
}
fun getPropertyKeyCookie(cookie: Any): Any = gradleVisitor.getPropertyKeyCookie(cookie)
fun getPropertyPairCookie(cookie: Any): Any = gradleVisitor.getPropertyPairCookie(cookie)
/**
* Reports an issue applicable to a given source location. The source location is used as the
* scope to check for suppress lint annotations.
*
* @param issue the issue to report
*
* @param cookie the node scope the error applies to. The lint infrastructure will
* check whether there are suppress annotations on this node (or its
* enclosing nodes) and if so suppress the warning without involving the
* client.
*
* @param location the location of the issue, or null if not known
*
* @param message the message for this warning
*
* @param fix optional data to pass to the IDE for use by a quickfix.
*/
fun report(
issue: Issue,
cookie: Any,
location: Location,
message: String,
fix: LintFix? = null
) {
val context = this
if (context.isEnabled(issue)) {
// Suppressed?
// Temporarily unconditionally checking for suppress comments in Gradle files
// since Studio insists on an AndroidLint id prefix
val checkComments = /*context.getClient().checkForSuppressComments() &&*/
context.containsCommentSuppress()
if (checkComments) {
val startOffset = gradleVisitor.getStartOffset(context, cookie)
if (startOffset >= 0 && context.isSuppressedWithComment(startOffset, issue)) {
return
}
}
super.doReport(issue, location, message, fix)
}
}
companion object {
fun getStringLiteralValue(value: String): String? {
return if (value.length > 2 && (value.startsWith("'") && value.endsWith("'") || value.startsWith(
"\""
) && value.endsWith(
"\""
))
) {
value.substring(1, value.length - 1)
} else null
}
fun getIntLiteralValue(value: String, defaultValue: Int): Int {
return try {
Integer.parseInt(value)
} catch (e: NumberFormatException) {
defaultValue
}
}
private val DIGITS = Pattern.compile("\\d+")
fun isNonNegativeInteger(token: String): Boolean {
return DIGITS.matcher(token).matches()
}
fun isStringLiteral(token: String): Boolean {
return token.startsWith("\"") && token.endsWith("\"") ||
token.startsWith("'") && token.endsWith("'")
}
}
}