mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-02-04 23:39:07 +07:00
[gradle] IDEA-325703: Allow generating setters for various gradle classes
GitOrigin-RevId: 85cea2fdb05577f4b96219e452e13cba3266d60f
This commit is contained in:
committed by
intellij-monorepo-bot
parent
94ba4e6f5f
commit
e2d099f419
@@ -89,7 +89,7 @@
|
||||
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleSettingsScriptContributor"/>
|
||||
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleScriptMembersContributor"/>
|
||||
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleProjectExtensionContributor"/>
|
||||
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.transformation.GradlePropertySetterMemberContributor"/>
|
||||
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.transformation.GradleSyntheticSetterMemberContributor"/>
|
||||
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.transformation.GradleConfigurableCallContributor"/>
|
||||
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.transformation.GradleActionToClosureMemberContributor"/>
|
||||
<membersContributor implementation="org.jetbrains.plugins.gradle.service.resolve.GradleProjectMembersContributor"/>
|
||||
|
||||
@@ -18,7 +18,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessProperties
|
||||
* For each getter with type [org.gradle.api.provider.Property], Gradle generates a corresponding setter
|
||||
* @see org.gradle.internal.instantiation.generator.AbstractClassGenerator
|
||||
*/
|
||||
class GradlePropertySetterMemberContributor : NonCodeMembersContributor() {
|
||||
class GradleSyntheticSetterMemberContributor : NonCodeMembersContributor() {
|
||||
override fun getClassNames(): Collection<String> = emptyList()
|
||||
|
||||
override fun getParentClassName(): String? = null
|
||||
@@ -49,23 +49,48 @@ class GradlePropertySetterMemberContributor : NonCodeMembersContributor() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hardcoded set of classes for which there is a synthetic setter generated
|
||||
*/
|
||||
private val assignmentPermittedClasses = listOf(
|
||||
GradleCommonClassNames.GRADLE_API_PROVIDER_PROPERTY,
|
||||
GradleCommonClassNames.GRADLE_API_FILE_CONFIGURABLE_FILE_COLLECTION,
|
||||
GradleCommonClassNames.GRADLE_API_PROVIDER_MAP_PROPERTY,
|
||||
GradleCommonClassNames.GRADLE_API_PROVIDER_HAS_MULTIPLE_VALUES,
|
||||
)
|
||||
|
||||
private fun processSetter(method: PsiMethod, simpleName : String, processor: PsiScopeProcessor, state: ResolveState) {
|
||||
if (!isSimplePropertyGetter(method)) {
|
||||
return
|
||||
}
|
||||
val returnType = method.returnType.asSafely<PsiClassType>() ?: return
|
||||
if (returnType.resolve()?.qualifiedName != GradleCommonClassNames.GRADLE_API_PROVIDER_PROPERTY) {
|
||||
val resolvedResult = returnType.resolveGenerics()
|
||||
val resolvedClass = resolvedResult.element ?: return
|
||||
if (resolvedClass.qualifiedName !in assignmentPermittedClasses && !hasGeneratedAssignmentInKotlin(resolvedClass)) {
|
||||
return
|
||||
}
|
||||
val setterName = getAccessorName(simpleName, PropertyKind.SETTER)
|
||||
val setter = with(LightMethodBuilder(method.manager, setterName)) {
|
||||
navigationElement = method
|
||||
containingClass = method.containingClass
|
||||
originInfo = "Generated by decoration of Gradle property getter"
|
||||
setMethodReturnType(PsiTypes.voidType())
|
||||
val innerParameter = returnType.parameters.singleOrNull() ?: return
|
||||
addParameter("value", innerParameter)
|
||||
this
|
||||
val backingSetters = resolvedClass.findMethodsAndTheirSubstitutorsByName("set", true) + resolvedClass.findMethodsAndTheirSubstitutorsByName("setFrom", true)
|
||||
for (backingSetter in backingSetters) {
|
||||
val generatedSetter = generateSetter(backingSetter.first, resolvedResult.substitutor, backingSetter.second, method, setterName)
|
||||
processor.execute(generatedSetter, state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateSetter(backingMethod: PsiMethod, deepSubstitutor: PsiSubstitutor, substitutor: PsiSubstitutor, originMethod: PsiMethod, setterName: String) : PsiMethod = LightMethodBuilder(backingMethod.manager, setterName).apply {
|
||||
navigationElement = originMethod
|
||||
containingClass = originMethod.containingClass
|
||||
originInfo = "Generated by decoration of Gradle property-like class"
|
||||
setMethodReturnType(PsiTypes.voidType())
|
||||
for (backingParameter in backingMethod.parameterList.parameters) {
|
||||
addParameter(backingParameter.name, deepSubstitutor.substitute(substitutor.substitute(backingParameter.type)))
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasGeneratedAssignmentInKotlin(clazz : PsiClass) : Boolean {
|
||||
val superClasses = arrayOf(clazz) + clazz.supers
|
||||
return superClasses.any {superClass ->
|
||||
superClass.annotations.any { it.hasQualifiedName(GradleCommonClassNames.GRADLE_API_SUPPORTS_KOTLIN_ASSIGNMENT_OVERLOADING) }
|
||||
}
|
||||
processor.execute(setter, state)
|
||||
}
|
||||
@@ -6,9 +6,12 @@ import com.intellij.psi.PsiMethod
|
||||
import com.intellij.testFramework.assertInstanceOf
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.plugins.gradle.testFramework.GradleCodeInsightTestCase
|
||||
import org.jetbrains.plugins.gradle.testFramework.GradleTestFixtureBuilder
|
||||
import org.jetbrains.plugins.gradle.testFramework.annotations.BaseGradleVersionSource
|
||||
import org.jetbrains.plugins.gradle.testFramework.util.withSettingsFile
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
@@ -61,4 +64,68 @@ class GradleResolveTest: GradleCodeInsightTestCase() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
fun testGradleGeneratedSetters(gradleVersion: GradleVersion) {
|
||||
test(gradleVersion, BUILD_SRC_FIXTURE) {
|
||||
testBuildscript("""
|
||||
tasks.register("myTask", MyTask) {
|
||||
myFirstPro<caret>perty = "value" // ok
|
||||
}
|
||||
""".trimIndent()) {
|
||||
val expression = elementUnderCaret(GrReferenceExpression::class.java)
|
||||
val results = expression.multiResolve(false)
|
||||
assertEquals(1, results.size)
|
||||
val method = assertInstanceOf<PsiMethod>(results[0].element)
|
||||
assertEquals("setMyFirstProperty", method.name)
|
||||
assertEquals("getMyFirstProperty", (method.navigationElement as PsiMethod).name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@BaseGradleVersionSource
|
||||
fun testGradleGeneratedSetters2(gradleVersion: GradleVersion) {
|
||||
test(gradleVersion, BUILD_SRC_FIXTURE) {
|
||||
testBuildscript("""
|
||||
tasks.register("myTask", MyTask) {
|
||||
myCollec<caret>tion = files("hello")
|
||||
}
|
||||
""".trimIndent()) {
|
||||
val expression = elementUnderCaret(GrReferenceExpression::class.java)
|
||||
val results = expression.multiResolve(false)
|
||||
assertEquals(1, results.size)
|
||||
val method = assertInstanceOf<PsiMethod>(results[0].element)
|
||||
assertEquals("setMyCollection", method.name)
|
||||
assertEquals("getMyCollection", (method.navigationElement as PsiMethod).name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val BUILD_SRC_FIXTURE = GradleTestFixtureBuilder.create("GradleResolveTest-buildSrc") {
|
||||
withSettingsFile {
|
||||
setProjectName("GradleResolveTest-buildSrc")
|
||||
}
|
||||
withFile("buildSrc/src/main/java/MyTask.java", """
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
|
||||
public abstract class MyTask extends DefaultTask {
|
||||
|
||||
@Input
|
||||
public abstract Property<String> getMyFirstProperty();
|
||||
|
||||
@InputFiles
|
||||
public abstract ConfigurableFileCollection getMyCollection();
|
||||
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,9 +87,12 @@ public final class GradleCommonClassNames {
|
||||
@NonNls public static final String GRADLE_API_EXTRA_PROPERTIES_EXTENSION = "org.gradle.api.plugins.ExtraPropertiesExtension";
|
||||
@NonNls public static final String GRADLE_PROCESS_EXEC_SPEC = "org.gradle.process.ExecSpec";
|
||||
@NonNls public static final String GRADLE_API_PROVIDER_PROPERTY = "org.gradle.api.provider.Property";
|
||||
@NonNls public static final String GRADLE_API_PROVIDER_MAP_PROPERTY = "org.gradle.api.provider.MapProperty";
|
||||
@NonNls public static final String GRADLE_API_PROVIDER_HAS_MULTIPLE_VALUES = "org.gradle.api.provider.HasMultipleValues";
|
||||
@NonNls public static final String GRADLE_API_PROVIDER_PROVIDER = "org.gradle.api.provider.Provider";
|
||||
@NonNls public static final String GRADLE_API_PROVIDER_PROVIDER_CONVERTIBLE = "org.gradle.api.provider.ProviderConvertible";
|
||||
@NonNls public static final String GRADLE_PLUGIN_USE_PLUGIN_DEPENDENCY = "org.gradle.plugin.use.PluginDependency";
|
||||
@NonNls public static final String GRADLE_API_SUPPORTS_KOTLIN_ASSIGNMENT_OVERLOADING = "org.gradle.api.SupportsKotlinAssignmentOverloading";
|
||||
|
||||
private GradleCommonClassNames() {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user