diff --git a/annotations/com/intellij/codeInsight/lookup/annotations.xml b/annotations/com/intellij/codeInsight/lookup/annotations.xml
index ad8a832f1e4..2c3b30ff6ac 100644
--- a/annotations/com/intellij/codeInsight/lookup/annotations.xml
+++ b/annotations/com/intellij/codeInsight/lookup/annotations.xml
@@ -26,14 +26,26 @@
name='com.intellij.codeInsight.lookup.LookupElementBuilder com.intellij.codeInsight.lookup.LookupElementBuilder setTypeText(java.lang.String, boolean)'>
+ -
+
+
-
+ -
+
+
-
+ -
+
+
-
diff --git a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java
index ff2e14dcaf4..18a42860061 100644
--- a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java
+++ b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/ClassDescriptor.java
@@ -30,7 +30,7 @@ import java.util.List;
public interface ClassDescriptor extends ClassifierDescriptor, MemberDescriptor, ClassOrNamespaceDescriptor {
@NotNull
- JetScope getMemberScope(List extends TypeProjection> typeArguments);
+ JetScope getMemberScope(@NotNull List extends TypeProjection> typeArguments);
@NotNull
JetScope getUnsubstitutedInnerClassesScope();
diff --git a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/AbstractClassDescriptor.java b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/AbstractClassDescriptor.java
index eb1dd61723b..16792c9af7c 100644
--- a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/AbstractClassDescriptor.java
+++ b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/AbstractClassDescriptor.java
@@ -107,7 +107,7 @@ public abstract class AbstractClassDescriptor implements ClassDescriptor {
@NotNull
@Override
- public JetScope getMemberScope(List extends TypeProjection> typeArguments) {
+ public JetScope getMemberScope(@NotNull List extends TypeProjection> typeArguments) {
assert typeArguments.size() == getTypeConstructor().getParameters().size() : "Illegal number of type arguments: expected "
+ getTypeConstructor().getParameters().size() + " but was " + typeArguments.size()
+ " for " + getTypeConstructor() + " " + getTypeConstructor().getParameters();
diff --git a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/LazySubstitutingClassDescriptor.java b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/LazySubstitutingClassDescriptor.java
index cc549a47621..47e1f8d93d0 100644
--- a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/LazySubstitutingClassDescriptor.java
+++ b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/LazySubstitutingClassDescriptor.java
@@ -87,7 +87,7 @@ public class LazySubstitutingClassDescriptor implements ClassDescriptor {
@NotNull
@Override
- public JetScope getMemberScope(List extends TypeProjection> typeArguments) {
+ public JetScope getMemberScope(@NotNull List extends TypeProjection> typeArguments) {
JetScope memberScope = original.getMemberScope(typeArguments);
if (originalSubstitutor.isEmpty()) {
return memberScope;
diff --git a/idea/src/org/jetbrains/jet/plugin/completion/SmartCompletion.kt b/idea/src/org/jetbrains/jet/plugin/completion/SmartCompletion.kt
index 625ff538c96..51eba98d146 100644
--- a/idea/src/org/jetbrains/jet/plugin/completion/SmartCompletion.kt
+++ b/idea/src/org/jetbrains/jet/plugin/completion/SmartCompletion.kt
@@ -19,6 +19,12 @@ import org.jetbrains.jet.lang.resolve.scopes.JetScope
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration
import org.jetbrains.jet.lang.resolve.name.Name
+import org.jetbrains.jet.lang.resolve.java.descriptor.JavaPropertyDescriptor
+import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiModifier
+import com.intellij.psi.util.PsiTreeUtil
trait SmartCompletionData{
fun accepts(descriptor: DeclarationDescriptor): Boolean
@@ -49,6 +55,7 @@ fun buildSmartCompletionData(expression: JetSimpleNameExpression, resolveSession
if (receiver == null) {
typeInstantiationItems(expectedType, resolveSession, bindingContext).toCollection(additionalElements)
thisItems(expressionWithType, expectedType, bindingContext).toCollection(additionalElements)
+ staticMembers(expressionWithType, expectedType, resolveSession, bindingContext).toCollection(additionalElements)
}
val dataFlowInfo = bindingContext.get(BindingContext.EXPRESSION_DATA_FLOW_INFO, expressionWithType)
@@ -231,6 +238,59 @@ private fun processDataFlowInfo(dataFlowInfo: DataFlowInfo?, receiver: JetExpres
return ProcessDataFlowInfoResult()
}
+// adds java static members, enum members and members from class object
+private fun staticMembers(context: JetExpression, expectedType: JetType, resolveSession: CancelableResolveSession, bindingContext: BindingContext): Iterable {
+ val classDescriptor = TypeUtils.getClassDescriptor(expectedType)
+ if (classDescriptor == null) return listOf()
+ if (classDescriptor.getName().isSpecial()) return listOf()
+ val scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, context)
+ if (scope == null) return listOf()
+
+ val descriptors = ArrayList()
+
+ val isSuitableCallable: (DeclarationDescriptor) -> Boolean = { it is CallableDescriptor && it.getReturnType()?.let { JetTypeChecker.INSTANCE.isSubtypeOf(it, expectedType) } ?: false }
+
+ if (classDescriptor is JavaClassDescriptor) {
+ //TODO: shouldn't we have special util to obtain this pseudo package?
+ val container = classDescriptor.getContainingDeclaration() //TODO: nested classes!
+ if (container is NamespaceDescriptor) {
+ val pseudoPackage: NamespaceDescriptor? = container.getMemberScope().getNamespace(classDescriptor.getName())
+ if (pseudoPackage != null) {
+ pseudoPackage.getMemberScope().getAllDescriptors().filterTo(descriptors, isSuitableCallable)
+ }
+ }
+ }
+
+ val classObject = classDescriptor.getClassObjectDescriptor()
+ if (classObject != null) {
+ classObject.getDefaultType().getMemberScope().getAllDescriptors().filterTo(descriptors, isSuitableCallable)
+ }
+
+ if (classDescriptor.getKind() == ClassKind.ENUM_CLASS) {
+ classDescriptor.getDefaultType().getMemberScope().getAllDescriptors()
+ .filterTo(descriptors) { it is ClassDescriptor && it.getKind() == ClassKind.ENUM_ENTRY && JetTypeChecker.INSTANCE.isSubtypeOf(it.getDefaultType(), expectedType) }
+ }
+
+ return descriptors
+ .filter { !(it is DeclarationDescriptorWithVisibility) || Visibilities.isVisible(it, scope.getContainingDeclaration()) }
+ .map {
+ val lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, bindingContext, it)
+ val presentation = LookupElementPresentation()
+ lookupElement.renderElement(presentation)
+ var builder = LookupElementBuilder.create(lookupElement.getObject(), classDescriptor.getName().asString() + "." + lookupElement.getLookupString())
+ .withIcon(presentation.getIcon())
+ .withStrikeoutness(presentation.isStrikeout())
+ .withTailText(" (" + DescriptorUtils.getFQName(classDescriptor.getContainingDeclaration()) + ")")
+ .withTypeText(if (presentation.getTypeText() != "") presentation.getTypeText() else DescriptorRenderer.TEXT.renderType(classDescriptor.getDefaultType()))
+ if (it is FunctionDescriptor) {
+ builder = builder.withPresentableText(builder.getLookupString() + "()")
+ val caretPosition = if (it.getValueParameters().empty) CaretPosition.AFTER_BRACKETS else CaretPosition.IN_BRACKETS
+ builder = builder.withInsertHandler(JetFunctionInsertHandler(caretPosition, BracketType.PARENTHESIS))
+ }
+ builder
+ }
+}
+
private fun T?.toList(): List = if (this != null) listOf(this) else listOf()
private fun MutableCollection.addAll(iterator: Iterator) {
diff --git a/idea/testData/completion/handlers/smart/ClassObjectMethod1.kt b/idea/testData/completion/handlers/smart/ClassObjectMethod1.kt
new file mode 100644
index 00000000000..dfc201ce219
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/ClassObjectMethod1.kt
@@ -0,0 +1,11 @@
+package sample
+
+class K {
+ class object {
+ fun bar(): K = K()
+ }
+}
+
+fun foo(){
+ val k : K =
+}
diff --git a/idea/testData/completion/handlers/smart/ClassObjectMethod1.kt.after b/idea/testData/completion/handlers/smart/ClassObjectMethod1.kt.after
new file mode 100644
index 00000000000..fa8dd4357dd
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/ClassObjectMethod1.kt.after
@@ -0,0 +1,11 @@
+package sample
+
+class K {
+ class object {
+ fun bar(): K = K()
+ }
+}
+
+fun foo(){
+ val k : K = K.bar()
+}
diff --git a/idea/testData/completion/handlers/smart/ClassObjectMethod2.kt b/idea/testData/completion/handlers/smart/ClassObjectMethod2.kt
new file mode 100644
index 00000000000..c6dd96c5070
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/ClassObjectMethod2.kt
@@ -0,0 +1,11 @@
+package sample
+
+class K {
+ class object {
+ fun bar(p: Int): K = K()
+ }
+}
+
+fun foo(){
+ val k : K =
+}
diff --git a/idea/testData/completion/handlers/smart/ClassObjectMethod2.kt.after b/idea/testData/completion/handlers/smart/ClassObjectMethod2.kt.after
new file mode 100644
index 00000000000..369ec744e06
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/ClassObjectMethod2.kt.after
@@ -0,0 +1,11 @@
+package sample
+
+class K {
+ class object {
+ fun bar(p: Int): K = K()
+ }
+}
+
+fun foo(){
+ val k : K = K.bar()
+}
diff --git a/idea/testData/completion/handlers/smart/JavaStaticFieldInsertImport.kt b/idea/testData/completion/handlers/smart/JavaStaticFieldInsertImport.kt
new file mode 100644
index 00000000000..37592e3e6bb
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/JavaStaticFieldInsertImport.kt
@@ -0,0 +1,3 @@
+fun foo(){
+ var l : java.util.Locale =
+}
diff --git a/idea/testData/completion/handlers/smart/JavaStaticFieldInsertImport.kt.after b/idea/testData/completion/handlers/smart/JavaStaticFieldInsertImport.kt.after
new file mode 100644
index 00000000000..9b67d7c879c
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/JavaStaticFieldInsertImport.kt.after
@@ -0,0 +1,5 @@
+import java.util.Locale
+
+fun foo(){
+ var l : java.util.Locale = Locale.ENGLISH
+}
diff --git a/idea/testData/completion/handlers/smart/JavaStaticMethod.kt b/idea/testData/completion/handlers/smart/JavaStaticMethod.kt
new file mode 100644
index 00000000000..52ce3361f82
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/JavaStaticMethod.kt
@@ -0,0 +1,3 @@
+fun foo(){
+ val l : java.lang.Thread =
+}
diff --git a/idea/testData/completion/handlers/smart/JavaStaticMethod.kt.after b/idea/testData/completion/handlers/smart/JavaStaticMethod.kt.after
new file mode 100644
index 00000000000..a5741b81458
--- /dev/null
+++ b/idea/testData/completion/handlers/smart/JavaStaticMethod.kt.after
@@ -0,0 +1,3 @@
+fun foo(){
+ val l : java.lang.Thread = Thread.currentThread()
+}
diff --git a/idea/testData/completion/smart/ClassObjectMembers.kt b/idea/testData/completion/smart/ClassObjectMembers.kt
new file mode 100644
index 00000000000..760623bc32a
--- /dev/null
+++ b/idea/testData/completion/smart/ClassObjectMembers.kt
@@ -0,0 +1,21 @@
+package sample
+
+class K {
+ class object {
+ val foo: K = K()
+ fun bar(): K = K()
+ val x: String = ""
+ var kk: K? = null
+ private val privateVal: K = K()
+ }
+}
+
+fun foo(){
+ val k : K =
+}
+
+// EXIST: { lookupString:"K.foo", itemText:"K.foo", tailText:" (sample)", typeText:"sample.K" }
+// EXIST: { lookupString:"K.bar", itemText:"K.bar()", tailText:" (sample)", typeText:"sample.K" }
+// ABSENT: K.x
+// ABSENT: K.kk
+// ABSENT: K.privateVal
diff --git a/idea/testData/completion/smart/ClassObjectMembersForNullable.kt b/idea/testData/completion/smart/ClassObjectMembersForNullable.kt
new file mode 100644
index 00000000000..05759289160
--- /dev/null
+++ b/idea/testData/completion/smart/ClassObjectMembersForNullable.kt
@@ -0,0 +1,19 @@
+package sample
+
+class K {
+ class object {
+ val foo: K = K()
+ fun bar(): K = K()
+ val x: String = ""
+ var kk: K? = null
+ }
+}
+
+fun foo(){
+ val k : K? =
+}
+
+// EXIST: { lookupString:"K.foo", itemText:"K.foo", tailText:" (sample)", typeText:"sample.K" }
+// EXIST: { lookupString:"K.bar", itemText:"K.bar()", tailText:" (sample)", typeText:"sample.K" }
+// ABSENT: K.x
+// EXIST: { lookupString:"K.kk", itemText:"K.kk", tailText:" (sample)", typeText:"sample.K?" }
diff --git a/idea/testData/completion/smart/EnumMembers.kt b/idea/testData/completion/smart/EnumMembers.kt
new file mode 100644
index 00000000000..564a6226a87
--- /dev/null
+++ b/idea/testData/completion/smart/EnumMembers.kt
@@ -0,0 +1,13 @@
+package sample
+
+enum class Foo {
+ X
+ Y
+}
+
+fun foo(){
+ val f : Foo =
+}
+
+// EXIST: { lookupString:"Foo.X", itemText:"Foo.X", tailText:" (sample)", typeText:"sample.Foo" }
+// EXIST: { lookupString:"Foo.Y", itemText:"Foo.Y", tailText:" (sample)", typeText:"sample.Foo" }
diff --git a/idea/testData/completion/smart/JavaEnumMembers.kt b/idea/testData/completion/smart/JavaEnumMembers.kt
new file mode 100644
index 00000000000..c81cc4c1e77
--- /dev/null
+++ b/idea/testData/completion/smart/JavaEnumMembers.kt
@@ -0,0 +1,8 @@
+import java.lang.annotation.ElementType
+
+fun foo(){
+ val e : ElementType =
+}
+
+// EXIST: { lookupString:"ElementType.TYPE", itemText:"ElementType.TYPE", tailText:" (java.lang.annotation)", typeText:"java.lang.annotation.ElementType" }
+// EXIST: { lookupString:"ElementType.FIELD", itemText:"ElementType.FIELD", tailText:" (java.lang.annotation)", typeText:"java.lang.annotation.ElementType" }
diff --git a/idea/testData/completion/smart/JavaEnumMembersForNullable.kt b/idea/testData/completion/smart/JavaEnumMembersForNullable.kt
new file mode 100644
index 00000000000..a4a5fdd10f0
--- /dev/null
+++ b/idea/testData/completion/smart/JavaEnumMembersForNullable.kt
@@ -0,0 +1,8 @@
+import java.lang.annotation.ElementType
+
+fun foo(){
+ var e : ElementType? =
+}
+
+// EXIST: { lookupString:"ElementType.TYPE", itemText:"ElementType.TYPE", tailText:" (java.lang.annotation)", typeText:"java.lang.annotation.ElementType" }
+// EXIST: { lookupString:"ElementType.FIELD", itemText:"ElementType.FIELD", tailText:" (java.lang.annotation)", typeText:"java.lang.annotation.ElementType" }
diff --git a/idea/testData/completion/smart/JavaStaticFields.kt b/idea/testData/completion/smart/JavaStaticFields.kt
new file mode 100644
index 00000000000..4d6d8c2e03c
--- /dev/null
+++ b/idea/testData/completion/smart/JavaStaticFields.kt
@@ -0,0 +1,6 @@
+fun foo(){
+ var l : java.util.Locale =
+}
+
+// EXIST: { lookupString:"Locale.ENGLISH", itemText:"Locale.ENGLISH", tailText:" (java.util)", typeText:"Locale" }
+// EXIST: { lookupString:"Locale.FRENCH", itemText:"Locale.FRENCH", tailText:" (java.util)", typeText:"Locale" }
diff --git a/idea/testData/completion/smart/JavaStaticFieldsForNullable.kt b/idea/testData/completion/smart/JavaStaticFieldsForNullable.kt
new file mode 100644
index 00000000000..e0bf222b8e0
--- /dev/null
+++ b/idea/testData/completion/smart/JavaStaticFieldsForNullable.kt
@@ -0,0 +1,6 @@
+fun foo(){
+ var l : java.util.Locale? =
+}
+
+// EXIST: { lookupString:"Locale.ENGLISH", itemText:"Locale.ENGLISH", tailText:" (java.util)", typeText:"Locale" }
+// EXIST: { lookupString:"Locale.FRENCH", itemText:"Locale.FRENCH", tailText:" (java.util)", typeText:"Locale" }
diff --git a/idea/testData/completion/smart/JavaStaticMethods.kt b/idea/testData/completion/smart/JavaStaticMethods.kt
new file mode 100644
index 00000000000..907d4ac16ff
--- /dev/null
+++ b/idea/testData/completion/smart/JavaStaticMethods.kt
@@ -0,0 +1,5 @@
+fun foo(){
+ val l : java.lang.Thread =
+}
+
+// EXIST: { lookupString:"Thread.currentThread", itemText:"Thread.currentThread()", tailText:" (java.lang)", typeText:"Thread" }
diff --git a/idea/tests/org/jetbrains/jet/completion/JetSmartCompletionTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/JetSmartCompletionTestGenerated.java
index 2c23bf587ba..6518c69d089 100644
--- a/idea/tests/org/jetbrains/jet/completion/JetSmartCompletionTestGenerated.java
+++ b/idea/tests/org/jetbrains/jet/completion/JetSmartCompletionTestGenerated.java
@@ -61,6 +61,16 @@ public class JetSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
doTest("idea/testData/completion/smart/ChainedCall.kt");
}
+ @TestMetadata("ClassObjectMembers.kt")
+ public void testClassObjectMembers() throws Exception {
+ doTest("idea/testData/completion/smart/ClassObjectMembers.kt");
+ }
+
+ @TestMetadata("ClassObjectMembersForNullable.kt")
+ public void testClassObjectMembersForNullable() throws Exception {
+ doTest("idea/testData/completion/smart/ClassObjectMembersForNullable.kt");
+ }
+
@TestMetadata("Constructor.kt")
public void testConstructor() throws Exception {
doTest("idea/testData/completion/smart/Constructor.kt");
@@ -81,11 +91,41 @@ public class JetSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
doTest("idea/testData/completion/smart/EmptyPrefix.kt");
}
+ @TestMetadata("EnumMembers.kt")
+ public void testEnumMembers() throws Exception {
+ doTest("idea/testData/completion/smart/EnumMembers.kt");
+ }
+
@TestMetadata("InsideIdentifier.kt")
public void testInsideIdentifier() throws Exception {
doTest("idea/testData/completion/smart/InsideIdentifier.kt");
}
+ @TestMetadata("JavaEnumMembers.kt")
+ public void testJavaEnumMembers() throws Exception {
+ doTest("idea/testData/completion/smart/JavaEnumMembers.kt");
+ }
+
+ @TestMetadata("JavaEnumMembersForNullable.kt")
+ public void testJavaEnumMembersForNullable() throws Exception {
+ doTest("idea/testData/completion/smart/JavaEnumMembersForNullable.kt");
+ }
+
+ @TestMetadata("JavaStaticFields.kt")
+ public void testJavaStaticFields() throws Exception {
+ doTest("idea/testData/completion/smart/JavaStaticFields.kt");
+ }
+
+ @TestMetadata("JavaStaticFieldsForNullable.kt")
+ public void testJavaStaticFieldsForNullable() throws Exception {
+ doTest("idea/testData/completion/smart/JavaStaticFieldsForNullable.kt");
+ }
+
+ @TestMetadata("JavaStaticMethods.kt")
+ public void testJavaStaticMethods() throws Exception {
+ doTest("idea/testData/completion/smart/JavaStaticMethods.kt");
+ }
+
@TestMetadata("MethodCallArgument.kt")
public void testMethodCallArgument() throws Exception {
doTest("idea/testData/completion/smart/MethodCallArgument.kt");
diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTest.kt b/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTest.kt
index 9efd3d36dd7..79ec10c8eca 100644
--- a/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTest.kt
+++ b/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTest.kt
@@ -42,4 +42,8 @@ public class SmartCompletionHandlerTest() : CompletionHandlerTestBase() {
fun testConstructorForNullable() = doTest()
fun testConstructorForJavaClass() = doTest()
//fun testConstructorInsertsImport() = doTest() //TODO
+ fun testJavaStaticMethod() = doTest(1, "Thread.currentThread", null, '\n')
+ fun testClassObjectMethod1() = doTest(1, "K.bar", null, '\n')
+ fun testClassObjectMethod2() = doTest(1, "K.bar", null, '\n')
+ //fun testJavaStaticFieldInsertImport() = doTest(1, "Locale.ENGLISH", null, '\n') //TODO
}