Add support for "implementation" gradle directive (KT-21746)
#KT-21746 Fixed
This commit is contained in:
+1
-1
@@ -89,7 +89,7 @@ abstract class GradleKotlinFrameworkSupportProvider(
|
|||||||
.addBuildscriptPropertyDefinition("ext.kotlin_version = '$kotlinVersion'")
|
.addBuildscriptPropertyDefinition("ext.kotlin_version = '$kotlinVersion'")
|
||||||
|
|
||||||
for (dependency in getDependencies(sdk)) {
|
for (dependency in getDependencies(sdk)) {
|
||||||
buildScriptData.addDependencyNotation(KotlinWithGradleConfigurator.getGroovyDependencySnippet(dependency))
|
buildScriptData.addDependencyNotation(KotlinWithGradleConfigurator.getGroovyDependencySnippet(dependency, "compile"))
|
||||||
}
|
}
|
||||||
for (dependency in getTestDependencies()) {
|
for (dependency in getTestDependencies()) {
|
||||||
buildScriptData.addDependencyNotation(
|
buildScriptData.addDependencyNotation(
|
||||||
|
|||||||
+7
-5
@@ -20,6 +20,7 @@ import com.intellij.openapi.roots.DependencyScope
|
|||||||
import com.intellij.openapi.roots.ExternalLibraryDescriptor
|
import com.intellij.openapi.roots.ExternalLibraryDescriptor
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
|
import org.jetbrains.kotlin.idea.inspections.gradle.GradleHeuristicHelper.PRODUCTION_DEPENDENCY_STATEMENTS
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
|
||||||
@@ -105,10 +106,10 @@ class KotlinBuildScriptManipulator(private val kotlinScript: KtFile) : GradleBui
|
|||||||
override fun getKotlinStdlibVersion(): String? = kotlinScript.getKotlinStdlibVersion()
|
override fun getKotlinStdlibVersion(): String? = kotlinScript.getKotlinStdlibVersion()
|
||||||
|
|
||||||
private fun KtBlockExpression.addCompileStdlibIfMissing(stdlibArtifactName: String): KtCallExpression? =
|
private fun KtBlockExpression.addCompileStdlibIfMissing(stdlibArtifactName: String): KtCallExpression? =
|
||||||
findCompileStdLib() ?: addExpressionIfMissing(getCompileDependencySnippet(KOTLIN_GROUP_ID, stdlibArtifactName)) as? KtCallExpression
|
findStdLibDependency() ?: addExpressionIfMissing(getCompileDependencySnippet(KOTLIN_GROUP_ID, stdlibArtifactName)) as? KtCallExpression
|
||||||
|
|
||||||
private fun KtFile.containsCompileStdLib(): Boolean =
|
private fun KtFile.containsCompileStdLib(): Boolean =
|
||||||
findScriptInitializer("dependencies")?.getBlock()?.findCompileStdLib() != null
|
findScriptInitializer("dependencies")?.getBlock()?.findStdLibDependency() != null
|
||||||
|
|
||||||
private fun KtFile.containsApplyKotlinPlugin(pluginName: String): Boolean =
|
private fun KtFile.containsApplyKotlinPlugin(pluginName: String): Boolean =
|
||||||
findScriptInitializer("apply")?.getBlock()?.findPlugin(pluginName) != null
|
findScriptInitializer("apply")?.getBlock()?.findPlugin(pluginName) != null
|
||||||
@@ -137,7 +138,7 @@ class KotlinBuildScriptManipulator(private val kotlinScript: KtFile) : GradleBui
|
|||||||
|
|
||||||
private fun KtFile.getKotlinStdlibVersion(): String? {
|
private fun KtFile.getKotlinStdlibVersion(): String? {
|
||||||
return findScriptInitializer("dependencies")?.getBlock()?.let {
|
return findScriptInitializer("dependencies")?.getBlock()?.let {
|
||||||
val expression = it.findCompileStdLib()?.valueArguments?.firstOrNull()?.getArgumentExpression()
|
val expression = it.findStdLibDependency()?.valueArguments?.firstOrNull()?.getArgumentExpression()
|
||||||
when (expression) {
|
when (expression) {
|
||||||
is KtCallExpression -> expression.valueArguments[1].text.trim('\"')
|
is KtCallExpression -> expression.valueArguments[1].text.trim('\"')
|
||||||
is KtStringTemplateExpression -> expression.text?.trim('\"')?.substringAfterLast(":")?.removePrefix("$")
|
is KtStringTemplateExpression -> expression.text?.trim('\"')?.substringAfterLast(":")?.removePrefix("$")
|
||||||
@@ -146,9 +147,10 @@ class KotlinBuildScriptManipulator(private val kotlinScript: KtFile) : GradleBui
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtBlockExpression.findCompileStdLib(): KtCallExpression? {
|
private fun KtBlockExpression.findStdLibDependency(): KtCallExpression? {
|
||||||
return PsiTreeUtil.getChildrenOfType(this, KtCallExpression::class.java)?.find {
|
return PsiTreeUtil.getChildrenOfType(this, KtCallExpression::class.java)?.find {
|
||||||
it.calleeExpression?.text == "compile" && (it.valueArguments.firstOrNull()?.getArgumentExpression()?.isKotlinStdLib() ?: false)
|
val calleeText = it.calleeExpression?.text
|
||||||
|
calleeText in PRODUCTION_DEPENDENCY_STATEMENTS && (it.valueArguments.firstOrNull()?.getArgumentExpression()?.isKotlinStdLib() ?: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -264,7 +264,7 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
|
|||||||
|
|
||||||
private val KOTLIN_BUILD_SCRIPT_NAME = "build.gradle.kts"
|
private val KOTLIN_BUILD_SCRIPT_NAME = "build.gradle.kts"
|
||||||
|
|
||||||
fun getGroovyDependencySnippet(artifactName: String, scope: String = "compile") =
|
fun getGroovyDependencySnippet(artifactName: String, scope: String) =
|
||||||
"$scope \"org.jetbrains.kotlin:$artifactName:\$kotlin_version\""
|
"$scope \"org.jetbrains.kotlin:$artifactName:\$kotlin_version\""
|
||||||
|
|
||||||
fun getGroovyApplyPluginDirective(pluginName: String) = "apply plugin: '$pluginName'"
|
fun getGroovyApplyPluginDirective(pluginName: String) = "apply plugin: '$pluginName'"
|
||||||
|
|||||||
+3
-1
@@ -25,6 +25,7 @@ import com.intellij.util.text.VersionComparatorUtil
|
|||||||
import org.jetbrains.kotlin.idea.configuration.allModules
|
import org.jetbrains.kotlin.idea.configuration.allModules
|
||||||
import org.jetbrains.kotlin.idea.configuration.getWholeModuleGroup
|
import org.jetbrains.kotlin.idea.configuration.getWholeModuleGroup
|
||||||
import org.jetbrains.kotlin.idea.inspections.ReplaceStringInDocumentFix
|
import org.jetbrains.kotlin.idea.inspections.ReplaceStringInDocumentFix
|
||||||
|
import org.jetbrains.kotlin.idea.inspections.gradle.GradleHeuristicHelper.PRODUCTION_DEPENDENCY_STATEMENTS
|
||||||
import org.jetbrains.kotlin.idea.versions.DEPRECATED_LIBRARIES_INFORMATION
|
import org.jetbrains.kotlin.idea.versions.DEPRECATED_LIBRARIES_INFORMATION
|
||||||
import org.jetbrains.kotlin.idea.versions.DeprecatedLibInfo
|
import org.jetbrains.kotlin.idea.versions.DeprecatedLibInfo
|
||||||
import org.jetbrains.kotlin.idea.versions.LibInfo
|
import org.jetbrains.kotlin.idea.versions.LibInfo
|
||||||
@@ -47,7 +48,8 @@ class DeprecatedGradleDependencyInspection : GradleBaseInspection() {
|
|||||||
val dependenciesCall = closure.getStrictParentOfType<GrMethodCall>() ?: return
|
val dependenciesCall = closure.getStrictParentOfType<GrMethodCall>() ?: return
|
||||||
if (dependenciesCall.invokedExpression.text != "dependencies") return
|
if (dependenciesCall.invokedExpression.text != "dependencies") return
|
||||||
|
|
||||||
val dependencyEntries = GradleHeuristicHelper.findStatementWithPrefix(closure, "compile")
|
val dependencyEntries = GradleHeuristicHelper.findStatementWithPrefixes(
|
||||||
|
closure, PRODUCTION_DEPENDENCY_STATEMENTS)
|
||||||
for (dependencyStatement in dependencyEntries) {
|
for (dependencyStatement in dependencyEntries) {
|
||||||
visitDependencyEntry(dependencyStatement)
|
visitDependencyEntry(dependencyStatement)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-15
@@ -20,8 +20,8 @@ import com.intellij.openapi.externalSystem.model.DataNode
|
|||||||
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||||
import com.intellij.openapi.roots.ProjectRootManager
|
import com.intellij.openapi.roots.ProjectRootManager
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
|
import org.jetbrains.kotlin.idea.inspections.gradle.GradleHeuristicHelper.PRODUCTION_DEPENDENCY_STATEMENTS
|
||||||
import org.jetbrains.kotlin.idea.versions.*
|
import org.jetbrains.kotlin.idea.versions.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.plugins.gradle.codeInspection.GradleBaseInspection
|
import org.jetbrains.plugins.gradle.codeInspection.GradleBaseInspection
|
||||||
import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor
|
import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor
|
||||||
@@ -29,7 +29,6 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase
|
|||||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement
|
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement
|
||||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock
|
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock
|
||||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall
|
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall
|
||||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression
|
|
||||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression
|
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -70,8 +69,6 @@ class DifferentStdlibGradleVersionInspection : GradleBaseInspection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val COMPILE_DEPENDENCY_STATEMENTS = listOf("classpath", "compile")
|
|
||||||
|
|
||||||
fun getKotlinStdlibVersions(gradleFile: GroovyFileBase, libraryId: List<String>): Collection<String> {
|
fun getKotlinStdlibVersions(gradleFile: GroovyFileBase, libraryId: List<String>): Collection<String> {
|
||||||
val versions = LinkedHashSet<String>()
|
val versions = LinkedHashSet<String>()
|
||||||
val visitor = object : VersionFinder(libraryId) {
|
val visitor = object : VersionFinder(libraryId) {
|
||||||
@@ -88,18 +85,9 @@ class DifferentStdlibGradleVersionInspection : GradleBaseInspection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun findLibraryStatement(closure: GrClosableBlock, libraryGroup: String, libraryIds: List<String>): GrCallExpression? {
|
private fun findLibraryStatement(closure: GrClosableBlock, libraryGroup: String, libraryIds: List<String>): GrCallExpression? {
|
||||||
val applicationStatements = closure.getChildrenOfType<GrCallExpression>()
|
return GradleHeuristicHelper.findStatementWithPrefixes(closure, PRODUCTION_DEPENDENCY_STATEMENTS).firstOrNull { statement ->
|
||||||
|
libraryIds.any { it in statement.text } && statement.text.contains(libraryGroup)
|
||||||
for (statement in applicationStatements) {
|
|
||||||
val startExpression = statement.getChildrenOfType<GrReferenceExpression>().firstOrNull() ?: continue
|
|
||||||
if (startExpression.text in COMPILE_DEPENDENCY_STATEMENTS) {
|
|
||||||
if (libraryIds.any { it in statement.text } && statement.text.contains(libraryGroup)) {
|
|
||||||
return statement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getResolvedKotlinStdlibVersion(file: PsiFile, libraryIds: List<String>): String? {
|
fun getResolvedKotlinStdlibVersion(file: PsiFile, libraryIds: List<String>): String? {
|
||||||
|
|||||||
+8
-2
@@ -30,6 +30,8 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrC
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
object GradleHeuristicHelper {
|
object GradleHeuristicHelper {
|
||||||
|
val PRODUCTION_DEPENDENCY_STATEMENTS = setOf("classpath", "compile", "api", "implementation", "compileOnly", "runtimeOnly")
|
||||||
|
|
||||||
fun getHeuristicVersionInBuildScriptDependency(classpathStatement: GrCallExpression): String? {
|
fun getHeuristicVersionInBuildScriptDependency(classpathStatement: GrCallExpression): String? {
|
||||||
val argumentList = when (classpathStatement) {
|
val argumentList = when (classpathStatement) {
|
||||||
is GrMethodCall -> classpathStatement.argumentList // classpath('argument')
|
is GrMethodCall -> classpathStatement.argumentList // classpath('argument')
|
||||||
@@ -83,14 +85,18 @@ object GradleHeuristicHelper {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findStatementWithPrefix(closure: GrClosableBlock, prefix: String): List<GrCallExpression> {
|
fun findStatementWithPrefix(closure: GrClosableBlock, prefix: String) =
|
||||||
|
findStatementWithPrefixes(closure, setOf(prefix))
|
||||||
|
|
||||||
|
fun findStatementWithPrefixes(closure: GrClosableBlock, prefixes: Set<String>): List<GrCallExpression> {
|
||||||
val applicationStatements = closure.getChildrenOfType<GrCallExpression>()
|
val applicationStatements = closure.getChildrenOfType<GrCallExpression>()
|
||||||
|
|
||||||
val classPathStatements = ArrayList<GrCallExpression>()
|
val classPathStatements = ArrayList<GrCallExpression>()
|
||||||
|
|
||||||
for (statement in applicationStatements) {
|
for (statement in applicationStatements) {
|
||||||
val startExpression = statement.getChildrenOfType<GrReferenceExpression>().firstOrNull() ?: continue
|
val startExpression = statement.getChildrenOfType<GrReferenceExpression>().firstOrNull() ?: continue
|
||||||
if (prefix == startExpression.text) {
|
val expressionText = startExpression.text ?: continue
|
||||||
|
if (expressionText in prefixes) {
|
||||||
classPathStatements.add(statement)
|
classPathStatements.add(statement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+33
@@ -254,6 +254,39 @@ class GradleConfiguratorTest : GradleImportingTestCase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testListNonConfiguredModules_ConfiguredWithImplementation() {
|
||||||
|
createProjectSubFile("settings.gradle", "include ':app'")
|
||||||
|
createProjectSubFile(
|
||||||
|
"app/build.gradle", """
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'java'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.1.3"
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
createProjectSubFile("app/src/main/java/foo.kt", "")
|
||||||
|
|
||||||
|
importProject()
|
||||||
|
|
||||||
|
runReadAction {
|
||||||
|
assertEmpty(getCanBeConfiguredModulesWithKotlinFiles(myProject))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testListNonConfiguredModules_ConfiguredOnlyTest() {
|
fun testListNonConfiguredModules_ConfiguredOnlyTest() {
|
||||||
createProjectSubFile("settings.gradle", "include ':app'")
|
createProjectSubFile("settings.gradle", "include ':app'")
|
||||||
|
|||||||
+69
@@ -61,6 +61,39 @@ class GradleInspectionTest : GradleImportingTestCase() {
|
|||||||
Assert.assertEquals("Plugin version (1.0.2) is not the same as library version (1.0.3)", problems.single())
|
Assert.assertEquals("Plugin version (1.0.2) is not the same as library version (1.0.3)", problems.single())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDifferentStdlibGradleVersionWithImplementation() {
|
||||||
|
val localFile = createProjectSubFile(
|
||||||
|
"build.gradle", """
|
||||||
|
group 'Again'
|
||||||
|
version '1.0-SNAPSHOT'
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'kotlin'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.0.3"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
importProject()
|
||||||
|
|
||||||
|
val tool = DifferentStdlibGradleVersionInspection()
|
||||||
|
val problems = getInspectionResult(tool, localFile)
|
||||||
|
|
||||||
|
Assert.assertTrue(problems.size == 1)
|
||||||
|
Assert.assertEquals("Plugin version (1.0.2) is not the same as library version (1.0.3)", problems.single())
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testDifferentStdlibJre7GradleVersion() {
|
fun testDifferentStdlibJre7GradleVersion() {
|
||||||
val localFile = createProjectSubFile(
|
val localFile = createProjectSubFile(
|
||||||
@@ -274,6 +307,42 @@ class GradleInspectionTest : GradleImportingTestCase() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testJreIsDeprecatedWithImplementation() {
|
||||||
|
val localFile = createProjectSubFile(
|
||||||
|
"build.gradle", """
|
||||||
|
group 'Again'
|
||||||
|
version '1.0-SNAPSHOT'
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'kotlin'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
importProject()
|
||||||
|
|
||||||
|
val tool = DeprecatedGradleDependencyInspection()
|
||||||
|
val problems = getInspectionResult(tool, localFile)
|
||||||
|
|
||||||
|
Assert.assertTrue(problems.size == 1)
|
||||||
|
Assert.assertEquals(
|
||||||
|
"kotlin-stdlib-jre7 is deprecated since 1.2.0 and should be replaced with kotlin-stdlib-jdk7",
|
||||||
|
problems.single()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun getInspectionResult(tool: LocalInspectionTool, file: VirtualFile): List<String> {
|
fun getInspectionResult(tool: LocalInspectionTool, file: VirtualFile): List<String> {
|
||||||
val resultRef = Ref<List<String>>()
|
val resultRef = Ref<List<String>>()
|
||||||
invokeTestRunnable {
|
invokeTestRunnable {
|
||||||
|
|||||||
Reference in New Issue
Block a user