[gradle] dsl: support binary operator task declaration

GitOrigin-RevId: b7a22b66134927e1c7afc47da687dd8aa3d59315
This commit is contained in:
Daniil Ovchinnikov
2019-04-28 14:45:03 +03:00
committed by intellij-monorepo-bot
parent ff5feb4f2a
commit 305fba4b65
4 changed files with 95 additions and 39 deletions
@@ -70,9 +70,9 @@
<callTypeCalculator implementation="org.jetbrains.plugins.gradle.service.resolve.GradleProjectCallTypeCalculator"/>
<callTypeCalculator implementation="org.jetbrains.plugins.gradle.service.resolve.GradleArtifactCallTypeCalculator"/>
<delegatesToProvider implementation="org.jetbrains.plugins.gradle.service.resolve.GradleDelegatesToProvider"/>
<expressionFilter implementation="org.jetbrains.plugins.gradle.service.resolve.GradleTaskIdExpressionFilter"/>
<expressionFilter implementation="org.jetbrains.plugins.gradle.service.resolve.GradleTaskDeclarationExpressionFilter"/>
<typeCalculator forClass="org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression"
implementationClass="org.jetbrains.plugins.gradle.service.resolve.GradleTaskIdTypeCalculator"/>
implementationClass="org.jetbrains.plugins.gradle.service.resolve.GradleTaskDeclarationTypeCalculator"/>
<unresolvedHighlightFilter implementation="org.jetbrains.plugins.gradle.service.resolve.GradleUnresolvedReferenceFilter"/>
</extensions>
@@ -0,0 +1,87 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.gradle.service.resolve
import com.intellij.psi.CommonClassNames.JAVA_LANG_STRING
import com.intellij.psi.PsiType
import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_TASK
import org.jetbrains.plugins.groovy.lang.GroovyExpressionFilter
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinaryExpression
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression
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.literals.GrLiteral
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil.createType
import org.jetbrains.plugins.groovy.lang.typing.GrTypeCalculator
class GradleTaskDeclarationExpressionFilter : GroovyExpressionFilter {
override fun isFake(expression: GrExpression): Boolean = when (expression) {
is GrReferenceExpression -> isTaskIdExpression(expression) || isTaskIdExpressionInBinaryOp(expression)
is GrMethodCall -> isFakeTaskCall(expression)
else -> false
}
}
class GradleTaskDeclarationTypeCalculator : GrTypeCalculator<GrReferenceExpression> {
override fun getType(expression: GrReferenceExpression): PsiType? = when {
isTaskIdExpression(expression) -> createType(JAVA_LANG_STRING, expression.containingFile)
isTaskIdExpressionInBinaryOp(expression) -> createType(GRADLE_API_TASK, expression.containingFile)
else -> null
}
}
/**
* Matches `id` in: `task id`
* which gets transformed to: `task("id")`
*/
private fun isTaskIdExpression(expression: GrReferenceExpression): Boolean {
if (expression.isQualified) return false
if (!isFirstArgumentOfTaskMethod(expression)) return false
if (!expression.containingFile.isGradleScript()) return false
if (expression.staticReference.resolve() != null) return false
return true
}
/**
* Matches `id` in: `task id <op> right`
* which gets transformed to: `task("id") <op> right`
*/
private fun isTaskIdExpressionInBinaryOp(expression: GrReferenceExpression): Boolean {
if (expression.isQualified) return false
val binary = expression.parent as? GrBinaryExpression ?: return false
if (expression != binary.leftOperand) return false
if (!isFirstArgumentOfTaskMethod(binary)) return false
if (!expression.containingFile.isGradleScript()) return false
return true
}
private fun isFirstArgumentOfTaskMethod(expression: GrExpression): Boolean {
val argumentList = expression.parent as? GrArgumentList ?: return false
if (expression != argumentList.expressionArguments[0]) return false
val methodCall = argumentList.parent as? GrMethodCall ?: return false
return isTaskCall(methodCall)
}
/**
* Matches `task` in: `task id <op> right`
* which gets transformed to: `task("id") <op> right`
*/
private fun isFakeTaskCall(expression: GrMethodCall): Boolean {
return isTaskCall(expression) && isCallWithSingleBinaryExpressionArgument(expression)
}
private fun isTaskCall(methodCall: GrMethodCall): Boolean {
val invokedExpression = methodCall.invokedExpression as? GrReferenceExpression ?: return false
return invokedExpression.referenceName == "task" && !invokedExpression.isQualified
}
private fun isCallWithSingleBinaryExpressionArgument(methodCall: GrMethodCall): Boolean =
methodCall.namedArguments.isEmpty() &&
methodCall.closureArguments.isEmpty() &&
methodCall.expressionArguments.singleOrNull().let { argument ->
argument is GrBinaryExpression && argument.leftOperand.let { left ->
left is GrLiteral || left is GrReferenceExpression && !left.isQualified
}
}
@@ -1,37 +0,0 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.gradle.service.resolve
import com.intellij.psi.CommonClassNames.JAVA_LANG_STRING
import com.intellij.psi.PsiType
import org.jetbrains.plugins.groovy.lang.GroovyExpressionFilter
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression
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.impl.statements.expressions.TypesUtil.createType
import org.jetbrains.plugins.groovy.lang.typing.GrTypeCalculator
class GradleTaskIdExpressionFilter : GroovyExpressionFilter {
override fun isFake(expression: GrExpression): Boolean {
return expression is GrReferenceExpression && isTaskIdExpression(expression)
}
}
class GradleTaskIdTypeCalculator : GrTypeCalculator<GrReferenceExpression> {
override fun getType(expression: GrReferenceExpression): PsiType? {
return if (isTaskIdExpression(expression)) createType(JAVA_LANG_STRING, expression.containingFile) else null
}
}
private fun isTaskIdExpression(expression: GrReferenceExpression): Boolean {
if (expression.isQualified) return false
val argumentList = expression.parent as? GrArgumentList ?: return false
if (expression != argumentList.expressionArguments[0]) return false
val methodCall = argumentList.parent as? GrMethodCall ?: return false
val invokedExpression = methodCall.invokedExpression as? GrReferenceExpression ?: return false
if (invokedExpression.referenceName != "task") return false
if (invokedExpression.isQualified) return false
return expression.containingFile.isGradleScript() && expression.staticReference.resolve() == null
}
@@ -115,6 +115,8 @@ def t2_ = task<warning descr="'task' in 'org.gradle.api.Project' cannot be appli
def t3 = task(description: 'oh', idt3)
def t4 = task(description: 'hi', idt4, {})
def t4_ = task<warning descr="'task' in 'org.gradle.api.Project' cannot be applied to '(['description':java.lang.String], groovy.lang.Closure<java.lang.Void>, ?)'">(description: 'mark', {}, <warning descr="Cannot resolve symbol 'idt4_'">idt4_</warning>)</warning>
def t5 = task idt5 << {}
def t6 = task idt6 + {}
def insideClosure = {
def ct1 = task(cidt1)
@@ -123,6 +125,8 @@ def insideClosure = {
def ct3 = task(description: 'oh', cidt3)
def ct4 = task(description: 'hi', cidt4, {})
def ct4_ = task<warning descr="'task' in 'org.gradle.api.Project' cannot be applied to '(['description':java.lang.String], groovy.lang.Closure<java.lang.Void>, ?)'">(description: 'mark', {}, <warning descr="Cannot resolve symbol 'cidt4_'">cidt4_</warning>)</warning>
def ct5 = task cidt5 << {}
def ct6 = task cidt6 + {}
}
insideClosure()
@@ -133,6 +137,8 @@ def insideMethod() {
def mt3 = task(description: 'oh', midt3)
def mt4 = task(description: 'hi', midt4, {})
def mt4_ = task<warning descr="'task' in 'org.gradle.api.Project' cannot be applied to '(['description':java.lang.String], groovy.lang.Closure<java.lang.Void>, ?)'">(description: 'mark', {}, <warning descr="Cannot resolve symbol 'midt4_'">midt4_</warning>)</warning>
def mt5 = task midt5 << {}
def mt6 = task midt6 + {}
}
insideMethod()