KT-9638 Optimize imports: don't create import for static methods from superclasses
#KT-9638 Fixed
This commit is contained in:
@@ -281,16 +281,28 @@ public fun LexicalScope.addImportScope(importScope: JetScope): LexicalScope {
|
|||||||
val fileScope = getFileScope()
|
val fileScope = getFileScope()
|
||||||
val scopeWithAdditionImport =
|
val scopeWithAdditionImport =
|
||||||
LexicalChainedScope(fileScope, fileScope.ownerDescriptor, false, null, "Scope with addition import", importScope)
|
LexicalChainedScope(fileScope, fileScope.ownerDescriptor, false, null, "Scope with addition import", importScope)
|
||||||
return LexicalScopeWrapper(this, scopeWithAdditionImport)
|
return replaceFileScope(scopeWithAdditionImport)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun LexicalScope.replaceFileScope(fileScopeReplace: LexicalScope): LexicalScope {
|
||||||
|
if (this is FileScope) return fileScopeReplace
|
||||||
|
|
||||||
|
return LexicalScopeWrapper(this, fileScopeReplace)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun LexicalScope.withNoFileScope(): LexicalScope = replaceFileScope(MemberScopeToFileScopeAdapter(JetScope.Empty))
|
||||||
|
|
||||||
private class LexicalScopeWrapper(val delegate: LexicalScope, val fileScopeReplace: LexicalScope): LexicalScope by delegate {
|
private class LexicalScopeWrapper(val delegate: LexicalScope, val fileScopeReplace: LexicalScope): LexicalScope by delegate {
|
||||||
override val parent: LexicalScope? by lazy(LazyThreadSafetyMode.NONE) {
|
override val parent: LexicalScope? by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
if (delegate is FileScope) {
|
assert(delegate !is FileScope) { "We should replace FileScope($delegate) to $fileScopeReplace" }
|
||||||
|
val parent = delegate.parent!!
|
||||||
|
|
||||||
|
if (parent is FileScope) {
|
||||||
fileScopeReplace
|
fileScopeReplace
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LexicalScopeWrapper(delegate.parent!!, fileScopeReplace)
|
LexicalScopeWrapper(parent, fileScopeReplace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,12 @@ import com.intellij.lang.ImportOptimizer
|
|||||||
import com.intellij.openapi.progress.ProgressIndicatorProvider
|
import com.intellij.openapi.progress.ProgressIndicatorProvider
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getFileTopLevelScope
|
import org.jetbrains.kotlin.idea.caches.resolve.getFileTopLevelScope
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.core.formatter.JetCodeStyleSettings
|
import org.jetbrains.kotlin.idea.core.formatter.JetCodeStyleSettings
|
||||||
|
import org.jetbrains.kotlin.idea.core.getResolutionScope
|
||||||
import org.jetbrains.kotlin.idea.references.JetReference
|
import org.jetbrains.kotlin.idea.references.JetReference
|
||||||
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
||||||
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||||
@@ -36,14 +35,15 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
|||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
|
||||||
import org.jetbrains.kotlin.renderer.render
|
import org.jetbrains.kotlin.renderer.render
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|
||||||
import org.jetbrains.kotlin.resolve.ImportPath
|
import org.jetbrains.kotlin.resolve.ImportPath
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.utils.asJetScope
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.utils.withNoFileScope
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
public class KotlinImportOptimizer() : ImportOptimizer {
|
public class KotlinImportOptimizer() : ImportOptimizer {
|
||||||
@@ -112,7 +112,7 @@ public class KotlinImportOptimizer() : ImportOptimizer {
|
|||||||
|
|
||||||
if (referencedName != null && importableDescriptor.name != referencedName) continue // resolved via alias
|
if (referencedName != null && importableDescriptor.name != referencedName) continue // resolved via alias
|
||||||
|
|
||||||
if (isAccessibleAsMember(importableDescriptor, element)) continue
|
if (isAccessibleAsMember(importableDescriptor, element, bindingContext)) continue
|
||||||
|
|
||||||
_descriptors.add(importableDescriptor)
|
_descriptors.add(importableDescriptor)
|
||||||
}
|
}
|
||||||
@@ -121,15 +121,29 @@ public class KotlinImportOptimizer() : ImportOptimizer {
|
|||||||
super.visitJetElement(element)
|
super.visitJetElement(element)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isAccessibleAsMember(target: DeclarationDescriptor, place: JetElement): Boolean {
|
private fun isAccessibleAsMember(target: DeclarationDescriptor, place: JetElement, bindingContext: BindingContext): Boolean {
|
||||||
val container = target.containingDeclaration
|
if (target.containingDeclaration !is ClassDescriptor) return false
|
||||||
if (container !is ClassDescriptor) return false
|
|
||||||
val scope = if (DescriptorUtils.isCompanionObject(container))
|
fun isInScope(scope: JetScope): Boolean {
|
||||||
container.getContainingDeclaration() as? ClassDescriptor ?: return false
|
return when (target) {
|
||||||
else
|
is FunctionDescriptor ->
|
||||||
container
|
scope.getFunctions(target.name, NoLookupLocation.FROM_IDE).contains(target)
|
||||||
val classBody = (DescriptorToSourceUtils.getSourceFromDescriptor(scope) as? JetClassOrObject)?.getBody()
|
|
||||||
return classBody != null && classBody.containingFile == file && classBody.isAncestor(place)
|
is PropertyDescriptor ->
|
||||||
|
scope.getProperties(target.name, NoLookupLocation.FROM_IDE).contains(target)
|
||||||
|
|
||||||
|
is ClassDescriptor ->
|
||||||
|
scope.getClassifier(target.name, NoLookupLocation.FROM_IDE) == target
|
||||||
|
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val resolutionScope = place.getResolutionScope(bindingContext, place.getResolutionFacade())
|
||||||
|
val noImportsScope = resolutionScope.withNoFileScope()
|
||||||
|
|
||||||
|
return isInScope(noImportsScope.asJetScope())
|
||||||
|
|| resolutionScope.getImplicitReceiversHierarchy().any { isInScope(it.type.memberScope) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
class B {
|
||||||
|
companion object {
|
||||||
|
fun foo(){}
|
||||||
|
|
||||||
|
val property = 0
|
||||||
|
|
||||||
|
class Nested
|
||||||
|
}
|
||||||
|
|
||||||
|
fun f(): Nested {
|
||||||
|
foo()
|
||||||
|
property
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
class B {
|
||||||
|
companion object {
|
||||||
|
fun foo(){}
|
||||||
|
|
||||||
|
val property = 0
|
||||||
|
|
||||||
|
class Nested
|
||||||
|
}
|
||||||
|
|
||||||
|
fun f(): Nested {
|
||||||
|
foo()
|
||||||
|
property
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import A.Companion.run
|
||||||
|
|
||||||
|
interface Action<T> {
|
||||||
|
fun run(t: T)
|
||||||
|
}
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
companion object : Action<String> {
|
||||||
|
override fun run(t: String) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A() {
|
||||||
|
fun foo() {
|
||||||
|
run("")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
interface Action<T> {
|
||||||
|
fun run(t: T)
|
||||||
|
}
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
companion object : Action<String> {
|
||||||
|
override fun run(t: String) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A() {
|
||||||
|
fun foo() {
|
||||||
|
run("")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
class B : Thread() {
|
||||||
|
init {
|
||||||
|
currentThread()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class B : Thread() {
|
||||||
|
init {
|
||||||
|
currentThread()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -107,6 +107,18 @@ public class OptimizeImportsTestGenerated extends AbstractOptimizeImportsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("FromCompanionObject.kt")
|
||||||
|
public void testFromCompanionObject() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/FromCompanionObject.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("FromCompanionObjectGeneric.kt")
|
||||||
|
public void testFromCompanionObjectGeneric() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/FromCompanionObjectGeneric.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("InvokeFunction.kt")
|
@TestMetadata("InvokeFunction.kt")
|
||||||
public void testInvokeFunction() throws Exception {
|
public void testInvokeFunction() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/InvokeFunction.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/InvokeFunction.kt");
|
||||||
@@ -191,6 +203,12 @@ public class OptimizeImportsTestGenerated extends AbstractOptimizeImportsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("StaticMethodFromSuper.kt")
|
||||||
|
public void testStaticMethodFromSuper() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/StaticMethodFromSuper.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("UnusedImports.kt")
|
@TestMetadata("UnusedImports.kt")
|
||||||
public void testUnusedImports() throws Exception {
|
public void testUnusedImports() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/UnusedImports.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/UnusedImports.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user