Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2 Disallow inner class #5

Merged
merged 4 commits into from
Oct 6, 2022
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package com.jayasuryat.dowel.lint

import com.android.tools.lint.detector.api.*
import com.intellij.lang.jvm.JvmClassKind
import com.intellij.psi.PsiModifier
import org.jetbrains.uast.UClass
import org.jetbrains.uast.UElement

Expand Down Expand Up @@ -99,6 +100,22 @@ internal class WrongConsiderForDowelUsageDetector : Detector(), SourceCodeScanne
message = InaccessibleConstructorIssue.MESSAGE,
)
}

// Inner class. (Nested and non-inner classes have the static modifier in the Java code)
val declarationClass = parent.uastParent
if (declarationClass != null &&
declarationClass is UClass &&
declarationClass.classKind == JvmClassKind.CLASS &&
!parent.hasModifierProperty(PsiModifier.STATIC)
) {

context.report(
issue = InnerClassIssue.Definition,
scope = element,
location = context.getLocation(element),
message = InnerClassIssue.MESSAGE,
)
}
}

internal object InvalidClassKindIssue {
Expand All @@ -116,7 +133,7 @@ internal class WrongConsiderForDowelUsageDetector : Detector(), SourceCodeScanne
priority = 7,
severity = Severity.ERROR,
implementation = Implementation(
WrongDowelUsageDetector::class.java,
WrongConsiderForDowelUsageDetector::class.java,
Scope.JAVA_FILE_SCOPE
)
)
Expand All @@ -143,6 +160,27 @@ internal class WrongConsiderForDowelUsageDetector : Detector(), SourceCodeScanne
)
}

internal object InnerClassIssue {

internal const val ISSUE_ID: String = "InnerConsiderForDowelClass"

internal const val MESSAGE: String =
"@ConsiderForDowel annotation can't be applied to inner classes"

internal val Definition: Issue = Issue.create(
id = ISSUE_ID,
briefDescription = MESSAGE,
explanation = "@ConsiderForDowel annotation can't be applied to inner classes",
category = Category.CORRECTNESS,
priority = 7,
severity = Severity.ERROR,
implementation = Implementation(
WrongConsiderForDowelUsageDetector::class.java,
Scope.JAVA_FILE_SCOPE
)
)
}

