Skip to content
Open

hw #1

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ plugins {
}

android {
compileSdk 30
compileSdk 32

defaultConfig {
applicationId "ru.otus.homework.androidlint"
minSdk 21
targetSdk 30
targetSdk 32
versionCode 1
versionName "1.0"

Expand All @@ -32,6 +32,7 @@ android {
}

dependencies {
implementation project(':library')
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
implementation 'androidx.core:core-ktx:1.6.0'
Expand Down
25 changes: 23 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext{

detekt_version = '1.20.0'
kotlinVersion = '1.6.21'
// Current release: Chipmunk / AGP 7.2
gradlePluginVersion = '7.0.2'
lintVersion = '30.2.0'
// lintVersion = '30.2.0-rc02'
// Upcoming lint target: Dolphin / AGP 7.3
// gradlePluginVersion = '7.3.0-beta01'
// lintVersion = '30.3.0-beta01'
// Upcoming lint target: Electric Eel / AGP 7.4
// gradlePluginVersion = '7.4.0-alpha02'
// lintVersion = '30.4.0-alpha02'
}
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
dependencies {
classpath "com.android.tools.build:gradle:7.0.2"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.30"
classpath "com.android.tools.build:gradle:$gradlePluginVersion"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:$detekt_version"


// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
apply from: "$rootDir/detekt.gradle"
}

task clean(type: Delete) {
delete rootProject.buildDir
Expand Down
26 changes: 26 additions & 0 deletions detekt.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apply plugin: "io.gitlab.arturbosch.detekt"

detekt {
toolVersion = detekt_version
input = files(
"src/main/java",
"src/main/kotlin"
)
failFast = false
parallel = true
buildUponDefaultConfig = false
ignoreFailures = false
reports {
xml {
enabled = true
destination = file("build/reports/detekt.xml")
}
html {
enabled = true
destination = file("build/reports/detekt.html")
}
}
dependencies {
detektPlugins "io.gitlab.arturbosch.detekt:detekt-formatting:$detekt_version"
}
}
1 change: 1 addition & 0 deletions library/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
22 changes: 22 additions & 0 deletions library/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
apply plugin: 'com.android.library'

android {
compileSdkVersion 32
defaultConfig {
minSdkVersion 19
targetSdkVersion 32
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
checkDependencies true
}
}

/** Package the given lint checks library into this AAR */
dependencies {
implementation project(':lintRules')
lintPublish project(':lintRules')
}
3 changes: 3 additions & 0 deletions library/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<manifest package="com.example.lint.library">

</manifest>
1 change: 1 addition & 0 deletions lintRules/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
28 changes: 28 additions & 0 deletions lintRules/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
plugins {
id 'java-library'
id 'org.jetbrains.kotlin.jvm'
id 'kotlin'
id 'com.android.lint'
}

lintOptions {
htmlReport true
htmlOutput file("lint-report.html")
textReport true
absolutePaths false
ignoreTestSources true
}

java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

dependencies {
compileOnly "com.android.tools.lint:lint-api:$lintVersion"
compileOnly "com.android.tools.lint:lint-checks:$lintVersion"

testImplementation "junit:junit:4.13.2"
testImplementation "com.android.tools.lint:lint:$lintVersion"
testImplementation "com.android.tools.lint:lint-tests:$lintVersion"
}
51 changes: 51 additions & 0 deletions lintRules/src/main/java/ru/otus/lintrules/GlobalScopeDetector.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package ru.otus.lintrules

import com.android.tools.lint.client.api.UElementHandler
import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Detector.UastScanner
import com.android.tools.lint.detector.api.Implementation
import com.android.tools.lint.detector.api.Issue
import com.android.tools.lint.detector.api.JavaContext
import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import org.jetbrains.uast.*

@Suppress("UnstableApiUsage")
class GlobalScopeDetector : Detector(), UastScanner {
override fun getApplicableUastTypes(): List<Class<out UElement?>> {
return listOf(USimpleNameReferenceExpression::class.java)
}

override fun createUastHandler(context: JavaContext): UElementHandler {
return object : UElementHandler() {

override fun visitSimpleNameReferenceExpression(node: USimpleNameReferenceExpression){
if (node.identifier.contains("GlobalScope")) {
context.report(
ISSUE, node, context.getLocation(node),
"Don't use GlobalScope!!!"
)
}
}
}
}

companion object {
@JvmField
val ISSUE: Issue = Issue.create(
id = "GlobalScopeWarningId",
briefDescription = "GlobalScope usage warning",
explanation = """
You shouldn't use GlobalScope! Instead of use a custom scope.
""",
category = Category.CORRECTNESS,
priority = 6,
severity = Severity.WARNING,
implementation = Implementation(
GlobalScopeDetector::class.java,
Scope.JAVA_FILE_SCOPE
)
)
}
}
64 changes: 64 additions & 0 deletions lintRules/src/main/java/ru/otus/lintrules/SampleCodeDetector.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package ru.otus.lintrules

import com.android.tools.lint.client.api.UElementHandler
import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Detector.UastScanner
import com.android.tools.lint.detector.api.Implementation
import com.android.tools.lint.detector.api.Issue
import com.android.tools.lint.detector.api.JavaContext
import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import org.jetbrains.uast.UElement
import org.jetbrains.uast.ULiteralExpression
import org.jetbrains.uast.evaluateString

@Suppress("UnstableApiUsage")
class SampleCodeDetector : Detector(), UastScanner {
override fun getApplicableUastTypes(): List<Class<out UElement?>> {
return listOf(ULiteralExpression::class.java)
}

override fun createUastHandler(context: JavaContext): UElementHandler {
return object : UElementHandler() {
override fun visitLiteralExpression(node: ULiteralExpression) {
val string = node.evaluateString() ?: return
if (string.contains("lint") && string.matches(Regex(".*\\blint\\b.*"))) {
context.report(
ISSUE, node, context.getLocation(node),
"This code mentions `lint`: **Congratulations**"
)
}
}
}
}

companion object {
/**
* Issue describing the problem and pointing to the detector
* implementation.
*/
@JvmField
val ISSUE: Issue = Issue.create(
// ID: used in @SuppressLint warnings etc
id = "SampleId",
// Title -- shown in the IDE's preference dialog, as category headers in the
// Analysis results window, etc
briefDescription = "Lint Mentions",
// Full explanation of the issue; you can use some markdown markup such as
// `monospace`, *italic*, and **bold**.
explanation = """
This check highlights string literals in code which mentions the word `lint`. \
Blah blah blah.
Another paragraph here.
""", // no need to .trimIndent(), lint does that automatically
category = Category.CORRECTNESS,
priority = 6,
severity = Severity.WARNING,
implementation = Implementation(
SampleCodeDetector::class.java,
Scope.JAVA_FILE_SCOPE
)
)
}
}
34 changes: 34 additions & 0 deletions lintRules/src/main/java/ru/otus/lintrules/SampleIssueRegistry.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2021 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 ru.otus.lintrules

import com.android.tools.lint.client.api.IssueRegistry
import com.android.tools.lint.client.api.Vendor
import com.android.tools.lint.detector.api.CURRENT_API

/*
* The list of issues that will be checked when running <code>lint</code>.
*/
@Suppress("UnstableApiUsage")
class SampleIssueRegistry : IssueRegistry() {
override val issues = listOf(SampleCodeDetector.ISSUE)

override val api: Int
get() = CURRENT_API

override val minApi: Int
get() = 8 // works with Studio 4.1 or later; see com.android.tools.lint.detector.api.Api / ApiKt
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ru.otus.lintrules.SampleIssueRegistry
46 changes: 46 additions & 0 deletions lintRules/src/test/kotlin/GlobalScopeDetectorTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package ru.otus.lint.checks

import com.android.tools.lint.checks.infrastructure.TestFiles.kotlin
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.checks.infrastructure.TestLintTask.lint
import org.junit.Before
import org.junit.Test
import ru.otus.lintrules.GlobalScopeDetector

@Suppress("UnstableApiUsage")
class GlobalScopeDetectorTest {

private lateinit var task: TestLintTask

@Before
fun prepare() {
task = lint().allowMissingSdk(true)
}

@Test
fun checkFoundGlobalScope() {
task.files(
kotlin(
"""
package test.pkg
class TestClass1 {

init {
GlobalScope.launch { }
}
}
"""
).indented()
)
.issues(GlobalScopeDetector.ISSUE)
.run()
.expect(
"""
src/test/pkg/TestClass1.kt:5: Warning: Don't use GlobalScope!!! [GlobalScopeWarningId]
GlobalScope.launch { }
~~~~~~~~~~~
0 errors, 1 warnings
"""
)
}
}
Loading