diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 78f3ec38c3a..cd3f4389b7a 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -1187,6 +1187,8 @@
level="WARNING"
/>
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AutoImportFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AutoImportFix.kt
index 1634d9ca5f1..92c814b48d0 100644
--- a/idea/src/org/jetbrains/kotlin/idea/quickfix/AutoImportFix.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AutoImportFix.kt
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.JetBundle
import org.jetbrains.kotlin.idea.actions.KotlinAddImportAction
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.getResolveScope
import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper
@@ -96,59 +97,6 @@ public class AutoImportFix(element: JetSimpleNameExpression) : JetHintAction {
- if (!element.isValid()) return listOf()
-
- val file = element.getContainingFile() as? JetFile ?: return listOf()
-
- var referenceName = element.getReferencedName()
- if (element.getIdentifier() == null) {
- val conventionName = JetPsiUtil.getConventionName(element)
- if (conventionName != null) {
- referenceName = conventionName.asString()
- }
- }
- if (referenceName.isEmpty()) return listOf()
-
- val resolutionFacade = element.getResolutionFacade()
-
- val searchScope = getResolveScope(file)
-
- val bindingContext = resolutionFacade.analyze(element, BodyResolveMode.PARTIAL)
-
- val diagnostics = bindingContext.getDiagnostics().forElement(element)
- if (!diagnostics.any { it.getFactory() in ERRORS }) return listOf()
-
- val resolutionScope = element.getResolutionScope(bindingContext, resolutionFacade)
- val containingDescriptor = resolutionScope.ownerDescriptor
-
- fun isVisible(descriptor: DeclarationDescriptor): Boolean {
- if (descriptor is DeclarationDescriptorWithVisibility) {
- return descriptor.isVisible(containingDescriptor, bindingContext, element)
- }
-
- return true
- }
-
- val result = ArrayList()
-
- val indicesHelper = KotlinIndicesHelper(resolutionFacade, searchScope, ::isVisible, true)
-
- if (!element.isImportDirectiveExpression() && !JetPsiUtil.isSelectorInQualified(element)) {
- if (ProjectStructureUtil.isJsKotlinModule(file)) {
- result.addAll(indicesHelper.getKotlinClasses({ it == referenceName }, { true }))
- }
- else {
- result.addAll(indicesHelper.getJvmClassesByName(referenceName))
- }
- result.addAll(indicesHelper.getTopLevelCallablesByName(referenceName))
- }
-
- result.addAll(indicesHelper.getCallableTopLevelExtensions({ it == referenceName }, element, bindingContext))
-
- return result
- }
-
companion object {
private val ERRORS = setOf(Errors.UNRESOLVED_REFERENCE, Errors.UNRESOLVED_REFERENCE_WRONG_RECEIVER)
@@ -168,5 +116,56 @@ public class AutoImportFix(element: JetSimpleNameExpression) : JetHintAction {
+ if (!element.isValid()) return listOf()
+
+ val file = element.getContainingFile() as? JetFile ?: return listOf()
+
+ var referenceName = element.getReferencedName()
+ if (element.getIdentifier() == null) {
+ val conventionName = JetPsiUtil.getConventionName(element)
+ if (conventionName != null) {
+ referenceName = conventionName.asString()
+ }
+ }
+ if (referenceName.isEmpty()) return listOf()
+
+ val searchScope = getResolveScope(file)
+
+ val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
+
+ val diagnostics = bindingContext.getDiagnostics().forElement(element)
+ if (!diagnostics.any { it.getFactory() in ERRORS }) return listOf()
+
+ val resolutionScope = element.getResolutionScope(bindingContext, file.getResolutionFacade())
+ val containingDescriptor = resolutionScope.ownerDescriptor
+
+ fun isVisible(descriptor: DeclarationDescriptor): Boolean {
+ if (descriptor is DeclarationDescriptorWithVisibility) {
+ return descriptor.isVisible(containingDescriptor, bindingContext, element)
+ }
+
+ return true
+ }
+
+ val result = ArrayList()
+
+ val indicesHelper = KotlinIndicesHelper(element.getResolutionFacade(), searchScope, ::isVisible, true)
+
+ if (!element.isImportDirectiveExpression() && !JetPsiUtil.isSelectorInQualified(element)) {
+ if (ProjectStructureUtil.isJsKotlinModule(file)) {
+ result.addAll(indicesHelper.getKotlinClasses({ it == referenceName }, { true }))
+ }
+ else {
+ result.addAll(indicesHelper.getJvmClassesByName(referenceName))
+ }
+ result.addAll(indicesHelper.getTopLevelCallablesByName(referenceName))
+ }
+
+ result.addAll(indicesHelper.getCallableTopLevelExtensions({ it == referenceName }, element, bindingContext))
+
+ return result
+ }
}
}
diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinReferenceImporter.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinReferenceImporter.kt
new file mode 100644
index 00000000000..e6db83c776d
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinReferenceImporter.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2010-2015 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.kotlin.idea.quickfix
+
+import com.intellij.codeInsight.CodeInsightSettings
+import com.intellij.codeInsight.daemon.ReferenceImporter
+import com.intellij.codeInsight.daemon.impl.DaemonListeners
+import com.intellij.openapi.command.CommandProcessor
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.util.TextRange
+import com.intellij.psi.PsiFile
+import org.jetbrains.kotlin.idea.actions.KotlinAddImportAction
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.core.targetDescriptors
+import org.jetbrains.kotlin.idea.imports.importableFqName
+import org.jetbrains.kotlin.idea.references.mainReference
+import org.jetbrains.kotlin.psi.JetFile
+import org.jetbrains.kotlin.psi.JetSimpleNameExpression
+import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
+import org.jetbrains.kotlin.psi.psiUtil.elementsInRange
+import org.jetbrains.kotlin.psi.psiUtil.endOffset
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+
+public class KotlinReferenceImporter : ReferenceImporter {
+ override fun autoImportReferenceAtCursor(editor: Editor, file: PsiFile)
+ = autoImportReferenceAtCursor(editor, file, allowCaretNearRef = false)
+
+ override fun autoImportReferenceAt(editor: Editor, file: PsiFile, offset: Int): Boolean {
+ if (file !is JetFile) return false
+
+ val nameExpression = file.findElementAt(offset)?.parent as? JetSimpleNameExpression ?: return false
+
+ return nameExpression.autoImport(editor, file)
+ }
+
+ companion object {
+
+ // TODO: use in table cell
+ // TODO: DependencyValidationManager
+ // TODO: filter out non-top level
+ public fun autoImportReferenceAtCursor(editor: Editor, file: PsiFile, allowCaretNearRef: Boolean): Boolean {
+ if (file !is JetFile) return false
+
+ val caretOffset = editor.caretModel.offset
+ val document = editor.document
+ val lineNumber = document.getLineNumber(caretOffset)
+ val startOffset = document.getLineStartOffset(lineNumber)
+ val endOffset = document.getLineEndOffset(lineNumber)
+
+ val elements = file.elementsInRange(TextRange(startOffset, endOffset))
+ .flatMap { it.collectDescendantsOfType() }
+ for (element in elements) {
+ if (!allowCaretNearRef && element.endOffset == caretOffset) continue
+
+ if (element.autoImport(editor, file)) {
+ return true
+ }
+ }
+
+ return false
+ }
+
+ protected fun hasUnresolvedImportWhichCanImport(file: JetFile, name: String): Boolean {
+ return file.importDirectives.any {
+ it.targetDescriptors().isEmpty() && (it.isAllUnder || it.importPath?.importedName?.asString() == name)
+ }
+ }
+
+ private fun JetSimpleNameExpression.autoImport(editor: Editor, file: JetFile): Boolean {
+ if (!CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY) return false
+ if (!DaemonListeners.canChangeFileSilently(file)) return false
+ if (hasUnresolvedImportWhichCanImport(file, getReferencedName())) return false
+
+ val bindingContext = analyze(BodyResolveMode.PARTIAL)
+ if (mainReference.resolveToDescriptors(bindingContext).isNotEmpty()) return false
+
+ val suggestions = AutoImportFix.computeSuggestions(this)
+
+ if (suggestions.distinctBy { it.importableFqName!! }.size() != 1) return false
+
+ var result = false
+ CommandProcessor.getInstance().runUndoTransparentAction {
+ result = KotlinAddImportAction(project, editor, this, suggestions).execute()
+ }
+ return result
+ }
+ }
+}
\ No newline at end of file