internal object PrivateClassIssue {

internal const val ISSUE_ID: String = "PrivateDowelListClass"
Expand All @@ -158,7 +196,7 @@ internal class WrongConsiderForDowelUsageDetector : Detector(), SourceCodeScanne
priority = 7,
severity = Severity.ERROR,
implementation = Implementation(
WrongDowelUsageDetector::class.java,
WrongConsiderForDowelUsageDetector::class.java,
Scope.JAVA_FILE_SCOPE
)
)
Expand All @@ -179,7 +217,7 @@ internal class WrongConsiderForDowelUsageDetector : Detector(), SourceCodeScanne
priority = 7,
severity = Severity.ERROR,
implementation = Implementation(
WrongDowelUsageDetector::class.java,
WrongConsiderForDowelUsageDetector::class.java,
Scope.JAVA_FILE_SCOPE
)
)
Expand All @@ -190,6 +228,7 @@ internal class WrongConsiderForDowelUsageDetector : Detector(), SourceCodeScanne
internal val ISSUES: Array<Issue> = arrayOf(
MissingSuperTypeIssue.Definition,
InvalidClassKindIssue.Definition,
InnerClassIssue.Definition,
PrivateClassIssue.Definition,
InaccessibleConstructorIssue.Definition,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package com.jayasuryat.dowel.lint

import com.android.tools.lint.detector.api.*
import com.intellij.lang.jvm.JvmClassKind
import com.intellij.psi.PsiModifier
import org.jetbrains.uast.UClass
import org.jetbrains.uast.UElement

Expand Down Expand Up @@ -59,6 +60,22 @@ internal class WrongDowelUsageDetector : Detector(), SourceCodeScanner {
return
}

// Inner class. (Nested and non-inner classes have the static modifier in the Java code)
val declarationClass = parent.uastParent
if (declarationClass != null &&
declarationClass is UClass &&
declarationClass.classKind == JvmClassKind.CLASS &&
!parent.hasModifierProperty(PsiModifier.STATIC)
) {

context.report(
issue = InnerClassIssue.Definition,
scope = element,
location = context.getLocation(element),
message = InnerClassIssue.MESSAGE,
)
}

// Class is private in file
// The check is not evaluator.isPrivate(parent) because that's how Java representation works
if (!evaluator.isPublic(parent)) {
Expand Down Expand Up @@ -105,6 +122,27 @@ internal class WrongDowelUsageDetector : Detector(), SourceCodeScanner {
)
}

internal object InnerClassIssue {

internal const val ISSUE_ID: String = "InnerClassForDowel"

internal const val MESSAGE: String =
"@Dowel annotation can't be applied to inner classes"

internal val Definition: Issue = Issue.create(
id = ISSUE_ID,
briefDescription = MESSAGE,
explanation = "@Dowel annotation can't be applied to inner classes",
category = Category.CORRECTNESS,
priority = 7,
severity = Severity.ERROR,
implementation = Implementation(
WrongDowelUsageDetector::class.java,
Scope.JAVA_FILE_SCOPE
)
)
}

internal object PrivateClassIssue {

internal const val ISSUE_ID: String = "PrivateDowelClass"
Expand Down Expand Up @@ -151,6 +189,7 @@ internal class WrongDowelUsageDetector : Detector(), SourceCodeScanner {

internal val ISSUES: Array<Issue> = arrayOf(
InvalidClassKindIssue.Definition,
InnerClassIssue.Definition,
PrivateClassIssue.Definition,
InaccessibleConstructorIssue.Definition,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,43 @@ class WrongConsiderForDowelUsageDetectorTest {
)
}

@Test
fun `should raise error for considerForDowel with inner class`() {

val source = kotlin(
"""
package dowel

import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.jayasuryat.dowel.annotation.ConsiderForDowel

class Person(
val name: String,
val age: String,
){

@ConsiderForDowel
inner class CustomPreviewParamProvider : PreviewParameterProvider<String>{
override val values : Sequence<String> = sequenceOf("", "", "")
}
}
""".trimIndent()
)

TestLintTask.lint()
.files(ConsiderForDowelStub, PreviewParameterProviderStub, source)
.issues(*issue)
.run()
.expectContains(
"""
src/dowel/Person.kt:11: Error: ${InnerClassIssue.MESSAGE} [${InnerClassIssue.ISSUE_ID}]
@ConsiderForDowel
~~~~~~~~~~~~~~~~~
1 errors, 0 warnings
""".trimIndent()
)
}

@Test
fun `should raise error for considerForDowel with private class`() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,41 @@ class WrongDowelUsageDetectorTest {
)
}

@Test
fun `should raise error for dowel with inner class`() {

val source = kotlin(
"""
package dowel
import com.jayasuryat.dowel.annotation.Dowel
@Dowel
class Person(
val name: String,
val age: String,
){

@Dowel
inner class Author(
val id : Long,
)
}
""".trimIndent()
)

lint()
.files(DowelStub, source)
.issues(*issue)
.run()
.expectContains(
"""
src/dowel/Person.kt:9: Error: ${InnerClassIssue.MESSAGE} [${InnerClassIssue.ISSUE_ID}]
@Dowel
~~~~~~
1 errors, 0 warnings
""".trimIndent()
)
}

@Test
fun `should raise error for dowel with private class`() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,14 @@ internal class DowelSymbolProcessor(
return false
}

if (declaration.modifiers.contains(Modifier.INNER)) {
logger.error(
message = "\n@${Dowel::class.simpleName} annotation can't be applied to inner classes",
symbol = declaration,
)
return false
}

if (declaration.modifiers.contains(Modifier.PRIVATE)) {
logger.error(
"\n@${Dowel::class.simpleName} cannot create an instance for `${declaration.simpleName.asString()}` class: it is private in file.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ internal class UserPredefinedParamProviderMapper(
return false
}

if (declaration.modifiers.contains(Modifier.INNER)) {
logger.error(
message = "\n@${ConsiderForDowel::class.simpleName} annotation can't be applied to inner classes",
symbol = declaration,
)
return false
}

return true
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,40 @@ internal class ConsiderForDowelProcessingTest {
""".trimIndent(), result.messages)
}

@Test
fun `should raise error for considerForDowel with inner class`() {

val source = """
package dowel

import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.jayasuryat.dowel.annotation.ConsiderForDowel

class Person(
val name: String,
val age: String,
){

@ConsiderForDowel
inner class CustomPreviewParamProvider : PreviewParameterProvider<String>{
override val values : Sequence<String> = sequenceOf("", "", "")
}
}
""".trimIndent()

val kotlinSource: SourceFile =
SourceFile.kotlin(name = "CustomPreviewParamProvider.kt", contents = source)
val result: KotlinCompilation.Result = compile(kotlinSource, PreviewParameterProviderStub)

Assert.assertEquals(KotlinCompilation.ExitCode.OK, result.exitCode)
Assert.assertEquals("""
e: Error occurred in KSP, check log for detail
e: [ksp] ${temporaryFolder.root.path}/sources/CustomPreviewParamProvider.kt:12:
@ConsiderForDowel annotation can't be applied to inner classes

""".trimIndent(), result.messages)
}

//spotless:on

private fun compile(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,41 @@ internal class DowelProcessingTest {
)
}

@Test
fun `should raise error for dowel with inner class`() {

val source = """
package dowel

import com.jayasuryat.dowel.annotation.Dowel

@Dowel
class Person(
val name: String,
val age: String,
){

@Dowel
inner class Author(
val id : Long,
)
}
""".trimIndent()

val kotlinSource: SourceFile = SourceFile.kotlin(name = "Person.kt", contents = source)
val result: KotlinCompilation.Result = compile(kotlinSource, PreviewParameterProviderStub)

Assert.assertEquals(
"""
e: Error occurred in KSP, check log for detail
e: [ksp] ${temporaryFolder.root.path}/sources/Person.kt:12:
@Dowel annotation can't be applied to inner classes

""".trimIndent(),
result.messages
)
}

@Test
fun `should raise error for dowel with private class`() {

Expand Down