diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java index f271c84e086a..12878ed20edf 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java @@ -74,12 +74,8 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrReferenceResolveUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyConstantExpressionEvaluator; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; -import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import org.jetbrains.plugins.groovy.lang.psi.util.*; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; -import org.jetbrains.plugins.groovy.lang.resolve.noncode.MixinMemberContributor; import java.util.ArrayList; import java.util.List; @@ -819,7 +815,7 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { if (method instanceof GrGdkMethod && place instanceof GrReferenceExpression) { final PsiMethod staticMethod = ((GrGdkMethod)method).getStaticMethod(); final PsiType qualifier = inferQualifierTypeByPlace((GrReferenceExpression)place); - if (qualifier != null && !MixinMemberContributor.isCategoryMethod(staticMethod, qualifier, methodResolveResult.getSubstitutor())) { + if (qualifier != null && !GdkMethodUtil.isCategoryMethod(staticMethod, qualifier, methodResolveResult.getSubstitutor())) { registerError(((GrReferenceExpression)place).getReferenceNameElement(), GroovyInspectionBundle.message("category.method.0.cannot.be.applied.to.1", method.getName(), qualifier.getCanonicalText())); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/AccessorMethodReferencesSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/AccessorMethodReferencesSearcher.java index 02d39661adf6..7a2d8e567a65 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/AccessorMethodReferencesSearcher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/AccessorMethodReferencesSearcher.java @@ -28,9 +28,9 @@ import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrGdkMethodImpl; +import org.jetbrains.plugins.groovy.lang.psi.util.GdkMethodUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; -import org.jetbrains.plugins.groovy.lang.resolve.noncode.MixinMemberContributor; /** * author ven @@ -46,7 +46,7 @@ public class AccessorMethodReferencesSearcher extends QueryExecutorBase 0 && place.equals(args[last]))) { - return true; - } + if (!(placeEqualsSingleClosureArg(place, closures) || placeEqualsLastArg(place, args))) return true; if (!(call.resolveMethod() instanceof GrGdkMethod)) return true; @@ -93,6 +96,14 @@ public class GdkMethodUtil { return true; } + private static boolean placeEqualsLastArg(GrClosableBlock place, GrExpression[] args) { + return args.length > 0 && place.equals(args[args.length - 1]); + } + + private static boolean placeEqualsSingleClosureArg(GrClosableBlock place, GrClosableBlock[] closures) { + return closures.length == 1 && place.equals(closures[0]); + } + /** * * @param place - context of processing @@ -106,13 +117,10 @@ public class GdkMethodUtil { @NotNull final PsiClass categoryClass) { final DelegatingScopeProcessor delegate = new DelegatingScopeProcessor(processor) { @Override - public boolean execute(@NotNull PsiElement element, ResolveState state) { - if (element instanceof PsiMethod) { + public boolean execute(@NotNull PsiElement element, ResolveState delegateState) { + if (isCategoryMethod(element, null, null)) { PsiMethod method = (PsiMethod)element; - if (!method.hasModifierProperty(PsiModifier.STATIC)) return true; - final PsiParameter[] parameters = method.getParameterList().getParameters(); - if (parameters.length == 0) return true; - return processor.execute(GrGdkMethodImpl.createGdkMethod(method, false, generateOriginInfo(method)), state); + return processor.execute(GrGdkMethodImpl.createGdkMethod(method, false, generateOriginInfo(method)), delegateState); } return true; } @@ -120,6 +128,14 @@ public class GdkMethodUtil { return categoryClass.processDeclarations(delegate, state, null, place); } + private static boolean acceptClass(@Nullable PsiType type, @NotNull PsiClass aClass) { + if (!(type instanceof PsiClassType)) return false; + + PsiClass resolved = ((PsiClassType)type).resolve(); + + return InheritanceUtil.isInheritorOrSelf(aClass, resolved, true); + } + public static boolean withIteration(GrClosableBlock block, final PsiScopeProcessor processor) { GrMethodCall call = checkMethodCall(block, WITH); if (call == null) { @@ -186,4 +202,168 @@ public class GdkMethodUtil { //'\u2191' return "via " + cc.getName(); } + + public static boolean processMixinToMetaclass(GrStatementOwner run, + final PsiScopeProcessor processor, + ResolveState state, + PsiElement lastParent, + GroovyPsiElement place) { + GrStatement[] statements = run.getStatements(); + for (GrStatement statement : statements) { + if (statement == lastParent) break; + + final Pair result = getMixinTypes(statement); + + if (result != null) { + final PsiClassType subjectType = result.first; + final PsiClass mixin = result.second; + + final DelegatingScopeProcessor delegate = new DelegatingScopeProcessor(processor) { + @Override + public boolean execute(@NotNull PsiElement element, ResolveState delegateState) { + if (isCategoryMethod(element, subjectType, null)) { + PsiMethod method = (PsiMethod)element; + return processor.execute(GrGdkMethodImpl.createGdkMethod(method, false, generateOriginInfo(method)), delegateState); + } + else if (element instanceof PsiMethod && ((PsiMethod)element).hasModifierProperty(PsiModifier.PUBLIC)) { + super.execute(element, delegateState); + } + return true; + } + }; + mixin.processDeclarations(delegate, state, null, place); + } + } + + return true; + } + + @Nullable + private static Pair getMixinTypes(GrStatement statement) { + if (statement instanceof GrMethodCall) { + GrMethodCall call = (GrMethodCall)statement; + PsiClassType original = getTypeToMixIn(call); + PsiClass mix = getTypeToMix(call); + + if (original != null && mix != null) { + return new Pair(original, mix); + + } + } + + return null; + } + + @Nullable + private static PsiClass getTypeToMix(GrMethodCall call) { + if (!isSingleExpressionArg(call)) return null; + + GrExpression mixinRef = call.getExpressionArguments()[0]; + if (isClassRef(mixinRef)) { + mixinRef = ((GrReferenceExpression)mixinRef).getQualifier(); + } + + if (mixinRef instanceof GrReferenceExpression) { + PsiElement resolved = ((GrReferenceExpression)mixinRef).resolve(); + if (resolved instanceof PsiClass) { + return (PsiClass)resolved; + } + } + + return null; + } + + private static boolean isSingleExpressionArg(GrMethodCall call) { + GrExpression[] exprs = call.getExpressionArguments(); + GrNamedArgument[] named = call.getNamedArguments(); + GrClosableBlock[] closures = call.getClosureArguments(); + + return exprs.length == 1 && named.length == 0 && closures.length == 0; + } + + @Nullable + private static PsiClassType getTypeToMixIn(GrMethodCall methodCall) { + GrExpression invoked = methodCall.getInvokedExpression(); + if (invoked instanceof GrReferenceExpression) { + PsiElement resolved = ((GrReferenceExpression)invoked).resolve(); + if (resolved instanceof PsiMethod && isMixinMethod((PsiMethod)resolved)) { + GrExpression qualifier = ((GrReferenceExpression)invoked).getQualifier(); + PsiClassType type = getPsiClassFromReference(qualifier); + if (type != null) { + return type; + } + if (qualifier == null) { + qualifier = PsiImplUtil.getRuntimeQualifier((GrReferenceExpression)invoked); + } + if (qualifier != null && isMetaClass(qualifier.getType())) { + if (qualifier instanceof GrMethodCall) qualifier = ((GrMethodCall)qualifier).getInvokedExpression(); + + if (qualifier instanceof GrReferenceExpression) { + GrExpression qqualifier = ((GrReferenceExpression)qualifier).getQualifier(); + if (qqualifier != null) { + PsiClassType type1 = getPsiClassFromReference(qqualifier); + if (type1 != null) { + return type1; + } + } + else { + PsiType qtype = GrReferenceResolveUtil.getQualifierType((GrReferenceExpression)qualifier); + if (qtype instanceof PsiClassType && ((PsiClassType)qtype).resolve() != null) { + return (PsiClassType)qtype; + } + } + } + } + } + } + return null; + } + + private static boolean isMixinMethod(PsiMethod method) { + if (method instanceof GrGdkMethod) method = ((GrGdkMethod)method).getStaticMethod(); + PsiClass containingClass = method.getContainingClass(); + String name = method.getName(); + return "mixin".equals(name) && containingClass != null && GroovyCommonClassNames.DEFAULT_GROOVY_METHODS.equals(containingClass.getQualifiedName()); + } + + private static boolean isMetaClass(PsiType qualifierType) { + return qualifierType != null && qualifierType.equalsToText(GroovyCommonClassNames.GROOVY_LANG_META_CLASS); + } + + private static boolean isClassRef(GrExpression mixinRef) { + return mixinRef instanceof GrReferenceExpression && "class".equals(((GrReferenceExpression)mixinRef).getReferenceName()); + } + + private static PsiClassType getPsiClassFromReference(GrExpression ref) { + if (isClassRef(ref)) ref = ((GrReferenceExpression)ref).getQualifier(); + if (ref instanceof GrReferenceExpression) { + PsiElement resolved = ((GrReferenceExpression)ref).resolve(); + if (resolved instanceof PsiClass) { + PsiType type = ref.getType(); + LOG.assertTrue(type instanceof PsiClassType, "reference resolved into PsiClass should have PsiClassType"); + return ((PsiClassType)type); + } + } + return null; + } + + public static boolean isCategoryMethod(@Nullable PsiElement element, @Nullable PsiType qualifierType, @Nullable PsiSubstitutor substitutor) { + if (!(element instanceof PsiMethod)) return false; + PsiMethod method = (PsiMethod)element; + if (!method.hasModifierProperty(PsiModifier.STATIC)) return false; + if (!method.hasModifierProperty(PsiModifier.PUBLIC)) return false; + + final PsiParameter[] parameters = method.getParameterList().getParameters(); + if (parameters.length == 0) return false; + + if (qualifierType == null) return true; + + PsiType selfType = parameters[0].getType(); + if (selfType instanceof PsiPrimitiveType) return false; + + if (substitutor != null) { + selfType = substitutor.substitute(selfType); + } + return TypesUtil.isAssignable(selfType, qualifierType, element.getManager(), element.getResolveScope()); + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java index 32e85b636a4b..447408b6cdc1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/GroovyCommonClassNames.java @@ -57,6 +57,7 @@ public final class GroovyCommonClassNames { @NonNls public static final String JAVA_LANG_CHAR_SEQUENCE = "java.lang.CharSequence"; public static final String GROOVY_TRANSFORM_INHERIT_CONSTRUCTORS = "groovy.transform.InheritConstructors"; public static final String GROOVY_LANG_IMMUTABLE = "groovy.lang.Immutable"; + @NonNls public static final String GROOVY_LANG_META_CLASS = "groovy.lang.MetaClass"; private GroovyCommonClassNames() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java index 92beb259eca8..aa1816d83f51 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.java @@ -56,6 +56,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGd import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; @@ -112,9 +113,10 @@ public class ResolveUtil { static boolean doProcessDeclarations(GroovyPsiElement place, PsiElement lastParent, PsiElement scope, - @NotNull PsiScopeProcessor plainProcessor, @Nullable PsiScopeProcessor nonCodeProcessor) { + @NotNull PsiScopeProcessor plainProcessor, + @Nullable PsiScopeProcessor nonCodeProcessor) { if (!scope.processDeclarations(plainProcessor, ResolveState.initial(), lastParent, place)) return false; - if (nonCodeProcessor != null && !processScopeNonCodeMethods(place, nonCodeProcessor, scope)) return false; + if (nonCodeProcessor != null && !processScopeNonCodeMethods(place, lastParent, nonCodeProcessor, scope)) return false; return true; } @@ -136,14 +138,16 @@ public class ResolveUtil { return processor; } - static boolean processScopeNonCodeMethods(GroovyPsiElement place, PsiScopeProcessor processor, PsiElement scope) { + static boolean processScopeNonCodeMethods(GroovyPsiElement place, PsiElement lastParent, PsiScopeProcessor processor, PsiElement scope) { if (scope instanceof GrTypeDefinition) { return processNonCodeMembers(createPsiType((GrTypeDefinition)scope), processor, place, ResolveState.initial()); } if (scope instanceof GroovyFileBase && ((GroovyFileBase)scope).isScript()) { final PsiClass psiClass = ((GroovyFileBase)scope).getScriptClass(); - return psiClass == null || processNonCodeMembers(createPsiType(psiClass), processor, place, ResolveState.initial()); + if (psiClass != null) { + if (!processNonCodeMembers(createPsiType(psiClass), processor, place, ResolveState.initial())) return false; + } } if (scope instanceof GrClosableBlock) { @@ -154,6 +158,10 @@ public class ResolveUtil { if (!GdkMethodUtil.withIteration((GrClosableBlock)scope, processor)) return false; } + if (scope instanceof GrStatementOwner) { + if (!GdkMethodUtil.processMixinToMetaclass((GrStatementOwner)scope, processor, ResolveState.initial(), lastParent, place)) return false; + } + return true; } @@ -188,7 +196,6 @@ public class ResolveUtil { public static boolean processElement(PsiScopeProcessor processor, PsiNamedElement namedElement, ResolveState state) { NameHint nameHint = processor.getHint(NameHint.KEY); - //todo [DIANA] look more carefully String name = nameHint == null ? null : nameHint.getName(state); if (name == null || name.equals(namedElement.getName())) { return processor.execute(namedElement, state); @@ -215,10 +222,10 @@ public class ResolveUtil { return true; } - public static boolean processNonCodeMembers(PsiType type, - PsiScopeProcessor processor, + public static boolean processNonCodeMembers(@NotNull PsiType type, + @NotNull PsiScopeProcessor processor, GroovyPsiElement place, - ResolveState state) { + @NotNull ResolveState state) { if (type instanceof PsiEllipsisType) { type = ((PsiEllipsisType)type).toArrayType(); } @@ -407,6 +414,8 @@ public class ResolveUtil { boolean inCodeBlock = true; PsiElement run = place; + PsiElement lastParent = null; + while (run != null) { if (run instanceof GrMember) { inCodeBlock = false; @@ -417,11 +426,18 @@ public class ResolveUtil { PsiClass superClass = getLiteralSuperClass((GrClosableBlock)run); if (superClass != null && !GdkMethodUtil.processCategoryMethods(((GrClosableBlock)run), processor, state, superClass)) return false; } + if (gpp && run instanceof GrTypeDefinition) { final GrTypeDefinition typeDefinition = (GrTypeDefinition)run; state = state.put(ResolverProcessor.RESOLVE_CONTEXT, typeDefinition); if (!GdkMethodUtil.processCategoryMethods(typeDefinition, processor, state, typeDefinition)) return false; } + + if (run instanceof GrStatementOwner) { + if (!GdkMethodUtil.processMixinToMetaclass((GrStatementOwner)run, processor, state, lastParent, place)) return false; + } + + lastParent = run; run = run.getContext(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/MixinMemberContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/MixinMemberContributor.java index 1d3a4aa85ce9..afc0bf53ab54 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/MixinMemberContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/noncode/MixinMemberContributor.java @@ -19,15 +19,14 @@ import com.intellij.psi.*; import com.intellij.psi.scope.DelegatingScopeProcessor; import com.intellij.psi.scope.PsiScopeProcessor; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationArrayInitializer; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationMemberValue; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrGdkMethodImpl; +import org.jetbrains.plugins.groovy.lang.psi.util.GdkMethodUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor; @@ -71,7 +70,7 @@ public class MixinMemberContributor extends NonCodeMembersContributor { if (!mixin.processDeclarations(new DelegatingScopeProcessor(processor) { @Override public boolean execute(@NotNull PsiElement element, ResolveState state) { - if (isCategoryMethod(element, qualifierType, state.get(PsiSubstitutor.KEY))) { + if (GdkMethodUtil.isCategoryMethod(element, qualifierType, state.get(PsiSubstitutor.KEY))) { PsiMethod method = (PsiMethod)element; String originInfo = getOriginInfo(method); return super.execute(GrGdkMethodImpl.createGdkMethod(method, false, originInfo), state); @@ -104,26 +103,6 @@ public class MixinMemberContributor extends NonCodeMembersContributor { return result; } - public static boolean isCategoryMethod(@Nullable PsiElement element, @Nullable PsiType qualifierType, @Nullable PsiSubstitutor substitutor) { - if (!(element instanceof PsiMethod)) return false; - PsiMethod method = (PsiMethod)element; - if (!method.hasModifierProperty(PsiModifier.STATIC)) return false; - if (!method.hasModifierProperty(PsiModifier.PUBLIC)) return false; - - final PsiParameter[] parameters = method.getParameterList().getParameters(); - if (parameters.length == 0) return false; - - if (qualifierType == null) return true; - - PsiType selfType = parameters[0].getType(); - if (selfType instanceof PsiPrimitiveType) return false; - - if (substitutor != null) { - selfType = substitutor.substitute(selfType); - } - return TypesUtil.isAssignable(selfType, qualifierType, element.getManager(), element.getResolveScope()); - } - private static boolean isInAnnotation(GroovyPsiElement place) { return place.getParent() instanceof GrAnnotation || place.getParent() instanceof GrAnnotationArrayInitializer; } 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 ee73029d828c..62328a66cbc4 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 @@ -1111,4 +1111,322 @@ setFoo(2) assertEquals('setFoo', resolved.name) } + void testRuntimeMixin1() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +metaClass.mixin(Foo) +doSmth() +''', PsiMethod) + } + + void testRuntimeMixin2() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +this.metaClass.mixin(Foo) +doSmth() +''', PsiMethod) + } + + void testRuntimeMixin3() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +_a.metaClass.mixin(Foo) +doSmth() +''', PsiMethod) + } + + void testRuntimeMixin4() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +_a.class.mixin(Foo) +doSmth() +''', PsiMethod) + } + + void testRuntimeMixin5() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +_a.mixin(Foo) +doSmth() +''', PsiMethod) + } + + void testRuntimeMixin6() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +class _a { + def foo() { + metaClass.mixin(Foo) + doSmth() + } +} +''', PsiMethod) + } + + void testRuntimeMixin7() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +class _a { + def foo() { + this.metaClass.mixin(Foo) + doSmth() + } +} + +''', PsiMethod) + } + + void testRuntimeMixin8() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +class _a { + def foo() { + _a.metaClass.mixin(Foo) + doSmth() + } +} +''', PsiMethod) + } + + void testRuntimeMixin9() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +class _a { + def foo() { + _a.class.mixin(Foo) + doSmth() + } +} +''', PsiMethod) + } + + void testRuntimeMixin10() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +class _a { + def foo() { + _a.mixin(Foo) + doSmth() + } +} +''', PsiMethod) + } + + void testRuntimeMixin11() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +metaClass.mixin(Foo) +new _a().doSmth() +''', PsiMethod) + } + + void testRuntimeMixin12() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +this.metaClass.mixin(Foo) +new _a().doSmth() +''', PsiMethod) + } + + void testRuntimeMixin13() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +_a.metaClass.mixin(Foo) +new _a().doSmth() +''', PsiMethod) + } + + void testRuntimeMixin14() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +_a.class.mixin(Foo) +new _a().doSmth() +''', PsiMethod) + } + + void testRuntimeMixin15() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +_a.mixin(Foo) +new _a().doSmth() +''', PsiMethod) + } + + void testRuntimeMixin16() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +class _a { + def foo() { + metaClass.mixin(Foo) + new _a().doSmth() + } +} +''', PsiMethod) + } + + void testRuntimeMixin17() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +class _a { + def foo() { + this.metaClass.mixin(Foo) + new _a().doSmth() + } +} + +''', PsiMethod) + } + + void testRuntimeMixin18() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +class _a { + def foo() { + _a.metaClass.mixin(Foo) + new _a().doSmth() + } +} +''', PsiMethod) + } + + void testRuntimeMixin19() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +class _a { + def foo() { + _a.class.mixin(Foo) + new _a().doSmth() + } +} +''', PsiMethod) + } + + void testRuntimeMixin20() { + resolveByText('''\ +class Foo { + public static void doSmth(Script u) { + println "hello" + } +} + +class _a { + def foo() { + _a.mixin(Foo) + new _a().doSmth() + } +} +''', PsiMethod) + } + + void testRuntimeMixin21() { + resolveByText('''\ +class Foo { + public void doSmth() { + println "hello" + } +} + +class _a { + def foo() { + _a.mixin(Foo) + new _a().doSmth() + } +} +''', PsiMethod) + } }