Merge remote-tracking branch 'origin/master'

This commit is contained in:
Eugene.Kudelevsky
2011-05-14 23:52:01 +04:00
19 changed files with 239 additions and 66 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -175,7 +175,8 @@ public abstract class JavaPsiFacade {
*/
public abstract boolean isPartOfPackagePrefix(String packageName);
/* Checks if the specified PSI element belongs to the specified package.
/**
* Checks if the specified PSI element belongs to the specified package.
*
* @param element the element to check the package for.
* @param aPackage the package to check.
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -116,7 +116,7 @@ public abstract class JavaCodeStyleManager {
*
* @param name the name of the variable.
* @param variableKind the kind of the variable.
* @return the stipped-down name.
* @return the stripped-down name.
*/
public abstract String variableNameToPropertyName(@NonNls String name, VariableKind variableKind);
@@ -146,7 +146,7 @@ public abstract class JavaCodeStyleManager {
* @param baseNameInfo the base name info for the variable.
* @param place the location where the variable will be used.
* @param lookForward if true, the existing variables are searched in both directions; if false - only backward
* @return the generated unique name,
* @return the generated unique name
*/
@NotNull
public SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo,
@@ -163,6 +163,7 @@ public abstract class JavaCodeStyleManager {
* @param place the location where the variable will be used.
* @param ignorePlaceName if true and place is PsiNamedElement, place.getName() would be still treated as unique name
* @param lookForward if true, the existing variables are searched in both directions; if false - only backward @return the generated unique name,
* @return the generated unique name
*/
@NotNull public abstract SuggestedNameInfo suggestUniqueVariableName(@NotNull SuggestedNameInfo baseNameInfo,
PsiElement place,
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -29,12 +29,16 @@ public interface JavadocTagInfo {
@NonNls String getName();
boolean isInline();
boolean isValidInContext(PsiElement element);
Object[] getPossibleValues(PsiElement context, PsiElement place, String prefix);
/**
* Checks the tag value for correctnes. Returns null if correct. Error message otherwise.
* Checks the tag value for correctness.
*
* @param value Doc tag to check.
* @return Returns null if correct, error message otherwise.
*/
@Nullable
String checkTagValue(PsiDocTagValue value);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2011 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.
@@ -22,7 +22,8 @@ import com.intellij.util.xmlb.XmlSerializer;
* Every component which would like to persist its state across IDEA restarts
* should implement this interface.
*
* todo: describe registration procedures
* See <a href="http://confluence.jetbrains.net/display/IDEADEV/Persisting+State+of+Components">JetBrains WIKI</a>
* for detailed description.
*/
public interface PersistentStateComponent<T> {
/**
@@ -24,10 +24,15 @@ import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiType;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import java.util.*;
import java.util.HashSet;
/**
* @author peter
@@ -67,6 +72,31 @@ public class GrMapType extends GrLiteralClassType {
facade.findClass(JAVA_UTIL_LINKED_HASH_MAP, scope) != null ? JAVA_UTIL_LINKED_HASH_MAP : CommonClassNames.JAVA_UTIL_MAP;
}
public GrMapType(JavaPsiFacade facade, GlobalSearchScope scope, GrNamedArgument[] args) {
super(LanguageLevel.JDK_1_5, scope, facade);
myJavaClassName =
facade.findClass(JAVA_UTIL_LINKED_HASH_MAP, scope) != null ? JAVA_UTIL_LINKED_HASH_MAP : CommonClassNames.JAVA_UTIL_MAP;
myStringEntries = new HashMap<String, PsiType>();
myOtherEntries=new ArrayList<Pair<PsiType, PsiType>>();
for (GrNamedArgument arg : args) {
GrArgumentLabel label = arg.getLabel();
if (label == null) continue;
GrExpression expression = arg.getExpression();
if (expression == null || expression.getType() == null) continue;
if (label.getName() != null) {
myStringEntries.put(label.getName(), expression.getType());
}
else if (label.getExpression() != null) {
PsiType type = label.getExpression().getType();
myOtherEntries.add(new Pair<PsiType, PsiType>(type, expression.getType()));
}
}
}
@NotNull
@Override
public PsiClassType rawType() {
@@ -364,8 +364,6 @@ public class TypesUtil {
public static PsiType getLeastUpperBoundNullable(@Nullable PsiType type1, @Nullable PsiType type2, PsiManager manager) {
if (type1 == null) return type2;
if (type2 == null) return type1;
if (type1.isAssignableFrom(type2)) return type1;
if (type2.isAssignableFrom(type1)) return type2;
return getLeastUpperBound(type1, type2, manager);
}
@@ -17,6 +17,7 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.types;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.MethodSignatureUtil;
@@ -41,6 +42,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCurriedClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
@@ -645,4 +647,56 @@ public class GrClosureSignatureUtil {
@NotNull GrClosureSignature signature) {
return generateAllMethodSignaturesByClosureSignature(name, signature, PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY);
}
@Nullable
public static PsiType getTypeByTypeArg(ArgInfo<PsiType> arg, PsiManager manager, GlobalSearchScope resolveScope) {
if (arg.isMultiArg) {
if (arg.args.size() == 0) return PsiType.getJavaLangObject(manager, resolveScope).createArrayType();
PsiType leastUpperBound = null;
for (PsiType type : arg.args) {
leastUpperBound = TypesUtil.getLeastUpperBoundNullable(leastUpperBound, type, manager);
}
if (leastUpperBound == null) return null;
return leastUpperBound.createArrayType();
}
else {
if (arg.args.size() > 0) return arg.args.get(0);
return null;
}
}
@Nullable
public static PsiType getTypeByArg(ArgInfo<PsiElement> arg, PsiManager manager, GlobalSearchScope resolveScope) {
if (arg.isMultiArg) {
if (arg.args.size() == 0) return PsiType.getJavaLangObject(manager, resolveScope).createArrayType();
PsiType leastUpperBound = null;
PsiElement first = arg.args.get(0);
if (first instanceof GrNamedArgument) {
GrNamedArgument[] args=new GrNamedArgument[arg.args.size()];
for (int i = 0, size = arg.args.size(); i < size; i++) {
args[i] = (GrNamedArgument)arg.args.get(i);
}
return new GrMapType(JavaPsiFacade.getInstance(manager.getProject()), resolveScope, args);
}
else {
for (PsiElement elem : arg.args) {
if (elem instanceof GrExpression) {
leastUpperBound = TypesUtil.getLeastUpperBoundNullable(leastUpperBound, ((GrExpression)elem).getType(), manager);
}
}
if (leastUpperBound == null) return null;
return leastUpperBound.createArrayType();
}
}
else {
if (arg.args.size() == 0) return null;
PsiElement elem = arg.args.get(0);
if (elem instanceof GrExpression) {
return ((GrExpression)elem).getType();
}
return null;
}
}
}
@@ -29,9 +29,9 @@ public class AnnotationGenerator extends Generator {
private final ExpressionContext context;
private final ExpressionGenerator expressionGenerator;
public AnnotationGenerator(StringBuilder builder, Project project) {
public AnnotationGenerator(StringBuilder builder, ExpressionContext context) {
this.builder = builder;
this.context = new ExpressionContext(project);
this.context = context.extend();
expressionGenerator = new ExpressionGenerator(builder, context);
}
@@ -105,7 +105,7 @@ public class AnonymousFromMapGenerator {
PsiType returnType;
if (found != null) {
returnType = substitutor.substitute(TypeProvider.getReturnType(found));
returnType = substitutor.substitute(context.typeProvider.getReturnType(found));
}
else {
returnType = signature.getReturnType();
@@ -186,9 +186,9 @@ public class ClassGenerator {
private static boolean shouldBeGenerated(PsiMethod method) {
for (PsiMethod psiMethod : method.findSuperMethods()) {
if (!psiMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
final PsiType type = TypeProvider.getReturnType(method);
final PsiType superType = TypeProvider.getReturnType(psiMethod);
if (!superType.isAssignableFrom(type)) {
final PsiType type = method.getReturnType();
final PsiType superType = psiMethod.getReturnType();
if (type != null && superType != null && !superType.isAssignableFrom(type)) {
return false;
}
}
@@ -120,7 +120,7 @@ public class ClassItemGeneratorImpl implements ClassItemGenerator {
//append return type
if (!method.isConstructor()) {
PsiType retType = TypeProvider.getReturnType(method);
PsiType retType = context.typeProvider.getReturnType(method);
/*
if (!method.hasModifierProperty(PsiModifier.STATIC)) {
@@ -161,7 +161,7 @@ public class ClassItemGeneratorImpl implements ClassItemGenerator {
builder.append("default ");
GrAnnotationMemberValue defaultValue = defaultAnnotationValue.getDefaultValue();
if (defaultValue != null) {
defaultValue.accept(new AnnotationGenerator(builder, context.project));
defaultValue.accept(new AnnotationGenerator(builder, context));
}
}
}
@@ -206,7 +206,7 @@ public class ClassItemGeneratorImpl implements ClassItemGenerator {
builder.append("this");
}
else {
if (TypeProvider.getReturnType(method) != PsiType.VOID) {
if (context.typeProvider.getReturnType(method) != PsiType.VOID) {
builder.append("return ");
}
builder.append(method.getName());
@@ -18,7 +18,6 @@ package org.jetbrains.plugins.groovy.refactoring.convertToJava;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.util.containers.hash.HashSet;
import org.codehaus.groovy.util.ManagedConcurrentMap;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.noReturnMethod.MissingReturnInspection;
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
@@ -91,7 +90,7 @@ public class CodeBlockGenerator extends Generator {
boolean shouldInsertReturnNull = false;
myExitPoints.clear();
PsiType returnType = TypeProvider.getReturnType(method);
PsiType returnType = context.typeProvider.getReturnType(method);
if (!method.isConstructor() && returnType != PsiType.VOID) {
myExitPoints.addAll(ControlFlowUtils.collectReturns(block));
shouldInsertReturnNull = !(returnType instanceof PsiPrimitiveType) &&
@@ -121,7 +120,7 @@ public class CodeBlockGenerator extends Generator {
for (GrParameter parameter : parameters) {
if (context.analyzedVars.toWrap(parameter)) {
StringBuilder typeText = new StringBuilder(GroovyCommonClassNames.GROOVY_LANG_REFERENCE);
GenerationUtil.writeTypeParameters(typeText, new PsiType[]{TypeProvider.getParameterType(parameter)}, method,
GenerationUtil.writeTypeParameters(typeText, new PsiType[]{context.typeProvider.getParameterType(parameter)}, method,
new GeneratorClassNameProvider());
builder.append("final ").append(typeText).append(' ').append(context.analyzedVars.toVarName(parameter))
.append(" = new ").append(typeText).append('(').append(parameter.getName()).append(");\n");
@@ -193,7 +192,7 @@ public class CodeBlockGenerator extends Generator {
return;
}
final ExpressionGenerator expressionGenerator = new ExpressionGenerator(context.project);
final ExpressionGenerator expressionGenerator = new ExpressionGenerator(context);
returnValue.accept(expressionGenerator);
StringBuilder builder = new StringBuilder();
builder.append("return ").append(expressionGenerator.getBuilder()).append(";"); //todo add casts to return type
@@ -209,7 +208,7 @@ public class CodeBlockGenerator extends Generator {
@Override
public void visitAssertStatement(GrAssertStatement assertStatement) {
final GrExpression assertion = assertStatement.getAssertion();
final ExpressionGenerator expressionGenerator = new ExpressionGenerator(context.project);
final ExpressionGenerator expressionGenerator = new ExpressionGenerator(context);
assertion.accept(expressionGenerator);
final StringBuilder builder = new StringBuilder("assert ").append(expressionGenerator.getBuilder()).append(";");
writeStatement(builder, assertStatement, expressionGenerator.getContext());
@@ -218,7 +217,7 @@ public class CodeBlockGenerator extends Generator {
@Override
public void visitThrowStatement(GrThrowStatement throwStatement) {
final GrExpression exception = throwStatement.getException();
final ExpressionGenerator expressionGenerator = new ExpressionGenerator(context.project);
final ExpressionGenerator expressionGenerator = new ExpressionGenerator(context);
exception.accept(expressionGenerator);
final StringBuilder builder =
new StringBuilder("throw ").append(expressionGenerator.getBuilder()).append(";"); //todo add exception to method 'throws' list
@@ -307,7 +306,7 @@ public class CodeBlockGenerator extends Generator {
final GrVariable declaredVariable = clause.getDeclaredVariable();
LOG.assertTrue(declaredVariable != null);
writeVariableWithoutSemicolonAndInitializer(builder, declaredVariable);
writeVariableWithoutSemicolonAndInitializer(builder, declaredVariable, context);
builder.append(" : ");
if (expression != null) {
final ExpressionContext context = forContext.copy();
@@ -322,7 +321,7 @@ public class CodeBlockGenerator extends Generator {
if (initialization instanceof GrParameter) {
StringBuilder partBuilder = new StringBuilder();
writeVariableWithoutSemicolonAndInitializer(partBuilder, (GrParameter)initialization);
writeVariableWithoutSemicolonAndInitializer(partBuilder, (GrParameter)initialization, context);
final GrExpression initializer = ((GrParameter)initialization).getDefaultInitializer();
if (initializer != null) {
final ExpressionContext partContext = forContext.copy();
@@ -371,9 +370,9 @@ public class CodeBlockGenerator extends Generator {
builder.append(visitor.getBuilder());
}
private static void writeVariableWithoutSemicolonAndInitializer(StringBuilder builder, GrVariable var) {
private static void writeVariableWithoutSemicolonAndInitializer(StringBuilder builder, GrVariable var, ExpressionContext context) {
ModifierListGenerator.writeModifiers(builder, var.getModifierList());
GenerationUtil.writeType(builder, TypeProvider.getVarType(var), var);
GenerationUtil.writeType(builder, context.typeProvider.getVarType(var), var);
builder.append(" ").append(var.getName());
}
@@ -422,7 +421,7 @@ public class CodeBlockGenerator extends Generator {
public void visitCatchClause(GrCatchClause catchClause) {
final GrParameter parameter = catchClause.getParameter();
builder.append("catch (");
writeVariableWithoutSemicolonAndInitializer(builder, parameter);
writeVariableWithoutSemicolonAndInitializer(builder, parameter, context);
builder.append(") ");
final GrOpenBlock body = catchClause.getBody();
if (body != null) {
@@ -494,7 +493,7 @@ public class CodeBlockGenerator extends Generator {
final GrModifierList modifierList = variableDeclaration.getModifierList();
for (final GrVariable v : variables) {
ModifierListGenerator.writeModifiers(builder, modifierList);
final PsiType type = TypeProvider.getVarType(v);
final PsiType type = context.typeProvider.getVarType(v);
GenerationUtil.writeType(builder, type, variableDeclaration);
builder.append(" ").append(v.getName());
builder.append(" = ").append(iteratorName).append(".hasNext() ? ").append(iteratorName).append(".next() : null;");
@@ -15,7 +15,6 @@
*/
package org.jetbrains.plugins.groovy.refactoring.convertToJava;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.util.containers.hash.HashMap;
import com.intellij.util.containers.hash.HashSet;
@@ -30,19 +29,21 @@ class ExpressionContext implements Cloneable {
List<String> myStatements = new ArrayList<String>();
Set<String> myUsedVarNames;
LocalVarAnalyzer.Result analyzedVars = LocalVarAnalyzer.initialResult();
TypeProvider typeProvider;
Project project;
private Map<String, Boolean> myProps = new HashMap<String, Boolean>();
private static final String myShouldInsertCurlyBrackets = "shouldInsertCurly";
private static final String myInAnonymousContext = "inAnonymousContext";
ExpressionContext(Project project, Set<String> usedVarNames) {
private ExpressionContext(Project project, Set<String> usedVarNames) {
this.project = project;
myUsedVarNames = usedVarNames;
}
ExpressionContext(Project project) {
this(project, new HashSet<String>());
typeProvider = new TypeProvider();
}
@Override
@@ -54,6 +55,7 @@ class ExpressionContext implements Cloneable {
final ExpressionContext expressionContext = new ExpressionContext(project, myUsedVarNames);
expressionContext.myProps.putAll(myProps);
expressionContext.analyzedVars = analyzedVars;
expressionContext.typeProvider = typeProvider;
return expressionContext;
}
@@ -63,6 +65,7 @@ class ExpressionContext implements Cloneable {
final ExpressionContext expressionContext = new ExpressionContext(project, usedVarNames);
expressionContext.myProps.putAll(myProps);
expressionContext.analyzedVars = analyzedVars;
expressionContext.typeProvider = typeProvider;
return expressionContext;
}
@@ -16,7 +16,6 @@
package org.jetbrains.plugins.groovy.refactoring.convertToJava;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightElement;
@@ -82,8 +81,11 @@ public class ExpressionGenerator extends Generator {
factory = GroovyPsiElementFactory.getInstance(context.project);
}
public ExpressionGenerator(Project project) {
this(new StringBuilder(), new ExpressionContext(project));
public ExpressionGenerator(ExpressionContext context) {
this.builder = new StringBuilder();
this.context = context;
factory = GroovyPsiElementFactory.getInstance(context.project);
}
@Override
@@ -289,10 +289,15 @@ public class GenerationUtil {
if (!classNameProvider.forStubs()) {
ModifierListGenerator.writeModifiers(text, parameter.getModifierList(), ModifierListGenerator.JAVA_MODIFIERS, true);
}
if (context != null && context.analyzedVars.toMakeFinal(parameter)) {
text.append(PsiModifier.FINAL).append(' ');
if (context != null) {
if (context.analyzedVars.toMakeFinal(parameter)) {
text.append(PsiModifier.FINAL).append(' ');
}
writeType(text, context.typeProvider.getParameterType(parameter), parameter, classNameProvider);
}
else {
writeType(text, parameter.getType(), parameter, classNameProvider);
}
writeType(text, TypeProvider.getParameterType(parameter), parameter, classNameProvider);
text.append(" ");
text.append(parameter.getName());
@@ -425,7 +430,7 @@ public class GenerationUtil {
}
static void writeVariableSeparately(GrVariable variable, StringBuilder builder, ExpressionContext expressionContext) {
PsiType type = TypeProvider.getVarType(variable);
PsiType type = expressionContext.typeProvider.getVarType(variable);
ModifierListGenerator.writeModifiers(builder, variable.getModifierList());
PsiType originalType = type;
@@ -83,7 +83,7 @@ public class ModifierListGenerator {
if (writeAnnotations && modifierList instanceof GrModifierList) {
GrAnnotation[] annotations = ((GrModifierList)modifierList).getAnnotations();
AnnotationGenerator annotationGenerator = new AnnotationGenerator(builder, modifierList.getProject());
AnnotationGenerator annotationGenerator = new AnnotationGenerator(builder, new ExpressionContext(modifierList.getProject()));
wasAddedModifiers = annotations.length > 0;
for (GrAnnotation annotation : annotations) {
annotation.accept(annotationGenerator);
@@ -40,6 +40,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrCo
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import java.util.*;
@@ -97,7 +98,7 @@ public class StubGenerator implements ClassItemGenerator {
for (int j = 0; j < superParams.length; j++) {
if (j > 0) text.append(", ");
text.append("(");
final PsiType type = TypeProvider.getParameterType(superParams[j]);
final PsiType type = superParams[j].getType();
writeType(text, substitutor.substitute(type), invocation, classNameProvider);
text.append(")").append(GroovyToJavaGenerator.getDefaultValueText(type.getCanonicalText()));
}
@@ -185,7 +186,10 @@ public class StubGenerator implements ClassItemGenerator {
}
//append return type
PsiType retType = TypeProvider.getReturnType(method, true);
PsiType retType = method.getReturnType();
if (retType == null) {
retType = TypesUtil.getJavaLangObject(method);
}
if (!method.hasModifierProperty(PsiModifier.STATIC)) {
final List<MethodSignatureBackedByPsiMethod> superSignatures = method.findSuperMethodSignaturesIncludingStatic(true);
@@ -320,7 +324,7 @@ public class StubGenerator implements ClassItemGenerator {
final LightMethodBuilder builder = new LightMethodBuilder(method.getManager(), method.getName());
substitutor = substitutor.putAll(TypeConversionUtil.getSuperClassSubstitutor(baseClass, typeDefinition, PsiSubstitutor.EMPTY));
for (PsiParameter parameter : method.getParameterList().getParameters()) {
builder.addParameter(StringUtil.notNullize(parameter.getName()), substitutor.substitute(TypeProvider.getParameterType(parameter)));
builder.addParameter(StringUtil.notNullize(parameter.getName()), substitutor.substitute(parameter.getType()));
}
builder.setReturnType(substitutor.substitute(method.getReturnType()));
for (String modifier : STUB_MODIFIERS) {
@@ -15,38 +15,39 @@
*/
package org.jetbrains.plugins.groovy.refactoring.convertToJava;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiParameter;
import com.intellij.psi.PsiType;
import com.intellij.psi.PsiVariable;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.MethodReferencesSearch;
import com.intellij.util.Processor;
import com.intellij.util.containers.HashMap;
import gnu.trove.TIntArrayList;
import gnu.trove.TIntProcedure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall;
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.api.statements.params.GrParameterList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import java.util.Map;
/**
* @author Medvedev Max
*/
public class TypeProvider {
private final Map<GrMethod, PsiType[]> inferredTypes = new HashMap<GrMethod, PsiType[]>();
private TypeProvider() {
public TypeProvider() {
}
@NotNull
public static PsiType getReturnType(PsiMethod method) {
return getReturnType(method, false);
}
@NotNull
public static PsiType getReturnType(PsiMethod method, boolean forStubs) {
if (forStubs) {
PsiType returnType = method.getReturnType();
if (returnType != null) return returnType;
return TypesUtil.getJavaLangObject(method);
}
public PsiType getReturnType(PsiMethod method) {
if (method instanceof GrMethod) {
GrTypeElement typeElement = ((GrMethod)method).getReturnTypeElementGroovy();
if (typeElement != null) return typeElement.getType();
@@ -59,7 +60,7 @@ public class TypeProvider {
}
@NotNull
public static PsiType getVarType(GrVariable variable) {
public PsiType getVarType(GrVariable variable) {
PsiType type = variable.getDeclaredType();
if (type == null) {
type = variable.getTypeGroovy();
@@ -71,7 +72,77 @@ public class TypeProvider {
}
@NotNull
public static PsiType getParameterType(PsiParameter parameter) {
return parameter.getType(); //todo make smarter
public PsiType getParameterType(PsiParameter parameter) {
if (!(parameter instanceof GrParameter)) {
return parameter.getType();
}
/*GrTypeElement typeElementGroovy = ((GrParameter)parameter).getTypeElementGroovy();
if (typeElementGroovy != null) {
return parameter.getType();
}*/
PsiElement parent = parameter.getParent();
if (!(parent instanceof GrParameterList)) return parameter.getType();
PsiElement pparent = parent.getParent();
if (!(pparent instanceof GrMethod)) return parameter.getType();
PsiType[] types = inferMethodParameters((GrMethod)pparent);
return types[((GrParameterList)parent).getParameterNumber((GrParameter)parameter)];
}
private PsiType[] inferMethodParameters(GrMethod method) {
PsiType[] psiTypes = inferredTypes.get(method);
if (psiTypes != null) return psiTypes;
final GrParameter[] parameters = method.getParameters();
final TIntArrayList paramInds = new TIntArrayList(parameters.length);
final PsiType[] types = new PsiType[parameters.length];
for (int i = 0; i < parameters.length; i++) {
if (parameters[i].getTypeElementGroovy() == null) {
paramInds.add(i);
} else {
types[i] = parameters[i].getType();
}
}
if (paramInds.size() > 0) {
final GrClosureSignature signature = GrClosureSignatureUtil.createSignature(method, PsiSubstitutor.EMPTY);
MethodReferencesSearch.search(method, true).forEach(new Processor<PsiReference>() {
@Override
public boolean process(PsiReference psiReference) {
final PsiElement element = psiReference.getElement();
final PsiManager manager = element.getManager();
final GlobalSearchScope resolveScope = element.getResolveScope();
if (element instanceof GrReferenceExpression) {
final GrCall call = (GrCall)element.getParent();
final GrClosureSignatureUtil.ArgInfo<PsiElement>[] argInfos = GrClosureSignatureUtil
.mapParametersToArguments(signature, call.getArgumentList(), ((GrReferenceExpression)element), call.getClosureArguments());
if (argInfos == null) return true;
paramInds.forEach(new TIntProcedure() {
@Override
public boolean execute(int i) {
PsiType type = GrClosureSignatureUtil.getTypeByArg(argInfos[i], manager, resolveScope);
types[i] = TypesUtil.getLeastUpperBoundNullable(type, types[i], manager);
return true;
}
});
}
return true;
}
});
}
paramInds.forEach(new TIntProcedure() {
@Override
public boolean execute(int i) {
if (types[i]==null) types[i] = parameters[i].getType();
return true;
}
});
inferredTypes.put(method, types);
return types;
}
}
@@ -32,7 +32,7 @@ return null;
}
public synchronized void out(java.lang.Object message) {
public synchronized void out(groovy.lang.GString message) {
println(message);
}