From ec6da702771899d73c4b8d963c82a5e97def908b Mon Sep 17 00:00:00 2001 From: "alexey.afanasiev" Date: Fri, 26 May 2017 17:22:17 +0300 Subject: [PATCH] IDEA-170804 Idea does't support @Newify annotation --- .../standardDsls/newifyTransform.gdsl | 53 ------ .../GroovyNamedArgumentProvider.java | 1 + ...roovyConstructorNamedArgumentProvider.java | 38 ++-- .../GroovyNewExprNamedArgumentProvider.kt | 34 ++++ .../lang/GroovyNewifyNamedArgumentProvider.kt | 30 +++ .../plugins/groovy/lang/psi/util/PsiUtil.java | 13 +- .../noncode/NewifyMemberContributor.kt | 99 ++++++++++ plugins/groovy/src/META-INF/plugin.xml | 4 +- .../dsl/GroovyTransformationsTest.groovy | 13 +- .../lang/resolve/NewifySupportTest.groovy | 171 ++++++++++++++++++ .../lang/resolve/ResolveMethodTest.groovy | 105 +++++++++++ .../dsl/transform/NewifyTransform1.groovy | 3 - .../dsl/transform/NewifyTransform2.groovy | 13 -- .../dsl/transform/NewifyTransform3.groovy | 25 --- 14 files changed, 469 insertions(+), 133 deletions(-) delete mode 100644 plugins/groovy/groovy-psi/resources/standardDsls/newifyTransform.gdsl create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyNewExprNamedArgumentProvider.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyNewifyNamedArgumentProvider.kt create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/NewifyMemberContributor.kt create mode 100644 plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/NewifySupportTest.groovy delete mode 100644 plugins/groovy/testdata/groovy/dsl/transform/NewifyTransform1.groovy delete mode 100644 plugins/groovy/testdata/groovy/dsl/transform/NewifyTransform2.groovy delete mode 100644 plugins/groovy/testdata/groovy/dsl/transform/NewifyTransform3.groovy diff --git a/plugins/groovy/groovy-psi/resources/standardDsls/newifyTransform.gdsl b/plugins/groovy/groovy-psi/resources/standardDsls/newifyTransform.gdsl deleted file mode 100644 index 93e4a091561c..000000000000 --- a/plugins/groovy/groovy-psi/resources/standardDsls/newifyTransform.gdsl +++ /dev/null @@ -1,53 +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 - -import com.intellij.psi.PsiClass - -contributor(context(scope:annotatedScope(ctype: "groovy.lang.Newify"))) { - // For methods - def memb = enclosingMember() - if (memb) { - // For classes - def newifyName = "groovy.lang.Newify" - def annotated = memb.getAnnotations(newifyName) - - def clazz = enclosingClass() - if (clazz) { - annotated += clazz.getAnnotations(newifyName) - } - for (a in annotated) { - def refs = a.findAttributeValue("value") - def auto = a.findAttributeValue("auto") - //For Python-like style - if (refs && !place.qualifier) { - for (c in refs.asList()) { - def targetClass = c.bind() - for (cons in (targetClass?.constructors ?: [])) { - method name: ((PsiClass) targetClass).name, params: cons.paramStringVector, type: targetClass.qualName - } - } - } - - // For Ruby-like style - if (!auto || auto.eval()) { - for (cons in psiClass?.getConstructors()) { - method name: 'new', isStatic: true, params: cons.paramStringVector, type: psiClass?.qualName ?: "java.lang.Object" - } - } - } - } -} \ No newline at end of file diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java index 396f0e1ca13c..2c9d87728ca3 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/extensions/GroovyNamedArgumentProvider.java @@ -109,6 +109,7 @@ public abstract class GroovyNamedArgumentProvider { if (element instanceof PsiMethod) { PsiMethod method = (PsiMethod)element; + method = PsiUtil.handleMirrorMethod(method); PsiParameter[] parameters = method.getParameterList().getParameters(); if (!method.isConstructor() && !(parameters.length > 0 && canBeMap(parameters[0]))) continue; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyConstructorNamedArgumentProvider.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyConstructorNamedArgumentProvider.java index e970aafba57e..06914787dcca 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyConstructorNamedArgumentProvider.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyConstructorNamedArgumentProvider.java @@ -32,7 +32,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; @@ -42,54 +41,43 @@ import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint; import java.util.EnumSet; import java.util.HashMap; +import java.util.List; import java.util.Map; /** * @author Sergey Evdokimov */ -public class GroovyConstructorNamedArgumentProvider extends GroovyNamedArgumentProvider { +public abstract class GroovyConstructorNamedArgumentProvider extends GroovyNamedArgumentProvider { private static final String METACLASS = "metaClass"; + @NotNull + abstract List getCorrespondingClasses(@NotNull GrCall call, @NotNull GroovyResolveResult resolveResult); + @Override public void getNamedArguments(@NotNull GrCall call, @NotNull GroovyResolveResult resolveResult, @Nullable String argumentName, boolean forCompletion, @NotNull Map result) { - if (!(call instanceof GrNewExpression)) return; - PsiElement resolve = resolveResult.getElement(); - - if (resolve != null) { - if (!(resolve instanceof PsiMethod)) return; - PsiMethod method = (PsiMethod)resolve; - if (!method.isConstructor()) return; - } - - GrNewExpression newCall = (GrNewExpression)call; - - GrArgumentList argumentList = newCall.getArgumentList(); + GrArgumentList argumentList = call.getArgumentList(); if (argumentList == null) return; - GrExpression[] expressionArguments = argumentList.getExpressionArguments(); if (expressionArguments.length > 1 || (expressionArguments.length == 1 && !(expressionArguments[0] instanceof GrReferenceExpression))) { return; } - for (GroovyResolveResult newResult : newCall.multiResolveClass()) { - PsiElement element = newResult.getElement(); - if (!(element instanceof PsiClass)) continue; + for (PsiClass psiClass : getCorrespondingClasses(call, resolveResult)) { + if (!isClassHasConstructorWithMap(psiClass)) continue; - PsiClass aClass = (PsiClass)element; - - if (!isClassHasConstructorWithMap(aClass)) continue; - - PsiClassType classType = JavaPsiFacade.getElementFactory(aClass.getProject()).createType(aClass); + PsiClassType classType = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass); processClass(call, classType, argumentName, result); } + } + public static void processClass(@NotNull GrCall call, PsiClassType type, @Nullable String argumentName, @@ -147,7 +135,7 @@ public class GroovyConstructorNamedArgumentProvider extends GroovyNamedArgumentP } } - private static boolean isClassHasConstructorWithMap(PsiClass aClass) { + public static boolean isClassHasConstructorWithMap(PsiClass aClass) { PsiMethod[] constructors = aClass.getConstructors(); if (constructors.length == 0) return true; @@ -197,7 +185,7 @@ public class GroovyConstructorNamedArgumentProvider extends GroovyNamedArgumentP propertyName = ((PsiField)element).getName(); } - if (propertyName.equals(METACLASS)) return true; + if (METACLASS.equals(propertyName)) return true; if (((PsiModifierListOwner)element).hasModifierProperty(PsiModifier.STATIC)) return true; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyNewExprNamedArgumentProvider.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyNewExprNamedArgumentProvider.kt new file mode 100644 index 000000000000..ffe6eaf95967 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyNewExprNamedArgumentProvider.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2017 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.lang + +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiMethod +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression + +class GroovyNewExprNamedArgumentProvider : GroovyConstructorNamedArgumentProvider() { + + internal override fun getCorrespondingClasses(call: GrCall, resolveResult: GroovyResolveResult): List { + val newExpr = call as? GrNewExpression ?: return emptyList() + val resolve = resolveResult.element + (resolve as? PsiMethod)?.let { + if (!it.isConstructor) return emptyList() + } + return newExpr.multiResolveClass().mapNotNull { it.element as? PsiClass } + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyNewifyNamedArgumentProvider.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyNewifyNamedArgumentProvider.kt new file mode 100644 index 000000000000..fe7f9dea4ab8 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/GroovyNewifyNamedArgumentProvider.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2017 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.lang + +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiMirrorElement +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall + +class GroovyNewifyNamedArgumentProvider : GroovyConstructorNamedArgumentProvider() { + internal override fun getCorrespondingClasses(call: GrCall, resolveResult: GroovyResolveResult): List { + val prototype = (resolveResult.element as? PsiMirrorElement)?.prototype as? PsiMethod ?: return emptyList() + if (!prototype.isConstructor) return emptyList() + return prototype.containingClass?.let { listOf(it) } ?: emptyList() + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index aec619806853..965ef543eb6d 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -182,7 +182,7 @@ public class PsiUtil { GrClosureSignature signature = GrClosureSignatureUtil.createSignature(method, substitutor, eraseParameterTypes); //check for default constructor - if (method.isConstructor()) { + if (method.isConstructor() || handleMirrorMethod(method).isConstructor()) { final PsiParameter[] parameters = method.getParameterList().getParameters(); if (parameters.length == 0 && argumentTypes.length == 1) { return InheritanceUtil.isInheritor(argumentTypes[0], CommonClassNames.JAVA_UTIL_MAP) @@ -212,6 +212,17 @@ public class PsiUtil { return GrClosureSignatureUtil.ApplicabilityResult.inapplicable; } + @NotNull + public static PsiMethod handleMirrorMethod(@NotNull PsiMethod method) { + if (method instanceof PsiMirrorElement) { + PsiElement prototype = ((PsiMirrorElement)method).getPrototype(); + if (prototype instanceof PsiMethod) { + return (PsiMethod)prototype; + } + } + return method; + } + public static boolean isApplicable(@Nullable PsiType[] argumentTypes, GrClosureType type, GroovyPsiElement context) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/NewifyMemberContributor.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/NewifyMemberContributor.kt new file mode 100644 index 000000000000..62122a1ba51b --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/NewifyMemberContributor.kt @@ -0,0 +1,99 @@ +/* + * Copyright 2000-2017 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.lang.resolve.noncode + +import com.intellij.lang.java.JavaLanguage +import com.intellij.psi.* +import com.intellij.psi.impl.light.LightMethod +import com.intellij.psi.impl.light.LightModifierList +import com.intellij.psi.scope.PsiScopeProcessor +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression +import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtil +import org.jetbrains.plugins.groovy.lang.psi.util.getParents +import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil + +internal val newifyAnnotationFqn = "groovy.lang.Newify" + +class NewifyMemberContributor : NonCodeMembersContributor() { + override fun processDynamicElements(qualifierType: PsiType, + aClass: PsiClass?, + processor: PsiScopeProcessor, + place: PsiElement, + state: ResolveState) { + + val qualifier = getQualifier(place) + for (annotation in listNewifyAnnotations(place)) { + val newifiedClasses = GrAnnotationUtil.getClassArrayValue(annotation, "value", true) + qualifier ?: newifiedClasses.flatMap { it.constructors.asList() }.forEach { + ResolveUtil.processElement(processor, NewifiedConstructor(it, "by @Newify", it.name, true, arrayOf(PsiModifier.STATIC)), state) + } + val createNewMethods = GrAnnotationUtil.inferBooleanAttributeNotNull(annotation, "auto") + val type = (qualifier as? GrReferenceExpression)?.resolve() as? PsiClass + if (type != null && createNewMethods) { + type.constructors.forEach { + ResolveUtil.processElement(processor, NewifiedConstructor(it, "by @Newify", "new", false, arrayOf(PsiModifier.STATIC)), state) + } + } + } + } + + + fun listNewifyAnnotations(place: PsiElement): List { + return place.getParents().map { it.second }.flatMap { + + val owner = it as? PsiModifierListOwner ?: return@flatMap emptySequence() + val seq = owner.modifierList?.annotations?.asSequence()?.filter { it.qualifiedName == newifyAnnotationFqn } + + return@flatMap seq ?: emptySequence() + }.toList() + + } + + fun getQualifier(elem: PsiElement): PsiElement? { + return (elem as? GrReferenceExpression)?.qualifierExpression + } + + class NewifiedConstructor(val myPrototype: PsiMethod, val myOriginInfo: String, val newName: String, val asConstructor: Boolean, val modifiers:Array) + : LightMethod(myPrototype.manager, myPrototype, myPrototype.containingClass!!), OriginInfoAwareElement, PsiMirrorElement { + override fun getPrototype(): PsiElement { + return myPrototype + } + + val myModifierList: LightModifierList = LightModifierList(myPrototype.manager, JavaLanguage.INSTANCE, *modifiers) + + + override fun getName(): String { + return newName + } + + override fun getOriginInfo(): String { + return myOriginInfo + } + + override fun hasModifierProperty(name: String): Boolean { + return myModifierList.hasModifierProperty(name) + } + + override fun getModifierList(): PsiModifierList { + return myModifierList + } + + override fun isConstructor(): Boolean { + return asConstructor + } + } +} \ No newline at end of file diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 294dbed39df0..16716de5643e 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -99,6 +99,7 @@ + @@ -178,7 +179,8 @@ - + + diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/GroovyTransformationsTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/GroovyTransformationsTest.groovy index 1059c81f840d..fe02ced296c5 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/GroovyTransformationsTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/GroovyTransformationsTest.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -61,15 +61,4 @@ class GroovyTransformationsTest extends LightCodeInsightFixtureTestCase { void testBindableTransform() throws Throwable { doPlainTest() } void testVetoableTransform() throws Throwable { doPlainTest() } - - void testNewifyTransform1() throws Throwable { - myFixture.configureByFile(getTestName(false) + ".groovy") - myFixture.completeBasic() - assert myFixture.lookupElementStrings.containsAll(['newInstance', 'new', 'new', 'newInstance']) - } - - void testNewifyTransform2() throws Throwable { doVariantsTest('Leaf', 'Leaf', 'Leaf', 'Boolean') } - - void testNewifyTransform3() throws Throwable { doVariantsTest('Bazz', 'Bazz') } - } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/NewifySupportTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/NewifySupportTest.groovy new file mode 100644 index 000000000000..91e8f17474ff --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/NewifySupportTest.groovy @@ -0,0 +1,171 @@ +/* + * Copyright 2000-2017 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.lang.resolve + +import com.intellij.testFramework.LightProjectDescriptor +import groovy.transform.CompileStatic +import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor +import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection +import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection +import org.jetbrains.plugins.groovy.lang.highlighting.GrHighlightingTestBase + +@CompileStatic +class NewifySupportTest extends GrHighlightingTestBase { + + final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST + + @Override + void setUp() throws Exception { + super.setUp() + fixture.enableInspections(GrUnresolvedAccessInspection, GroovyAssignabilityCheckInspection) + fixture.addClass(''' +public class A { + String name; + int age; + public A(){} + public A(String name){} +} +''') + } + + void testAutoNewify() { + testHighlighting """ +@Newify +class B { + def a = A.new() + def i = Integer.new(1) +} +""" + testHighlighting """ +@Newify +class B { + def a = A.new("B") +} +""" + + testHighlighting """ +@Newify +class B { + def a = A.new(name :"bar") +} +""" + + testHighlighting """ +class B { + @Newify + def a = A.new(name :"bar") +} +""" + + testHighlighting """ +class B { + @Newify + def a (){ return A.new(name :"bar")} +} +""" + testHighlighting """ +class B { + @Newify(value = A, auto = false) + def a (){ return A.new()} +} +""" + } + + void testNewifyByClass() { + testHighlighting """ +@Newify([A, Integer]) +class B { + def a = A() + def i = Integer(1) +} +""" + + testHighlighting """ +@Newify(A) +class B { + def a = A("B") +} +""" + + testHighlighting """ +@Newify(A) +class B { + def a = A(name :"bar") +} +""" + + testHighlighting """ +class B { + @Newify(A) + def a = A(name :"bar") +} +""" + + testHighlighting """ +class B { + @Newify(A) + def a (){ return A(name :"bar")} +} +""" + testHighlighting """ +class B { + @Newify + def a (){ return A()} +} +""" + } + + void testNewifyMapLookup() { + testHighlighting """ +@Newify(A) +class B { + def a = A() +} +""" + fixture.completeBasic() + fixture.lookupElementStrings.with { + assert contains("name") + assert contains("age") + } + } + + void testNewifyAutoLookup() { + fixture.configureByText 'a.groovy', """ +@Newify(A) +class B { + def a = A. +} +""" + fixture.completeBasic() + fixture.lookupElementStrings.with { + assert contains("new") + } + } + + void testNewifyAutoMapLookup() { + testHighlighting """ +@Newify(A) +class B { + def a = A.new() +} +""" + fixture.completeBasic() + fixture.lookupElementStrings.with { + assert contains("name") + assert contains("age") + } + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy index 79c84eb85700..7d2c92162a13 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy @@ -827,6 +827,111 @@ def test() { assertNotNull(ref.resolve()) } + void testAutoNewify() { + fixture.addClass(''' +class A { + String name; + public A(){} +} +''') + + def resolved = configureByText(""" +@Newify +class B { + def a = A.new() +} +""").resolve() + assertInstanceOf(resolved, PsiMethod) + + resolved = configureByText(""" +@Newify +class B { + def a = A.new(name :"bar") +} +""").resolve() + + assertInstanceOf(resolved, PsiMethod) + + resolved = configureByText(""" +class B { + @Newify + def a = A.new(name :"bar") +} +""").resolve() + + assertInstanceOf(resolved, PsiMethod) + + resolved = configureByText(""" +class B { + @Newify + def a (){ return A.new(name :"bar")} +} +""").resolve() + + assertInstanceOf(resolved, PsiMethod) + + def ref = configureByText(""" +class B { + @Newify(auto = false) + def a (){ return A.new()} +} +""") + assert ref.resolve() == null + } + + void testNewifyByClass() { + fixture.addClass(''' +class Aa { + String name; + public Aa(){} +} +''') + + def resolved = configureByText(""" +@Newify(Aa) +class B { + def a = Aa() +} +""").resolve() + assertInstanceOf(resolved, PsiMethod) + + resolved = configureByText(""" +@Newify(Aa) +class B { + def a = Aa(name :"bar") +} +""").resolve() + + assertInstanceOf(resolved, PsiMethod) + + resolved = configureByText(""" +class B { + @Newify(Aa) + def a = Aa(name :"bar") +} +""").resolve() + + assertInstanceOf(resolved, PsiMethod) + + resolved = configureByText(""" +class B { + @Newify(Aa) + def a (){ return Aa(name :"bar")} +} +""").resolve() + + assertInstanceOf(resolved, PsiMethod) + + resolved = configureByText(""" +class B { + @Newify + def a (){ return Aa(name :"bar")} +} +""").resolve() + + assertInstanceOf(resolved, PsiClass) + } + void testStringInjectionDontOverrideItParameter() { def ref = configureByText(""" [2, 3, 4].collect {"\${it.toBigDecimal()}"} diff --git a/plugins/groovy/testdata/groovy/dsl/transform/NewifyTransform1.groovy b/plugins/groovy/testdata/groovy/dsl/transform/NewifyTransform1.groovy deleted file mode 100644 index b0cd243ff5d3..000000000000 --- a/plugins/groovy/testdata/groovy/dsl/transform/NewifyTransform1.groovy +++ /dev/null @@ -1,3 +0,0 @@ -@Newify rubyLikeNew() { - assert Integer.ne == 42 -} diff --git a/plugins/groovy/testdata/groovy/dsl/transform/NewifyTransform2.groovy b/plugins/groovy/testdata/groovy/dsl/transform/NewifyTransform2.groovy deleted file mode 100644 index c9dd73b3e577..000000000000 --- a/plugins/groovy/testdata/groovy/dsl/transform/NewifyTransform2.groovy +++ /dev/null @@ -1,13 +0,0 @@ -class Tree { - Tree(Tree l, Tree r) { } -} - -class Leaf extends Tree { - Leaf(int value) {} - Leaf(String value) {} -} - -@Newify([Tree, Leaf]) -buildTree() { - Tree(Tree(Leaf(1), Leaf(2)), Lea) -} \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/dsl/transform/NewifyTransform3.groovy b/plugins/groovy/testdata/groovy/dsl/transform/NewifyTransform3.groovy deleted file mode 100644 index 9fc75aa28bd8..000000000000 --- a/plugins/groovy/testdata/groovy/dsl/transform/NewifyTransform3.groovy +++ /dev/null @@ -1,25 +0,0 @@ -class Foo { - Foo(String st){} -} - -class Bazz { - Bazz(String st){} -} - -@Newify(auto=false, value=Foo) - class Main { - @Newify() // turn auto on for field - def field1 = java.math.BigInteger.new(42) - def field2, field3, field4 - - @Newify(Bar) - def process() { - field2 = Bar("my bar") - } - - @Newify(Bazz) - Main() { - field3 = Foo("my foo") - field4 = Baz() - } - } \ No newline at end of file