diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 8020bfd686a..3e799806013 100644 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -141,6 +141,7 @@ import org.jetbrains.kotlin.idea.decompiler.stubBuilder.AbstractClsStubBuilderTe import org.jetbrains.kotlin.codegen.AbstractLineNumberTest import org.jetbrains.kotlin.completion.handlers.AbstractKeywordCompletionHandlerTest import org.jetbrains.kotlin.idea.kdoc.AbstractKDocHighlightingTest +import org.jetbrains.kotlin.addImport.AbstractAddImportTest fun main(args: Array) { System.setProperty("java.awt.headless", "true") @@ -595,6 +596,9 @@ fun main(args: Array) { testClass(javaClass()) { model("shortenRefs", pattern = """^([^\.]+)\.kt$""") } + testClass(javaClass()) { + model("addImport", pattern = """^([^\.]+)\.kt$""") + } testClass(javaClass()) { model("completion/injava", extension = "java") diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheService.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheService.kt index 51ce5600bc9..bf82ae989f3 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheService.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheService.kt @@ -39,6 +39,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.psi.JetDeclaration import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.resolve.scopes.JetScope private val LOG = Logger.getInstance(javaClass()) @@ -66,6 +67,10 @@ public class KotlinCacheService(val project: Project) { return cache.getAnalysisResultsForElements(elements) } + override fun getFileTopLevelScope(file: JetFile): JetScope { + return getLazyResolveSession(file).getScopeProvider().getFileScope(file) + } + override fun get(extension: CacheExtension): T { return cache[extension] } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ResolutionFacade.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ResolutionFacade.kt index 9a1d7c64867..568d8af9d09 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ResolutionFacade.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ResolutionFacade.kt @@ -23,6 +23,8 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.psi.JetDeclaration import org.jetbrains.kotlin.analyzer.AnalysisResult import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.psi.JetFile +import org.jetbrains.kotlin.resolve.scopes.JetScope public trait ResolutionFacade { @@ -32,6 +34,8 @@ public trait ResolutionFacade { public fun resolveToDescriptor(declaration: JetDeclaration): DeclarationDescriptor + public fun getFileTopLevelScope(file: JetFile): JetScope + public fun findModuleDescriptor(element: JetElement): ModuleDescriptor public fun get(extension: CacheExtension): T diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/codeInsight/ShortenReferences.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/codeInsight/ShortenReferences.kt index 9d669dcab41..be54379db4a 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/codeInsight/ShortenReferences.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/codeInsight/ShortenReferences.kt @@ -27,16 +27,15 @@ import com.intellij.psi.util.PsiTreeUtil import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiDocumentManager import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade -import org.jetbrains.kotlin.resolve.DescriptorUtils import java.util.Collections import org.jetbrains.kotlin.analyzer.analyzeInContext import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny import java.util.LinkedHashSet -import org.jetbrains.kotlin.resolve.ImportPath import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType +import org.jetbrains.kotlin.resolve.DescriptorUtils public object ShortenReferences { public fun process(element: JetElement) { @@ -303,17 +302,9 @@ public object ShortenReferences { private var optimizeImports = true fun addImport(target: DeclarationDescriptor): Boolean { - val realTarget = if (DescriptorUtils.isClassObject(target)) // references to class object are treated as ones to its owner class - target.getContainingDeclaration() as? ClassDescriptor ?: return false - else - target - - if (realTarget !is ClassDescriptor && realTarget !is PackageViewDescriptor) return false - if (realTarget.getContainingDeclaration() is ClassDescriptor) return false // do not insert imports for nested classes - + if (target !is ClassDescriptor && target !is PackageViewDescriptor) return false optimizeImports() - ImportInsertHelper.INSTANCE.writeImportToFile(ImportPath(DescriptorUtils.getFqNameSafe(realTarget), false), file) - return true + return ImportInsertHelper.INSTANCE.importDescriptor(file, target) } fun optimizeImports(): Boolean { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelper.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelper.kt index 2bb678f5cae..f35051cca5f 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelper.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelper.kt @@ -21,6 +21,8 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.JetFile import org.jetbrains.kotlin.psi.JetImportDirective import org.jetbrains.kotlin.resolve.ImportPath +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade public trait ImportInsertHelper { @@ -34,7 +36,13 @@ public trait ImportInsertHelper { public fun needImport(importPath: ImportPath, file: JetFile, importDirectives: List = file.getImportDirectives()): Boolean - public fun writeImportToFile(importPath: ImportPath, file: JetFile) + public fun writeImportToFile(importPath: ImportPath, file: JetFile): JetImportDirective + + /** + * Returns true, if the descriptor is imported (even if no import was added because it's not needed) + * and false, if importing of this descriptor is either impossible or not allowed by code style. + */ + public fun importDescriptor(file: JetFile, descriptor: DeclarationDescriptor): Boolean class object { public val INSTANCE: ImportInsertHelper diff --git a/idea/src/org/jetbrains/kotlin/idea/formatter/JetCodeStyleSettings.java b/idea/src/org/jetbrains/kotlin/idea/formatter/JetCodeStyleSettings.java index 987db6d99cf..f5a096be5a0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/formatter/JetCodeStyleSettings.java +++ b/idea/src/org/jetbrains/kotlin/idea/formatter/JetCodeStyleSettings.java @@ -41,6 +41,8 @@ public class JetCodeStyleSettings extends CustomCodeStyleSettings { public boolean LBRACE_ON_NEXT_LINE = false; + public boolean PREFER_ALL_UNDER_IMPORTS = false; + public static JetCodeStyleSettings getInstance(Project project) { return CodeStyleSettingsManager.getSettings(project).getCustomSettings(JetCodeStyleSettings.class); } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelperImpl.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelperImpl.kt index 16e672a7bf5..ab067457574 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelperImpl.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelperImpl.kt @@ -20,11 +20,32 @@ import com.intellij.codeInsight.CodeInsightSettings import com.intellij.codeInsight.actions.OptimizeImportsProcessor import org.jetbrains.kotlin.idea.project.ProjectStructureUtil import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS -import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.ImportPath import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor +import org.jetbrains.kotlin.descriptors.PackageViewDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import org.jetbrains.kotlin.idea.formatter.JetCodeStyleSettings +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered +import org.jetbrains.kotlin.descriptors.ClassifierDescriptor +import org.jetbrains.kotlin.idea.imports.importableFqName +import java.util.LinkedHashSet +import org.jetbrains.kotlin.idea.imports.importableFqNameSafe +import java.util.ArrayList +import org.jetbrains.kotlin.utils.addIfNotNull +import org.jetbrains.kotlin.resolve.scopes.JetScope +import org.jetbrains.kotlin.descriptors.ModuleDescriptor public class ImportInsertHelperImpl : ImportInsertHelper { /** @@ -53,28 +74,29 @@ public class ImportInsertHelperImpl : ImportInsertHelper { } } - override fun writeImportToFile(importPath: ImportPath, file: JetFile) { + override fun writeImportToFile(importPath: ImportPath, file: JetFile): JetImportDirective { val psiFactory = JetPsiFactory(file.getProject()) if (file is JetCodeFragment) { val newDirective = psiFactory.createImportDirective(importPath) file.addImportsFromString(newDirective.getText()) - return + return newDirective } val importList = file.getImportList() if (importList != null) { val newDirective = psiFactory.createImportDirective(importPath) importList.add(psiFactory.createNewLine()) - importList.add(newDirective) + return importList.add(newDirective) as JetImportDirective } else { - val newDirective = psiFactory.createImportDirectiveWithImportList(importPath) + val newImportList = psiFactory.createImportDirectiveWithImportList(importPath) val packageDirective = file.getPackageDirective() if (packageDirective == null) { throw IllegalStateException("Scripts are not supported: " + file.getName()) } - packageDirective.getParent().addAfter(newDirective, packageDirective) + val addedImportList = packageDirective.getParent().addAfter(newImportList, packageDirective) as JetImportList + return addedImportList.getImports().single() } } @@ -126,4 +148,220 @@ public class ImportInsertHelperImpl : ImportInsertHelper { return true } + + override fun importDescriptor(file: JetFile, descriptor: DeclarationDescriptor): Boolean { + return Importer(file).importDescriptor(descriptor) + } + + private inner class Importer( + private val file: JetFile + ) { + private val resolutionFacade = file.getResolutionFacade() + private val preferAllUnderImports = JetCodeStyleSettings.getInstance(file.getProject()).PREFER_ALL_UNDER_IMPORTS + + fun importDescriptor(descriptor: DeclarationDescriptor): Boolean { + val target = if (DescriptorUtils.isClassObject(descriptor)) // references to class object are treated as ones to its owner class + descriptor.getContainingDeclaration() as? ClassDescriptor ?: return false + else + descriptor + + val name = target.getName() + val topLevelScope = resolutionFacade.getFileTopLevelScope(file) + + // check if import is not needed + when (target) { + is ClassDescriptor -> { if (topLevelScope.getClassifier(name) == target) return true } + is PackageViewDescriptor -> { if (topLevelScope.getPackage(name) == target) return true } + is FunctionDescriptor -> { if (topLevelScope.getFunctions(name).contains(target)) return true } + is PropertyDescriptor -> { if (topLevelScope.getProperties(name).contains(target)) return true } + else -> return false + } + + // do not insert imports for non-top level declarations + if (target !is PackageViewDescriptor && target.getContainingDeclaration() !is PackageFragmentDescriptor) return false + + val imports = file.getImportDirectives() + + //TODO: is that correct? What if function is imported and we need to import class? + if (imports.any { it.getImportedName() == name.asString() }) return false + + val fqName = target.importableFqNameSafe + val packageFqName = fqName.parent() + + val allUnderImportPath = ImportPath(packageFqName, true) + val tryAllUnderImport = preferAllUnderImports + && !packageFqName.isRoot() + && !imports.any { it.getImportPath() == allUnderImportPath } + && when (target) { + is ClassDescriptor -> topLevelScope.getClassifier(name) == null // this check does not give a guarantee that import with * will import the class - for example, there can be classes with conflicting name in more than one import with * + is PackageViewDescriptor -> false + is FunctionDescriptor, is PropertyDescriptor -> true + else -> throw Exception() + } + + if (tryAllUnderImport && addAllUnderImport(target)) { + return true + } + + return addExplicitImport(target) + } + + private fun addAllUnderImport(target: DeclarationDescriptor): Boolean { + val targetFqName = target.importableFqNameSafe + val parentFqName = targetFqName.parent() + + val moduleDescriptor = resolutionFacade.findModuleDescriptor(file) + val imports = file.getImportDirectives() + val scopeToImport = getMemberScope(parentFqName, moduleDescriptor) ?: return false + val importedScopes = imports + .filter { it.isAllUnder () } + .map { + val importPath = it.getImportPath() + if (importPath != null) { + val fqName = importPath.fqnPart() + getMemberScope(fqName, moduleDescriptor) + } + else { + null + } + } + .filterNotNull() + + val classNamesToImport = scopeToImport + .getDescriptorsFiltered(DescriptorKindFilter.CLASSIFIERS, { true }) + .map { it.getName() } + + val aliasNames = imports.map { it.getImportedName() }.filterNotNull().toSet() + //TODO: check for visibility + var conflictCandidates: List = classNamesToImport + .filter { it.asString() !in aliasNames } + .flatMap { + importedScopes.map { scope -> scope.getClassifier(it) }.filterNotNull() + } + val conflicts = detectNeededImports(conflictCandidates) + + val addedImport = addImport(parentFqName, true) + + if (target is ClassDescriptor) { + val newTopLevelScope = resolutionFacade.getFileTopLevelScope(file) + val resolvedTo = newTopLevelScope.getClassifier(target.getName()) + if (resolvedTo?.importableFqNameSafe != targetFqName) { + addedImport.delete() + return false + } + } + + for (conflict in conflicts) { + addImport(DescriptorUtils.getFqNameSafe(conflict), false) + } + + dropRedundantExplicitImports(parentFqName) + + return true + } + + private fun getMemberScope(fqName: FqName, moduleDescriptor: ModuleDescriptor): JetScope? { + val packageView = moduleDescriptor.getPackage(fqName) + if (packageView != null) { + return packageView.getMemberScope() + } + + val parentScope = getMemberScope(fqName.parent(), moduleDescriptor) ?: return null + val classDescriptor = parentScope.getClassifier(fqName.shortName()) as? ClassDescriptor ?: return null + return classDescriptor.getDefaultType().getMemberScope() + } + + private fun addExplicitImport(target: DeclarationDescriptor): Boolean { + if (target is ClassDescriptor || target is PackageViewDescriptor) { + val topLevelScope = resolutionFacade.getFileTopLevelScope(file) + val name = target.getName() + + val classifier = topLevelScope.getClassifier(name) + if (classifier != null && detectNeededImports(listOf(classifier)).isNotEmpty()) { + return false + } + } + + addImport(target.importableFqNameSafe, false) + return true + } + + private fun dropRedundantExplicitImports(packageFqName: FqName) { + val dropCandidates = file.getImportDirectives().filter { + !it.isAllUnder() && it.getAliasName() == null && it.getImportPath()?.fqnPart()?.parent() == packageFqName + } + + val importsToCheck = ArrayList() + for (import in dropCandidates) { + val importedReference = import.getImportedReference() ?: continue + val refExpr = (importedReference as JetDotQualifiedExpression).getSelectorExpression() as JetSimpleNameExpression + val targets = refExpr.resolveTargets() + if (targets.any { it is PackageViewDescriptor }) continue // do not drop import of package + val classDescriptor = targets.filterIsInstance().firstOrNull() + importsToCheck.addIfNotNull(classDescriptor?.importableFqNameSafe) + import.delete() + } + + if (importsToCheck.isNotEmpty()) { + val topLevelScope = resolutionFacade.getFileTopLevelScope(file) + for (classFqName in importsToCheck) { + if (topLevelScope.getClassifier(classFqName.shortName())?.importableFqNameSafe != classFqName) { + addImport(classFqName, false) // restore explicit import + } + } + } + } + + private fun detectNeededImports(importedDescriptors: Collection): Set { + if (importedDescriptors.isEmpty()) return setOf() + + val descriptorsToCheck = importedDescriptors.map { it.getName() to it }.toMap().toLinkedMap() + val result = LinkedHashSet() + file.accept(object : JetVisitorVoid() { + override fun visitElement(element: PsiElement) { + if (descriptorsToCheck.isEmpty()) return + element.acceptChildren(this) + } + + override fun visitImportList(importList: JetImportList) { + } + + override fun visitPackageDirective(directive: JetPackageDirective) { + } + + override fun visitSimpleNameExpression(expression: JetSimpleNameExpression) { + if (JetPsiUtil.isSelectorInQualified(expression)) return + + val refName = expression.getReferencedNameAsName() + val descriptor = descriptorsToCheck[refName] + if (descriptor != null) { + val targetFqName = targetFqName(expression) + if (targetFqName != null && targetFqName == DescriptorUtils.getFqNameSafe(descriptor)) { + descriptorsToCheck.remove(refName) + result.add(descriptor) + } + } + } + }) + return result + } + + private fun JetImportDirective.getImportedName(): String? = JetPsiUtil.getAliasName(this)?.getIdentifier() + + private fun targetFqName(ref: JetReferenceExpression): FqName? { + return ref.resolveTargets().map { it.importableFqName }.toSet().singleOrNull() + + } + + private fun JetReferenceExpression.resolveTargets(): Collection { + val bindingContext = resolutionFacade.analyze(this, BodyResolveMode.PARTIAL) + return bindingContext[BindingContext.REFERENCE_TARGET, this]?.let { listOf(it) } + ?: bindingContext[BindingContext.AMBIGUOUS_REFERENCE_TARGET, this] + ?: return listOf() + } + + private fun addImport(fqName: FqName, allUnder: Boolean): JetImportDirective { + return writeImportToFile(ImportPath(fqName, allUnder), file) + } + } } diff --git a/idea/testData/addImport/CannotImportClass1.kt b/idea/testData/addImport/CannotImportClass1.kt new file mode 100644 index 00000000000..8f105829d49 --- /dev/null +++ b/idea/testData/addImport/CannotImportClass1.kt @@ -0,0 +1,6 @@ +// IMPORT: class: kotlin.String +package p + +import java.lang.String + +fun foo(): ArrayList {} diff --git a/idea/testData/addImport/CannotImportClass1.kt.after b/idea/testData/addImport/CannotImportClass1.kt.after new file mode 100644 index 00000000000..cfc992d7406 --- /dev/null +++ b/idea/testData/addImport/CannotImportClass1.kt.after @@ -0,0 +1 @@ +Failed to add import \ No newline at end of file diff --git a/idea/testData/addImport/CannotImportClass2.kt b/idea/testData/addImport/CannotImportClass2.kt new file mode 100644 index 00000000000..8c56acc92d2 --- /dev/null +++ b/idea/testData/addImport/CannotImportClass2.kt @@ -0,0 +1,4 @@ +// IMPORT: java.sql.Date +import java.util.* + +val d: Date = Date() \ No newline at end of file diff --git a/idea/testData/addImport/CannotImportClass2.kt.after b/idea/testData/addImport/CannotImportClass2.kt.after new file mode 100644 index 00000000000..cfc992d7406 --- /dev/null +++ b/idea/testData/addImport/CannotImportClass2.kt.after @@ -0,0 +1 @@ +Failed to add import \ No newline at end of file diff --git a/idea/testData/addImport/CannotImportClass3.kt b/idea/testData/addImport/CannotImportClass3.kt new file mode 100644 index 00000000000..d62ac78f867 --- /dev/null +++ b/idea/testData/addImport/CannotImportClass3.kt @@ -0,0 +1,4 @@ +// IMPORT: java.sql.Date +import java.util as Date + +val d: Date.Date = Date.Date() \ No newline at end of file diff --git a/idea/testData/addImport/CannotImportClass3.kt.after b/idea/testData/addImport/CannotImportClass3.kt.after new file mode 100644 index 00000000000..cfc992d7406 --- /dev/null +++ b/idea/testData/addImport/CannotImportClass3.kt.after @@ -0,0 +1 @@ +Failed to add import \ No newline at end of file diff --git a/idea/testData/addImport/ClassAlreadyImported1.kt b/idea/testData/addImport/ClassAlreadyImported1.kt new file mode 100644 index 00000000000..b9012370ea5 --- /dev/null +++ b/idea/testData/addImport/ClassAlreadyImported1.kt @@ -0,0 +1,6 @@ +// IMPORT: java.util.ArrayList +package p + +import java.util.* + +fun foo(): ArrayList {} diff --git a/idea/testData/addImport/ClassAlreadyImported1.kt.after b/idea/testData/addImport/ClassAlreadyImported1.kt.after new file mode 100644 index 00000000000..b9012370ea5 --- /dev/null +++ b/idea/testData/addImport/ClassAlreadyImported1.kt.after @@ -0,0 +1,6 @@ +// IMPORT: java.util.ArrayList +package p + +import java.util.* + +fun foo(): ArrayList {} diff --git a/idea/testData/addImport/ClassAlreadyImported2.kt b/idea/testData/addImport/ClassAlreadyImported2.kt new file mode 100644 index 00000000000..f07f6fb6e47 --- /dev/null +++ b/idea/testData/addImport/ClassAlreadyImported2.kt @@ -0,0 +1,6 @@ +// IMPORT: java.util.ArrayList +package p + +import java.util.ArrayList + +fun foo(): ArrayList {} diff --git a/idea/testData/addImport/ClassAlreadyImported2.kt.after b/idea/testData/addImport/ClassAlreadyImported2.kt.after new file mode 100644 index 00000000000..f07f6fb6e47 --- /dev/null +++ b/idea/testData/addImport/ClassAlreadyImported2.kt.after @@ -0,0 +1,6 @@ +// IMPORT: java.util.ArrayList +package p + +import java.util.ArrayList + +fun foo(): ArrayList {} diff --git a/idea/testData/addImport/ConflictingNameAppearsAndHasUsage1.kt b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage1.kt new file mode 100644 index 00000000000..64a1fde6dcd --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage1.kt @@ -0,0 +1,6 @@ +// IMPORT: java.util.ArrayList +package p + +import java.sql.* + +val d = Date() diff --git a/idea/testData/addImport/ConflictingNameAppearsAndHasUsage1.kt.after b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage1.kt.after new file mode 100644 index 00000000000..3084aae0512 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage1.kt.after @@ -0,0 +1,8 @@ +// IMPORT: java.util.ArrayList +package p + +import java.sql.* +import java.util.* +import java.sql.Date + +val d = Date() diff --git a/idea/testData/addImport/ConflictingNameAppearsAndHasUsage2.kt b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage2.kt new file mode 100644 index 00000000000..501d2c5363a --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage2.kt @@ -0,0 +1,6 @@ +// IMPORT: java.util.ArrayList +package p + +import java.sql.* + +val d: Date? = null diff --git a/idea/testData/addImport/ConflictingNameAppearsAndHasUsage2.kt.after b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage2.kt.after new file mode 100644 index 00000000000..3d0530e803f --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage2.kt.after @@ -0,0 +1,8 @@ +// IMPORT: java.util.ArrayList +package p + +import java.sql.* +import java.util.* +import java.sql.Date + +val d: Date? = null diff --git a/idea/testData/addImport/ConflictingNameAppearsAndHasUsage3.dependency.kt b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage3.dependency.kt new file mode 100644 index 00000000000..d687aec6e15 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage3.dependency.kt @@ -0,0 +1,5 @@ +package dependency + +class Date + +fun Date(s: String) = Date() \ No newline at end of file diff --git a/idea/testData/addImport/ConflictingNameAppearsAndHasUsage3.kt b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage3.kt new file mode 100644 index 00000000000..854530337b9 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage3.kt @@ -0,0 +1,6 @@ +// IMPORT: java.util.ArrayList +package p + +import dependency.* + +val d = Date(1, 2) diff --git a/idea/testData/addImport/ConflictingNameAppearsAndHasUsage3.kt.after b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage3.kt.after new file mode 100644 index 00000000000..1bc47329f0e --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage3.kt.after @@ -0,0 +1,8 @@ +// IMPORT: java.util.ArrayList +package p + +import dependency.* +import java.util.* +import dependency.Date + +val d = Date(1, 2) diff --git a/idea/testData/addImport/ConflictingNameAppearsAndHasUsage4.dependency.kt b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage4.dependency.kt new file mode 100644 index 00000000000..8304ee70896 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage4.dependency.kt @@ -0,0 +1,7 @@ +package dependency + +class Date { + class object { + val VALUE = 0 + } +} diff --git a/idea/testData/addImport/ConflictingNameAppearsAndHasUsage4.kt b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage4.kt new file mode 100644 index 00000000000..932b0fc8899 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage4.kt @@ -0,0 +1,6 @@ +// IMPORT: java.util.ArrayList +package p + +import dependency.* + +val d = Date.VALUE diff --git a/idea/testData/addImport/ConflictingNameAppearsAndHasUsage4.kt.after b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage4.kt.after new file mode 100644 index 00000000000..e713080d2ca --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage4.kt.after @@ -0,0 +1,8 @@ +// IMPORT: java.util.ArrayList +package p + +import dependency.* +import java.util.* +import dependency.Date + +val d = Date.VALUE diff --git a/idea/testData/addImport/ConflictingNameAppearsAndHasUsage5.dependency.kt b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage5.dependency.kt new file mode 100644 index 00000000000..cc56a51fe68 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage5.dependency.kt @@ -0,0 +1,5 @@ +package dependency + +class AClass { + class Date +} diff --git a/idea/testData/addImport/ConflictingNameAppearsAndHasUsage5.kt b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage5.kt new file mode 100644 index 00000000000..a2ae6fc2452 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage5.kt @@ -0,0 +1,6 @@ +// IMPORT: java.util.ArrayList +package p + +import dependency.AClass.* + +val d = Date() diff --git a/idea/testData/addImport/ConflictingNameAppearsAndHasUsage5.kt.after b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage5.kt.after new file mode 100644 index 00000000000..bcc5d17bf1e --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsAndHasUsage5.kt.after @@ -0,0 +1,8 @@ +// IMPORT: java.util.ArrayList +package p + +import dependency.AClass.* +import java.util.* +import dependency.AClass.Date + +val d = Date() diff --git a/idea/testData/addImport/ConflictingNameAppearsButUsageIsQualified.kt b/idea/testData/addImport/ConflictingNameAppearsButUsageIsQualified.kt new file mode 100644 index 00000000000..2e142bc1b84 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsButUsageIsQualified.kt @@ -0,0 +1,6 @@ +// IMPORT: java.util.ArrayList +package p + +import java.sql.* + +val d: java.sql.Date? = null diff --git a/idea/testData/addImport/ConflictingNameAppearsButUsageIsQualified.kt.after b/idea/testData/addImport/ConflictingNameAppearsButUsageIsQualified.kt.after new file mode 100644 index 00000000000..3565b51ddd7 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsButUsageIsQualified.kt.after @@ -0,0 +1,7 @@ +// IMPORT: java.util.ArrayList +package p + +import java.sql.* +import java.util.* + +val d: java.sql.Date? = null diff --git a/idea/testData/addImport/ConflictingNameAppearsFalseUsage.kt b/idea/testData/addImport/ConflictingNameAppearsFalseUsage.kt new file mode 100644 index 00000000000..282cfea6cc4 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsFalseUsage.kt @@ -0,0 +1,8 @@ +// IMPORT: java.util.ArrayList +package p + +import java.sql.* + +class Date + +val d: Date? = null diff --git a/idea/testData/addImport/ConflictingNameAppearsFalseUsage.kt.after b/idea/testData/addImport/ConflictingNameAppearsFalseUsage.kt.after new file mode 100644 index 00000000000..007e7beef1d --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsFalseUsage.kt.after @@ -0,0 +1,9 @@ +// IMPORT: java.util.ArrayList +package p + +import java.sql.* +import java.util.* + +class Date + +val d: Date? = null diff --git a/idea/testData/addImport/ConflictingNameAppearsFalseUsage2.dependency.kt b/idea/testData/addImport/ConflictingNameAppearsFalseUsage2.dependency.kt new file mode 100644 index 00000000000..418bf51e85f --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsFalseUsage2.dependency.kt @@ -0,0 +1,3 @@ +package dependency + +class Date diff --git a/idea/testData/addImport/ConflictingNameAppearsFalseUsage2.kt b/idea/testData/addImport/ConflictingNameAppearsFalseUsage2.kt new file mode 100644 index 00000000000..2122c35cf1b --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsFalseUsage2.kt @@ -0,0 +1,7 @@ +// IMPORT: java.util.ArrayList +package p + +import dependency.* +import java.sql.* + +val d = Date() diff --git a/idea/testData/addImport/ConflictingNameAppearsFalseUsage2.kt.after b/idea/testData/addImport/ConflictingNameAppearsFalseUsage2.kt.after new file mode 100644 index 00000000000..136aa239706 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsFalseUsage2.kt.after @@ -0,0 +1,8 @@ +// IMPORT: java.util.ArrayList +package p + +import dependency.* +import java.sql.* +import java.util.* + +val d = Date() diff --git a/idea/testData/addImport/ConflictingNameAppearsNoUsage.kt b/idea/testData/addImport/ConflictingNameAppearsNoUsage.kt new file mode 100644 index 00000000000..4accd4e9123 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsNoUsage.kt @@ -0,0 +1,6 @@ +// IMPORT: java.util.ArrayList +package p + +import java.sql.* + +val d: Driver? = null diff --git a/idea/testData/addImport/ConflictingNameAppearsNoUsage.kt.after b/idea/testData/addImport/ConflictingNameAppearsNoUsage.kt.after new file mode 100644 index 00000000000..7621599fd58 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameAppearsNoUsage.kt.after @@ -0,0 +1,7 @@ +// IMPORT: java.util.ArrayList +package p + +import java.sql.* +import java.util.* + +val d: Driver? = null diff --git a/idea/testData/addImport/ConflictingNameHasExplicitImportAlready.kt b/idea/testData/addImport/ConflictingNameHasExplicitImportAlready.kt new file mode 100644 index 00000000000..f7271bf2435 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameHasExplicitImportAlready.kt @@ -0,0 +1,7 @@ +// IMPORT: java.util.ArrayList +package p + +import java.sql.* +import java.sql.Date + +val d: Date? = null diff --git a/idea/testData/addImport/ConflictingNameHasExplicitImportAlready.kt.after b/idea/testData/addImport/ConflictingNameHasExplicitImportAlready.kt.after new file mode 100644 index 00000000000..c8e4662dc8b --- /dev/null +++ b/idea/testData/addImport/ConflictingNameHasExplicitImportAlready.kt.after @@ -0,0 +1,8 @@ +// IMPORT: java.util.ArrayList +package p + +import java.sql.* +import java.sql.Date +import java.util.* + +val d: Date? = null diff --git a/idea/testData/addImport/ConflictingNameNoAllUnderImport.kt b/idea/testData/addImport/ConflictingNameNoAllUnderImport.kt new file mode 100644 index 00000000000..d44471b9f88 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameNoAllUnderImport.kt @@ -0,0 +1,4 @@ +// IMPORT: java.sql.Date +package p + +import java.util.* diff --git a/idea/testData/addImport/ConflictingNameNoAllUnderImport.kt.after b/idea/testData/addImport/ConflictingNameNoAllUnderImport.kt.after new file mode 100644 index 00000000000..6cfec32bd13 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameNoAllUnderImport.kt.after @@ -0,0 +1,5 @@ +// IMPORT: java.sql.Date +package p + +import java.util.* +import java.sql.Date diff --git a/idea/testData/addImport/ConflictingNameNoAllUnderImport2.kt b/idea/testData/addImport/ConflictingNameNoAllUnderImport2.kt new file mode 100644 index 00000000000..aae7acc6ede --- /dev/null +++ b/idea/testData/addImport/ConflictingNameNoAllUnderImport2.kt @@ -0,0 +1,5 @@ +// IMPORT: java.sql.Date +package p + +import java.util.* +import java.sql.* diff --git a/idea/testData/addImport/ConflictingNameNoAllUnderImport2.kt.after b/idea/testData/addImport/ConflictingNameNoAllUnderImport2.kt.after new file mode 100644 index 00000000000..a40d215ba9c --- /dev/null +++ b/idea/testData/addImport/ConflictingNameNoAllUnderImport2.kt.after @@ -0,0 +1,6 @@ +// IMPORT: java.sql.Date +package p + +import java.util.* +import java.sql.* +import java.sql.Date diff --git a/idea/testData/addImport/ConflictingNameNoAllUnderImport3.dependency.kt b/idea/testData/addImport/ConflictingNameNoAllUnderImport3.dependency.kt new file mode 100644 index 00000000000..226f43311c7 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameNoAllUnderImport3.dependency.kt @@ -0,0 +1,3 @@ +package dependency + +class Date \ No newline at end of file diff --git a/idea/testData/addImport/ConflictingNameNoAllUnderImport3.kt b/idea/testData/addImport/ConflictingNameNoAllUnderImport3.kt new file mode 100644 index 00000000000..d20cf31e4e3 --- /dev/null +++ b/idea/testData/addImport/ConflictingNameNoAllUnderImport3.kt @@ -0,0 +1,5 @@ +// IMPORT: dependency.Date +package p + +import java.util.* +import java.sql.* diff --git a/idea/testData/addImport/ConflictingNameNoAllUnderImport3.kt.after b/idea/testData/addImport/ConflictingNameNoAllUnderImport3.kt.after new file mode 100644 index 00000000000..b473b9320df --- /dev/null +++ b/idea/testData/addImport/ConflictingNameNoAllUnderImport3.kt.after @@ -0,0 +1,6 @@ +// IMPORT: dependency.Date +package p + +import java.util.* +import java.sql.* +import dependency.Date diff --git a/idea/testData/addImport/DropExplicitImports.kt b/idea/testData/addImport/DropExplicitImports.kt new file mode 100644 index 00000000000..f883b5c0556 --- /dev/null +++ b/idea/testData/addImport/DropExplicitImports.kt @@ -0,0 +1,14 @@ +// IMPORT: java.util.HashMap +package p + +import java.sql.* +import java.util.ArrayList // maybe dropped on adding import with * +import java.util.Date // should not be dropped because of conflicting java.sql.Date class +import java.util.HashSet as JavaHashSet // alias import should not be dropped +import java.util.concurrent // import of package should not be dropped because packages are not imported by * + +fun foo() { + val v1 = JavaHashSet() + val v2 = Date() + val v3 = ArrayList() +} \ No newline at end of file diff --git a/idea/testData/addImport/DropExplicitImports.kt.after b/idea/testData/addImport/DropExplicitImports.kt.after new file mode 100644 index 00000000000..7746d48f660 --- /dev/null +++ b/idea/testData/addImport/DropExplicitImports.kt.after @@ -0,0 +1,14 @@ +// IMPORT: java.util.HashMap +package p + +import java.sql.* +import java.util.HashSet as JavaHashSet // alias import should not be dropped +import java.util.concurrent // import of package should not be dropped because packages are not imported by * +import java.util.* +import java.util.Date + +fun foo() { + val v1 = JavaHashSet() + val v2 = Date() + val v3 = ArrayList() +} \ No newline at end of file diff --git a/idea/testData/addImport/DropExplicitImports2.dependency.kt b/idea/testData/addImport/DropExplicitImports2.dependency.kt new file mode 100644 index 00000000000..404d402a371 --- /dev/null +++ b/idea/testData/addImport/DropExplicitImports2.dependency.kt @@ -0,0 +1,6 @@ +package dependency + +fun function(){} +val property: Int = 0 +class Class1 +class Class2 \ No newline at end of file diff --git a/idea/testData/addImport/DropExplicitImports2.kt b/idea/testData/addImport/DropExplicitImports2.kt new file mode 100644 index 00000000000..d9c2eaee97b --- /dev/null +++ b/idea/testData/addImport/DropExplicitImports2.kt @@ -0,0 +1,6 @@ +// IMPORT: dependency.Class2 +package p + +import dependency.Class1 +import dependency.function +import dependency.property diff --git a/idea/testData/addImport/DropExplicitImports2.kt.after b/idea/testData/addImport/DropExplicitImports2.kt.after new file mode 100644 index 00000000000..d38831ed2a4 --- /dev/null +++ b/idea/testData/addImport/DropExplicitImports2.kt.after @@ -0,0 +1,4 @@ +// IMPORT: dependency.Class2 +package p + +import dependency.* diff --git a/idea/testData/addImport/FunctionAlreadyImported1.dependency.kt b/idea/testData/addImport/FunctionAlreadyImported1.dependency.kt new file mode 100644 index 00000000000..57cb3df163f --- /dev/null +++ b/idea/testData/addImport/FunctionAlreadyImported1.dependency.kt @@ -0,0 +1,3 @@ +package dependency + +fun foo(){} \ No newline at end of file diff --git a/idea/testData/addImport/FunctionAlreadyImported1.kt b/idea/testData/addImport/FunctionAlreadyImported1.kt new file mode 100644 index 00000000000..83904812915 --- /dev/null +++ b/idea/testData/addImport/FunctionAlreadyImported1.kt @@ -0,0 +1,8 @@ +// IMPORT: dependency.foo +package p + +import dependency.foo + +fun f() { + foo() +} diff --git a/idea/testData/addImport/FunctionAlreadyImported1.kt.after b/idea/testData/addImport/FunctionAlreadyImported1.kt.after new file mode 100644 index 00000000000..83904812915 --- /dev/null +++ b/idea/testData/addImport/FunctionAlreadyImported1.kt.after @@ -0,0 +1,8 @@ +// IMPORT: dependency.foo +package p + +import dependency.foo + +fun f() { + foo() +} diff --git a/idea/testData/addImport/FunctionAlreadyImported2.dependency.kt b/idea/testData/addImport/FunctionAlreadyImported2.dependency.kt new file mode 100644 index 00000000000..57cb3df163f --- /dev/null +++ b/idea/testData/addImport/FunctionAlreadyImported2.dependency.kt @@ -0,0 +1,3 @@ +package dependency + +fun foo(){} \ No newline at end of file diff --git a/idea/testData/addImport/FunctionAlreadyImported2.kt b/idea/testData/addImport/FunctionAlreadyImported2.kt new file mode 100644 index 00000000000..1056ead1d5c --- /dev/null +++ b/idea/testData/addImport/FunctionAlreadyImported2.kt @@ -0,0 +1,8 @@ +// IMPORT: dependency.foo +package p + +import dependency.* + +fun f() { + foo() +} diff --git a/idea/testData/addImport/FunctionAlreadyImported2.kt.after b/idea/testData/addImport/FunctionAlreadyImported2.kt.after new file mode 100644 index 00000000000..1056ead1d5c --- /dev/null +++ b/idea/testData/addImport/FunctionAlreadyImported2.kt.after @@ -0,0 +1,8 @@ +// IMPORT: dependency.foo +package p + +import dependency.* + +fun f() { + foo() +} diff --git a/idea/testData/addImport/ImportClassSimple.kt b/idea/testData/addImport/ImportClassSimple.kt new file mode 100644 index 00000000000..946467d6551 --- /dev/null +++ b/idea/testData/addImport/ImportClassSimple.kt @@ -0,0 +1,4 @@ +// IMPORT: java.util.ArrayList +package p + +fun foo() {} diff --git a/idea/testData/addImport/ImportClassSimple.kt.after b/idea/testData/addImport/ImportClassSimple.kt.after new file mode 100644 index 00000000000..1cc467eaaed --- /dev/null +++ b/idea/testData/addImport/ImportClassSimple.kt.after @@ -0,0 +1,6 @@ +// IMPORT: java.util.ArrayList +package p + +import java.util.* + +fun foo() {} diff --git a/idea/testData/addImport/ImportPackage.kt b/idea/testData/addImport/ImportPackage.kt new file mode 100644 index 00000000000..611d7c1a16e --- /dev/null +++ b/idea/testData/addImport/ImportPackage.kt @@ -0,0 +1,4 @@ +// IMPORT: java.util +package p + +fun foo(): util.ArrayList {} diff --git a/idea/testData/addImport/ImportPackage.kt.after b/idea/testData/addImport/ImportPackage.kt.after new file mode 100644 index 00000000000..5a241e73832 --- /dev/null +++ b/idea/testData/addImport/ImportPackage.kt.after @@ -0,0 +1,6 @@ +// IMPORT: java.util +package p + +import java.util + +fun foo(): util.ArrayList {} diff --git a/idea/testData/addImport/NoNeedToImportStandardClass.kt b/idea/testData/addImport/NoNeedToImportStandardClass.kt new file mode 100644 index 00000000000..bddc3fecc65 --- /dev/null +++ b/idea/testData/addImport/NoNeedToImportStandardClass.kt @@ -0,0 +1,6 @@ +// IMPORT: class: kotlin.String +package p + +import java.util.* + +fun foo(): ArrayList {} diff --git a/idea/testData/addImport/NoNeedToImportStandardClass.kt.after b/idea/testData/addImport/NoNeedToImportStandardClass.kt.after new file mode 100644 index 00000000000..bddc3fecc65 --- /dev/null +++ b/idea/testData/addImport/NoNeedToImportStandardClass.kt.after @@ -0,0 +1,6 @@ +// IMPORT: class: kotlin.String +package p + +import java.util.* + +fun foo(): ArrayList {} diff --git a/idea/testData/addImport/PackageAlreadyImported.kt b/idea/testData/addImport/PackageAlreadyImported.kt new file mode 100644 index 00000000000..5a241e73832 --- /dev/null +++ b/idea/testData/addImport/PackageAlreadyImported.kt @@ -0,0 +1,6 @@ +// IMPORT: java.util +package p + +import java.util + +fun foo(): util.ArrayList {} diff --git a/idea/testData/addImport/PackageAlreadyImported.kt.after b/idea/testData/addImport/PackageAlreadyImported.kt.after new file mode 100644 index 00000000000..5a241e73832 --- /dev/null +++ b/idea/testData/addImport/PackageAlreadyImported.kt.after @@ -0,0 +1,6 @@ +// IMPORT: java.util +package p + +import java.util + +fun foo(): util.ArrayList {} diff --git a/idea/testData/addImport/PropertyAlreadyImported1.dependency.kt b/idea/testData/addImport/PropertyAlreadyImported1.dependency.kt new file mode 100644 index 00000000000..d725ef26c1c --- /dev/null +++ b/idea/testData/addImport/PropertyAlreadyImported1.dependency.kt @@ -0,0 +1,3 @@ +package dependency + +val foo: Int = 1 \ No newline at end of file diff --git a/idea/testData/addImport/PropertyAlreadyImported1.kt b/idea/testData/addImport/PropertyAlreadyImported1.kt new file mode 100644 index 00000000000..22631699e3b --- /dev/null +++ b/idea/testData/addImport/PropertyAlreadyImported1.kt @@ -0,0 +1,6 @@ +// IMPORT: dependency.foo +package p + +import dependency.foo + +fun f() = foo diff --git a/idea/testData/addImport/PropertyAlreadyImported1.kt.after b/idea/testData/addImport/PropertyAlreadyImported1.kt.after new file mode 100644 index 00000000000..22631699e3b --- /dev/null +++ b/idea/testData/addImport/PropertyAlreadyImported1.kt.after @@ -0,0 +1,6 @@ +// IMPORT: dependency.foo +package p + +import dependency.foo + +fun f() = foo diff --git a/idea/testData/addImport/PropertyAlreadyImported2.dependency.kt b/idea/testData/addImport/PropertyAlreadyImported2.dependency.kt new file mode 100644 index 00000000000..d725ef26c1c --- /dev/null +++ b/idea/testData/addImport/PropertyAlreadyImported2.dependency.kt @@ -0,0 +1,3 @@ +package dependency + +val foo: Int = 1 \ No newline at end of file diff --git a/idea/testData/addImport/PropertyAlreadyImported2.kt b/idea/testData/addImport/PropertyAlreadyImported2.kt new file mode 100644 index 00000000000..c003ea6fbf7 --- /dev/null +++ b/idea/testData/addImport/PropertyAlreadyImported2.kt @@ -0,0 +1,6 @@ +// IMPORT: dependency.foo +package p + +import dependency.* + +fun f() = foo diff --git a/idea/testData/addImport/PropertyAlreadyImported2.kt.after b/idea/testData/addImport/PropertyAlreadyImported2.kt.after new file mode 100644 index 00000000000..c003ea6fbf7 --- /dev/null +++ b/idea/testData/addImport/PropertyAlreadyImported2.kt.after @@ -0,0 +1,6 @@ +// IMPORT: dependency.foo +package p + +import dependency.* + +fun f() = foo diff --git a/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt b/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt index 0d08370f9a1..a56ebd0d694 100644 --- a/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt +++ b/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt @@ -1,4 +1,4 @@ -// OPTIMIZE_IMPORTS +// OPTIMIZE_IMPORTS: true import java.util.Date val x = java.sql.Date(1) diff --git a/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt.after b/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt.after index 0bce500e37a..817ce568428 100644 --- a/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt.after +++ b/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt.after @@ -1,4 +1,4 @@ -// OPTIMIZE_IMPORTS +// OPTIMIZE_IMPORTS: true import java.sql.Date val x = Date(1) diff --git a/idea/testData/shortenRefs/imports/leaveQualifiedType.kt b/idea/testData/shortenRefs/imports/leaveQualifiedType.kt index 94bee0a3da3..cac027f928d 100644 --- a/idea/testData/shortenRefs/imports/leaveQualifiedType.kt +++ b/idea/testData/shortenRefs/imports/leaveQualifiedType.kt @@ -1,4 +1,4 @@ -// OPTIMIZE_IMPORTS +// OPTIMIZE_IMPORTS: true import java.util.Date class A : java.sql.Date \ No newline at end of file diff --git a/idea/testData/shortenRefs/imports/leaveQualifiedType.kt.after b/idea/testData/shortenRefs/imports/leaveQualifiedType.kt.after index baf93cfc2c9..a9168645c7a 100644 --- a/idea/testData/shortenRefs/imports/leaveQualifiedType.kt.after +++ b/idea/testData/shortenRefs/imports/leaveQualifiedType.kt.after @@ -1,4 +1,4 @@ -// OPTIMIZE_IMPORTS +// OPTIMIZE_IMPORTS: true import java.sql.Date class A : Date \ No newline at end of file diff --git a/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt b/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt index 7d2b6bb180f..2b30f48ff5c 100644 --- a/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt +++ b/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt @@ -1,4 +1,4 @@ -// OPTIMIZE_IMPORTS +// OPTIMIZE_IMPORTS: true import java.io.* class A(val d: java.sql.Date, val rs: java.sql.ResultSet) diff --git a/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt.after b/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt.after index e421fe4a1e0..d9b8ae8be24 100644 --- a/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt.after +++ b/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt.after @@ -1,4 +1,4 @@ -// OPTIMIZE_IMPORTS +// OPTIMIZE_IMPORTS: true import java.sql.Date import java.sql.ResultSet diff --git a/idea/tests/org/jetbrains/kotlin/AbstractImportsTest.kt b/idea/tests/org/jetbrains/kotlin/AbstractImportsTest.kt new file mode 100644 index 00000000000..7f84a5d85fa --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/AbstractImportsTest.kt @@ -0,0 +1,77 @@ +/* + * 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 + +import org.jetbrains.kotlin.idea.JetLightCodeInsightFixtureTestCase +import org.jetbrains.kotlin.test.JetTestUtils +import org.jetbrains.kotlin.idea.JetWithJdkAndRuntimeLightProjectDescriptor +import com.intellij.codeInsight.CodeInsightSettings +import org.jetbrains.kotlin.idea.formatter.JetCodeStyleSettings +import java.io.File +import org.jetbrains.kotlin.psi.JetFile +import org.jetbrains.kotlin.test.InTextDirectivesUtils +import com.intellij.openapi.command.CommandProcessor +import com.intellij.openapi.application.ApplicationManager +import org.jetbrains.kotlin.idea.codeInsight.ShortenReferences + +public abstract class AbstractImportsTest : JetLightCodeInsightFixtureTestCase() { + override fun getTestDataPath() = JetTestUtils.getHomeDirectory() + override fun getProjectDescriptor() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE + + protected fun doTest(testPath: String) { + val codeInsightSettings = CodeInsightSettings.getInstance() + val codeStyleSettings = JetCodeStyleSettings.getInstance(getProject()) + val optimizeImportsBefore = codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY + val preferAllUnderBefore = codeStyleSettings.PREFER_ALL_UNDER_IMPORTS + + try { + val fixture = myFixture + val dependencyPath = testPath.replace(".kt", ".dependency.kt") + if (File(dependencyPath).exists()) { + fixture.configureByFile(dependencyPath) + } + val javaDependencyPath = testPath.replace(".kt", ".dependency.java") + if (File(javaDependencyPath).exists()) { + fixture.configureByFile(javaDependencyPath) + } + + fixture.configureByFile(testPath) + + val file = fixture.getFile() as JetFile + + codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY = InTextDirectivesUtils.getPrefixedBoolean(file.getText(), "// OPTIMIZE_IMPORTS:") ?: false + codeStyleSettings.PREFER_ALL_UNDER_IMPORTS = InTextDirectivesUtils.getPrefixedBoolean(file.getText(), "// ALL_UNDER_IMPORTS:") ?: preferAllUnderImportsDefault + + CommandProcessor.getInstance().executeCommand(getProject(), { + ApplicationManager.getApplication()!!.runWriteAction { + doTest(file) + } + }, null, null) + + fixture.checkResultByFile(testPath + ".after") + } + finally { + codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY = optimizeImportsBefore + codeStyleSettings.PREFER_ALL_UNDER_IMPORTS = preferAllUnderBefore + } + } + + protected abstract fun doTest(file: JetFile) + + protected open val preferAllUnderImportsDefault: Boolean + get() = true +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/addImport/AbstractAddImportTest.kt b/idea/tests/org/jetbrains/kotlin/addImport/AbstractAddImportTest.kt new file mode 100644 index 00000000000..5bd7f15e395 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/addImport/AbstractAddImportTest.kt @@ -0,0 +1,69 @@ +/* + * 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.addImport + +import org.jetbrains.kotlin.AbstractImportsTest +import org.jetbrains.kotlin.psi.JetFile +import org.jetbrains.kotlin.test.InTextDirectivesUtils +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import org.jetbrains.kotlin.idea.quickfix.ImportInsertHelper +import org.jetbrains.kotlin.psi.JetPsiFactory +import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver +import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver.LookupMode +import org.jetbrains.kotlin.resolve.JetModuleUtil +import org.jetbrains.kotlin.resolve.BindingTraceContext +import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import com.intellij.psi.PsiDocumentManager + +public abstract class AbstractAddImportTest : AbstractImportsTest() { + override fun doTest(file: JetFile) { + var descriptorName = InTextDirectivesUtils.findStringWithPrefixes(file.getText(), "// IMPORT:") + ?: error("No IMPORT directive defined") + + var filter: (DeclarationDescriptor) -> Boolean = { true } + if (descriptorName.startsWith("class:")) { + filter = { it is ClassDescriptor } + descriptorName = descriptorName.substring("class:".length()).trim() + } + + val importDirective = JetPsiFactory(getProject()).createImportDirective(descriptorName) + val moduleDescriptor = file.getResolutionFacade().findModuleDescriptor(file) + val scope = JetModuleUtil.getSubpackagesOfRootScope(moduleDescriptor) + val descriptors = QualifiedExpressionResolver() + .processImportReference(importDirective, scope, scope, null, BindingTraceContext(), LookupMode.EVERYTHING) + .filter(filter) + + when { + descriptors.isEmpty() -> + error("No descriptor $descriptorName found") + + descriptors.size() > 1 -> + error("Multiple descriptors found:\n " + descriptors.map { DescriptorRenderer.FQ_NAMES_IN_TYPES.render(it) }.joinToString("\n ")) + + else -> { + val success = ImportInsertHelper.INSTANCE.importDescriptor(file, descriptors.single()) + if (!success) { + val document = PsiDocumentManager.getInstance(getProject()).getDocument(file) + document.replaceString(0, document.getTextLength(), "Failed to add import") + PsiDocumentManager.getInstance(getProject()).commitAllDocuments() + } + } + } + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/addImport/AddImportTestGenerated.java b/idea/tests/org/jetbrains/kotlin/addImport/AddImportTestGenerated.java new file mode 100644 index 00000000000..d4aa75bd23d --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/addImport/AddImportTestGenerated.java @@ -0,0 +1,206 @@ +/* + * 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.addImport; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.InnerTestClasses; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.JetTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("idea/testData/addImport") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class AddImportTestGenerated extends AbstractAddImportTest { + public void testAllFilesPresentInAddImport() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/addImport"), Pattern.compile("^([^\\.]+)\\.kt$"), true); + } + + @TestMetadata("CannotImportClass1.kt") + public void testCannotImportClass1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/CannotImportClass1.kt"); + doTest(fileName); + } + + @TestMetadata("CannotImportClass2.kt") + public void testCannotImportClass2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/CannotImportClass2.kt"); + doTest(fileName); + } + + @TestMetadata("CannotImportClass3.kt") + public void testCannotImportClass3() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/CannotImportClass3.kt"); + doTest(fileName); + } + + @TestMetadata("ClassAlreadyImported1.kt") + public void testClassAlreadyImported1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ClassAlreadyImported1.kt"); + doTest(fileName); + } + + @TestMetadata("ClassAlreadyImported2.kt") + public void testClassAlreadyImported2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ClassAlreadyImported2.kt"); + doTest(fileName); + } + + @TestMetadata("ConflictingNameAppearsAndHasUsage1.kt") + public void testConflictingNameAppearsAndHasUsage1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsAndHasUsage1.kt"); + doTest(fileName); + } + + @TestMetadata("ConflictingNameAppearsAndHasUsage2.kt") + public void testConflictingNameAppearsAndHasUsage2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsAndHasUsage2.kt"); + doTest(fileName); + } + + @TestMetadata("ConflictingNameAppearsAndHasUsage3.kt") + public void testConflictingNameAppearsAndHasUsage3() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsAndHasUsage3.kt"); + doTest(fileName); + } + + @TestMetadata("ConflictingNameAppearsAndHasUsage4.kt") + public void testConflictingNameAppearsAndHasUsage4() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsAndHasUsage4.kt"); + doTest(fileName); + } + + @TestMetadata("ConflictingNameAppearsAndHasUsage5.kt") + public void testConflictingNameAppearsAndHasUsage5() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsAndHasUsage5.kt"); + doTest(fileName); + } + + @TestMetadata("ConflictingNameAppearsButUsageIsQualified.kt") + public void testConflictingNameAppearsButUsageIsQualified() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsButUsageIsQualified.kt"); + doTest(fileName); + } + + @TestMetadata("ConflictingNameAppearsFalseUsage.kt") + public void testConflictingNameAppearsFalseUsage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsFalseUsage.kt"); + doTest(fileName); + } + + @TestMetadata("ConflictingNameAppearsFalseUsage2.kt") + public void testConflictingNameAppearsFalseUsage2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsFalseUsage2.kt"); + doTest(fileName); + } + + @TestMetadata("ConflictingNameAppearsNoUsage.kt") + public void testConflictingNameAppearsNoUsage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsNoUsage.kt"); + doTest(fileName); + } + + @TestMetadata("ConflictingNameHasExplicitImportAlready.kt") + public void testConflictingNameHasExplicitImportAlready() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameHasExplicitImportAlready.kt"); + doTest(fileName); + } + + @TestMetadata("ConflictingNameNoAllUnderImport.kt") + public void testConflictingNameNoAllUnderImport() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameNoAllUnderImport.kt"); + doTest(fileName); + } + + @TestMetadata("ConflictingNameNoAllUnderImport2.kt") + public void testConflictingNameNoAllUnderImport2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameNoAllUnderImport2.kt"); + doTest(fileName); + } + + @TestMetadata("ConflictingNameNoAllUnderImport3.kt") + public void testConflictingNameNoAllUnderImport3() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameNoAllUnderImport3.kt"); + doTest(fileName); + } + + @TestMetadata("DropExplicitImports.kt") + public void testDropExplicitImports() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/DropExplicitImports.kt"); + doTest(fileName); + } + + @TestMetadata("DropExplicitImports2.kt") + public void testDropExplicitImports2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/DropExplicitImports2.kt"); + doTest(fileName); + } + + @TestMetadata("FunctionAlreadyImported1.kt") + public void testFunctionAlreadyImported1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/FunctionAlreadyImported1.kt"); + doTest(fileName); + } + + @TestMetadata("FunctionAlreadyImported2.kt") + public void testFunctionAlreadyImported2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/FunctionAlreadyImported2.kt"); + doTest(fileName); + } + + @TestMetadata("ImportClassSimple.kt") + public void testImportClassSimple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ImportClassSimple.kt"); + doTest(fileName); + } + + @TestMetadata("ImportPackage.kt") + public void testImportPackage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ImportPackage.kt"); + doTest(fileName); + } + + @TestMetadata("NoNeedToImportStandardClass.kt") + public void testNoNeedToImportStandardClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/NoNeedToImportStandardClass.kt"); + doTest(fileName); + } + + @TestMetadata("PackageAlreadyImported.kt") + public void testPackageAlreadyImported() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/PackageAlreadyImported.kt"); + doTest(fileName); + } + + @TestMetadata("PropertyAlreadyImported1.kt") + public void testPropertyAlreadyImported1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/PropertyAlreadyImported1.kt"); + doTest(fileName); + } + + @TestMetadata("PropertyAlreadyImported2.kt") + public void testPropertyAlreadyImported2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/PropertyAlreadyImported2.kt"); + doTest(fileName); + } +} diff --git a/idea/tests/org/jetbrains/kotlin/shortenRefs/AbstractShortenRefsTest.kt b/idea/tests/org/jetbrains/kotlin/shortenRefs/AbstractShortenRefsTest.kt index 68d6dd02073..07442fd4549 100644 --- a/idea/tests/org/jetbrains/kotlin/shortenRefs/AbstractShortenRefsTest.kt +++ b/idea/tests/org/jetbrains/kotlin/shortenRefs/AbstractShortenRefsTest.kt @@ -17,55 +17,17 @@ package org.jetbrains.kotlin.shortenRefs import org.jetbrains.kotlin.psi.JetFile -import org.jetbrains.kotlin.idea.JetWithJdkAndRuntimeLightProjectDescriptor -import com.intellij.openapi.application.ApplicationManager -import java.io.File -import com.intellij.openapi.command.CommandProcessor import org.jetbrains.kotlin.idea.codeInsight.ShortenReferences -import org.jetbrains.kotlin.idea.JetLightCodeInsightFixtureTestCase -import com.intellij.codeInsight.CodeInsightSettings -import org.jetbrains.kotlin.test.InTextDirectivesUtils -import org.jetbrains.kotlin.test.JetTestUtils +import org.jetbrains.kotlin.AbstractImportsTest -public abstract class AbstractShortenRefsTest : JetLightCodeInsightFixtureTestCase() { - override fun getTestDataPath() = JetTestUtils.getHomeDirectory() - override fun getProjectDescriptor() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE - - protected fun doTest(testPath: String) { - val codeInsightSettings = CodeInsightSettings.getInstance() - val optimizeImportsBefore = codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY - - try { - val fixture = myFixture - val dependencyPath = testPath.replace(".kt", ".dependency.kt") - if (File(dependencyPath).exists()) { - fixture.configureByFile(dependencyPath) - } - val javaDependencyPath = testPath.replace(".kt", ".dependency.java") - if (File(javaDependencyPath).exists()) { - fixture.configureByFile(javaDependencyPath) - } - - fixture.configureByFile(testPath) - - val file = fixture.getFile() as JetFile - val selectionModel = fixture.getEditor().getSelectionModel() - if (!selectionModel.hasSelection()) error("No selection in input file") - - codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY = - InTextDirectivesUtils.isDirectiveDefined(file.getText(), "// OPTIMIZE_IMPORTS") - - CommandProcessor.getInstance().executeCommand(getProject(), { - ApplicationManager.getApplication()!!.runWriteAction { - ShortenReferences.process(file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()) - } - }, null, null) - selectionModel.removeSelection() - - fixture.checkResultByFile(testPath + ".after") - } - finally { - codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY = optimizeImportsBefore - } +public abstract class AbstractShortenRefsTest : AbstractImportsTest() { + override fun doTest(file: JetFile) { + val selectionModel = myFixture.getEditor().getSelectionModel() + if (!selectionModel.hasSelection()) error("No selection in input file") + ShortenReferences.process(file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()) + selectionModel.removeSelection() } + + override val preferAllUnderImportsDefault: Boolean + get() = false }