diff --git a/plugins/gradle/java/resources/META-INF/gradle-groovy-integration.xml b/plugins/gradle/java/resources/META-INF/gradle-groovy-integration.xml
index 37fd60052ca9..1b23735b4f2e 100644
--- a/plugins/gradle/java/resources/META-INF/gradle-groovy-integration.xml
+++ b/plugins/gradle/java/resources/META-INF/gradle-groovy-integration.xml
@@ -63,6 +63,7 @@
+
diff --git a/plugins/gradle/java/src/service/resolve/GradleArtifactHandlerContributor.kt b/plugins/gradle/java/src/service/resolve/GradleArtifactHandlerContributor.kt
new file mode 100644
index 000000000000..e7dcd306a1d3
--- /dev/null
+++ b/plugins/gradle/java/src/service/resolve/GradleArtifactHandlerContributor.kt
@@ -0,0 +1,63 @@
+// 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.*
+import com.intellij.psi.scope.PsiScopeProcessor
+import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_ARTIFACT_HANDLER
+import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_CONFIGURABLE_PUBLISH_ARTIFACT
+import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil.createType
+import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil.getJavaLangObject
+import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder
+import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE
+import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor
+import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_KEY
+import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_STRATEGY_KEY
+import org.jetbrains.plugins.groovy.lang.resolve.getName
+import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessMethods
+
+class GradleArtifactHandlerContributor : NonCodeMembersContributor() {
+
+ override fun getParentClassName(): String? = GRADLE_API_ARTIFACT_HANDLER
+
+ override fun processDynamicElements(qualifierType: PsiType,
+ clazz: PsiClass?,
+ processor: PsiScopeProcessor,
+ place: PsiElement,
+ state: ResolveState) {
+ if (clazz == null) return
+ if (!processor.shouldProcessMethods()) return
+
+ val data = GradleExtensionsContributor.getExtensionsFor(place) ?: return
+ val methodName = processor.getName(state)
+ val manager = place.manager
+ val objectType = getJavaLangObject(place)
+ val objectVarargType = PsiEllipsisType(objectType)
+ val closureType = createType(GROOVY_LANG_CLOSURE, place)
+ val configurableArtifactType = createType(GRADLE_API_CONFIGURABLE_PUBLISH_ARTIFACT, place)
+
+ // TODO store configurations in a map
+ for (configuration in data.configurations) {
+ val configurationName = configuration.name ?: continue
+ if (methodName != null && configurationName != methodName) continue
+
+ val method1 = GrLightMethodBuilder(manager, configurationName).apply {
+ containingClass = clazz
+ returnType = configurableArtifactType
+ addParameter("artifactNotation", objectType)
+ addAndGetParameter("configureClosure", closureType).apply {
+ putUserData(DELEGATES_TO_KEY, GRADLE_API_CONFIGURABLE_PUBLISH_ARTIFACT)
+ putUserData(DELEGATES_TO_STRATEGY_KEY, 1)
+ }
+ }
+ if (!processor.execute(method1, state)) return
+
+ val method2 = GrLightMethodBuilder(manager, configurationName).apply {
+ containingClass = clazz
+ returnType = PsiType.NULL
+ addParameter("artifactNotation", objectType)
+ addParameter("artifactNotations", objectVarargType)
+ }
+ if (!processor.execute(method2, state)) return
+ }
+ }
+}
diff --git a/plugins/gradle/java/src/service/resolve/GradleArtifactsContributor.kt b/plugins/gradle/java/src/service/resolve/GradleArtifactsContributor.kt
index 1eeeae627068..625fea3802fb 100644
--- a/plugins/gradle/java/src/service/resolve/GradleArtifactsContributor.kt
+++ b/plugins/gradle/java/src/service/resolve/GradleArtifactsContributor.kt
@@ -1,28 +1,14 @@
// 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.patterns.PsiJavaPatterns.psiElement
-import com.intellij.psi.CommonClassNames.JAVA_LANG_OBJECT
-import com.intellij.psi.JavaPsiFacade
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiType
-import com.intellij.psi.ResolveState
-import com.intellij.psi.scope.PsiScopeProcessor
-import com.intellij.psi.util.PsiTreeUtil
import groovy.lang.Closure
-import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.*
+import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_ARTIFACT_HANDLER
+import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_PROJECT
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.GrReferenceExpression
-import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil
-import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightField
-import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder
-import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter
import org.jetbrains.plugins.groovy.lang.psi.patterns.GroovyClosurePattern
import org.jetbrains.plugins.groovy.lang.psi.patterns.groovyClosure
import org.jetbrains.plugins.groovy.lang.psi.patterns.psiMethod
-import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil
import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DelegatesToInfo
/**
@@ -34,53 +20,10 @@ class GradleArtifactsContributor : GradleMethodContextContributor {
val artifactsClosure: GroovyClosurePattern = groovyClosure().inMethod(psiMethod(GRADLE_API_PROJECT, "artifacts"))
}
- override fun process(methodCallInfo: List,
- processor: PsiScopeProcessor,
- state: ResolveState,
- place: PsiElement): Boolean {
- val methodName = if (methodCallInfo.isNotEmpty()) methodCallInfo[0] else null
- if (methodName != null && place is GrReferenceExpression && psiElement().inside(artifactsClosure).accepts(place)) {
- val text = place.text
- if (!methodCallInfo.contains(text)) {
- return false
- }
- // assuming that the method call is addition of an artifact to the given configuration.
- if (!processArtifactAddition(processor, state, place)) return false
- }
- return true
- }
-
override fun getDelegatesToInfo(closure: GrClosableBlock): DelegatesToInfo? {
if (artifactsClosure.accepts(closure)) {
return DelegatesToInfo(TypesUtil.createType(GRADLE_API_ARTIFACT_HANDLER, closure), Closure.DELEGATE_FIRST)
}
return null
}
-
- private fun processArtifactAddition(processor: PsiScopeProcessor,
- state: ResolveState,
- place: PsiElement): Boolean {
- val name = ResolveUtil.getNameHint(processor) ?: return true
- val groovyPsiManager = GroovyPsiManager.getInstance(place.project)
- val artifactHandlerClass = JavaPsiFacade.getInstance(place.project).findClass(GRADLE_API_ARTIFACT_HANDLER, place.resolveScope)
- ?: return true
-
- val call = PsiTreeUtil.getParentOfType(place, GrMethodCall::class.java) ?: return true
- val returnClass = groovyPsiManager.createTypeByFQClassName(GRADLE_API_PUBLISH_ARTIFACT, place.resolveScope) ?: return true
- val type = PsiType.getJavaLangObject(place.manager, place.resolveScope).createArrayType()
- val builder = GrLightMethodBuilder(place.manager, name).apply {
- containingClass = artifactHandlerClass
- addParameter(GrLightParameter("artifactNotation", type, place))
- returnType = returnClass
- }
- val args = call.argumentList
-
- var argsCount = GradleResolverUtil.getGrMethodArumentsCount(args)
- argsCount++ // Configuration name is delivered as an argument.
-
- val method = artifactHandlerClass.findMethodsByName("add", false).firstOrNull { it.parameterList.parametersCount == argsCount }
- if (method != null) builder.navigationElement = method
-
- return processor.execute(builder, state)
- }
}
diff --git a/plugins/gradle/java/src/service/resolve/GradleSetterAsMethodContributor.kt b/plugins/gradle/java/src/service/resolve/GradleSetterAsMethodContributor.kt
index 00da0871bcaa..5167df338ac2 100644
--- a/plugins/gradle/java/src/service/resolve/GradleSetterAsMethodContributor.kt
+++ b/plugins/gradle/java/src/service/resolve/GradleSetterAsMethodContributor.kt
@@ -8,8 +8,7 @@ import com.intellij.psi.scope.NameHint
import com.intellij.psi.scope.ProcessorWithHints
import com.intellij.psi.scope.PsiScopeProcessor
import com.intellij.util.text.nullize
-import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_ARTIFACTS_MODULE_DEPENDENCY
-import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_PROJECT
+import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.*
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrMethodWrapper
import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor
import org.jetbrains.plugins.groovy.lang.resolve.getName
@@ -20,6 +19,7 @@ class GradleSetterAsMethodContributor : NonCodeMembersContributor() {
companion object {
val knownDecoratedClasses = setOf(
GRADLE_API_PROJECT,
+ GRADLE_API_CONFIGURABLE_PUBLISH_ARTIFACT,
GRADLE_API_ARTIFACTS_MODULE_DEPENDENCY
)
}
diff --git a/plugins/gradle/java/testSources/dsl/GradleArtifactsTest.groovy b/plugins/gradle/java/testSources/dsl/GradleArtifactsTest.groovy
index 45ad78bbcb2e..b119e101d07c 100644
--- a/plugins/gradle/java/testSources/dsl/GradleArtifactsTest.groovy
+++ b/plugins/gradle/java/testSources/dsl/GradleArtifactsTest.groovy
@@ -2,13 +2,16 @@
package org.jetbrains.plugins.gradle.dsl
import com.intellij.psi.PsiMethod
+import com.intellij.psi.PsiType
import com.intellij.testFramework.RunAll
import groovy.transform.CompileStatic
import org.jetbrains.plugins.gradle.highlighting.GradleHighlightingBaseTest
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall
import org.jetbrains.plugins.groovy.util.ResolveTest
import org.junit.Test
import static org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_ARTIFACT_HANDLER
+import static org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames.GRADLE_API_CONFIGURABLE_PUBLISH_ARTIFACT
@CompileStatic
class GradleArtifactsTest extends GradleHighlightingBaseTest implements ResolveTest {
@@ -17,11 +20,23 @@ class GradleArtifactsTest extends GradleHighlightingBaseTest implements ResolveT
void artifactsTest() {
importProject("apply plugin: 'java'")
new RunAll().append {
- 'artifacts closure delegate'()
+ 'closure delegate'()
} append {
- 'artifacts member'()
+ 'member'()
} append {
- 'artifacts unresolved reference'()
+ 'unresolved reference'()
+ } append {
+ 'unresolved configuration reference'()
+ } append {
+ 'invalid artifact addition'()
+ } append {
+ 'artifact addition'()
+ } append {
+ 'configurable artifact addition'()
+ } append {
+ 'configuration delegate'()
+ } append {
+ 'configuration delegate method setter'()
} run()
}
@@ -30,21 +45,76 @@ class GradleArtifactsTest extends GradleHighlightingBaseTest implements ResolveT
return super.getParentCalls() + 'buildscript'
}
- void 'artifacts closure delegate'() {
+ void 'closure delegate'() {
doTest('artifacts { }') {
closureDelegateTest(GRADLE_API_ARTIFACT_HANDLER, 1)
}
}
- void 'artifacts member'() {
+ void 'member'() {
doTest('artifacts { add("conf", "notation") }') {
methodTest(resolveTest(PsiMethod), "add", GRADLE_API_ARTIFACT_HANDLER)
}
}
- void 'artifacts unresolved reference'() {
+ void 'unresolved reference'() {
doTest('artifacts { foo }') {
resolveTest(null)
}
}
+
+ void 'unresolved configuration reference'() {
+ doTest('artifacts { compile }') {
+ resolveTest(null)
+ }
+ }
+
+ void 'invalid artifact addition'() {
+ // foo configuration doesn't exist
+ doTest('artifacts { foo("artifactNotation") }') {
+ assertEmpty(elementUnderCaret(GrMethodCall).multiResolve(false))
+ }
+ }
+
+ void 'artifact addition'() {
+ def test = {
+ def call = elementUnderCaret(GrMethodCall)
+ def result = assertOneElement(call.multiResolve(false))
+ methodTest(assertInstanceOf(result.element, PsiMethod), "compile", GRADLE_API_ARTIFACT_HANDLER)
+ assert result.applicable
+ assert call.type == PsiType.NULL
+ }
+ doTest('artifacts { compile("artifactNotation") }', test)
+ doTest('artifacts { compile("artifactNotation", "artifactNotation2", "artifactNotation3") }', test)
+ doTest('artifacts.compile("artifactNotation")', test)
+ doTest('artifacts.compile("artifactNotation", "artifactNotation2", "artifactNotation3")', test)
+ }
+
+ void 'configurable artifact addition'() {
+ def test = {
+ def call = elementUnderCaret(GrMethodCall)
+ def result = assertOneElement(call.multiResolve(false))
+ methodTest(assertInstanceOf(result.element, PsiMethod), "compile", GRADLE_API_ARTIFACT_HANDLER)
+ assert result.applicable
+ assert call.type.equalsToText(GRADLE_API_CONFIGURABLE_PUBLISH_ARTIFACT)
+ }
+ doTest('artifacts { compile("artifactNotation") {} }', test)
+ doTest('artifacts.compile("artifactNotation") {}', test)
+ }
+
+ void 'configuration delegate'() {
+ doTest('artifacts { compile("artifactNotation") { } }') {
+ closureDelegateTest(GRADLE_API_CONFIGURABLE_PUBLISH_ARTIFACT, 1)
+ }
+ }
+
+ void 'configuration delegate method setter'() {
+ doTest('artifacts { compile("artifactNotation") { name("hi") } }') {
+ def result = assertOneElement(elementUnderCaret(GrMethodCall).multiResolve(false))
+ def method = assertInstanceOf(result.element, PsiMethod)
+ methodTest(method, 'name', GRADLE_API_CONFIGURABLE_PUBLISH_ARTIFACT)
+ def original = assertInstanceOf(method.navigationElement, PsiMethod)
+ methodTest(original, 'setName', GRADLE_API_CONFIGURABLE_PUBLISH_ARTIFACT)
+ }
+ }
}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/resolve/GradleCommonClassNames.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/resolve/GradleCommonClassNames.java
index cc4155a8b24b..6609e960f68f 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/resolve/GradleCommonClassNames.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/resolve/GradleCommonClassNames.java
@@ -19,6 +19,7 @@ public final class GradleCommonClassNames {
@NonNls public static final String GRADLE_API_CONFIGURATION = "org.gradle.api.artifacts.Configuration";
@NonNls public static final String GRADLE_API_ARTIFACT_HANDLER = "org.gradle.api.artifacts.dsl.ArtifactHandler";
@NonNls public static final String GRADLE_API_PUBLISH_ARTIFACT = "org.gradle.api.artifacts.PublishArtifact";
+ @NonNls public static final String GRADLE_API_CONFIGURABLE_PUBLISH_ARTIFACT = "org.gradle.api.artifacts.ConfigurablePublishArtifact";
@NonNls public static final String GRADLE_API_PUBLICATION_CONTAINER = "org.gradle.api.publish.PublicationContainer";
@NonNls public static final String GRADLE_API_DEPENDENCY_HANDLER = "org.gradle.api.artifacts.dsl.DependencyHandler";
@NonNls public static final String GRADLE_API_COMPONENT_METADATA_HANDLER = "org.gradle.api.artifacts.dsl.ComponentMetadataHandler";
diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightMethodBuilder.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightMethodBuilder.java
index 375c76dfbed1..0a044abb0f64 100644
--- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightMethodBuilder.java
+++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrLightMethodBuilder.java
@@ -1,4 +1,4 @@
-// Copyright 2000-2018 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.
+// 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.groovy.lang.psi.impl.synthetic;
import com.intellij.navigation.ItemPresentation;
@@ -274,6 +274,11 @@ public class GrLightMethodBuilder extends LightElement implements GrMethod, Orig
return addAndGetParameter(name, type, false);
}
+ @NotNull
+ public GrLightParameter addAndGetParameter(@NotNull String name, @NotNull PsiType type) {
+ return addAndGetParameter(name, type, false);
+ }
+
@NotNull
public GrLightParameter addAndGetOptionalParameter(@NotNull String name, @NotNull String type) {
return addAndGetParameter(name, type, true);