diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinCopyPasteReferenceProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinCopyPasteReferenceProcessor.kt index 56ef519fcb8..4bb0cb65ed8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinCopyPasteReferenceProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinCopyPasteReferenceProcessor.kt @@ -164,32 +164,13 @@ public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor - KotlinReferenceData.Kind.CLASS - - is PackageViewDescriptor -> - KotlinReferenceData.Kind.PACKAGE - - is FunctionDescriptor -> - if (descriptor.isExtension) KotlinReferenceData.Kind.EXTENSION_FUNCTION else KotlinReferenceData.Kind.NON_EXTENSION_CALLABLE - - is PropertyDescriptor -> - if (descriptor.isExtension) KotlinReferenceData.Kind.EXTENSION_PROPERTY else KotlinReferenceData.Kind.NON_EXTENSION_CALLABLE - - else -> - null - } - } - private data class ReferenceToRestoreData( val reference: JetReference, val refData: KotlinReferenceData @@ -234,7 +215,7 @@ public class KotlinCopyPasteReferenceProcessor() : CopyPastePostProcessor { val importDirective = JetPsiFactory(file.getProject()).createImportDirective(ImportPath(fqName, false)) val moduleDescriptor = file.getResolutionFacade().findModuleDescriptor(file) val scope = JetModuleUtil.getSubpackagesOfRootScope(moduleDescriptor) return QualifiedExpressionResolver() .processImportReference(importDirective, scope, scope, BindingTraceContext(), LookupMode.EVERYTHING) .getAllDescriptors() - .firstIsInstanceOrNull() } + private fun findCallableToImport(fqName: FqName, file: JetFile): CallableDescriptor? + = findImportableDescriptors(fqName, file).firstIsInstanceOrNull() + private fun showRestoreReferencesDialog(project: Project, referencesToRestore: List): Collection { val fqNames = referencesToRestore.map { it.refData.fqName }.toSortedSet() diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinReferenceTransferableData.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinReferenceTransferableData.kt index 97a8cb95723..54982d28e8f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinReferenceTransferableData.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinReferenceTransferableData.kt @@ -16,8 +16,10 @@ package org.jetbrains.kotlin.idea.codeInsight -import com.intellij.codeInsight.editorActions.ReferenceData import com.intellij.codeInsight.editorActions.TextBlockTransferableData +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor +import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension import java.awt.datatransfer.DataFlavor import java.io.Serializable import kotlin.properties.Delegates @@ -64,6 +66,27 @@ public class KotlinReferenceData( NON_EXTENSION_CALLABLE EXTENSION_FUNCTION EXTENSION_PROPERTY + + companion object { + public fun fromDescriptor(descriptor: DeclarationDescriptor): KotlinReferenceData.Kind? { + return when (descriptor.getImportableDescriptor()) { + is ClassDescriptor -> + KotlinReferenceData.Kind.CLASS + + is PackageViewDescriptor -> + KotlinReferenceData.Kind.PACKAGE + + is FunctionDescriptor -> + if (descriptor.isExtension) KotlinReferenceData.Kind.EXTENSION_FUNCTION else KotlinReferenceData.Kind.NON_EXTENSION_CALLABLE + + is PropertyDescriptor -> + if (descriptor.isExtension) KotlinReferenceData.Kind.EXTENSION_PROPERTY else KotlinReferenceData.Kind.NON_EXTENSION_CALLABLE + + else -> + null + } + } + } } public override fun clone(): KotlinReferenceData { diff --git a/idea/testData/copyPaste/imports/DefaultPackage.expected.names b/idea/testData/copyPaste/imports/DefaultPackage.expected.names index f70f10e4db1..e69de29bb2d 100644 --- a/idea/testData/copyPaste/imports/DefaultPackage.expected.names +++ b/idea/testData/copyPaste/imports/DefaultPackage.expected.names @@ -1 +0,0 @@ -A diff --git a/idea/testData/copyPaste/imports/DependenciesNotAccessibleOnPaste.dependency.kt b/idea/testData/copyPaste/imports/DependenciesNotAccessibleOnPaste.dependency.kt new file mode 100644 index 00000000000..575fc833834 --- /dev/null +++ b/idea/testData/copyPaste/imports/DependenciesNotAccessibleOnPaste.dependency.kt @@ -0,0 +1,9 @@ +package pack.dependency + +class Dependency + +fun topLevelFun(){} + +fun String.extensionFun(){} + +fun String.extensionProp: Int = 1 diff --git a/idea/testData/copyPaste/imports/DependenciesNotAccessibleOnPaste.expected.kt b/idea/testData/copyPaste/imports/DependenciesNotAccessibleOnPaste.expected.kt new file mode 100644 index 00000000000..55664dd4c27 --- /dev/null +++ b/idea/testData/copyPaste/imports/DependenciesNotAccessibleOnPaste.expected.kt @@ -0,0 +1,14 @@ +// ERROR: Unresolved reference: Dependency +// ERROR: Unresolved reference: topLevelFun +// ERROR: Unresolved reference: extensionFun +// ERROR: Unresolved reference: extensionProp +// ERROR: Unresolved reference: dependency +package to + + +fun foo(d: Dependency) { + topLevelFun() + "".extensionFun() + println("".extensionProp) + dependency.Dependency() +} diff --git a/idea/testData/copyPaste/imports/DependenciesNotAccessibleOnPaste.expected.names b/idea/testData/copyPaste/imports/DependenciesNotAccessibleOnPaste.expected.names new file mode 100644 index 00000000000..e69de29bb2d diff --git a/idea/testData/copyPaste/imports/DependenciesNotAccessibleOnPaste.kt b/idea/testData/copyPaste/imports/DependenciesNotAccessibleOnPaste.kt new file mode 100644 index 00000000000..fc097400d06 --- /dev/null +++ b/idea/testData/copyPaste/imports/DependenciesNotAccessibleOnPaste.kt @@ -0,0 +1,14 @@ +// RUNTIME +// DELETE_DEPENDENCIES_BEFORE_PASTE + +import pack.dependency.* +import pack.dependency + + +fun foo(d: Dependency) { + topLevelFun() + "".extensionFun() + println("".extensionProp) + dependency.Dependency() +} + \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractInsertImportOnPasteTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractInsertImportOnPasteTest.kt index 818921ce04d..a0a79adbe44 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractInsertImportOnPasteTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractInsertImportOnPasteTest.kt @@ -18,9 +18,11 @@ package org.jetbrains.kotlin.idea.codeInsight import com.intellij.openapi.actionSystem.IdeActions import com.intellij.openapi.util.io.FileUtil +import com.intellij.psi.PsiFile import org.jetbrains.kotlin.idea.AbstractCopyPasteTest import org.jetbrains.kotlin.idea.PluginTestCaseBase import org.jetbrains.kotlin.idea.testUtils.dumpTextWithErrors +import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.psi.JetFile import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.JetTestUtils @@ -29,7 +31,9 @@ import java.io.File public abstract class AbstractInsertImportOnPasteTest : AbstractCopyPasteTest() { private val BASE_PATH = PluginTestCaseBase.getTestDataPathBase() + "/copyPaste/imports" private val DEFAULT_TO_FILE_TEXT = "package to\n\n" + private val NO_ERRORS_DUMP_DIRECTIVE = "// NO_ERRORS_DUMP" + private val DELETE_DEPENDENCIES_BEFORE_PASTE_DIRECTIVE = "// DELETE_DEPENDENCIES_BEFORE_PASTE" override fun getTestDataPath() = BASE_PATH @@ -44,13 +48,22 @@ public abstract class AbstractInsertImportOnPasteTest : AbstractCopyPasteTest() private fun doTestAction(cutOrCopy: String, path: String) { myFixture.setTestDataPath(BASE_PATH) val testFile = File(path) + val testFileText = FileUtil.loadFile(testFile, true) val testFileName = testFile.getName() - configureByDependencyIfExists(testFileName.replace(".kt", ".dependency.kt")) - configureByDependencyIfExists(testFileName.replace(".kt", ".dependency.java")) + val dependencyPsiFile1 = configureByDependencyIfExists(testFileName.replace(".kt", ".dependency.kt")) + val dependencyPsiFile2 = configureByDependencyIfExists(testFileName.replace(".kt", ".dependency.java")) myFixture.configureByFile(testFileName) myFixture.performEditorAction(cutOrCopy) + if (InTextDirectivesUtils.isDirectiveDefined(testFileText, DELETE_DEPENDENCIES_BEFORE_PASTE_DIRECTIVE)) { + assert(dependencyPsiFile1 != null || dependencyPsiFile2 != null) + runWriteAction { + dependencyPsiFile1?.getVirtualFile()?.delete(null) + dependencyPsiFile2?.getVirtualFile()?.delete(null) + } + } + KotlinCopyPasteReferenceProcessor.declarationsToImportSuggested = emptyList() configureToFile(testFileName.replace(".kt", ".to.kt")) @@ -60,7 +73,7 @@ public abstract class AbstractInsertImportOnPasteTest : AbstractCopyPasteTest() JetTestUtils.assertEqualsToFile(File(path.replace(".kt", ".expected.names")), namesToImportDump) val resultFile = myFixture.getFile() as JetFile - val resultText = if (InTextDirectivesUtils.isDirectiveDefined(FileUtil.loadFile(testFile, true), NO_ERRORS_DUMP_DIRECTIVE)) + val resultText = if (InTextDirectivesUtils.isDirectiveDefined(testFileText, NO_ERRORS_DUMP_DIRECTIVE)) resultFile.getText() else resultFile.dumpTextWithErrors() @@ -76,16 +89,15 @@ public abstract class AbstractInsertImportOnPasteTest : AbstractCopyPasteTest() } } - private fun configureByDependencyIfExists(dependencyFileName: String) { + private fun configureByDependencyIfExists(dependencyFileName: String): PsiFile? { val file = File(BASE_PATH + "/" + dependencyFileName) - if (file.exists()) { - if (dependencyFileName.endsWith(".java")) { - //allow test framework to put it under right directory - myFixture.addClass(FileUtil.loadFile(file, true)) - } - else { - myFixture.configureByFile(dependencyFileName) - } + if (!file.exists()) return null + return if (dependencyFileName.endsWith(".java")) { + //allow test framework to put it under right directory + myFixture.addClass(FileUtil.loadFile(file, true)).getContainingFile() + } + else { + myFixture.configureByFile(dependencyFileName) } } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InsertImportOnPasteTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InsertImportOnPasteTestGenerated.java index e6af1ee18a8..5714042f524 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InsertImportOnPasteTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InsertImportOnPasteTestGenerated.java @@ -132,6 +132,12 @@ public class InsertImportOnPasteTestGenerated extends AbstractInsertImportOnPast doTestCopy(fileName); } + @TestMetadata("DependenciesNotAccessibleOnPaste.kt") + public void testDependenciesNotAccessibleOnPaste() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/copyPaste/imports/DependenciesNotAccessibleOnPaste.kt"); + doTestCopy(fileName); + } + @TestMetadata("DependencyOnJava.kt") public void testDependencyOnJava() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/copyPaste/imports/DependencyOnJava.kt"); @@ -465,6 +471,12 @@ public class InsertImportOnPasteTestGenerated extends AbstractInsertImportOnPast doTestCut(fileName); } + @TestMetadata("DependenciesNotAccessibleOnPaste.kt") + public void testDependenciesNotAccessibleOnPaste() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/copyPaste/imports/DependenciesNotAccessibleOnPaste.kt"); + doTestCut(fileName); + } + @TestMetadata("DependencyOnJava.kt") public void testDependencyOnJava() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/copyPaste/imports/DependencyOnJava.kt");