IDEA-61962 Groovy runtime mixin support

This commit is contained in:
Max Medvedev
2012-11-09 13:49:51 +04:00
parent c5e1ed9c80
commit 2da0894f66
7 changed files with 540 additions and 50 deletions
@@ -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()));
@@ -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<PsiRefer
final PsiMethod method = queryParameters.getMethod();
final String propertyName;
if (MixinMemberContributor.isCategoryMethod(method, null, PsiSubstitutor.EMPTY)) {
if (GdkMethodUtil.isCategoryMethod(method, null, PsiSubstitutor.EMPTY)) {
final GrGdkMethod cat = GrGdkMethodImpl.createGdkMethod(method, false, null);
propertyName = GroovyPropertyUtils.getPropertyName((PsiMethod)cat);
}
@@ -16,21 +16,28 @@
package org.jetbrains.plugins.groovy.lang.psi.util;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.scope.DelegatingScopeProcessor;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
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.statements.GrStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
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.api.statements.typedef.members.GrGdkMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner;
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
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.impl.synthetic.GrGdkMethodImpl;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor;
@@ -73,11 +80,7 @@ public class GdkMethodUtil {
final GrClosableBlock[] closures = call.getClosureArguments();
final GrExpression[] args = call.getExpressionArguments();
int last = args.length - 1;
if (!(closures.length == 1 && place.equals(closures[0])) &&
!(args.length > 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<PsiClassType, PsiClass> 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<PsiClassType, PsiClass> 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<PsiClassType, PsiClass>(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());
}
}
@@ -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() {
@@ -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();
}
@@ -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;
}
@@ -1111,4 +1111,322 @@ setFo<caret>o(2)
assertEquals('setFoo', resolved.name)
}
void testRuntimeMixin1() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
metaClass.mixin(Foo)
d<caret>oSmth()
''', PsiMethod)
}
void testRuntimeMixin2() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
this.metaClass.mixin(Foo)
do<caret>Smth()
''', PsiMethod)
}
void testRuntimeMixin3() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
_a.metaClass.mixin(Foo)
do<caret>Smth()
''', PsiMethod)
}
void testRuntimeMixin4() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
_a.class.mixin(Foo)
do<caret>Smth()
''', PsiMethod)
}
void testRuntimeMixin5() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
_a.mixin(Foo)
do<caret>Smth()
''', PsiMethod)
}
void testRuntimeMixin6() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
class _a {
def foo() {
metaClass.mixin(Foo)
d<caret>oSmth()
}
}
''', PsiMethod)
}
void testRuntimeMixin7() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
class _a {
def foo() {
this.metaClass.mixin(Foo)
do<caret>Smth()
}
}
''', PsiMethod)
}
void testRuntimeMixin8() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
class _a {
def foo() {
_a.metaClass.mixin(Foo)
do<caret>Smth()
}
}
''', PsiMethod)
}
void testRuntimeMixin9() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
class _a {
def foo() {
_a.class.mixin(Foo)
do<caret>Smth()
}
}
''', PsiMethod)
}
void testRuntimeMixin10() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
class _a {
def foo() {
_a.mixin(Foo)
do<caret>Smth()
}
}
''', PsiMethod)
}
void testRuntimeMixin11() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
metaClass.mixin(Foo)
new _a().d<caret>oSmth()
''', PsiMethod)
}
void testRuntimeMixin12() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
this.metaClass.mixin(Foo)
new _a().do<caret>Smth()
''', PsiMethod)
}
void testRuntimeMixin13() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
_a.metaClass.mixin(Foo)
new _a().do<caret>Smth()
''', PsiMethod)
}
void testRuntimeMixin14() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
_a.class.mixin(Foo)
new _a().do<caret>Smth()
''', PsiMethod)
}
void testRuntimeMixin15() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
_a.mixin(Foo)
new _a().do<caret>Smth()
''', PsiMethod)
}
void testRuntimeMixin16() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
class _a {
def foo() {
metaClass.mixin(Foo)
new _a().d<caret>oSmth()
}
}
''', PsiMethod)
}
void testRuntimeMixin17() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
class _a {
def foo() {
this.metaClass.mixin(Foo)
new _a().do<caret>Smth()
}
}
''', PsiMethod)
}
void testRuntimeMixin18() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
class _a {
def foo() {
_a.metaClass.mixin(Foo)
new _a().do<caret>Smth()
}
}
''', PsiMethod)
}
void testRuntimeMixin19() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
class _a {
def foo() {
_a.class.mixin(Foo)
new _a().do<caret>Smth()
}
}
''', PsiMethod)
}
void testRuntimeMixin20() {
resolveByText('''\
class Foo {
public static void doSmth(Script u) {
println "hello"
}
}
class _a {
def foo() {
_a.mixin(Foo)
new _a().do<caret>Smth()
}
}
''', PsiMethod)
}
void testRuntimeMixin21() {
resolveByText('''\
class Foo {
public void doSmth() {
println "hello"
}
}
class _a {
def foo() {
_a.mixin(Foo)
new _a().do<caret>Smth()
}
}
''', PsiMethod)
}
}