Auto-import popup uses new algorithm for import insertion
This commit is contained in:
-1
@@ -402,7 +402,6 @@
|
|||||||
</scope>
|
</scope>
|
||||||
<option name="m_ignoreJavadoc" value="true" />
|
<option name="m_ignoreJavadoc" value="true" />
|
||||||
</inspection_tool>
|
</inspection_tool>
|
||||||
<inspection_tool class="UnnecessaryInterfaceModifier" enabled="true" level="WARNING" enabled_by_default="true" />
|
|
||||||
<inspection_tool class="UnnecessaryLabelOnBreakStatement" enabled="false" level="WARNING" enabled_by_default="false" />
|
<inspection_tool class="UnnecessaryLabelOnBreakStatement" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="UnnecessaryLabelOnContinueStatement" enabled="false" level="WARNING" enabled_by_default="false" />
|
<inspection_tool class="UnnecessaryLabelOnContinueStatement" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="UnnecessaryQualifierForThis" enabled="true" level="WARNING" enabled_by_default="true" />
|
<inspection_tool class="UnnecessaryQualifierForThis" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
|||||||
@@ -34,7 +34,16 @@ import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
|||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.JetFile
|
import org.jetbrains.kotlin.psi.JetFile
|
||||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
||||||
import org.jetbrains.kotlin.resolve.ImportPath
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import com.intellij.openapi.module.ModuleUtilCore
|
||||||
|
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||||
|
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToDeclarationUtil
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.imports.importableFqNameSafe
|
||||||
|
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||||
|
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Automatically adds import directive to the file for resolving reference.
|
* Automatically adds import directive to the file for resolving reference.
|
||||||
@@ -44,32 +53,72 @@ public class JetAddImportAction(
|
|||||||
private val project: Project,
|
private val project: Project,
|
||||||
private val editor: Editor,
|
private val editor: Editor,
|
||||||
private val element: JetSimpleNameExpression,
|
private val element: JetSimpleNameExpression,
|
||||||
imports: Iterable<FqName>
|
candidates: Collection<DeclarationDescriptor>
|
||||||
) : QuestionAction {
|
) : QuestionAction {
|
||||||
private val possibleImports = imports.toList()
|
|
||||||
|
private val module = ModuleUtilCore.findModuleForPsiElement(element)
|
||||||
|
|
||||||
|
private enum class Priority {
|
||||||
|
MODULE
|
||||||
|
PROJECT
|
||||||
|
OTHER
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun detectPriority(descriptor: DeclarationDescriptor): Priority {
|
||||||
|
val declaration = DescriptorToDeclarationUtil.getDeclaration(element.getContainingJetFile(), descriptor)
|
||||||
|
return when {
|
||||||
|
declaration == null -> Priority.OTHER
|
||||||
|
ModuleUtilCore.findModuleForPsiElement(declaration) == module -> Priority.MODULE
|
||||||
|
ProjectRootsUtil.isInProjectSource(declaration) -> Priority.PROJECT
|
||||||
|
else -> Priority.OTHER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class Variant(
|
||||||
|
val fqName: FqName,
|
||||||
|
val descriptors: Collection<DeclarationDescriptor>
|
||||||
|
) {
|
||||||
|
val priority = descriptors.map { detectPriority(it) }.min()!!
|
||||||
|
|
||||||
|
val descriptorToImport: DeclarationDescriptor
|
||||||
|
get() {
|
||||||
|
if (descriptors.size() == 1) return descriptors.single()
|
||||||
|
return descriptors.sortBy {
|
||||||
|
when (it) {
|
||||||
|
is ClassDescriptor -> 0
|
||||||
|
is PackageViewDescriptor -> 1
|
||||||
|
else -> 2
|
||||||
|
}
|
||||||
|
}.first()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val variants = candidates
|
||||||
|
.groupBy { DescriptorUtils.getFqNameSafe(it) }
|
||||||
|
.map { Variant(it.key, it.value) }
|
||||||
|
.sortBy { it.priority }
|
||||||
|
|
||||||
override fun execute(): Boolean {
|
override fun execute(): Boolean {
|
||||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||||
|
|
||||||
if (!element.isValid()) return false
|
if (!element.isValid()) return false
|
||||||
|
|
||||||
// TODO: Validate resolution variants. See AddImportAction.execute()
|
// TODO: Validate resolution variants. See AddImportAction.execute()
|
||||||
|
|
||||||
if (possibleImports.size() == 1 || ApplicationManager.getApplication().isUnitTestMode()) {
|
if (variants.size() == 1 || ApplicationManager.getApplication().isUnitTestMode()) {
|
||||||
addImport(element, project, possibleImports[0])
|
addImport(element, project, variants.first())
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
chooseClassAndImport()
|
chooseCandidateAndImport()
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun getImportSelectionPopup(): BaseListPopupStep<FqName> {
|
protected fun getImportSelectionPopup(): BaseListPopupStep<Variant> {
|
||||||
return object : BaseListPopupStep<FqName>(JetBundle.message("imports.chooser.title"), possibleImports) {
|
return object : BaseListPopupStep<Variant>(JetBundle.message("imports.chooser.title"), variants) {
|
||||||
override fun isAutoSelectionEnabled() = false
|
override fun isAutoSelectionEnabled() = false
|
||||||
|
|
||||||
override fun onChosen(selectedValue: FqName?, finalChoice: Boolean): PopupStep<String>? {
|
override fun onChosen(selectedValue: Variant?, finalChoice: Boolean): PopupStep<String>? {
|
||||||
if (selectedValue == null) return null
|
if (selectedValue == null) return null
|
||||||
|
|
||||||
if (finalChoice) {
|
if (finalChoice) {
|
||||||
@@ -77,7 +126,7 @@ public class JetAddImportAction(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val toExclude = AddImportAction.getAllExcludableStrings(selectedValue.asString())
|
val toExclude = AddImportAction.getAllExcludableStrings(selectedValue.fqName.asString())
|
||||||
|
|
||||||
return object : BaseListPopupStep<String>(null, toExclude) {
|
return object : BaseListPopupStep<String>(null, toExclude) {
|
||||||
override fun getTextFor(value: String): String {
|
override fun getTextFor(value: String): String {
|
||||||
@@ -93,29 +142,38 @@ public class JetAddImportAction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hasSubstep(selectedValue: FqName?) = true
|
override fun hasSubstep(selectedValue: Variant?) = true
|
||||||
|
|
||||||
override fun getTextFor(value: FqName) = value.asString()
|
override fun getTextFor(value: Variant) = value.fqName.asString()
|
||||||
|
|
||||||
// TODO: change icon
|
// TODO: change icon
|
||||||
override fun getIconFor(aValue: FqName) = PlatformIcons.CLASS_ICON
|
override fun getIconFor(aValue: Variant) = PlatformIcons.CLASS_ICON
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun chooseClassAndImport() {
|
private fun chooseCandidateAndImport() {
|
||||||
JBPopupFactory.getInstance().createListPopup(getImportSelectionPopup()).showInBestPositionFor(editor)
|
JBPopupFactory.getInstance().createListPopup(getImportSelectionPopup()).showInBestPositionFor(editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
class object {
|
class object {
|
||||||
|
|
||||||
protected fun addImport(element: PsiElement, project: Project, selectedImport: FqName) {
|
protected fun addImport(element: PsiElement, project: Project, selectedVariant: Variant) {
|
||||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||||
|
|
||||||
CommandProcessor.getInstance().executeCommand(project, object : Runnable {
|
CommandProcessor.getInstance().executeCommand(project, object : Runnable {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
ApplicationManager.getApplication().runWriteAction {
|
ApplicationManager.getApplication().runWriteAction {
|
||||||
val file = element.getContainingFile() as JetFile
|
val file = element.getContainingFile() as JetFile
|
||||||
ImportInsertHelper.getInstance(project).writeImportToFile(ImportPath(selectedImport, false), file)
|
val descriptor = selectedVariant.descriptorToImport
|
||||||
|
// for class or package we use ShortenReferences because we not necessary insert an import but may want to insert partly qualified name
|
||||||
|
if (descriptor is ClassDescriptor || descriptor is PackageViewDescriptor) {
|
||||||
|
val fqName = descriptor.importableFqNameSafe
|
||||||
|
val reference = element.getReference() as JetSimpleNameReference
|
||||||
|
reference.bindToFqName(fqName, JetSimpleNameReference.ShorteningMode.FORCED_SHORTENING)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ImportInsertHelper.getInstance(project).importDescriptor(file, descriptor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, QuickFixBundle.message("add.import"), null)
|
}, QuickFixBundle.message("add.import"), null)
|
||||||
|
|||||||
@@ -43,11 +43,8 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
|||||||
import com.intellij.psi.PsiClass
|
import com.intellij.psi.PsiClass
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.psi.search.searches.ClassInheritorsSearch
|
import com.intellij.psi.search.searches.ClassInheritorsSearch
|
||||||
import org.jetbrains.kotlin.asJava.KotlinLightClass
|
|
||||||
import org.jetbrains.kotlin.types.TypeProjection
|
import org.jetbrains.kotlin.types.TypeProjection
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.JavaResolveExtension
|
|
||||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
|
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||||
import org.jetbrains.kotlin.psi.JetClassOrObject
|
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||||
import org.jetbrains.kotlin.resolve.PossiblyBareType
|
import org.jetbrains.kotlin.resolve.PossiblyBareType
|
||||||
@@ -61,7 +58,7 @@ import org.jetbrains.kotlin.types.TypeProjectionImpl
|
|||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import org.jetbrains.kotlin.psi.JetDeclaration
|
import org.jetbrains.kotlin.psi.JetDeclaration
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.KotlinLightClassForDecompiledDeclaration
|
import org.jetbrains.kotlin.idea.util.psiClassToDescriptor.psiClassToDescriptor
|
||||||
|
|
||||||
class TypeInstantiationItems(
|
class TypeInstantiationItems(
|
||||||
val resolutionFacade: ResolutionFacade,
|
val resolutionFacade: ResolutionFacade,
|
||||||
@@ -285,14 +282,9 @@ class TypeInstantiationItems(
|
|||||||
override fun search(nameFilter: (String) -> Boolean, consumer: (LookupElement) -> Unit) {
|
override fun search(nameFilter: (String) -> Boolean, consumer: (LookupElement) -> Unit) {
|
||||||
val parameters = ClassInheritorsSearch.SearchParameters(psiClass, inheritorSearchScope, true, true, false, nameFilter)
|
val parameters = ClassInheritorsSearch.SearchParameters(psiClass, inheritorSearchScope, true, true, false, nameFilter)
|
||||||
for (inheritor in ClassInheritorsSearch.search(parameters)) {
|
for (inheritor in ClassInheritorsSearch.search(parameters)) {
|
||||||
val descriptor = if (inheritor is KotlinLightClass && inheritor !is KotlinLightClassForDecompiledDeclaration) {
|
val descriptor = resolutionFacade.psiClassToDescriptor(
|
||||||
val origin = inheritor.getOrigin() ?: continue
|
inheritor,
|
||||||
val declaration = toFromOriginalFileMapper.toSyntheticFile(origin) ?: continue
|
{ toFromOriginalFileMapper.toSyntheticFile(it) as JetClassOrObject? }) as? ClassDescriptor ?: continue
|
||||||
resolutionFacade.resolveToDescriptor(declaration)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
resolutionFacade.get(JavaResolveExtension)(inheritor).first.resolveClass(JavaClassImpl(inheritor))
|
|
||||||
} as? ClassDescriptor ?: continue
|
|
||||||
if (!visibilityFilter(descriptor)) continue
|
if (!visibilityFilter(descriptor)) continue
|
||||||
|
|
||||||
val hasTypeArgs = descriptor.getTypeConstructor().getParameters().isNotEmpty()
|
val hasTypeArgs = descriptor.getTypeConstructor().getParameters().isNotEmpty()
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ import org.jetbrains.kotlin.psi.JetPsiUtil
|
|||||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.ImportPath
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.jetbrains.kotlin.idea.JetBundle
|
import org.jetbrains.kotlin.idea.JetBundle
|
||||||
import org.jetbrains.kotlin.idea.actions.JetAddImportAction
|
import org.jetbrains.kotlin.idea.actions.JetAddImportAction
|
||||||
import org.jetbrains.kotlin.idea.caches.JetShortNamesCache
|
import org.jetbrains.kotlin.idea.caches.JetShortNamesCache
|
||||||
@@ -44,32 +42,27 @@ import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
|||||||
import org.jetbrains.kotlin.idea.util.JetPsiHeuristicsUtil
|
import org.jetbrains.kotlin.idea.util.JetPsiHeuristicsUtil
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToDeclarationUtil
|
|
||||||
import com.intellij.openapi.module.ModuleUtilCore
|
|
||||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
|
||||||
import org.jetbrains.kotlin.asJava.unwrapped
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import com.intellij.psi.util.PsiModificationTracker
|
import com.intellij.psi.util.PsiModificationTracker
|
||||||
import org.jetbrains.kotlin.idea.completion.isVisible
|
import org.jetbrains.kotlin.idea.completion.isVisible
|
||||||
import org.jetbrains.kotlin.utils.CachedValueProperty
|
import org.jetbrains.kotlin.utils.CachedValueProperty
|
||||||
|
import org.jetbrains.kotlin.idea.util.psiClassToDescriptor.psiClassToDescriptor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check possibility and perform fix for unresolved references.
|
* Check possibility and perform fix for unresolved references.
|
||||||
*/
|
*/
|
||||||
public class AutoImportFix(element: JetSimpleNameExpression) : JetHintAction<JetSimpleNameExpression>(element), HighPriorityAction {
|
public class AutoImportFix(element: JetSimpleNameExpression) : JetHintAction<JetSimpleNameExpression>(element), HighPriorityAction {
|
||||||
private val module = ModuleUtilCore.findModuleForPsiElement(element)
|
|
||||||
private val modificationCountOnCreate = PsiModificationTracker.SERVICE.getInstance(element.getProject()).getModificationCount()
|
private val modificationCountOnCreate = PsiModificationTracker.SERVICE.getInstance(element.getProject()).getModificationCount()
|
||||||
|
|
||||||
volatile private var anySuggestionFound: Boolean? = null
|
volatile private var anySuggestionFound: Boolean? = null
|
||||||
|
|
||||||
private val suggestions: Collection<FqName> by CachedValueProperty(
|
private val suggestions: Collection<DeclarationDescriptor> by CachedValueProperty(
|
||||||
{
|
{
|
||||||
val fqNames = computeSuggestions(element)
|
val descriptors = computeSuggestions(element)
|
||||||
anySuggestionFound = !fqNames.isEmpty()
|
anySuggestionFound = !descriptors.isEmpty()
|
||||||
fqNames
|
descriptors
|
||||||
},
|
},
|
||||||
{ PsiModificationTracker.SERVICE.getInstance(element.getProject()).getModificationCount() })
|
{ PsiModificationTracker.SERVICE.getInstance(element.getProject()).getModificationCount() })
|
||||||
|
|
||||||
@@ -81,7 +74,7 @@ public class AutoImportFix(element: JetSimpleNameExpression) : JetHintAction<Jet
|
|||||||
if (suggestions.isEmpty()) return false
|
if (suggestions.isEmpty()) return false
|
||||||
|
|
||||||
if (!ApplicationManager.getApplication()!!.isUnitTestMode()) {
|
if (!ApplicationManager.getApplication()!!.isUnitTestMode()) {
|
||||||
val hintText = ShowAutoImportPass.getMessage(suggestions.size() > 1, suggestions.first().asString())
|
val hintText = ShowAutoImportPass.getMessage(suggestions.size() > 1, DescriptorUtils.getFqNameSafe(suggestions.first()).asString())
|
||||||
|
|
||||||
val project = editor.getProject() ?: return false
|
val project = editor.getProject() ?: return false
|
||||||
HintManager.getInstance().showQuestionHint(editor, hintText, element.getTextOffset(), element.getTextRange()!!.getEndOffset(), createAction(project, editor))
|
HintManager.getInstance().showQuestionHint(editor, hintText, element.getTextOffset(), element.getTextRange()!!.getEndOffset(), createAction(project, editor))
|
||||||
@@ -109,7 +102,7 @@ public class AutoImportFix(element: JetSimpleNameExpression) : JetHintAction<Jet
|
|||||||
|
|
||||||
private fun createAction(project: Project, editor: Editor) = JetAddImportAction(project, editor, element, suggestions)
|
private fun createAction(project: Project, editor: Editor) = JetAddImportAction(project, editor, element, suggestions)
|
||||||
|
|
||||||
private fun computeSuggestions(element: JetSimpleNameExpression): Collection<FqName> {
|
private fun computeSuggestions(element: JetSimpleNameExpression): Collection<DeclarationDescriptor> {
|
||||||
if (!element.isValid()) return listOf()
|
if (!element.isValid()) return listOf()
|
||||||
|
|
||||||
val file = element.getContainingFile() as? JetFile ?: return listOf()
|
val file = element.getContainingFile() as? JetFile ?: return listOf()
|
||||||
@@ -143,37 +136,32 @@ public class AutoImportFix(element: JetSimpleNameExpression) : JetHintAction<Jet
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
val result = ArrayList<PrioritizedFqName>()
|
val result = ArrayList<DeclarationDescriptor>()
|
||||||
|
|
||||||
val moduleDescriptor = resolutionFacade.findModuleDescriptor(element)
|
val moduleDescriptor = resolutionFacade.findModuleDescriptor(element)
|
||||||
val indicesHelper = KotlinIndicesHelper(file.getProject(), resolutionFacade, bindingContext, searchScope, moduleDescriptor, ::isVisible)
|
val indicesHelper = KotlinIndicesHelper(file.getProject(), resolutionFacade, bindingContext, searchScope, moduleDescriptor, ::isVisible)
|
||||||
|
|
||||||
if (!element.isImportDirectiveExpression() && !JetPsiUtil.isSelectorInQualified(element)) {
|
if (!element.isImportDirectiveExpression() && !JetPsiUtil.isSelectorInQualified(element)) {
|
||||||
result.addAll(getClassNames(referenceName, file, searchScope))
|
result.addAll(getClasses(referenceName, file, searchScope))
|
||||||
result.addAll(getTopLevelCallables(referenceName, element, indicesHelper))
|
result.addAll(getTopLevelCallables(referenceName, element, indicesHelper))
|
||||||
}
|
}
|
||||||
|
|
||||||
result.addAll(getExtensions(referenceName, element, indicesHelper))
|
result.addAll(getExtensions(referenceName, element, indicesHelper))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
.sortBy { it.priority }
|
|
||||||
.map { it.fqName }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTopLevelCallables(name: String, context: JetExpression, indicesHelper: KotlinIndicesHelper): Collection<PrioritizedFqName>
|
private fun getTopLevelCallables(name: String, context: JetExpression, indicesHelper: KotlinIndicesHelper): Collection<DeclarationDescriptor>
|
||||||
= indicesHelper.getTopLevelCallablesByName(name, context)
|
= indicesHelper.getTopLevelCallablesByName(name, context)
|
||||||
.map { PrioritizedFqName(it) }
|
|
||||||
.toSet()
|
|
||||||
|
|
||||||
private fun getExtensions(name: String, expression: JetSimpleNameExpression, indicesHelper: KotlinIndicesHelper): Collection<PrioritizedFqName>
|
private fun getExtensions(name: String, expression: JetSimpleNameExpression, indicesHelper: KotlinIndicesHelper): Collection<DeclarationDescriptor>
|
||||||
= indicesHelper.getCallableExtensions({ it == name }, expression)
|
= indicesHelper.getCallableExtensions({ it == name }, expression)
|
||||||
.map { PrioritizedFqName(it) }
|
|
||||||
.toSet()
|
|
||||||
|
|
||||||
private fun getClassNames(name: String, file: JetFile, searchScope: GlobalSearchScope): Collection<PrioritizedFqName>
|
private fun getClasses(name: String, file: JetFile, searchScope: GlobalSearchScope): Collection<DeclarationDescriptor>
|
||||||
= getShortNamesCache(file).getClassesByName(name, searchScope)
|
= getShortNamesCache(file).getClassesByName(name, searchScope)
|
||||||
.filter { JetPsiHeuristicsUtil.isAccessible(it, file) }
|
.filter { JetPsiHeuristicsUtil.isAccessible(it, file) }
|
||||||
.map { PrioritizedFqName(it.unwrapped, FqName(it.getQualifiedName()!!)) }
|
.map { element.getResolutionFacade().psiClassToDescriptor(it) }
|
||||||
|
.filterNotNull()
|
||||||
.toSet()
|
.toSet()
|
||||||
|
|
||||||
private fun getShortNamesCache(jetFile: JetFile): PsiShortNamesCache {
|
private fun getShortNamesCache(jetFile: JetFile): PsiShortNamesCache {
|
||||||
@@ -184,31 +172,6 @@ public class AutoImportFix(element: JetSimpleNameExpression) : JetHintAction<Jet
|
|||||||
PsiShortNamesCache.getInstance(jetFile.getProject())
|
PsiShortNamesCache.getInstance(jetFile.getProject())
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum class Priority {
|
|
||||||
MODULE
|
|
||||||
PROJECT
|
|
||||||
OTHER
|
|
||||||
}
|
|
||||||
private data class PrioritizedFqName(val fqName: FqName, val priority: Priority)
|
|
||||||
|
|
||||||
private fun PrioritizedFqName(declaration: PsiElement?, fqName: FqName): PrioritizedFqName {
|
|
||||||
val priority = when {
|
|
||||||
declaration == null -> Priority.OTHER
|
|
||||||
ModuleUtilCore.findModuleForPsiElement(declaration) == module -> Priority.MODULE
|
|
||||||
ProjectRootsUtil.isInProjectSource(declaration) -> Priority.PROJECT
|
|
||||||
else -> Priority.OTHER
|
|
||||||
}
|
|
||||||
|
|
||||||
return PrioritizedFqName(fqName, priority)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun PrioritizedFqName(descriptor: DeclarationDescriptor): PrioritizedFqName {
|
|
||||||
return PrioritizedFqName(
|
|
||||||
DescriptorToDeclarationUtil.getDeclaration(element.getContainingJetFile(), descriptor),
|
|
||||||
DescriptorUtils.getFqNameSafe(descriptor)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class object {
|
class object {
|
||||||
private val ERRORS = setOf(Errors.UNRESOLVED_REFERENCE, Errors.UNRESOLVED_REFERENCE_WRONG_RECEIVER)
|
private val ERRORS = setOf(Errors.UNRESOLVED_REFERENCE, Errors.UNRESOLVED_REFERENCE_WRONG_RECEIVER)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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.util.psiClassToDescriptor
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
|
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||||
|
import org.jetbrains.kotlin.asJava.KotlinLightClass
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.KotlinLightClassForDecompiledDeclaration
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.JavaResolveExtension
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||||
|
|
||||||
|
public fun ResolutionFacade.psiClassToDescriptor(
|
||||||
|
psiClass: PsiClass,
|
||||||
|
declarationTranslator: (JetClassOrObject) -> JetClassOrObject? = { it }
|
||||||
|
): ClassifierDescriptor? {
|
||||||
|
return if (psiClass is KotlinLightClass && psiClass !is KotlinLightClassForDecompiledDeclaration) {
|
||||||
|
val origin = psiClass.getOrigin ()?: return null
|
||||||
|
val declaration = declarationTranslator(origin) ?: return null
|
||||||
|
resolveToDescriptor(declaration)
|
||||||
|
} else {
|
||||||
|
get(JavaResolveExtension)(psiClass).first.resolveClass(JavaClassImpl(psiClass))
|
||||||
|
} as? ClassifierDescriptor
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// "Import" "true"
|
||||||
|
// ERROR: Unresolved reference: Nested
|
||||||
|
|
||||||
|
import test.Test
|
||||||
|
|
||||||
|
val a = <caret>Test.Nested
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// "Import" "true"
|
||||||
|
// ERROR: Unresolved reference: Nested
|
||||||
|
|
||||||
|
val a = <caret>Nested
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class Test {
|
||||||
|
class Nested
|
||||||
|
}
|
||||||
@@ -134,6 +134,12 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
|
|||||||
doTestWithExtraFile(fileName);
|
doTestWithExtraFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nestedClass.before.Main.kt")
|
||||||
|
public void testNestedClass() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/nestedClass.before.Main.kt");
|
||||||
|
doTestWithExtraFile(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("noImportForFunInQualifiedNotFirst.before.Main.kt")
|
@TestMetadata("noImportForFunInQualifiedNotFirst.before.Main.kt")
|
||||||
public void testNoImportForFunInQualifiedNotFirst() throws Exception {
|
public void testNoImportForFunInQualifiedNotFirst() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/noImportForFunInQualifiedNotFirst.before.Main.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/noImportForFunInQualifiedNotFirst.before.Main.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user