Fixed parameter info issues: 1. Constructors. 2. Green background. 3. Default parameters text is better for literals now. 4. Added few tests.

This commit is contained in:
Alefas
2012-01-24 18:27:17 +04:00
parent 855a0097a0
commit 9246cd5b81
17 changed files with 556 additions and 22 deletions
@@ -11,12 +11,11 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.compiler.TipsManager;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.JetVisibilityChecker;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
@@ -34,6 +33,8 @@ import java.util.List;
*/
public class JetFunctionParameterInfoHandler implements
ParameterInfoHandlerWithTabActionSupport<JetValueArgumentList, Object, JetValueArgument> {
public final static Color GREEN_BACKGROUND = new Color(231, 254, 234);
@NotNull
@Override
public JetValueArgument[] getActualParameters(@NotNull JetValueArgumentList arguments) {
@@ -56,7 +57,7 @@ public class JetFunctionParameterInfoHandler implements
@NotNull
@Override
public Set<Class> getArgumentListAllowedParentClasses() {
return Collections.singleton((Class) JetCallExpression.class);
return Collections.singleton((Class) JetCallElement.class);
}
@NotNull
@@ -78,7 +79,7 @@ public class JetFunctionParameterInfoHandler implements
@Override
public Object[] getParametersForLookup(LookupElement item, ParameterInfoContext context) {
return ArrayUtil.EMPTY_OBJECT_ARRAY; //todo:
return ArrayUtil.EMPTY_OBJECT_ARRAY; //todo: ?
}
@Override
@@ -124,7 +125,7 @@ public class JetFunctionParameterInfoHandler implements
return true;
}
private static String renderParameter(ValueParameterDescriptor descriptor, boolean named) {
private static String renderParameter(ValueParameterDescriptor descriptor, boolean named, BindingContext bindingContext) {
StringBuilder builder = new StringBuilder();
if (named) builder.append("[");
if (descriptor.getVarargElementType() != null) {
@@ -133,7 +134,24 @@ public class JetFunctionParameterInfoHandler implements
builder.append(descriptor.getName()).append(": ").
append(DescriptorRenderer.TEXT.renderType(getActualParameterType(descriptor)));
if (descriptor.hasDefaultValue()) {
builder.append(" = {...}");
PsiElement element = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
String defaultExpression = "?";
if (element instanceof JetParameter) {
JetParameter parameter = (JetParameter) element;
JetExpression defaultValue = parameter.getDefaultValue();
if (defaultValue != null) {
if (defaultValue instanceof JetConstantExpression) {
JetConstantExpression constantExpression = (JetConstantExpression) defaultValue;
defaultExpression = constantExpression.getText();
if (defaultExpression.length() > 10) {
if (defaultExpression.startsWith("\"")) defaultExpression = "\"...\"";
else if (defaultExpression.startsWith("\'")) defaultExpression = "\'...\'";
else defaultExpression = defaultExpression.substring(0, 7) + "...";
}
}
}
}
builder.append(" = ").append(defaultExpression);
}
if (named) builder.append("]");
return builder.toString();
@@ -147,9 +165,7 @@ public class JetFunctionParameterInfoHandler implements
@Override
public void updateUI(Object descriptor, ParameterInfoUIContext context) {
//todo: when we will have ability to pass Array as vararg, implement such feature here too
//todo: check for constructors
//todo: TESTS!!!
//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()) {
return;
}
@@ -169,7 +185,33 @@ public class JetFunctionParameterInfoHandler implements
int boldEndOffset = -1;
boolean isGrey = false;
boolean isDeprecated = false; //todo: add deprecation check
Color color = context.getDefaultParameterColor(); //todo: choose descriptors to highlight green
Color color = context.getDefaultParameterColor();
PsiElement parent = argumentList.getParent();
if (parent instanceof JetCallElement) {
JetCallElement callExpression = (JetCallElement) parent;
JetExpression calleeExpression = callExpression.getCalleeExpression();
JetSimpleNameExpression refExpression = null;
if (calleeExpression instanceof JetSimpleNameExpression) {
refExpression = (JetSimpleNameExpression) calleeExpression;
} else if (calleeExpression instanceof JetConstructorCalleeExpression) {
JetConstructorCalleeExpression constructorCalleeExpression = (JetConstructorCalleeExpression) calleeExpression;
if (constructorCalleeExpression.getConstructorReferenceExpression() instanceof JetSimpleNameExpression) {
refExpression = (JetSimpleNameExpression) constructorCalleeExpression.getConstructorReferenceExpression();
}
}
if (refExpression != null) {
ResolvedCall<? extends CallableDescriptor> call = bindingContext.get(BindingContext.RESOLVED_CALL, refExpression);
if (call != null) {
CallableDescriptor candidateDescriptor = call.getCandidateDescriptor();
PsiElement elem = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, candidateDescriptor);
PsiElement ourElem = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, functionDescriptor);
if (elem.equals(ourElem)) {
color = GREEN_BACKGROUND;
}
}
}
}
boolean[] usedIndexes = new boolean[valueParameters.size()];
boolean namedMode = false;
Arrays.fill(usedIndexes, false);
@@ -193,7 +235,7 @@ public class JetFunctionParameterInfoHandler implements
namedMode = true;
} else {
ValueParameterDescriptor param = valueParameters.get(i);
builder.append(renderParameter(param, false));
builder.append(renderParameter(param, false, bindingContext));
if (i < currentParameterIndex) {
if (argument.getArgumentExpression() != null) {
//check type
@@ -207,7 +249,7 @@ public class JetFunctionParameterInfoHandler implements
}
} else {
ValueParameterDescriptor param = valueParameters.get(i);
builder.append(renderParameter(param, false));
builder.append(renderParameter(param, false, bindingContext));
}
}
if (namedMode) {
@@ -222,7 +264,7 @@ public class JetFunctionParameterInfoHandler implements
param.getName().equals(referenceExpression.getReferencedName())) {
takeAnyArgument = false;
usedIndexes[j] = true;
builder.append(renderParameter(param, true));
builder.append(renderParameter(param, true, bindingContext));
if (i < currentParameterIndex) {
if (argument.getArgumentExpression() != null) {
//check type
@@ -245,7 +287,7 @@ public class JetFunctionParameterInfoHandler implements
ValueParameterDescriptor param = valueParameters.get(j);
if (!usedIndexes[j]) {
usedIndexes[j] = true;
builder.append(renderParameter(param, true));
builder.append(renderParameter(param, true, bindingContext));
break;
}
}
@@ -253,7 +295,7 @@ public class JetFunctionParameterInfoHandler implements
}
if (highlightParameter) boldEndOffset = builder.length();
}
if (builder.toString() == "") context.setUIComponentEnabled(false);
if (builder.toString().isEmpty()) context.setUIComponentEnabled(false);
else context.setupUIComponentPresentation(builder.toString(), boldStartOffset, boldEndOffset, isGrey,
isDeprecated, false, color);
} else context.setUIComponentEnabled(false);
@@ -261,6 +303,7 @@ public class JetFunctionParameterInfoHandler implements
}
private static JetValueArgumentList findCall(CreateParameterInfoContext context) {
//todo: calls to this constructors, when we will have auxiliary constructors
PsiFile file = context.getFile();
if (!(file instanceof JetFile)) return null;
PsiElement element = file.findElementAt(context.getOffset());
@@ -269,16 +312,24 @@ public class JetFunctionParameterInfoHandler implements
}
if (element == null) return null;
JetValueArgumentList argumentList = (JetValueArgumentList) element;
JetCallExpression callExpression;
if (element.getParent() instanceof JetCallExpression) {
callExpression = (JetCallExpression) element.getParent();
JetCallElement callExpression;
if (element.getParent() instanceof JetCallElement) {
callExpression = (JetCallElement) element.getParent();
} else return null;
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache((JetFile) file,
AnalyzerFacade.SINGLE_DECLARATION_PROVIDER);
JetExpression calleeExpression = callExpression.getCalleeExpression();
if (calleeExpression == null) return null;
JetSimpleNameExpression refExpression = null;
if (calleeExpression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression refExpression = (JetSimpleNameExpression) calleeExpression;
refExpression = (JetSimpleNameExpression) calleeExpression;
} else if (calleeExpression instanceof JetConstructorCalleeExpression) {
JetConstructorCalleeExpression constructorCalleeExpression = (JetConstructorCalleeExpression) calleeExpression;
if (constructorCalleeExpression.getConstructorReferenceExpression() instanceof JetSimpleNameExpression) {
refExpression = (JetSimpleNameExpression) constructorCalleeExpression.getConstructorReferenceExpression();
}
}
if (refExpression != null) {
JetScope scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, refExpression);
DeclarationDescriptor placeDescriptor = null;
if (scope != null) {
@@ -297,13 +348,21 @@ public class JetFunctionParameterInfoHandler implements
if (placeDescriptor != null && !JetVisibilityChecker.isVisible(placeDescriptor, functionDescriptor)) continue;
itemsToShow.add(functionDescriptor);
}
} else if (variant instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) variant;
if (classDescriptor.getName().equals(refName)) {
//todo: renamed classes?
for (ConstructorDescriptor constructorDescriptor : classDescriptor.getConstructors()) {
if (placeDescriptor != null && !JetVisibilityChecker.isVisible(placeDescriptor, constructorDescriptor)) continue;
itemsToShow.add(constructorDescriptor);
}
}
}
}
context.setItemsToShow(ArrayUtil.toObjectArray(itemsToShow));
return argumentList;
} else {
return null; //todo: this expression?
}
return null;
}
private static JetValueArgumentList findCallAndUpdateContext(UpdateParameterInfoContext context) {
@@ -0,0 +1,13 @@
open class A(x: Int) {
fun m(x: Int) = 1
fun m(x: Int, y: Boolean) = 2
}
class B(): A(5) {
fun d(x: Int, y: Boolean, z: String) {
m(1, <caret>false)
}
}
/*
smth
*/
@@ -0,0 +1,14 @@
open class A(x: Int) {
fun m(x: Int) = 1
fun m(x: Int, y: Boolean) = 2
}
class B(): A(5) {
fun m(x: Int, y: Boolean, z: String) {
m(1, <caret>false)
}
}
/*
Text: (x: Int, y: Boolean, z: String), Disabled: false, Strikeout: false, Green: false
smth
*/
@@ -0,0 +1,12 @@
open class A(x: Int) {
fun m(x: Int) = 1
fun m(x: Int, y: Boolean = true, z: Long = 12345678901234) = 2
fun d(x: Int) {
m(<caret>y = false, x = 1)
}
}
/*
Text: ([x: Int]), Disabled: false, Strikeout: false, Green: false
Text: ([y: Boolean = true], [x: Int], [z: Long = 1234567...]), Disabled: false, Strikeout: false, Green: true
*/
@@ -0,0 +1,12 @@
open class A(x: Int) {
fun m(x: Int) = 1
fun m(x: Int, y: Boolean) = 2
fun d(x: Int) {
m(x = 1, <caret>y = false)
}
}
/*
Text: ([x: Int]), Disabled: true, Strikeout: false, Green: false
Text: ([x: Int], [y: Boolean]), Disabled: false, Strikeout: false, Green: true
*/
@@ -0,0 +1,12 @@
open class A(x: Int) {
fun m(x: Int) = 1
fun m(x: Int, y: Boolean) = 2
fun d(x: Int) {
m(<caret>y = false, x = 1)
}
}
/*
Text: ([x: Int]), Disabled: false, Strikeout: false, Green: false
Text: ([y: Boolean], [x: Int]), Disabled: false, Strikeout: false, Green: true
*/
@@ -0,0 +1,10 @@
open class A(x: Int) {
fun m(x: Int, y: Boolean) = 2
fun m(x: Int) = 1
fun d(x: Int) {
m(1, false, false)
}
}
/*
*/
@@ -0,0 +1,14 @@
open class A(x: Int) {
fun println(x: String) {}
fun println() {}
fun println(x: Boolean) {}
fun d(x: Int) {
println(<caret>)
}
}
/*
Text: (<no parameters>), Disabled: false, Strikeout: false, Green: true
Text: (x: Boolean), Disabled: false, Strikeout: false, Green: false
Text: (x: String), Disabled: false, Strikeout: false, Green: false
*/
@@ -0,0 +1,8 @@
open class A(x: Int) {
fun m(x: Int, y: Boolean) = 2
fun d(x: Int) {
m(<caret>1, false)
}
}
//Text: (x: Int, y: Boolean), Disabled: false, Strikeout: false, Green: true
@@ -0,0 +1,9 @@
open class A(x: Int) {
}
class B(): A(5) {
fun m() {
A(<caret>3)
}
}
//Text: (x: Int), Disabled: false, Strikeout: false, Green: true
@@ -0,0 +1,9 @@
open class A(x: Int) {
}
class B(): A(<caret>5) {
fun m() {
A(3)
}
}
//Text: (x: Int), Disabled: false, Strikeout: false, Green: true
@@ -0,0 +1,12 @@
open class A(x: Int) {
fun m(x: Int) = 1
fun m(x: Int, y: Boolean) = 2
fun d(x: Int) {
m(<caret>1, false)
}
}
/*
Text: (x: Int), Disabled: false, Strikeout: false, Green: false
Text: (x: Int, y: Boolean), Disabled: false, Strikeout: false, Green: true
*/
@@ -0,0 +1,12 @@
open class A(x: Int) {
fun m(x: Int) = 1
fun m(x: Int, y: Boolean) = 2
fun d(x: Int) {
m(1, <caret>false)
}
}
/*
Text: (x: Int), Disabled: true, Strikeout: false, Green: false
Text: (x: Int, y: Boolean), Disabled: false, Strikeout: false, Green: true
*/
@@ -0,0 +1,99 @@
package org.jetbrains.jet.plugin.parameterInfo;
import com.intellij.psi.PsiElement;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetValueArgumentList;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.PluginTestCaseBase;
/**
* User: Alexander Podkhalyuzin
* Date: 24.01.12
*/
public class JetFunctionParameterInfoTest extends LightCodeInsightFixtureTestCase {
public void testInheritedFunctions() {
doTest();
}
public void testInheritedWithCurrentFunctions() {
doTest();
}
public void testNamedAndDefaultParameter() {
doTest();
}
public void testNamedParameter() {
doTest();
}
public void testNamedParameter2() {
doTest();
}
public void testNotGreen() {
doTest();
}
public void testPrintln() {
doTest();
}
public void testSimple() {
doTest();
}
public void testSimpleConstructor() {
doTest();
}
public void testSuperConstructorCall() {
doTest();
}
public void testTwoFunctions() {
doTest();
}
public void testTwoFunctionsGrey() {
doTest();
}
@Override
protected void setUp() throws Exception {
super.setUp();
myFixture.setTestDataPath(PluginTestCaseBase.getTestDataPathBase() + "/parameterInfo/functionParameterInfo");
}
private void doTest() {
myFixture.configureByFile(getTestName(false) + ".kt");
final JetFile file = (JetFile) myFixture.getFile();
PsiElement lastChild = file.getLastChild();
assert lastChild != null;
String expectedResultText = null;
if (lastChild.getNode().getElementType().equals(JetTokens.BLOCK_COMMENT)) {
String lastChildText = lastChild.getText();
expectedResultText = lastChildText.substring(2, lastChildText.length() - 2).trim();
} else if (lastChild.getNode().getElementType().equals(JetTokens.EOL_COMMENT)) {
expectedResultText = lastChild.getText().substring(2).trim();
}
assert expectedResultText != null;
JetFunctionParameterInfoHandler parameterInfoHandler = new JetFunctionParameterInfoHandler();
MockCreateParameterInfoContext mockCreateParameterInfoContext = new MockCreateParameterInfoContext(file, myFixture);
final JetValueArgumentList parameterOwner = parameterInfoHandler.findElementForParameterInfo(mockCreateParameterInfoContext);
final MockUpdateParameterInfoContext updateContext = new MockUpdateParameterInfoContext(file, myFixture);
//to update current parameter index
parameterInfoHandler.findElementForUpdatingParameterInfo(updateContext);
MockParameterInfoUIContext parameterInfoUIContext =
new MockParameterInfoUIContext(parameterOwner, updateContext.getCurrentParameter());
for (Object item : mockCreateParameterInfoContext.getItemsToShow()) {
parameterInfoHandler.updateUI(item, parameterInfoUIContext);
}
assertEquals(expectedResultText, parameterInfoUIContext.getResultText());
}
}
@@ -0,0 +1,77 @@
package org.jetbrains.jet.plugin.parameterInfo;
import com.intellij.lang.parameterInfo.CreateParameterInfoContext;
import com.intellij.lang.parameterInfo.ParameterInfoHandler;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
/**
* User: Alexander Podkhalyuzin
* Date: 24.01.12
*/
public class MockCreateParameterInfoContext implements CreateParameterInfoContext {
private Object[] myItemsToShow = ArrayUtil.EMPTY_OBJECT_ARRAY;
private PsiElement myHighlightedElement = null;
private JavaCodeInsightTestFixture myFixture;
private PsiFile myFile;
MockCreateParameterInfoContext(PsiFile file, JavaCodeInsightTestFixture fixture) {
myFile = file;
myFixture = fixture;
}
@Override
public Object[] getItemsToShow() {
return myItemsToShow;
}
@Override
public void setItemsToShow(Object[] items) {
myItemsToShow = items;
}
@Override
public void showHint(PsiElement element, int offset, ParameterInfoHandler handler) {
}
@Override
public int getParameterListStart() {
return 0;
}
@Override
public PsiElement getHighlightedElement() {
return myHighlightedElement;
}
@Override
public void setHighlightedElement(PsiElement elements) {
myHighlightedElement = elements;
}
@Override
public Project getProject() {
return myFixture.getProject();
}
@Override
public PsiFile getFile() {
return myFile;
}
@Override
public int getOffset() {
return myFixture.getCaretOffset();
}
@NotNull
@Override
public Editor getEditor() {
return myFixture.getEditor();
}
}
@@ -0,0 +1,70 @@
package org.jetbrains.jet.plugin.parameterInfo;
import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.lang.parameterInfo.ParameterInfoUIContext;
import com.intellij.psi.PsiElement;
import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
/**
* User: Alexander Podkhalyuzin
* Date: 24.01.12
*/
public class MockParameterInfoUIContext implements ParameterInfoUIContext {
private PsiElement myParaeterOwner;
private int myCurrentParameterIndex;
private ArrayList<String> result = new ArrayList<String>();
MockParameterInfoUIContext(PsiElement parameterOwner, int currentParameterIndex) {
myParaeterOwner = parameterOwner;
myCurrentParameterIndex = currentParameterIndex;
}
@Override
public void setupUIComponentPresentation(String text, int highlightStartOffset, int highlightEndOffset,
boolean isDisabled, boolean strikeout,
boolean isDisabledBeforeHighlight, Color background) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Text: (").append(text).append("), Disabled: ").append(isDisabled).
append(", Strikeout: ").append(strikeout).append(", Green: ").
append(background.equals(JetFunctionParameterInfoHandler.GREEN_BACKGROUND));
result.add(stringBuilder.toString());
}
@Override
public boolean isUIComponentEnabled() {
return false;
}
@Override
public void setUIComponentEnabled(boolean enabled) {
}
@Override
public int getCurrentParameterIndex() {
return myCurrentParameterIndex;
}
@Override
public PsiElement getParameterOwner() {
return myParaeterOwner;
}
@Override
public Color getDefaultParameterColor() {
return HintUtil.INFORMATION_COLOR;
}
public String getResultText() {
StringBuilder stringBuilder = new StringBuilder();
Collections.sort(result);
for (String s : result) {
stringBuilder.append(s).append("\n");
}
return stringBuilder.toString().trim();
}
}
@@ -0,0 +1,92 @@
package org.jetbrains.jet.plugin.parameterInfo;
import com.intellij.lang.parameterInfo.UpdateParameterInfoContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
/**
* User: Alexander Podkhalyuzin
* Date: 24.01.12
*/
public class MockUpdateParameterInfoContext implements UpdateParameterInfoContext {
private int myCurrentParameter = -1;
private PsiFile myFile;
private JavaCodeInsightTestFixture myFixture;
MockUpdateParameterInfoContext(PsiFile file, JavaCodeInsightTestFixture fixture) {
myFile = file;
myFixture = fixture;
}
@Override
public void removeHint() {
}
@Override
public void setParameterOwner(PsiElement o) {
}
@Override
public PsiElement getParameterOwner() {
return null;
}
@Override
public void setHighlightedParameter(Object parameter) {
}
@Override
public void setCurrentParameter(int index) {
myCurrentParameter = index;
}
public int getCurrentParameter() {
return myCurrentParameter;
}
@Override
public boolean isUIComponentEnabled(int index) {
return false;
}
@Override
public void setUIComponentEnabled(int index, boolean b) {
}
@Override
public int getParameterListStart() {
return 0;
}
@Override
public Object[] getObjectsToView() {
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
@Override
public Project getProject() {
return null;
}
@Override
public PsiFile getFile() {
return myFile;
}
@Override
public int getOffset() {
return myFixture.getCaretOffset();
}
@NotNull
@Override
public Editor getEditor() {
return myFixture.getEditor();
}
}