Auto-import popup to import global properties
#KT-4541 Fixed #KT-3097 Fixed
This commit is contained in:
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.plugin.stubindex;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.stubs.StringStubIndexExtension;
|
||||
import com.intellij.psi.stubs.StubIndexKey;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetProperty;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class JetTopLevelExtensionPropertyShortNameIndex extends StringStubIndexExtension<JetProperty> {
|
||||
private static final StubIndexKey<String, JetProperty> KEY = KotlinIndexUtil.createIndexKey(JetTopLevelExtensionPropertyShortNameIndex.class);
|
||||
|
||||
private static final JetTopLevelExtensionPropertyShortNameIndex ourInstance = new JetTopLevelExtensionPropertyShortNameIndex();
|
||||
|
||||
@NotNull
|
||||
public static JetTopLevelExtensionPropertyShortNameIndex getInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
private JetTopLevelExtensionPropertyShortNameIndex() {}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public StubIndexKey<String, JetProperty> getKey() {
|
||||
return KEY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<JetProperty> get(String s, Project project, @NotNull GlobalSearchScope scope) {
|
||||
return super.get(s, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project));
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.plugin.stubindex;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.stubs.StringStubIndexExtension;
|
||||
import com.intellij.psi.stubs.StubIndexKey;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetProperty;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class JetTopLevelNonExtensionPropertyShortNameIndex extends StringStubIndexExtension<JetProperty> {
|
||||
private static final StubIndexKey<String, JetProperty> KEY = KotlinIndexUtil.createIndexKey(JetTopLevelNonExtensionPropertyShortNameIndex.class);
|
||||
|
||||
private static final JetTopLevelNonExtensionPropertyShortNameIndex ourInstance = new JetTopLevelNonExtensionPropertyShortNameIndex();
|
||||
|
||||
@NotNull
|
||||
public static JetTopLevelNonExtensionPropertyShortNameIndex getInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
private JetTopLevelNonExtensionPropertyShortNameIndex() {}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public StubIndexKey<String, JetProperty> getKey() {
|
||||
return KEY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<JetProperty> get(String s, Project project, @NotNull GlobalSearchScope scope) {
|
||||
return super.get(s, project, JetSourceFilterScope.kotlinSourcesAndLibraries(scope, project));
|
||||
}
|
||||
}
|
||||
+13
-3
@@ -123,9 +123,19 @@ public class StubIndexServiceImpl implements StubIndexService {
|
||||
|
||||
@Override
|
||||
public void indexProperty(PsiJetPropertyStub stub, IndexSink sink) {
|
||||
String propertyName = stub.getName();
|
||||
if (propertyName != null) {
|
||||
sink.occurrence(JetPropertyShortNameIndex.getInstance().getKey(), propertyName);
|
||||
String name = stub.getName();
|
||||
if (name != null) {
|
||||
if (stub.isTopLevel()) {
|
||||
// Collection only top level functions as only they are expected in completion without explicit import
|
||||
if (!stub.hasReceiverTypeRef()) {
|
||||
sink.occurrence(JetTopLevelNonExtensionPropertyShortNameIndex.getInstance().getKey(), name);
|
||||
}
|
||||
else {
|
||||
sink.occurrence(JetTopLevelExtensionPropertyShortNameIndex.getInstance().getKey(), name);
|
||||
}
|
||||
}
|
||||
|
||||
sink.occurrence(JetPropertyShortNameIndex.getInstance().getKey(), name);
|
||||
}
|
||||
// can have special fq name in case of syntactically incorrect function with no name
|
||||
if (stub.isTopLevel()) {
|
||||
|
||||
@@ -366,8 +366,10 @@
|
||||
<stubIndex implementation="org.jetbrains.jet.plugin.stubindex.JetClassShortNameIndex"/>
|
||||
<stubIndex implementation="org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex"/>
|
||||
<stubIndex implementation="org.jetbrains.jet.plugin.stubindex.JetTopLevelNonExtensionFunctionShortNameIndex"/>
|
||||
<stubIndex implementation="org.jetbrains.jet.plugin.stubindex.JetTopLevelNonExtensionPropertyShortNameIndex"/>
|
||||
<stubIndex implementation="org.jetbrains.jet.plugin.stubindex.JetPropertyShortNameIndex"/>
|
||||
<stubIndex implementation="org.jetbrains.jet.plugin.stubindex.JetTopLevelExtensionFunctionShortNameIndex"/>
|
||||
<stubIndex implementation="org.jetbrains.jet.plugin.stubindex.JetTopLevelExtensionPropertyShortNameIndex"/>
|
||||
<stubIndex implementation="org.jetbrains.jet.plugin.stubindex.JetFunctionShortNameIndex"/>
|
||||
<stubIndex implementation="org.jetbrains.jet.plugin.stubindex.JetSuperClassIndex"/>
|
||||
<stubIndex implementation="org.jetbrains.jet.plugin.stubindex.JetTopLevelFunctionsFqnNameIndex"/>
|
||||
|
||||
@@ -28,8 +28,6 @@ import org.jetbrains.jet.lang.resolve.BindingContext
|
||||
import org.jetbrains.jet.lang.resolve.name.Name
|
||||
import org.jetbrains.jet.plugin.stubindex.JetTopLevelNonExtensionFunctionShortNameIndex
|
||||
import org.jetbrains.jet.lang.psi.JetFile
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
|
||||
import java.util.ArrayList
|
||||
import org.jetbrains.jet.plugin.stubindex.JetTopLevelFunctionsFqnNameIndex
|
||||
import org.jetbrains.jet.plugin.stubindex.JetTopLevelPropertiesFqnNameIndex
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
|
||||
@@ -45,6 +43,9 @@ import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver
|
||||
import org.jetbrains.jet.lang.resolve.BindingTraceContext
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor
|
||||
import com.intellij.openapi.project.Project
|
||||
import java.util.HashSet
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.jet.plugin.stubindex.JetTopLevelNonExtensionPropertyShortNameIndex
|
||||
|
||||
public class KotlinIndicesHelper(private val project: Project) {
|
||||
public fun getTopLevelObjects(nameFilter: (String) -> Boolean, resolveSession: ResolveSessionForBodies, scope: GlobalSearchScope): Collection<ClassDescriptor> {
|
||||
@@ -75,21 +76,21 @@ public class KotlinIndicesHelper(private val project: Project) {
|
||||
return result
|
||||
}
|
||||
|
||||
public fun getTopLevelFunctionDescriptorsByName(name: String, context: JetExpression /*TODO: to be dropped*/, resolveSession: ResolveSessionForBodies, scope: GlobalSearchScope): Collection<FunctionDescriptor> {
|
||||
|
||||
public fun getTopLevelCallablesByName(name: String, context: JetExpression /*TODO: to be dropped*/, resolveSession: ResolveSessionForBodies, scope: GlobalSearchScope): Collection<CallableDescriptor> {
|
||||
val jetScope = resolveSession.resolveToElement(context).get(BindingContext.RESOLUTION_SCOPE, context) ?: return listOf()
|
||||
|
||||
val result = hashSetOf<FunctionDescriptor>()
|
||||
val result = HashSet<CallableDescriptor>()
|
||||
|
||||
//TODO: this code is temporary and is to be dropped when compiled top level functions are indexed
|
||||
val identifier = Name.identifier(name)
|
||||
for (fqName in JetFromJavaDescriptorHelper.getTopLevelCallableFqNames(project, scope, false)) {
|
||||
if (fqName.lastSegmentIs(identifier)) {
|
||||
findTopLevelCallables(fqName, context, jetScope, resolveSession).filterIsInstanceTo(result, javaClass<FunctionDescriptor>())
|
||||
result.addAll(findTopLevelCallables(fqName, context, jetScope, resolveSession))
|
||||
}
|
||||
}
|
||||
|
||||
result.addSourceTopLevelFunctions(name, resolveSession, scope)
|
||||
result.addSourceTopLevelProperties(name, resolveSession, scope)
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -109,24 +110,36 @@ public class KotlinIndicesHelper(private val project: Project) {
|
||||
}
|
||||
}
|
||||
|
||||
public fun getTopLevelCallables(nameFilter: (String) -> Boolean, context: JetExpression /*TODO: to be dropped*/, resolveSession: ResolveSessionForBodies, scope: GlobalSearchScope): Collection<DeclarationDescriptor> {
|
||||
val result = ArrayList<DeclarationDescriptor>()
|
||||
private fun MutableCollection<in PropertyDescriptor>.addSourceTopLevelProperties(name: String, resolveSession: ResolveSessionForBodies, scope: GlobalSearchScope) {
|
||||
val identifier = Name.identifier(name)
|
||||
val affectedPackages = JetTopLevelNonExtensionPropertyShortNameIndex.getInstance().get(name, project, scope)
|
||||
.map { it.getContainingFile() }
|
||||
.filterIsInstance(javaClass<JetFile>())
|
||||
.map { it.getPackageFqName() }
|
||||
.toSet()
|
||||
|
||||
for (affectedPackage in affectedPackages) {
|
||||
val packageDescriptor = resolveSession.getModuleDescriptor().getPackage(affectedPackage)
|
||||
?: error("There's a property in stub index with invalid package: $affectedPackage")
|
||||
addAll(packageDescriptor.getMemberScope().getProperties(identifier))
|
||||
}
|
||||
}
|
||||
|
||||
public fun getTopLevelCallables(nameFilter: (String) -> Boolean, context: JetExpression /*TODO: to be dropped*/, resolveSession: ResolveSessionForBodies, scope: GlobalSearchScope): Collection<CallableDescriptor> {
|
||||
val sourceNames = JetTopLevelFunctionsFqnNameIndex.getInstance().getAllKeys(project).stream() + JetTopLevelPropertiesFqnNameIndex.getInstance().getAllKeys(project).stream()
|
||||
val allFqNames = sourceNames.map { FqName(it) } + JetFromJavaDescriptorHelper.getTopLevelCallableFqNames(project, scope, false).stream()
|
||||
|
||||
val jetScope = resolveSession.resolveToElement(context).get(BindingContext.RESOLUTION_SCOPE, context) ?: return listOf()
|
||||
allFqNames.filter { nameFilter(it.shortName().asString()) }
|
||||
.toSet()
|
||||
.flatMapTo(result) { findTopLevelCallables(it, context, jetScope, resolveSession) }
|
||||
|
||||
return result
|
||||
return allFqNames.filter { nameFilter(it.shortName().asString()) }
|
||||
.toSet()
|
||||
.flatMap { findTopLevelCallables(it, context, jetScope, resolveSession) }
|
||||
}
|
||||
|
||||
public fun getCallableExtensions(nameFilter: (String) -> Boolean,
|
||||
expression: JetSimpleNameExpression,
|
||||
resolveSession: ResolveSessionForBodies,
|
||||
scope: GlobalSearchScope): Collection<DeclarationDescriptor> {
|
||||
scope: GlobalSearchScope): Collection<CallableDescriptor> {
|
||||
val context = resolveSession.resolveToElement(expression)
|
||||
val receiverExpression = expression.getReceiverExpression() ?: return listOf()
|
||||
val expressionType = context.get<JetExpression, JetType>(BindingContext.EXPRESSION_TYPE, receiverExpression)
|
||||
@@ -166,7 +179,7 @@ public class KotlinIndicesHelper(private val project: Project) {
|
||||
return ResolveSessionUtils.getClassDescriptorsByFqName(analyzer, classFQName)
|
||||
}
|
||||
|
||||
private fun findTopLevelCallables(fqName: FqName, context: JetExpression, jetScope: JetScope, resolveSession: ResolveSessionForBodies): Collection<DeclarationDescriptor> {
|
||||
private fun findTopLevelCallables(fqName: FqName, context: JetExpression, jetScope: JetScope, resolveSession: ResolveSessionForBodies): Collection<CallableDescriptor> {
|
||||
val importDirective = JetPsiFactory(context.getProject()).createImportDirective(ImportPath(fqName, false))
|
||||
val allDescriptors = QualifiedExpressionResolver().analyseImportReference(importDirective, jetScope, BindingTraceContext(), resolveSession.getModuleDescriptor())
|
||||
return allDescriptors.filterIsInstance(javaClass<CallableDescriptor>()).filter { it.getReceiverParameter() == null }
|
||||
|
||||
@@ -112,7 +112,7 @@ public class AutoImportFix(element: JetSimpleNameExpression) : JetHintAction<Jet
|
||||
|
||||
if (!element.isImportDirectiveExpression() && !JetPsiUtil.isSelectorInQualified(element)) {
|
||||
result.addAll(getClassNames(referenceName, file, searchScope))
|
||||
result.addAll(getTopLevelFunctions(referenceName, element, searchScope, resolveSession, file.getProject()))
|
||||
result.addAll(getTopLevelCallables(referenceName, element, searchScope, resolveSession, file.getProject()))
|
||||
}
|
||||
|
||||
result.addAll(getExtensions(referenceName, element, searchScope, resolveSession, file.getProject()))
|
||||
@@ -120,8 +120,8 @@ public class AutoImportFix(element: JetSimpleNameExpression) : JetHintAction<Jet
|
||||
return result.filter { ImportInsertHelper.needImport(ImportPath(it, false), file) }
|
||||
}
|
||||
|
||||
private fun getTopLevelFunctions(name: String, context: JetExpression, searchScope: GlobalSearchScope, resolveSession: ResolveSessionForBodies, project: Project): Collection<FqName>
|
||||
= KotlinIndicesHelper(project).getTopLevelFunctionDescriptorsByName(name, context, resolveSession, searchScope)
|
||||
private fun getTopLevelCallables(name: String, context: JetExpression, searchScope: GlobalSearchScope, resolveSession: ResolveSessionForBodies, project: Project): Collection<FqName>
|
||||
= KotlinIndicesHelper(project).getTopLevelCallablesByName(name, context, resolveSession, searchScope)
|
||||
.map { DescriptorUtils.getFqNameSafe(it) }
|
||||
.toSet()
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Import" "true"
|
||||
|
||||
package test
|
||||
|
||||
import kotlin.concurrent.currentThread
|
||||
|
||||
fun foo() {
|
||||
currentThread
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// "Import" "true"
|
||||
|
||||
package test
|
||||
|
||||
fun foo() {
|
||||
<caret>currentThread
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Import" "true"
|
||||
// ERROR: Unresolved reference: someTestProp
|
||||
|
||||
package test
|
||||
|
||||
import test.data.someTestProp
|
||||
|
||||
fun foo() {
|
||||
someTestProp
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Import" "true"
|
||||
// ERROR: Unresolved reference: someTestProp
|
||||
|
||||
package test
|
||||
|
||||
fun foo() {
|
||||
<caret>someTestProp
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package test.data
|
||||
|
||||
val someTestProp = 1
|
||||
@@ -154,6 +154,11 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
|
||||
doTestWithExtraFile("idea/testData/quickfix/autoImports/postfixOperator.before.Main.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyImport.before.Main.kt")
|
||||
public void testPropertyImport() throws Exception {
|
||||
doTestWithExtraFile("idea/testData/quickfix/autoImports/propertyImport.before.Main.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("timesAssign.before.Main.kt")
|
||||
public void testTimesAssign() throws Exception {
|
||||
doTestWithExtraFile("idea/testData/quickfix/autoImports/timesAssign.before.Main.kt");
|
||||
|
||||
@@ -308,6 +308,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
doTest("idea/testData/quickfix/autoImports/beforeCheckNoStackOverflowInImportInnerClassInCurrentFile.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeLibraryPropertyRuntime.kt")
|
||||
public void testLibraryPropertyRuntime() throws Exception {
|
||||
doTest("idea/testData/quickfix/autoImports/beforeLibraryPropertyRuntime.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("beforeLibraryTopLevelFunctionImportRuntime.kt")
|
||||
public void testLibraryTopLevelFunctionImportRuntime() throws Exception {
|
||||
doTest("idea/testData/quickfix/autoImports/beforeLibraryTopLevelFunctionImportRuntime.kt");
|
||||
|
||||
Reference in New Issue
Block a user