Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -4,7 +4,7 @@ import com.intellij.ide.IconProvider;
|
||||
import com.intellij.openapi.util.Iconable;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.Icons;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
@@ -15,21 +15,21 @@ import javax.swing.*;
|
||||
* @author yole
|
||||
*/
|
||||
public class JetIconProvider extends IconProvider {
|
||||
public static final Icon ICON_FOR_OBJECT = Icons.ANONYMOUS_CLASS_ICON;
|
||||
public static final Icon ICON_FOR_OBJECT = PlatformIcons.ANONYMOUS_CLASS_ICON;
|
||||
|
||||
@Override
|
||||
public Icon getIcon(@NotNull PsiElement psiElement, int flags) {
|
||||
if (psiElement instanceof JetNamespace) {
|
||||
return (flags & Iconable.ICON_FLAG_OPEN) != 0 ? Icons.PACKAGE_OPEN_ICON : Icons.PACKAGE_ICON;
|
||||
return (flags & Iconable.ICON_FLAG_OPEN) != 0 ? PlatformIcons.PACKAGE_OPEN_ICON : PlatformIcons.PACKAGE_ICON;
|
||||
}
|
||||
if (psiElement instanceof JetNamedFunction) {
|
||||
return PsiTreeUtil.getParentOfType(psiElement, JetNamedDeclaration.class) instanceof JetClass
|
||||
? Icons.METHOD_ICON
|
||||
: Icons.FUNCTION_ICON;
|
||||
? PlatformIcons.METHOD_ICON
|
||||
: PlatformIcons.FUNCTION_ICON;
|
||||
}
|
||||
if (psiElement instanceof JetClass) {
|
||||
JetClass jetClass = (JetClass) psiElement;
|
||||
Icon icon = jetClass.hasModifier(JetTokens.ENUM_KEYWORD) ? Icons.ENUM_ICON : Icons.CLASS_ICON;
|
||||
Icon icon = jetClass.hasModifier(JetTokens.ENUM_KEYWORD) ? PlatformIcons.ENUM_ICON : PlatformIcons.CLASS_ICON;
|
||||
if (jetClass instanceof JetEnumEntry) {
|
||||
JetEnumEntry enumEntry = (JetEnumEntry) jetClass;
|
||||
if (enumEntry.getPrimaryConstructorParameterList() == null) {
|
||||
@@ -42,13 +42,13 @@ public class JetIconProvider extends IconProvider {
|
||||
if (((JetParameter) psiElement).getValOrVarNode() != null) {
|
||||
JetParameterList parameterList = PsiTreeUtil.getParentOfType(psiElement, JetParameterList.class);
|
||||
if (parameterList != null && parameterList.getParent() instanceof JetClass) {
|
||||
return Icons.PROPERTY_ICON;
|
||||
return PlatformIcons.PROPERTY_ICON;
|
||||
}
|
||||
}
|
||||
return Icons.PARAMETER_ICON;
|
||||
return PlatformIcons.PARAMETER_ICON;
|
||||
}
|
||||
if (psiElement instanceof JetProperty) {
|
||||
return Icons.PROPERTY_ICON;
|
||||
return PlatformIcons.PROPERTY_ICON;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -24,13 +24,23 @@ import java.util.Set;
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class WholeProjectAnalyzerFacade {
|
||||
public static final Function<JetFile, Collection<JetDeclaration>> WHOLE_PROJECT_DECLARATION_PROVIDER = new Function<JetFile, Collection<JetDeclaration>>() {
|
||||
public final class WholeProjectAnalyzerFacade {
|
||||
|
||||
/** Forbid creating */
|
||||
private WholeProjectAnalyzerFacade() {}
|
||||
|
||||
/**
|
||||
* Will collect all root-namespaces in all kotlin files in the project.
|
||||
*/
|
||||
public static final Function<JetFile, Collection<JetDeclaration>> WHOLE_PROJECT_DECLARATION_PROVIDER =
|
||||
new Function<JetFile, Collection<JetDeclaration>>() {
|
||||
|
||||
@Override
|
||||
public Collection<JetDeclaration> fun(final JetFile rootFile) {
|
||||
final Project project = rootFile.getProject();
|
||||
final Set<JetDeclaration> namespaces = Sets.newLinkedHashSet();
|
||||
ProjectRootManager rootManager = ProjectRootManager.getInstance(project);
|
||||
final ProjectRootManager rootManager = ProjectRootManager.getInstance(project);
|
||||
|
||||
if (rootManager != null && !ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
VirtualFile[] contentRoots = rootManager.getContentRoots();
|
||||
|
||||
@@ -55,9 +65,9 @@ public class WholeProjectAnalyzerFacade {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@NotNull
|
||||
public static BindingContext analyzeProjectWithCacheOnAFile(@NotNull JetFile file) {
|
||||
return AnalyzerFacade.analyzeFileWithCache(file, WHOLE_PROJECT_DECLARATION_PROVIDER);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,27 +21,31 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.ui.content.ContentFactory;
|
||||
import com.intellij.util.Alarm;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolutionDebugInfo;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.plugin.JetFileType;
|
||||
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
|
||||
import org.jetbrains.jet.plugin.internal.codewindow.BytecodeToolwindow;
|
||||
import org.jetbrains.jet.util.slicedmap.ReadOnlySlice;
|
||||
import org.jetbrains.jet.util.slicedmap.WritableSlice;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.EXPRESSION_TYPE;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLVED_CALL;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.ResolutionDebugInfo.*;
|
||||
|
||||
/*
|
||||
* @author abreslav
|
||||
@@ -121,19 +125,20 @@ public class ResolveToolwindow extends JPanel {
|
||||
PsiElement currentElement = elementAtOffset;
|
||||
|
||||
boolean callFound = false;
|
||||
while (currentElement != null && !(currentElement instanceof PsiFile)) {
|
||||
if (currentElement instanceof JetElement) {
|
||||
JetElement atOffset = (JetElement) currentElement;
|
||||
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(RESOLVED_CALL, (JetElement) atOffset);
|
||||
if (resolvedCall != null) {
|
||||
setText(renderCall(resolvedCall) + "\n===\n" + currentElement + ": " + currentElement.getText());
|
||||
callFound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
currentElement = currentElement.getParent();
|
||||
PsiElement elementWithDebugInfo = findData(bindingContext, currentElement, RESOLUTION_DEBUG_INFO);
|
||||
if (elementWithDebugInfo != null) {
|
||||
callFound = true;
|
||||
setText(renderDebugInfo(elementWithDebugInfo, bindingContext.get(RESOLUTION_DEBUG_INFO, elementWithDebugInfo), null));
|
||||
}
|
||||
else {
|
||||
PsiElement elementWithResolvedCall = findData(bindingContext, currentElement, (WritableSlice) RESOLVED_CALL);
|
||||
if (elementWithResolvedCall instanceof JetElement) {
|
||||
callFound = true;
|
||||
setText(renderDebugInfo(elementWithResolvedCall, null, bindingContext.get(RESOLVED_CALL, (JetElement) elementWithResolvedCall)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!callFound) {
|
||||
|
||||
JetExpression parentExpression = (elementAtOffset instanceof JetExpression) ? (JetExpression) elementAtOffset
|
||||
@@ -153,8 +158,70 @@ public class ResolveToolwindow extends JPanel {
|
||||
}
|
||||
}
|
||||
|
||||
private String renderCall(ResolvedCall<? extends CallableDescriptor> resolvedCall) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
@Nullable
|
||||
private <D> PsiElement findData(BindingContext bindingContext, PsiElement currentElement, ReadOnlySlice<PsiElement, D> slice) {
|
||||
while (currentElement != null && !(currentElement instanceof PsiFile)) {
|
||||
if (currentElement instanceof JetElement) {
|
||||
JetElement atOffset = (JetElement) currentElement;
|
||||
D data = bindingContext.get(slice, atOffset);
|
||||
if (data != null && data != NO_DEBUG_INFO) {
|
||||
return currentElement;
|
||||
}
|
||||
|
||||
}
|
||||
currentElement = currentElement.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String renderDebugInfo(PsiElement currentElement, @Nullable ResolutionDebugInfo.Data debugInfo, @Nullable ResolvedCall<? extends CallableDescriptor> call) {
|
||||
final String bar = "\n\n===\n\n";
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
if (debugInfo != null) {
|
||||
StringBuilder errors = debugInfo.get(ERRORS);
|
||||
if (errors != null) {
|
||||
result.append("Errors: \n").append(errors).append(bar);
|
||||
}
|
||||
|
||||
StringBuilder log = debugInfo.get(LOG);
|
||||
if (log != null) {
|
||||
result.append("Log: \n").append(log).append(bar);
|
||||
}
|
||||
|
||||
Map<JetType, ConstraintSystemImpl.TypeValue> knowns = debugInfo.get(BOUNDS_FOR_KNOWNS);
|
||||
renderMap(knowns, result);
|
||||
Map<TypeParameterDescriptor, ConstraintSystemImpl.TypeValue> unknowns = debugInfo.get(BOUNDS_FOR_UNKNOWNS);
|
||||
renderMap(unknowns, result);
|
||||
|
||||
result.append(bar);
|
||||
|
||||
call = debugInfo.get(RESULT);
|
||||
}
|
||||
|
||||
renderCall(result, call);
|
||||
result.append(currentElement + ": " + currentElement.getText());
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private <K> void renderMap(Map<K, ConstraintSystemImpl.TypeValue> map, StringBuilder builder) {
|
||||
if (map == null) return;
|
||||
|
||||
for (Map.Entry<K, ConstraintSystemImpl.TypeValue> entry : map.entrySet()) {
|
||||
K key = entry.getKey();
|
||||
ConstraintSystemImpl.TypeValue typeValue = entry.getValue();
|
||||
builder.append("Bounds for ").append(key).append("\n");
|
||||
for (ConstraintSystemImpl.TypeValue bound : typeValue.getLowerBounds()) {
|
||||
builder.append(" >: ").append(bound).append("\n");
|
||||
}
|
||||
for (ConstraintSystemImpl.TypeValue bound : typeValue.getUpperBounds()) {
|
||||
builder.append(" <: ").append(bound).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String renderCall(StringBuilder builder, ResolvedCall<? extends CallableDescriptor> resolvedCall) {
|
||||
|
||||
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
|
||||
ReceiverDescriptor receiverArgument = resolvedCall.getReceiverArgument();
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Tests
|
||||
|
||||
import java.util.*
|
||||
|
||||
fun hello() {
|
||||
val a = So<caret>
|
||||
}
|
||||
|
||||
// EXIST: SortedSet, SortedMap
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Tests
|
||||
|
||||
class A : java.<caret>
|
||||
|
||||
// EXIST: lang, util, io
|
||||
// ABSENT: fun, val, var, namespace
|
||||
@@ -1,10 +1,10 @@
|
||||
open class MyClass() {
|
||||
}
|
||||
|
||||
class A() : My<caret> {
|
||||
class A() {
|
||||
public fun test() {
|
||||
val a : MyC<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: MyClass
|
||||
// EXIST: MyClass
|
||||
|
||||
@@ -3,4 +3,4 @@ fun foo() {
|
||||
}
|
||||
|
||||
// TODO: Move all keywords to absent
|
||||
// EXPECT: fun, val, var, namespace
|
||||
// EXIST: fun, val, var, namespace
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<caret>
|
||||
|
||||
// EXPECT: namespace, as, type, class, this, super, val, var, fun, for, null, true
|
||||
// EXPECT: false, is, in, throw, return, break, continue, object, if, try, else, while
|
||||
// EXPECT: do, when, trait, This
|
||||
// EXPECT: import, where, by, get, set, abstract, enum, open, annotation, override, private
|
||||
// EXPECT: public, internal, protected, catch, out, vararg, inline, finally, final, ref
|
||||
// EXIST: namespace, as, type, class, this, super, val, var, fun, for, null, true
|
||||
// EXIST: false, is, in, throw, return, break, continue, object, if, try, else, while
|
||||
// EXIST: do, when, trait, This
|
||||
// EXIST: import, where, by, get, set, abstract, enum, open, annotation, override, private
|
||||
// EXIST: public, internal, protected, catch, out, vararg, inline, finally, final, ref
|
||||
// ABSENT: ?in, new, extends, implements
|
||||
@@ -23,7 +23,7 @@ public class JetBasicCompletionTest extends JetCompletionTestBase {
|
||||
setName("testCompletionExecute");
|
||||
}
|
||||
|
||||
public void testCompletionExecute() {
|
||||
public void testCompletionExecute() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,70 +2,64 @@ package org.jetbrains.jet.completion;
|
||||
|
||||
import com.intellij.codeInsight.completion.CodeCompletionHandlerBase;
|
||||
import com.intellij.codeInsight.completion.CompletionType;
|
||||
import com.intellij.codeInsight.completion.LightCompletionTestCase;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupEx;
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.testFramework.LightCodeInsightTestCase;
|
||||
import com.intellij.codeInsight.lookup.impl.LookupImpl;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.plugin.PluginTestCaseBase;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Nikolay.Krasko
|
||||
*/
|
||||
public abstract class JetCompletionTestBase extends LightCodeInsightTestCase {
|
||||
public abstract class JetCompletionTestBase extends LightCompletionTestCase {
|
||||
|
||||
protected void doTest() {
|
||||
private CompletionType type;
|
||||
|
||||
protected void doTest() throws Exception {
|
||||
final String testName = getTestName(false);
|
||||
|
||||
type = (testName.startsWith("Smart")) ? CompletionType.SMART : CompletionType.BASIC;
|
||||
|
||||
configureByFile(testName + ".kt");
|
||||
|
||||
CompletionType completionType = (testName.startsWith("Smart")) ? CompletionType.SMART : CompletionType.BASIC;
|
||||
new CodeCompletionHandlerBase(completionType, false, false, true).invokeCompletion(getProject(), getEditor());
|
||||
|
||||
LookupEx lookup = LookupManager.getActiveLookup(getEditor());
|
||||
assert lookup != null;
|
||||
|
||||
HashSet<String> items = new HashSet<String>(resolveLookups(lookup.getItems()));
|
||||
|
||||
List<String> shouldExist = itemsShouldExist(getFile().getText());
|
||||
for (String shouldExistItem : shouldExist) {
|
||||
assertTrue(String.format("Should contain proposal '%s'.", shouldExistItem),
|
||||
items.contains(shouldExistItem));
|
||||
}
|
||||
|
||||
List<String> shouldAbsent = itemsShouldAbsent(getFile().getText());
|
||||
for (String shouldAbsentItem : shouldAbsent) {
|
||||
assertTrue(String.format("Shouldn't contain proposal '%s'.", shouldAbsentItem),
|
||||
!items.contains(shouldAbsentItem));
|
||||
}
|
||||
assertContainsItems(itemsShouldExist(getFile().getText()));
|
||||
assertNotContainItems(itemsShouldAbsent(getFile().getText()));
|
||||
}
|
||||
|
||||
private static List<String> resolveLookups(List<LookupElement> items) {
|
||||
ArrayList<String> result = new ArrayList<String>(items.size());
|
||||
for (LookupElement item : items) {
|
||||
result.add(item.getLookupString());
|
||||
}
|
||||
|
||||
return result;
|
||||
@Override
|
||||
protected Sdk getProjectJDK() {
|
||||
return PluginTestCaseBase.jdkFromIdeaHome();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void complete(final int time) {
|
||||
new CodeCompletionHandlerBase(type, false, false, true).invokeCompletion(getProject(), getEditor(), time, false);
|
||||
|
||||
LookupImpl lookup = (LookupImpl) LookupManager.getActiveLookup(myEditor);
|
||||
myItems = lookup == null ? null : lookup.getItems().toArray(LookupElement.EMPTY_ARRAY);
|
||||
myPrefix = lookup == null ? null : lookup.itemPattern(lookup.getItems().get(0));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<String> itemsShouldExist(String fileText) {
|
||||
private static String[] itemsShouldExist(String fileText) {
|
||||
return findListWithPrefix("// EXIST:", fileText);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<String> itemsShouldAbsent(String fileText) {
|
||||
private static String[] itemsShouldAbsent(String fileText) {
|
||||
return findListWithPrefix("// ABSENT:", fileText);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<String> findListWithPrefix(String prefix, String fileText) {
|
||||
private static String[] findListWithPrefix(String prefix, String fileText) {
|
||||
ArrayList<String> result = new ArrayList<String>();
|
||||
|
||||
for (String line : findLinesWithPrefixRemoved(prefix, fileText)) {
|
||||
@@ -76,7 +70,7 @@ public abstract class JetCompletionTestBase extends LightCodeInsightTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result.toArray(new String[result.size()]);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.jetbrains.jet.completion;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.JetTestCaseBuilder;
|
||||
@@ -25,7 +26,7 @@ public class KeywordsCompletionTest extends JetCompletionTestBase {
|
||||
setName("testCompletionExecute");
|
||||
}
|
||||
|
||||
public void testCompletionExecute() {
|
||||
public void testCompletionExecute() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@@ -49,13 +50,14 @@ public class KeywordsCompletionTest extends JetCompletionTestBase {
|
||||
PluginTestCaseBase.getTestDataPathBase(), "/completion/keywords/", false,
|
||||
JetTestCaseBuilder.emptyFilter, new JetTestCaseBuilder.NamedTestFactory() {
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public junit.framework.Test createTest(@NotNull String dataPath, @NotNull String name, @NotNull File file) {
|
||||
public Test createTest(@NotNull String dataPath, @NotNull String name, @NotNull File file) {
|
||||
return new KeywordsCompletionTest(dataPath, name);
|
||||
}
|
||||
}, suite);
|
||||
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user