Changes on review of pull request
This commit is contained in:
@@ -16,7 +16,6 @@ remove.unnecessary.non.null.assertion=Remove unnecessary non-null assertion (!!)
|
|||||||
change.to.backing.field=Change reference to backing field
|
change.to.backing.field=Change reference to backing field
|
||||||
implement.members=Implement members
|
implement.members=Implement members
|
||||||
import.fix=Import
|
import.fix=Import
|
||||||
import.static.fix=Static import
|
|
||||||
imports.chooser.title=Imports
|
imports.chooser.title=Imports
|
||||||
rename.kotlin.package.class.error=Can't rename Kotlin package facade class
|
rename.kotlin.package.class.error=Can't rename Kotlin package facade class
|
||||||
add.semicolon.after.invocation=Add semicolon after invocation of ''{0}''
|
add.semicolon.after.invocation=Add semicolon after invocation of ''{0}''
|
||||||
|
|||||||
@@ -205,32 +205,29 @@ class KotlinIndicesHelper(
|
|||||||
.toSet()
|
.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getJvmCallablesByName(name: String): Collection<CallableDescriptor> {
|
||||||
fun getJvmStatics(name: String): Collection<DeclarationDescriptor> {
|
val javaDeclarations = PsiShortNamesCache.getInstance(project).getFieldsByName(name, scope).asSequence() +
|
||||||
return sequenceOf(PsiShortNamesCache.getInstance(project).getFieldsByName(name, scope),
|
PsiShortNamesCache.getInstance(project).getMethodsByName(name, scope).asSequence()
|
||||||
PsiShortNamesCache.getInstance(project).getMethodsByName(name, scope))
|
return javaDeclarations
|
||||||
.flatMap { it.asSequence() }
|
.mapNotNull { (it as PsiMember).getJavaMemberDescriptor(resolutionFacade) as? CallableDescriptor }
|
||||||
.mapNotNull { (it as PsiMember).getJavaMemberDescriptor(resolutionFacade) }
|
|
||||||
.filter(descriptorFilter)
|
.filter(descriptorFilter)
|
||||||
.toSet()
|
.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getKotlinStatics(name: String): Collection<DeclarationDescriptor> {
|
fun getKotlinCallablesByName(name: String): Collection<CallableDescriptor> {
|
||||||
return sequenceOf(KotlinFunctionShortNameIndex.getInstance().get(name, project, scope),
|
val functions = KotlinFunctionShortNameIndex.getInstance().get(name, project, scope)
|
||||||
KotlinPropertyShortNameIndex.getInstance().get(name, project, scope))
|
.asSequence()
|
||||||
.flatMap { it.asSequence() }
|
.map { it.descriptor as? CallableDescriptor }
|
||||||
.mapNotNull {
|
val properties = KotlinPropertyShortNameIndex.getInstance().get(name, project, scope)
|
||||||
when (it) {
|
.asSequence()
|
||||||
is KtNamedFunction -> it.descriptor
|
.map { it.descriptor as? CallableDescriptor }
|
||||||
is KtProperty -> it.descriptor
|
|
||||||
else -> null
|
return (functions + properties)
|
||||||
}
|
.filterNotNull()
|
||||||
}.filterNot { it.importableFqName == null }
|
|
||||||
.filter(descriptorFilter)
|
.filter(descriptorFilter)
|
||||||
.toSet()
|
.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun getKotlinClasses(nameFilter: (String) -> Boolean, kindFilter: (ClassKind) -> Boolean): Collection<ClassDescriptor> {
|
fun getKotlinClasses(nameFilter: (String) -> Boolean, kindFilter: (ClassKind) -> Boolean): Collection<ClassDescriptor> {
|
||||||
return KotlinFullClassNameIndex.getInstance().getAllKeys(project).asSequence()
|
return KotlinFullClassNameIndex.getInstance().getAllKeys(project).asSequence()
|
||||||
.map { FqName(it) }
|
.map { FqName(it) }
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.intellij.psi.PsiFile
|
|||||||
import com.intellij.psi.util.PsiModificationTracker
|
import com.intellij.psi.util.PsiModificationTracker
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
||||||
|
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
@@ -42,6 +43,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolveScope
|
|||||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||||
import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper
|
import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper
|
||||||
import org.jetbrains.kotlin.idea.core.isVisible
|
import org.jetbrains.kotlin.idea.core.isVisible
|
||||||
|
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
|
||||||
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
||||||
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
@@ -147,8 +149,7 @@ internal abstract class AutoImportFixBase<T : KtExpression>(expression: T) :
|
|||||||
|
|
||||||
val indicesHelper = KotlinIndicesHelper(resolutionFacade, searchScope, ::isVisible)
|
val indicesHelper = KotlinIndicesHelper(resolutionFacade, searchScope, ::isVisible)
|
||||||
|
|
||||||
val result = fillCandidates(callTypeAndReceiver, file, bindingContext,
|
val result = fillCandidates(nameStr, callTypeAndReceiver, bindingContext, indicesHelper)
|
||||||
indicesHelper, nameStr, filterByCallType = { callTypeAndReceiver.callType.descriptorKindFilter.accepts(it) })
|
|
||||||
|
|
||||||
return if (result.size > 1)
|
return if (result.size > 1)
|
||||||
reduceCandidatesBasedOnDependencyRuleViolation(result, file)
|
reduceCandidatesBasedOnDependencyRuleViolation(result, file)
|
||||||
@@ -156,9 +157,12 @@ internal abstract class AutoImportFixBase<T : KtExpression>(expression: T) :
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun fillCandidates(callTypeAndReceiver: CallTypeAndReceiver<*, *>, file: KtFile,
|
abstract fun fillCandidates(
|
||||||
bindingContext: BindingContext, indicesHelper: KotlinIndicesHelper,
|
name: String,
|
||||||
nameStr: String, filterByCallType: (descriptor: DeclarationDescriptor) -> (Boolean)): List<DeclarationDescriptor>
|
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||||
|
bindingContext: BindingContext,
|
||||||
|
indicesHelper: KotlinIndicesHelper
|
||||||
|
): List<DeclarationDescriptor>
|
||||||
|
|
||||||
private fun reduceCandidatesBasedOnDependencyRuleViolation(
|
private fun reduceCandidatesBasedOnDependencyRuleViolation(
|
||||||
candidates: Collection<DeclarationDescriptor>, file: PsiFile): Collection<DeclarationDescriptor> {
|
candidates: Collection<DeclarationDescriptor>, file: PsiFile): Collection<DeclarationDescriptor> {
|
||||||
@@ -172,25 +176,32 @@ internal abstract class AutoImportFixBase<T : KtExpression>(expression: T) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class AutoImportFixBaseDynamicContext<T : KtExpression>(expression: T) : AutoImportFixBase<T>(expression) {
|
internal abstract class AutoImportFixBaseDynamicContext<T : KtExpression>(expression: T) : AutoImportFixBase<T>(expression) {
|
||||||
override fun fillCandidates(callTypeAndReceiver: CallTypeAndReceiver<*, *>, file: KtFile, bindingContext: BindingContext, indicesHelper: KotlinIndicesHelper, nameStr: String, filterByCallType: (DeclarationDescriptor) -> Boolean): List<DeclarationDescriptor> {
|
override fun fillCandidates(
|
||||||
|
name: String,
|
||||||
|
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||||
|
bindingContext: BindingContext,
|
||||||
|
indicesHelper: KotlinIndicesHelper
|
||||||
|
): List<DeclarationDescriptor> {
|
||||||
val result = ArrayList<DeclarationDescriptor>()
|
val result = ArrayList<DeclarationDescriptor>()
|
||||||
|
|
||||||
val expression = element
|
val expression = element
|
||||||
|
|
||||||
if (expression is KtSimpleNameExpression) {
|
if (expression is KtSimpleNameExpression) {
|
||||||
if (!expression.isImportDirectiveExpression() && !KtPsiUtil.isSelectorInQualified(expression)) {
|
if (!expression.isImportDirectiveExpression() && !KtPsiUtil.isSelectorInQualified(expression)) {
|
||||||
if (ProjectStructureUtil.isJsKotlinModule(file)) {
|
val filterByCallType = { descriptor: DeclarationDescriptor -> callTypeAndReceiver.callType.descriptorKindFilter.accepts(descriptor) }
|
||||||
indicesHelper.getKotlinClasses({ it == nameStr }, { true }).filterTo(result, filterByCallType)
|
|
||||||
|
if (ProjectStructureUtil.isJsKotlinModule(expression.getContainingKtFile())) {
|
||||||
|
indicesHelper.getKotlinClasses({ it == name }, { true }).filterTo(result, filterByCallType)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
indicesHelper.getJvmClassesByName(nameStr).filterTo(result, filterByCallType)
|
indicesHelper.getJvmClassesByName(name).filterTo(result, filterByCallType)
|
||||||
}
|
}
|
||||||
|
|
||||||
indicesHelper.getTopLevelCallablesByName(nameStr).filterTo(result, filterByCallType)
|
indicesHelper.getTopLevelCallablesByName(name).filterTo(result, filterByCallType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.addAll(indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, expression, bindingContext) { it == nameStr })
|
result.addAll(indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, expression, bindingContext) { it == name })
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,16 +377,28 @@ internal class MissingComponentsAutoImportFix(element: KtExpression, override va
|
|||||||
|
|
||||||
internal class AutoImportStaticFix(expression: KtSimpleNameExpression) : AutoImportFixBase<KtSimpleNameExpression>(expression) {
|
internal class AutoImportStaticFix(expression: KtSimpleNameExpression) : AutoImportFixBase<KtSimpleNameExpression>(expression) {
|
||||||
|
|
||||||
override fun getText() = KotlinBundle.message("import.static.fix")
|
override fun getText() = "Static import"
|
||||||
|
|
||||||
override fun fillCandidates(callTypeAndReceiver: CallTypeAndReceiver<*, *>, file: KtFile, bindingContext: BindingContext, indicesHelper: KotlinIndicesHelper, nameStr: String, filterByCallType: (DeclarationDescriptor) -> Boolean): List<DeclarationDescriptor> {
|
override fun fillCandidates(
|
||||||
|
name: String,
|
||||||
|
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
|
||||||
|
bindingContext: BindingContext,
|
||||||
|
indicesHelper: KotlinIndicesHelper
|
||||||
|
): List<DeclarationDescriptor> {
|
||||||
val result = ArrayList<DeclarationDescriptor>()
|
val result = ArrayList<DeclarationDescriptor>()
|
||||||
val expression = element
|
val expression = element
|
||||||
if (expression is KtSimpleNameExpression) {
|
if (expression is KtSimpleNameExpression) {
|
||||||
if (!expression.isImportDirectiveExpression() && !KtPsiUtil.isSelectorInQualified(expression)) {
|
if (!expression.isImportDirectiveExpression() && !KtPsiUtil.isSelectorInQualified(expression)) {
|
||||||
indicesHelper.getKotlinStatics(nameStr).filterTo(result, filterByCallType)
|
val filterByCallType = { descriptor: DeclarationDescriptor -> callTypeAndReceiver.callType.descriptorKindFilter.accepts(descriptor) }
|
||||||
if (!(ProjectStructureUtil.isJsKotlinModule(file))) {
|
|
||||||
indicesHelper.getJvmStatics(nameStr).filterTo(result, filterByCallType)
|
indicesHelper.getKotlinCallablesByName(name)
|
||||||
|
.filter { it.canBeReferencedViaImport() && it.containingDeclaration !is PackageFragmentDescriptor }
|
||||||
|
.filterTo(result, filterByCallType)
|
||||||
|
|
||||||
|
if (!ProjectStructureUtil.isJsKotlinModule(expression.getContainingKtFile())) {
|
||||||
|
indicesHelper.getJvmCallablesByName(name)
|
||||||
|
.filter { it.canBeReferencedViaImport() }
|
||||||
|
.filterTo(result, filterByCallType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -385,28 +408,18 @@ internal class AutoImportStaticFix(expression: KtSimpleNameExpression) : AutoImp
|
|||||||
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.detect(element)
|
override fun getCallTypeAndReceiver() = CallTypeAndReceiver.detect(element)
|
||||||
|
|
||||||
override val importNames: Collection<Name> = run {
|
override val importNames: Collection<Name> = run {
|
||||||
if (element.getIdentifier() == null) {
|
if (element.getIdentifier() != null) {
|
||||||
val conventionName = KtPsiUtil.getConventionName(element)
|
val name = element.getReferencedName()
|
||||||
if (conventionName != null) {
|
if (Name.isValidIdentifier(name)) {
|
||||||
if (element is KtOperationReferenceExpression) {
|
Name.identifier(name).singletonList()
|
||||||
val elementType = element.firstChild.node.elementType
|
}
|
||||||
if (elementType in OperatorConventions.ASSIGNMENT_OPERATIONS) {
|
else {
|
||||||
val counterpart = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS[elementType]
|
emptyList<Name>()
|
||||||
val counterpartName = OperatorConventions.BINARY_OPERATION_NAMES[counterpart]
|
|
||||||
if (counterpartName != null) {
|
|
||||||
return@run listOf(conventionName, counterpartName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return@run conventionName.singletonOrEmptyList()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Name.isValidIdentifier(element.getReferencedName())) {
|
else {
|
||||||
return@run Name.identifier(element.getReferencedName()).singletonOrEmptyList()
|
emptyList<Name>()
|
||||||
}
|
}
|
||||||
|
|
||||||
emptyList<Name>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSupportedErrors(): Collection<DiagnosticFactory<*>> = ERRORS
|
override fun getSupportedErrors(): Collection<DiagnosticFactory<*>> = ERRORS
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// FILE: main.before.kt
|
||||||
|
// "Static import" "false"
|
||||||
|
// ERROR: Unresolved reference: foobar
|
||||||
|
// ACTION: Create function 'foobar'
|
||||||
|
// ACTION: Import
|
||||||
|
// ACTION: Rename reference
|
||||||
|
|
||||||
|
//KT-9009
|
||||||
|
|
||||||
|
|
||||||
|
fun f() {
|
||||||
|
foobar<caret>()
|
||||||
|
}
|
||||||
|
|
||||||
|
//FILE: dependency.before.kt
|
||||||
|
package bar
|
||||||
|
|
||||||
|
fun foobar() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//FILE: main.after.kt
|
||||||
|
// "Static import" "false"
|
||||||
|
// ERROR: Unresolved reference: foobar
|
||||||
|
// ACTION: Create function 'foobar'
|
||||||
|
// ACTION: Rename reference
|
||||||
|
|
||||||
|
//KT-9009
|
||||||
|
|
||||||
|
|
||||||
|
fun f() {
|
||||||
|
foobar<caret>()
|
||||||
|
}
|
||||||
@@ -367,15 +367,19 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
|
|||||||
|
|
||||||
@TestMetadata("noStaticImportForJavaNonStaticField.test")
|
@TestMetadata("noStaticImportForJavaNonStaticField.test")
|
||||||
public void testNoStaticImportForJavaNonStaticField() throws Exception {
|
public void testNoStaticImportForJavaNonStaticField() throws Exception {
|
||||||
String fileName =
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/noStaticImportForJavaNonStaticField.test");
|
||||||
KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/noStaticImportForJavaNonStaticField.test");
|
|
||||||
doTestWithExtraFile(fileName);
|
doTestWithExtraFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("noStaticImportForJavaNonStaticMethod.test")
|
@TestMetadata("noStaticImportForJavaNonStaticMethod.test")
|
||||||
public void testNoStaticImportForJavaNonStaticMethod() throws Exception {
|
public void testNoStaticImportForJavaNonStaticMethod() throws Exception {
|
||||||
String fileName =
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/noStaticImportForJavaNonStaticMethod.test");
|
||||||
KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/noStaticImportForJavaNonStaticMethod.test");
|
doTestWithExtraFile(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("noStaticImportForTopLevelFunction.test")
|
||||||
|
public void testNoStaticImportForTopLevelFunction() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/noStaticImportForTopLevelFunction.test");
|
||||||
doTestWithExtraFile(fileName);
|
doTestWithExtraFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user