Merge remote-tracking branch 'origin/master'

This commit is contained in:
anna
2013-07-24 19:02:57 +02:00
8 changed files with 287 additions and 26 deletions
+2
View File
@@ -371,6 +371,8 @@
<psi.referenceContributor language="Properties" implementation="org.jetbrains.plugins.groovy.dgm.DGMReferenceContributor"/>
<psi.referenceContributor language="Groovy" implementation="org.jetbrains.plugins.groovy.lang.resolve.GroovyMethodArgumentReferenceContributor"/>
<weigher key="completion" implementationClass="org.jetbrains.plugins.groovy.lang.completion.weighers.GrWithWeigher"
id="groovyWithWeigher" order="after prefix"/>
<weigher key="completion" implementationClass="org.jetbrains.plugins.groovy.lang.completion.weighers.GrKindWeigher"
@@ -67,6 +67,14 @@ public class GroovyMethodDescriptor {
@Attribute("names")
public String names;
@Attribute("referenceProvider")
public String referenceProvider;
protected Iterable<String> getNames() {
assert !StringUtil.isEmptyOrSpaces(names);
return StringUtil.tokenize(names, ATTR_NAMES_DELIMITER);
}
}
@Nullable
@@ -92,6 +100,23 @@ public class GroovyMethodDescriptor {
}
}
public Map<String, String> getNamedArgumentsReferenceProviders() {
if (myArguments == null) return Collections.emptyMap();
Map<String, String> res = new HashMap<String, String>();
for (NamedArguments argument : myArguments) {
if (argument.referenceProvider != null) {
for (String name : argument.getNames()) {
Object oldValue = res.put(name, argument.referenceProvider);
assert oldValue == null;
}
}
}
return res;
}
@Nullable
public Map<String, NamedArgumentDescriptor> getArgumentsMap() {
if (myArguments == null && namedArgs == null) {
@@ -108,13 +133,7 @@ public class GroovyMethodDescriptor {
for (NamedArguments arguments : myArguments) {
NamedArgumentDescriptor descriptor = getDescriptor(isNamedArgsShowFirst, arguments.isFirst, arguments.type);
assert !StringUtil.isEmptyOrSpaces(arguments.names);
String names = arguments.names;
for (StringTokenizer st = new StringTokenizer(names, ATTR_NAMES_DELIMITER); st.hasMoreTokens(); ) {
String name = st.nextToken();
for (String name : arguments.getNames()) {
Object oldValue = res.put(name, descriptor);
assert oldValue == null;
}
@@ -1,7 +1,9 @@
package org.jetbrains.plugins.groovy.extensions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.psi.*;
import com.intellij.util.PairFunction;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
@@ -19,7 +21,9 @@ public class GroovyMethodInfo {
private static volatile Map<String, Map<String, List<GroovyMethodInfo>>> METHOD_INFOS;
private static Map<String, Map<String, List<GroovyMethodInfo>>> LIGHT_METHOD_INFOS;
private static final Set<String> myAllSupportedNamedArguments = new HashSet<String>();
private final List<String> myParams;
private final ClassLoader myClassLoader;
@@ -28,9 +32,11 @@ public class GroovyMethodInfo {
private PairFunction<GrMethodCall, PsiMethod, PsiType> myReturnTypeCalculatorInstance;
private final Map<String, NamedArgumentDescriptor> myNamedArguments;
private final String myNamedArgProviderClassName;
private final String myNamedArgProviderClassName;
private GroovyNamedArgumentProvider myNamedArgProviderInstance;
private Map<String, String> myNamedArgReferenceProviderClassNames;
private static void ensureInit() {
if (METHOD_INFOS != null) return;
@@ -92,15 +98,14 @@ public class GroovyMethodInfo {
ensureInit();
List<GroovyMethodInfo> lightMethodInfos = null;
if (method instanceof GrLightMethodBuilder) {
Object methodKind = ((GrLightMethodBuilder)method).getMethodKind();
if (methodKind instanceof String) {
lightMethodInfos = getInfos(LIGHT_METHOD_INFOS, (String)methodKind, method);
}
Object methodKind = GrLightMethodBuilder.getMethodKind(method);
if (methodKind instanceof String) {
lightMethodInfos = getInfos(LIGHT_METHOD_INFOS, (String)methodKind, method);
}
List<GroovyMethodInfo> methodInfos = null;
PsiClass containingClass = method.getContainingClass();
if (containingClass != null) {
methodInfos = getInfos(METHOD_INFOS, containingClass.getQualifiedName(), method);
@@ -114,10 +119,7 @@ public class GroovyMethodInfo {
return methodInfos;
}
else {
List<GroovyMethodInfo> res = new ArrayList<GroovyMethodInfo>(lightMethodInfos.size() + methodInfos.size());
res.addAll(lightMethodInfos);
res.addAll(methodInfos);
return res;
return ContainerUtil.concat(lightMethodInfos, methodInfos);
}
}
}
@@ -132,6 +134,31 @@ public class GroovyMethodInfo {
myNamedArguments = method.getArgumentsMap();
myNamedArgProviderClassName = method.namedArgsProvider;
assert myNamedArguments == null || myNamedArgProviderClassName == null;
myNamedArgReferenceProviderClassNames = method.getNamedArgumentsReferenceProviders();
myAllSupportedNamedArguments.addAll(myNamedArgReferenceProviderClassNames.keySet());
if (ApplicationManager.getApplication().isInternal()) {
// Check classes to avoid typo.
try {
if (myReturnTypeCalculatorClassName != null) {
classLoader.loadClass(myReturnTypeCalculatorClassName);
}
if (myNamedArgProviderClassName != null) {
classLoader.loadClass(myNamedArgProviderClassName);
}
for (String className : myNamedArgReferenceProviderClassNames.values()) {
Class<?> aClass = classLoader.loadClass(className);
assert PsiReferenceProvider.class.isAssignableFrom(aClass) || GroovyNamedArgumentReferenceProvider.class.isAssignableFrom(aClass);
}
}
catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
private static void addMethodDescriptor(Map<String, Map<String, List<GroovyMethodInfo>>> res,
@@ -187,6 +214,21 @@ public class GroovyMethodInfo {
return myReturnTypeCalculatorInstance;
}
public static Set<String> getAllSupportedNamedArguments() {
return myAllSupportedNamedArguments;
}
/**
* @return instance of PsiReferenceProvider or GroovyNamedArgumentReferenceProvider or null.
*/
@Nullable
public Object getNamedArgReferenceProvider(String namedArgumentName) {
String className = myNamedArgReferenceProviderClassNames.get(namedArgumentName);
if (className == null) return null;
return ClassInstanceCache.getInstance(className, myClassLoader);
}
@Nullable
public Map<String, NamedArgumentDescriptor> getNamedArguments() {
return myNamedArguments;
@@ -0,0 +1,19 @@
package org.jetbrains.plugins.groovy.extensions;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
/**
* @author Sergey Evdokimov
*/
public interface GroovyNamedArgumentReferenceProvider {
PsiReference[] createRef(@NotNull PsiElement element,
@NotNull GrNamedArgument namedArgument,
@NotNull GroovyResolveResult resolveResult,
@NotNull ProcessingContext context);
}
@@ -17,6 +17,7 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.synthetic;
import com.intellij.codeInsight.completion.originInfo.OriginInfoAwareElement;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.util.Key;
import com.intellij.psi.*;
import com.intellij.psi.impl.ElementPresentationUtil;
import com.intellij.psi.impl.PsiClassImplUtil;
@@ -56,6 +57,9 @@ import java.util.Map;
* @author Sergey Evdokimov
*/
public class GrLightMethodBuilder extends LightElement implements GrMethod, OriginInfoAwareElement {
public static final Key<String> KIND_KEY = Key.create("GrLightMethodBuilder.Key");
protected String myName;
private PsiType myReturnType = PsiType.VOID;
private final GrLightModifierList myModifierList;
@@ -366,16 +370,23 @@ public class GrLightMethodBuilder extends LightElement implements GrMethod, Ori
public void acceptChildren(GroovyElementVisitor visitor) {
}
public static Object getMethodKind(@Nullable PsiElement method) {
if (method == null) return null;
if (method instanceof GrLightMethodBuilder) {
return ((GrLightMethodBuilder)method).getMethodKind();
}
return method.getUserData(KIND_KEY);
}
public static boolean checkKind(@Nullable PsiElement method, @NotNull Object kind) {
return method instanceof GrLightMethodBuilder && kind.equals(((GrLightMethodBuilder)method).myMethodKind);
return kind.equals(getMethodKind(method));
}
public static boolean checkKind(@Nullable PsiElement method, @NotNull Object kind1, @NotNull Object kind2) {
if (method instanceof GrLightMethodBuilder) {
Object kind = ((GrLightMethodBuilder)method).getMethodKind();
return kind1.equals(kind) || kind2.equals(kind);
}
return false;
Object kind = getMethodKind(method);
return kind1.equals(kind) || kind2.equals(kind);
}
@Override
@@ -67,7 +67,7 @@ public class GroovyPatterns extends PsiJavaPatterns {
return PsiJavaPatterns.psiMethod().with(new PatternCondition<PsiMethod>("GrLightMethodBuilder") {
@Override
public boolean accepts(@NotNull PsiMethod method, ProcessingContext context) {
return method instanceof GrLightMethodBuilder && key.equals(((GrLightMethodBuilder)method).getMethodKind());
return GrLightMethodBuilder.checkKind(method, key);
}
});
}
@@ -0,0 +1,159 @@
package org.jetbrains.plugins.groovy.lang.resolve;
import com.intellij.psi.*;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.extensions.GroovyMethodInfo;
import org.jetbrains.plugins.groovy.extensions.GroovyNamedArgumentReferenceProvider;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
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.expressions.GrConditionalExpression;
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.util.PsiUtil;
import static org.jetbrains.plugins.groovy.lang.psi.patterns.GroovyPatterns.stringLiteral;
/**
* @author Sergey Evdokimov
*/
public final class GroovyMethodArgumentReferenceContributor extends PsiReferenceContributor {
@Override
public void registerReferenceProviders(PsiReferenceRegistrar registrar) {
registrar.registerReferenceProvider(stringLiteral(), new MyProvider());
}
private static class MyProvider extends PsiReferenceProvider {
@NotNull
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
GrExpression argument = (GrExpression)element;
PsiElement parent = element.getParent();
if (parent instanceof GrConditionalExpression) {
// support case: foo(a > b ? "aaa" : "bbb")
if (((GrConditionalExpression)parent).getCondition() == parent) return PsiReference.EMPTY_ARRAY;
argument = (GrConditionalExpression)parent;
parent = parent.getParent();
}
if (parent instanceof GrListOrMap) {
// support case: foo(["aaa", "bbb"])
if (!((GrListOrMap)parent).isMap()) {
argument = (GrListOrMap)parent;
parent = parent.getParent();
}
}
if (parent instanceof GrNamedArgument) {
return createReferencesForNamedArgument(element, (GrNamedArgument)parent, context);
}
if (parent instanceof GrArgumentList) {
GrArgumentList argumentList = (GrArgumentList)parent;
int index = argumentList.getExpressionArgumentIndex(argument);
PsiElement call = argumentList.getParent();
if (!(call instanceof GrMethodCall)) return PsiReference.EMPTY_ARRAY;
return PsiReference.EMPTY_ARRAY;
}
return PsiReference.EMPTY_ARRAY;
}
private static PsiReference[] createReferencesForNamedArgument(@NotNull PsiElement element,
GrNamedArgument namedArgument,
@NotNull ProcessingContext context) {
String labelName = namedArgument.getLabelName();
if (labelName == null) return PsiReference.EMPTY_ARRAY;
if (!GroovyMethodInfo.getAllSupportedNamedArguments().contains(labelName)) {
// Optimization: avoid unnecessary resolve.
return PsiReference.EMPTY_ARRAY;
}
PsiElement call = PsiUtil.getCallByNamedParameter(namedArgument);
if (!(call instanceof GrMethodCall)) return PsiReference.EMPTY_ARRAY;
GrExpression invokedExpression = ((GrMethodCall)call).getInvokedExpression();
if (!(invokedExpression instanceof GrReferenceExpression)) return PsiReference.EMPTY_ARRAY;
for (GroovyResolveResult result : ((GrReferenceExpression)invokedExpression).multiResolve(false)) {
PsiElement eMethod = result.getElement();
if (!(eMethod instanceof PsiMethod)) continue;
PsiMethod method = (PsiMethod)eMethod;
for (GroovyMethodInfo info : GroovyMethodInfo.getInfos(method)) {
Object referenceProvider = info.getNamedArgReferenceProvider(labelName);
if (referenceProvider != null) {
PsiReference[] refs;
if (referenceProvider instanceof GroovyNamedArgumentReferenceProvider) {
refs = ((GroovyNamedArgumentReferenceProvider)referenceProvider).createRef(element, namedArgument, result, context);
}
else {
refs = ((PsiReferenceProvider)referenceProvider).getReferencesByElement(element, context);
}
if (refs.length > 0) {
return refs;
}
}
}
}
return PsiReference.EMPTY_ARRAY;
}
//@NotNull
//private PsiReference[] createReferencesForArgument(@NotNull PsiElement element,
// int index,
// @NotNull GrMethodCall methodCall) {
// GrExpression invokedExpression = methodCall.getInvokedExpression();
// if (!(invokedExpression instanceof GrReferenceExpression)) return PsiReference.EMPTY_ARRAY;
//
// String methodName = ((GrReferenceExpression)invokedExpression).getReferenceName();
// if (methodName == null) return PsiReference.EMPTY_ARRAY;
//
// for (String key : new String[] {methodName, null}) {
// for (GroovyResolveResult result : ((GrReferenceExpression)invokedExpression).multiResolve(false)) {
// PsiElement eMethod = result.getElement();
// if (eMethod instanceof PsiMethod) {
// PsiMethod method = (PsiMethod)eMethod;
//
// //noinspection ConstantConditions
// if (key != null && !key.equals(method.getName())) continue;
//
// for (Pair<Contributor.Provider, Condition<PsiMethod>> pair : list) {
// if (pair.second.value(method)) {
// PsiReference[] res;
// if (attrNameOrParameterIndex instanceof Integer) {
// res = pair.first.createRef(element, methodCall, (Integer)attrNameOrParameterIndex, result);
// }
// else {
// assert namedArgument != null;
// res = pair.first.createRef(element, namedArgument, result);
// }
//
// if (res.length > 0) {
// return res;
// }
// }
// }
// }
// }
// }
//
// return PsiReference.EMPTY_ARRAY;
//}
}
}
@@ -35,6 +35,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrReflectedMethod;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder;
import org.jetbrains.plugins.groovy.lang.psi.util.StaticChecker;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint;
@@ -198,6 +199,14 @@ public class DynamicMemberUtils {
}
dynamicMethod.setOriginalInfo(originalInfo);
String kind = commentMap.get("kind");
if (kind == null) {
kind = classCommentMap.get("kind");
}
if (kind != null) {
dynamicMethod.putUserData(GrLightMethodBuilder.KIND_KEY, kind);
}
multiMap.putValue(null, dynamicMethod);
multiMap.putValue(method.getName(), dynamicMethod);