mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[groovy] reimplement @Vetoable support as transformation
This commit is contained in:
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package standardDsls
|
||||
|
||||
def vetoableMethods = {
|
||||
method name: "addVetoableChangeListener",
|
||||
type: "void",
|
||||
params: [propertyName: "java.lang.String",
|
||||
listener: "java.beans.VetoableChangeListener"],
|
||||
doc: """
|
||||
Add a VetoableChangeListener for a specific property. The listener will be invoked only when a call on
|
||||
fireVetoableChange names that specific property. The same listener object may be added more than once.
|
||||
For each property, the listener will be invoked the number of times it was added for that property. If
|
||||
propertyName or listener is null, no exception is thrown and no action is taken.
|
||||
@param propertyName The name of the property to listen on.
|
||||
@param listener The VetoableChangeListener to be added"""
|
||||
|
||||
method name: "addVetoableChangeListener",
|
||||
type: "void",
|
||||
params: [listener: "java.beans.VetoableChangeListener"],
|
||||
doc: """
|
||||
Add a VetoableListener to the listener list. The listener is registered for all properties. The same listener
|
||||
object may beadded more than once, and will be called as many times as it is added. If listener is null, no
|
||||
exception is thrown and no action is taken.
|
||||
@param listener The VetoableChangeListener to be added"""
|
||||
|
||||
method name: "removeVetoableChangeListener",
|
||||
type: "void",
|
||||
params: [propertyName: "java.lang.String",
|
||||
listener: "java.beans.VetoableChangeListener"],
|
||||
doc: """
|
||||
Remove a VetoableChangeListener for a specific property. If listener was added more than once to the same event
|
||||
source for the specified property, it will be notified one less time after being removed. If propertyName is null,
|
||||
no exception is thrown and no action is taken. If listener is null, or was never added for the specified property,
|
||||
no exception is thrown and no action is taken.
|
||||
@param propertyName The name of the property that was listened on.
|
||||
@param listener The VetoableChangeListener to be removed"""
|
||||
|
||||
method name: "removeVetoableChangeListener",
|
||||
type: "void",
|
||||
params: [listener: "java.beans.VetoableChangeListener"],
|
||||
doc: """
|
||||
Remove a VetoableChangeListener from the listener list. This removes a VetoableChangeListener that was registered
|
||||
for all properties. If listener was added more than once to the same event source, it will be notified one less
|
||||
time after being removed. If listener is null, or was never added, no exception is thrown and no action is taken.
|
||||
@param listener The VetoableChangeListener to be removed"""
|
||||
|
||||
method name: "fireVetoableChange",
|
||||
type: "void",
|
||||
params: [propertyName: "java.lang.String", oldValue: "java.lang.Object", newValue: "java.lang.Object"],
|
||||
doc: """
|
||||
Report a vetoable property update to any registered listeners. If anyone vetos the change, then fire a new event
|
||||
reverting everyone to the old value and then rethrow the PropertyVetoException.
|
||||
No event is fired if old and new are equal and non-null.
|
||||
@param propertyName The programmatic name of the property that is about to change..
|
||||
@param oldValue The old value of the property.
|
||||
@param newValue The new value of the property. """
|
||||
|
||||
method name: "getVetoableChangeListeners",
|
||||
type: "java.beans.VetoableChangeListener[]",
|
||||
doc: """
|
||||
Returns the list of VetoableChangeListeners. If named vetoable change listeners were added, then VetoableChangeListenerProxy
|
||||
wrappers will returned.
|
||||
@return List of VetoableChangeListeners and VetoableChangeListenerProxys if named property change listeners were added."""
|
||||
|
||||
method name: "getVetoableChangeListeners",
|
||||
type: "java.beans.VetoableChangeListener[]",
|
||||
params: [propertyName: "java.lang.String"],
|
||||
doc: """
|
||||
Returns an array of all the listeners which have been associated with the named property.
|
||||
@param propertyName The name of the property being listened to
|
||||
@return all the VetoableChangeListeners associated with the named property. If no such listeners have been added, or if
|
||||
propertyName is null, an empty array is returned."""
|
||||
}
|
||||
|
||||
contributor(ctype:hasField(hasAnnotation("groovy.beans.Vetoable"))) {
|
||||
if (psiClass?.fields?.find {it.hasAnnotation("groovy.beans.Vetoable")}) {
|
||||
Closure c = vetoableMethods.clone()
|
||||
c.delegate = delegate
|
||||
c.resolveStrategy = Closure.DELEGATE_FIRST
|
||||
c()
|
||||
}
|
||||
}
|
||||
+2
-5
@@ -94,7 +94,7 @@ import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.*;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyConstantExpressionEvaluator;
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.*;
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.ast.*;
|
||||
import org.jetbrains.plugins.groovy.transformations.impl.BindableTransformationSupport;
|
||||
import org.jetbrains.plugins.groovy.transformations.impl.*;
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.ast.builder.strategy.DefaultBuilderStrategySupport;
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.ast.builder.strategy.ExternalBuilderStrategySupport;
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.ast.builder.strategy.InitializerBuilderStrategySupport;
|
||||
@@ -108,10 +108,6 @@ import org.jetbrains.plugins.groovy.structure.GroovyStructureViewFactory;
|
||||
import org.jetbrains.plugins.groovy.swingBuilder.SwingBuilderNamedArgumentProvider;
|
||||
import org.jetbrains.plugins.groovy.swingBuilder.SwingBuilderNonCodeMemberContributor;
|
||||
import org.jetbrains.plugins.groovy.transformations.AstTransformationSupport;
|
||||
import org.jetbrains.plugins.groovy.transformations.impl.CategoryTransformationSupport;
|
||||
import org.jetbrains.plugins.groovy.transformations.impl.DefaultTransformationSupport;
|
||||
import org.jetbrains.plugins.groovy.transformations.impl.DelegateTransformationSupport;
|
||||
import org.jetbrains.plugins.groovy.transformations.impl.TraitTransformationSupport;
|
||||
|
||||
/**
|
||||
* Upsource
|
||||
@@ -156,6 +152,7 @@ public class GroovyCoreEnvironment {
|
||||
appEnvironment.addExtension(AstTransformationSupport.EP_NAME, new ExternalBuilderStrategySupport());
|
||||
appEnvironment.addExtension(AstTransformationSupport.EP_NAME, new InitializerBuilderStrategySupport());
|
||||
appEnvironment.addExtension(AstTransformationSupport.EP_NAME, new BindableTransformationSupport());
|
||||
appEnvironment.addExtension(AstTransformationSupport.EP_NAME, new VetoableTransformationSupport());
|
||||
appEnvironment.addExtension(AstTransformationSupport.EP_NAME, new LoggingContributor());
|
||||
appEnvironment.addExtension(AstTransformationSupport.EP_NAME, new CategoryTransformationSupport());
|
||||
appEnvironment.addExtension(AstTransformationSupport.EP_NAME, new DelegateTransformationSupport());
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.transformations.impl
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil
|
||||
import com.intellij.psi.CommonClassNames
|
||||
import com.intellij.psi.PsiArrayType
|
||||
import com.intellij.psi.PsiModifier
|
||||
import com.intellij.psi.PsiType
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil
|
||||
import org.jetbrains.plugins.groovy.transformations.AstTransformationSupport
|
||||
import org.jetbrains.plugins.groovy.transformations.TransformationContext
|
||||
|
||||
private val VETOABLE_FQN = "groovy.beans.Vetoable"
|
||||
private val VCL_FQN = "java.beans.VetoableChangeListener"
|
||||
private val VCS_FQN = "java.beans.VetoableChangeSupport"
|
||||
val ORIGIN_INFO = "via @Vetoable"
|
||||
|
||||
class VetoableTransformationSupport : AstTransformationSupport {
|
||||
|
||||
override fun applyTransformation(context: TransformationContext) {
|
||||
val clazz = context.codeClass
|
||||
if (!isApplicable(clazz)) return
|
||||
|
||||
val methods = mutableListOf<GrLightMethodBuilder>()
|
||||
|
||||
methods += context.memberBuilder.method ("addVetoableChangeListener") {
|
||||
returnType = PsiType.VOID
|
||||
addParameter("propertyName", CommonClassNames.JAVA_LANG_STRING)
|
||||
addParameter("listener", VCL_FQN)
|
||||
}
|
||||
|
||||
methods += context.memberBuilder.method("addVetoableChangeListener") {
|
||||
returnType = PsiType.VOID
|
||||
addParameter("listener", VCL_FQN)
|
||||
}
|
||||
|
||||
methods += context.memberBuilder.method("removeVetoableChangeListener") {
|
||||
returnType = PsiType.VOID
|
||||
addParameter("propertyName", CommonClassNames.JAVA_LANG_STRING)
|
||||
addParameter("listener", VCL_FQN)
|
||||
}
|
||||
|
||||
methods += context.memberBuilder.method("removeVetoableChangeListener") {
|
||||
returnType = PsiType.VOID
|
||||
addParameter("listener", VCL_FQN)
|
||||
}
|
||||
|
||||
methods += context.memberBuilder.method("fireVetoableChange") {
|
||||
returnType = PsiType.VOID
|
||||
addParameter("propertyName", CommonClassNames.JAVA_LANG_STRING)
|
||||
addParameter("oldValue", CommonClassNames.JAVA_LANG_OBJECT)
|
||||
addParameter("newValue", CommonClassNames.JAVA_LANG_OBJECT)
|
||||
}
|
||||
|
||||
val vclArrayType = PsiArrayType(TypesUtil.createType(VCL_FQN, context.codeClass))
|
||||
|
||||
methods += context.memberBuilder.method("getVetoableChangeListeners") {
|
||||
returnType = vclArrayType
|
||||
}
|
||||
|
||||
methods += context.memberBuilder.method("getVetoableChangeListeners") {
|
||||
returnType = vclArrayType
|
||||
addParameter("propertyName", CommonClassNames.JAVA_LANG_STRING)
|
||||
}
|
||||
|
||||
val docDelegate = context.psiFacade.findClass(VCS_FQN, context.resolveScope)
|
||||
for (method in methods) {
|
||||
method.addModifier(PsiModifier.PUBLIC)
|
||||
method.originInfo = ORIGIN_INFO
|
||||
method.putUserData(ResolveUtil.DOCUMENTATION_DELEGATE, docDelegate?.findMethodBySignature(method, false))
|
||||
}
|
||||
|
||||
context.addMethods(methods)
|
||||
}
|
||||
|
||||
private fun isApplicable(clazz: GrTypeDefinition): Boolean {
|
||||
val annotation = AnnotationUtil.findAnnotation(clazz, true, VETOABLE_FQN)
|
||||
if (annotation != null) return true
|
||||
|
||||
for (method in clazz.codeFields) {
|
||||
if (AnnotationUtil.findAnnotation(method, true, VETOABLE_FQN) != null) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -125,6 +125,7 @@
|
||||
<astTransformationSupport implementation="org.jetbrains.plugins.groovy.lang.resolve.ast.builder.strategy.ExternalBuilderStrategySupport"/>
|
||||
<astTransformationSupport implementation="org.jetbrains.plugins.groovy.lang.resolve.ast.builder.strategy.InitializerBuilderStrategySupport"/>
|
||||
<astTransformationSupport implementation="org.jetbrains.plugins.groovy.transformations.impl.BindableTransformationSupport"/>
|
||||
<astTransformationSupport implementation="org.jetbrains.plugins.groovy.transformations.impl.VetoableTransformationSupport"/>
|
||||
|
||||
<astTransformationSupport implementation="org.jetbrains.plugins.groovy.lang.resolve.ast.LoggingContributor"/>
|
||||
<astTransformationSupport implementation="org.jetbrains.plugins.groovy.transformations.impl.CategoryTransformationSupport"/>
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.transformations
|
||||
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.psi.PsiCall
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiExpressionStatement
|
||||
import com.intellij.psi.PsiJavaFile
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture
|
||||
import groovy.transform.CompileStatic
|
||||
import org.jetbrains.plugins.groovy.SetupRule
|
||||
import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection
|
||||
import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil
|
||||
import org.jetbrains.plugins.groovy.transformations.impl.VetoableTransformationSupportKt
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
@CompileStatic
|
||||
@RunWith(Parameterized)
|
||||
class GrVetoableSupportTest {
|
||||
|
||||
public @Rule SetupRule setupRule = new SetupRule()
|
||||
|
||||
JavaCodeInsightTestFixture getFixture() {
|
||||
setupRule.testCase.fixture
|
||||
}
|
||||
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
public static Collection<Object[]> data() {
|
||||
[
|
||||
'@Vetoable on class' : '@groovy.beans.Vetoable class Person {}',
|
||||
'@Vetoable on class @CompileStatic': '@groovy.transform.CompileStatic @groovy.beans.Vetoable class Person {}',
|
||||
'@Vetoable on field' : 'class Person { @groovy.beans.Vetoable foo }',
|
||||
'@Vetoable on field @CompileStatic': '@groovy.transform.CompileStatic class Person { @groovy.beans.Vetoable foo }'
|
||||
].collect { k, v ->
|
||||
[k, v] as Object[]
|
||||
}
|
||||
}
|
||||
|
||||
@Parameterized.Parameter
|
||||
public String name
|
||||
|
||||
@Parameterized.Parameter(1)
|
||||
public String clazzText
|
||||
|
||||
private PsiClass clazz
|
||||
|
||||
@Before
|
||||
void addPerson() {
|
||||
fixture.addFileToProject('Person.groovy', clazzText)
|
||||
clazz = fixture.findClass('Person')
|
||||
assert clazz
|
||||
}
|
||||
|
||||
@Test
|
||||
void 'test groovy'() {
|
||||
fixture.enableInspections(GrUnresolvedAccessInspection, GroovyAssignabilityCheckInspection)
|
||||
[
|
||||
"new Person().addVetoableChangeListener {}",
|
||||
"new Person().addVetoableChangeListener('') {}",
|
||||
"new Person().removeVetoableChangeListener {}",
|
||||
"new Person().removeVetoableChangeListener('') {}",
|
||||
"new Person().fireVetoableChange('', null, null)",
|
||||
"new Person().getVetoableChangeListeners()",
|
||||
"new Person().getVetoableChangeListeners('')"
|
||||
].each {
|
||||
def file = fixture.configureByText('test.groovy', it) as GroovyFile
|
||||
def call = file.statements.last() as GrCall
|
||||
def method = call.resolveMethod() as GrLightMethodBuilder
|
||||
assert method
|
||||
assert method.containingClass == clazz
|
||||
assert method.originInfo == VetoableTransformationSupportKt.ORIGIN_INFO
|
||||
assert method.getUserData(ResolveUtil.DOCUMENTATION_DELEGATE)
|
||||
fixture.checkHighlighting()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void 'test java'() {
|
||||
LanguageLevelProjectExtension.getInstance(fixture.project).languageLevel = LanguageLevel.HIGHEST
|
||||
[
|
||||
'new Person().addVetoableChangeListener(e -> {});',
|
||||
'new Person().addVetoableChangeListener("", e -> {});',
|
||||
'new Person().removeVetoableChangeListener(e -> {});',
|
||||
'new Person().removeVetoableChangeListener("", e -> {});',
|
||||
'new Person().fireVetoableChange("", null, null);',
|
||||
'new Person().getVetoableChangeListeners();',
|
||||
'new Person().getVetoableChangeListeners("");'
|
||||
].each {
|
||||
def file = fixture.configureByText('Main.java', "class Main { void bar() {$it} }") as PsiJavaFile
|
||||
def call = (file.classes[0].methods[0].body.statements[0] as PsiExpressionStatement).expression as PsiCall
|
||||
def method = call.resolveMethod() as GrLightMethodBuilder
|
||||
assert method
|
||||
assert method.containingClass == clazz
|
||||
assert method.originInfo == VetoableTransformationSupportKt.ORIGIN_INFO
|
||||
fixture.checkHighlighting()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user