Refactorings in counting parameters tips

This commit is contained in:
Nikolay Krasko
2013-06-19 16:30:13 +04:00
parent e7bdee7994
commit b0484c9680
3 changed files with 60 additions and 70 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.jet.plugin.parameterInfo; package org.jetbrains.jet.plugin.parameterInfo;
import com.google.common.collect.Iterables;
import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
@@ -55,8 +56,11 @@ import java.util.List;
* User: Alefas * User: Alefas
* Date: 17.01.12 * Date: 17.01.12
*/ */
public class JetFunctionParameterInfoHandler implements public class JetFunctionParameterInfoHandler implements ParameterInfoHandlerWithTabActionSupport<
ParameterInfoHandlerWithTabActionSupport<JetValueArgumentList, Object, JetValueArgument> { JetValueArgumentList,
Pair<? extends FunctionDescriptor, ResolveSession>,
JetValueArgument>
{
public final static Color GREEN_BACKGROUND = new JBColor(new Color(231, 254, 234), Gray._100); public final static Color GREEN_BACKGROUND = new JBColor(new Color(231, 254, 234), Gray._100);
@NotNull @NotNull
@@ -106,8 +110,9 @@ public class JetFunctionParameterInfoHandler implements
return ArrayUtil.EMPTY_OBJECT_ARRAY; //todo: ? return ArrayUtil.EMPTY_OBJECT_ARRAY; //todo: ?
} }
@Nullable
@Override @Override
public Object[] getParametersForDocumentation(Object p, ParameterInfoContext context) { public Object[] getParametersForDocumentation(Pair<? extends FunctionDescriptor, ResolveSession> p, ParameterInfoContext context) {
return ArrayUtil.EMPTY_OBJECT_ARRAY; //todo: ? return ArrayUtil.EMPTY_OBJECT_ARRAY; //todo: ?
} }
@@ -148,15 +153,16 @@ public class JetFunctionParameterInfoHandler implements
public boolean tracksParameterIndex() { public boolean tracksParameterIndex() {
return true; return true;
} }
private static String renderParameter(ValueParameterDescriptor parameter, boolean named, BindingContext bindingContext) { private static String renderParameter(ValueParameterDescriptor parameter, boolean named, BindingContext bindingContext) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
if (named) builder.append("["); if (named) builder.append("[");
if (parameter.getVarargElementType() != null) { if (parameter.getVarargElementType() != null) {
builder.append("vararg "); builder.append("vararg ");
} }
builder.append(parameter.getName()).append(": "). builder.append(parameter.getName())
append(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(getActualParameterType(parameter))); .append(": ")
.append(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(getActualParameterType(parameter)));
if (parameter.hasDefaultValue()) { if (parameter.hasDefaultValue()) {
PsiElement parameterDeclaration = BindingContextUtils.descriptorToDeclaration(bindingContext, parameter); PsiElement parameterDeclaration = BindingContextUtils.descriptorToDeclaration(bindingContext, parameter);
builder.append(" = ").append(getDefaultExpressionString(parameterDeclaration)); builder.append(" = ").append(getDefaultExpressionString(parameterDeclaration));
@@ -194,7 +200,7 @@ public class JetFunctionParameterInfoHandler implements
} }
@Override @Override
public void updateUI(Object itemToShow, ParameterInfoUIContext context) { public void updateUI(Pair<? extends FunctionDescriptor, ResolveSession> itemToShow, ParameterInfoUIContext context) {
//todo: when we will have ability to pass Array as vararg, implement such feature here too? //todo: when we will have ability to pass Array as vararg, implement such feature here too?
if (context == null || context.getParameterOwner() == null || !context.getParameterOwner().isValid()) { if (context == null || context.getParameterOwner() == null || !context.getParameterOwner().isValid()) {
context.setUIComponentEnabled(false); context.setUIComponentEnabled(false);
@@ -209,26 +215,12 @@ public class JetFunctionParameterInfoHandler implements
JetValueArgumentList argumentList = (JetValueArgumentList) parameterOwner; JetValueArgumentList argumentList = (JetValueArgumentList) parameterOwner;
if (!(itemToShow instanceof Pair<?, ?>)) { FunctionDescriptor functionDescriptor = itemToShow.first;
context.setUIComponentEnabled(false); ResolveSession resolveSession = itemToShow.second;
return;
}
Pair<?, ?> pair = (Pair<?, ?>) itemToShow;
if (!(pair.first instanceof FunctionDescriptor && pair.second instanceof ResolveSession)) {
context.setUIComponentEnabled(false);
return;
}
FunctionDescriptor functionDescriptor = (FunctionDescriptor) pair.first;
ResolveSession resolveSession = (ResolveSession) pair.second;
JetFile file = (JetFile) argumentList.getContainingFile();
List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters(); List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
List<JetValueArgument> valueArguments = argumentList.getArguments(); List<JetValueArgument> valueArguments = argumentList.getArguments();
StringBuilder builder = new StringBuilder();
int currentParameterIndex = context.getCurrentParameterIndex(); int currentParameterIndex = context.getCurrentParameterIndex();
int boldStartOffset = -1; int boldStartOffset = -1;
int boldEndOffset = -1; int boldEndOffset = -1;
@@ -236,17 +228,15 @@ public class JetFunctionParameterInfoHandler implements
boolean isDeprecated = false; //todo: add deprecation check boolean isDeprecated = false; //todo: add deprecation check
boolean[] usedIndexes = new boolean[valueParameters.size()]; boolean[] usedIndexes = new boolean[valueParameters.size()];
boolean namedMode = false;
Arrays.fill(usedIndexes, false); Arrays.fill(usedIndexes, false);
if ((currentParameterIndex >= valueParameters.size() && (valueParameters.size() > 0 || currentParameterIndex > 0)) && boolean namedMode = false;
(valueParameters.size() == 0 || valueParameters.get(valueParameters.size() - 1).getVarargElementType() == null)) {
if (!isIndexValid(valueParameters, currentParameterIndex)) {
isGrey = true; isGrey = true;
} }
if (valueParameters.size() == 0) { StringBuilder builder = new StringBuilder();
builder.append(CodeInsightBundle.message("parameter.info.no.parameters"));
}
PsiElement owner = context.getParameterOwner(); PsiElement owner = context.getParameterOwner();
BindingContext bindingContext = ResolveSessionUtils.resolveToExpression(resolveSession, (JetElement) owner); BindingContext bindingContext = ResolveSessionUtils.resolveToExpression(resolveSession, (JetElement) owner);
@@ -257,7 +247,7 @@ public class JetFunctionParameterInfoHandler implements
} }
boolean highlightParameter = i == currentParameterIndex || boolean highlightParameter = i == currentParameterIndex ||
(!namedMode && i < currentParameterIndex && valueParameters.get(valueParameters.size() - 1).getVarargElementType() != null); (!namedMode && i < currentParameterIndex && Iterables.getLast(valueParameters).getVarargElementType() != null);
if (highlightParameter) { if (highlightParameter) {
boldStartOffset = builder.length(); boldStartOffset = builder.length();
@@ -272,18 +262,8 @@ public class JetFunctionParameterInfoHandler implements
else { else {
ValueParameterDescriptor param = valueParameters.get(i); ValueParameterDescriptor param = valueParameters.get(i);
builder.append(renderParameter(param, false, bindingContext)); builder.append(renderParameter(param, false, bindingContext));
if (i < currentParameterIndex) { if (i <= currentParameterIndex && !isArgumentTypeValid(bindingContext, argument, param)) {
if (argument.getArgumentExpression() != null) { isGrey = true;
//check type
JetType paramType = getActualParameterType(param);
JetType exprType = bindingContext.get(BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression());
if (exprType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(exprType, paramType)) {
isGrey = true;
}
}
else {
isGrey = true;
}
} }
usedIndexes[i] = true; usedIndexes[i] = true;
} }
@@ -293,6 +273,7 @@ public class JetFunctionParameterInfoHandler implements
builder.append(renderParameter(param, false, bindingContext)); builder.append(renderParameter(param, false, bindingContext));
} }
} }
if (namedMode) { if (namedMode) {
boolean takeAnyArgument = true; boolean takeAnyArgument = true;
if (valueArguments.size() > i) { if (valueArguments.size() > i) {
@@ -301,21 +282,12 @@ public class JetFunctionParameterInfoHandler implements
for (int j = 0; j < valueParameters.size(); ++j) { for (int j = 0; j < valueParameters.size(); ++j) {
JetSimpleNameExpression referenceExpression = argument.getArgumentName().getReferenceExpression(); JetSimpleNameExpression referenceExpression = argument.getArgumentName().getReferenceExpression();
ValueParameterDescriptor param = valueParameters.get(j); ValueParameterDescriptor param = valueParameters.get(j);
if (referenceExpression != null && !usedIndexes[j] && if (referenceExpression != null && !usedIndexes[j] && param.getName().equals(referenceExpression.getReferencedNameAsName())) {
param.getName().equals(referenceExpression.getReferencedNameAsName())) {
takeAnyArgument = false; takeAnyArgument = false;
usedIndexes[j] = true; usedIndexes[j] = true;
builder.append(renderParameter(param, true, bindingContext)); builder.append(renderParameter(param, true, bindingContext));
if (i < currentParameterIndex) { if (i < currentParameterIndex && !isArgumentTypeValid(bindingContext, argument, param)) {
if (argument.getArgumentExpression() != null) { isGrey = true;
//check type
JetType paramType = getActualParameterType(param);
JetType exprType = bindingContext.get(BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression());
if (exprType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(exprType, paramType)) isGrey = true;
}
else {
isGrey = true;
}
} }
break; break;
} }
@@ -344,35 +316,48 @@ public class JetFunctionParameterInfoHandler implements
} }
} }
Color color = getBackgroundColor(context, argumentList, functionDescriptor, bindingContext); if (valueParameters.size() == 0) {
builder.append(CodeInsightBundle.message("parameter.info.no.parameters"));
}
if (builder.toString().isEmpty()) { assert !builder.toString().isEmpty() : "A message about 'no parameters' or some parameters should be present: " + functionDescriptor;
context.setUIComponentEnabled(false);
} Color color = isResolvedToDescriptor(argumentList, functionDescriptor, bindingContext) ? GREEN_BACKGROUND : context.getDefaultParameterColor();
else { context.setupUIComponentPresentation(builder.toString(), boldStartOffset, boldEndOffset, isGrey, isDeprecated, false, color);
context.setupUIComponentPresentation(builder.toString(), boldStartOffset, boldEndOffset, isGrey,
isDeprecated, false, color);
}
} }
private static Color getBackgroundColor( private static boolean isArgumentTypeValid(BindingContext bindingContext, JetValueArgument argument, ValueParameterDescriptor param) {
ParameterInfoUIContext context, if (argument.getArgumentExpression() != null) {
JetType paramType = getActualParameterType(param);
JetType exprType = bindingContext.get(BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression());
return exprType == null || JetTypeChecker.INSTANCE.isSubtypeOf(exprType, paramType);
}
return false;
}
private static boolean isIndexValid(List<ValueParameterDescriptor> valueParameters, int index) {
// Index is within range of parameters or last parameter is vararg
return index < valueParameters.size() ||
(valueParameters.size() > 0 && Iterables.getLast(valueParameters).getVarargElementType() != null);
}
private static Boolean isResolvedToDescriptor(
JetValueArgumentList argumentList, JetValueArgumentList argumentList,
FunctionDescriptor functionDescriptor, FunctionDescriptor functionDescriptor,
BindingContext bindingContext BindingContext bindingContext
) { ) {
JetSimpleNameExpression callNameExpression = getCallSimpleNameExpression(argumentList); JetSimpleNameExpression callNameExpression = getCallSimpleNameExpression(argumentList);
if (callNameExpression != null) { if (callNameExpression != null) {
// Mark with green background the variant with resolved call
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, callNameExpression); DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, callNameExpression);
if (declarationDescriptor != null) { if (declarationDescriptor != null) {
if (declarationDescriptor == functionDescriptor) { if (declarationDescriptor == functionDescriptor) {
return GREEN_BACKGROUND; return true;
} }
} }
} }
return context.getDefaultParameterColor(); return false;
} }
private static JetValueArgumentList findCall(CreateParameterInfoContext context) { private static JetValueArgumentList findCall(CreateParameterInfoContext context) {
@@ -408,6 +393,7 @@ public class JetFunctionParameterInfoHandler implements
} }
Collection<DeclarationDescriptor> variants = TipsManager.getReferenceVariants(callNameExpression, bindingContext); Collection<DeclarationDescriptor> variants = TipsManager.getReferenceVariants(callNameExpression, bindingContext);
Name refName = callNameExpression.getReferencedNameAsName(); Name refName = callNameExpression.getReferencedNameAsName();
Collection<Pair<? extends DeclarationDescriptor, ResolveSession>> itemsToShow = new ArrayList<Pair<? extends DeclarationDescriptor, ResolveSession>>(); Collection<Pair<? extends DeclarationDescriptor, ResolveSession>> itemsToShow = new ArrayList<Pair<? extends DeclarationDescriptor, ResolveSession>>();
@@ -16,10 +16,13 @@
package org.jetbrains.jet.plugin.parameterInfo; package org.jetbrains.jet.plugin.parameterInfo;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetValueArgumentList; import org.jetbrains.jet.lang.psi.JetValueArgumentList;
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.PluginTestCaseBase; import org.jetbrains.jet.plugin.PluginTestCaseBase;
@@ -113,7 +116,8 @@ public class JetFunctionParameterInfoTest extends LightCodeInsightFixtureTestCas
new MockParameterInfoUIContext(parameterOwner, updateContext.getCurrentParameter()); new MockParameterInfoUIContext(parameterOwner, updateContext.getCurrentParameter());
for (Object item : mockCreateParameterInfoContext.getItemsToShow()) { for (Object item : mockCreateParameterInfoContext.getItemsToShow()) {
parameterInfoHandler.updateUI(item, parameterInfoUIContext); //noinspection unchecked
parameterInfoHandler.updateUI((Pair<? extends FunctionDescriptor, ResolveSession>)item, parameterInfoUIContext);
} }
assertEquals(expectedResultText, parameterInfoUIContext.getResultText()); assertEquals(expectedResultText, parameterInfoUIContext.getResultText());
} }
@@ -33,8 +33,8 @@ import org.jetbrains.annotations.NotNull;
public class MockCreateParameterInfoContext implements CreateParameterInfoContext { public class MockCreateParameterInfoContext implements CreateParameterInfoContext {
private Object[] myItemsToShow = ArrayUtil.EMPTY_OBJECT_ARRAY; private Object[] myItemsToShow = ArrayUtil.EMPTY_OBJECT_ARRAY;
private PsiElement myHighlightedElement = null; private PsiElement myHighlightedElement = null;
private JavaCodeInsightTestFixture myFixture; private final JavaCodeInsightTestFixture myFixture;
private PsiFile myFile; private final PsiFile myFile;
MockCreateParameterInfoContext(PsiFile file, JavaCodeInsightTestFixture fixture) { MockCreateParameterInfoContext(PsiFile file, JavaCodeInsightTestFixture fixture) {
myFile = file; myFile = file;