mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[gradle] resolve ArtifactHandler methods using imported configurations data
This commit is contained in:
@@ -63,6 +63,7 @@
|
||||
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleScriptContributor"/>
|
||||
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleSetterAsMethodContributor"/>
|
||||
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleConventionsContributor"/>
|
||||
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleArtifactHandlerContributor"/>
|
||||
<delegatesToProvider implementation="org.jetbrains.plugins.gradle.service.resolve.GradleDelegatesToProvider"/>
|
||||
<referenceTypeEnhancer implementation="org.jetbrains.plugins.gradle.service.resolve.NamedDomainObjectCollectionTypeEnhancer"/>
|
||||
<unresolvedHighlightFilter implementation="org.jetbrains.plugins.gradle.service.resolve.GradleUnresolvedReferenceFilter"/>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<String>,
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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 { <caret> }') {
|
||||
closureDelegateTest(GRADLE_API_ARTIFACT_HANDLER, 1)
|
||||
}
|
||||
}
|
||||
|
||||
void 'artifacts member'() {
|
||||
void 'member'() {
|
||||
doTest('artifacts { <caret>add("conf", "notation") }') {
|
||||
methodTest(resolveTest(PsiMethod), "add", GRADLE_API_ARTIFACT_HANDLER)
|
||||
}
|
||||
}
|
||||
|
||||
void 'artifacts unresolved reference'() {
|
||||
void 'unresolved reference'() {
|
||||
doTest('artifacts { <caret>foo }') {
|
||||
resolveTest(null)
|
||||
}
|
||||
}
|
||||
|
||||
void 'unresolved configuration reference'() {
|
||||
doTest('artifacts { <caret>compile }') {
|
||||
resolveTest(null)
|
||||
}
|
||||
}
|
||||
|
||||
void 'invalid artifact addition'() {
|
||||
// foo configuration doesn't exist
|
||||
doTest('artifacts { <caret>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 { <caret>compile("artifactNotation") }', test)
|
||||
doTest('artifacts { <caret>compile("artifactNotation", "artifactNotation2", "artifactNotation3") }', test)
|
||||
doTest('artifacts.<caret>compile("artifactNotation")', test)
|
||||
doTest('artifacts.<caret>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 { <caret>compile("artifactNotation") {} }', test)
|
||||
doTest('artifacts.<caret>compile("artifactNotation") {}', test)
|
||||
}
|
||||
|
||||
void 'configuration delegate'() {
|
||||
doTest('artifacts { compile("artifactNotation") { <caret> } }') {
|
||||
closureDelegateTest(GRADLE_API_CONFIGURABLE_PUBLISH_ARTIFACT, 1)
|
||||
}
|
||||
}
|
||||
|
||||
void 'configuration delegate method setter'() {
|
||||
doTest('artifacts { compile("artifactNotation") { <caret>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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -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";
|
||||
|
||||
+6
-1
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user