Fixed ReplaceWith quickfix not working when synthetic extensions are used in the pattern

This commit is contained in:
Valentin Kipyatkov
2015-09-01 15:51:19 +03:00
parent 16650e8f5c
commit 37ed77467f
8 changed files with 46 additions and 22 deletions
@@ -114,7 +114,7 @@ public class ReplInterpreter {
FileScopeProvider.AdditionalScopes scopeProvider = new FileScopeProvider.AdditionalScopes() { FileScopeProvider.AdditionalScopes scopeProvider = new FileScopeProvider.AdditionalScopes() {
@NotNull @NotNull
@Override @Override
public List<JetScope> scopes(@NotNull JetFile file) { public List<JetScope> getScopes() {
return lastLineScope != null ? new SmartList<JetScope>(lastLineScope) : Collections.<JetScope>emptyList(); return lastLineScope != null ? new SmartList<JetScope>(lastLineScope) : Collections.<JetScope>emptyList();
} }
}; };
@@ -16,12 +16,9 @@
package org.jetbrains.kotlin.synthetic package org.jetbrains.kotlin.synthetic
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
class AdditionalScopesWithJavaSyntheticExtensions(storageManager: StorageManager) : FileScopeProvider.AdditionalScopes { class AdditionalScopesWithJavaSyntheticExtensions(storageManager: StorageManager) : FileScopeProvider.AdditionalScopes {
private val scopes = listOf(JavaSyntheticPropertiesScope(storageManager), SamAdapterFunctionsScope(storageManager)) override val scopes = listOf(JavaSyntheticPropertiesScope(storageManager), SamAdapterFunctionsScope(storageManager))
override fun scopes(file: JetFile) = scopes
} }
@@ -29,7 +29,7 @@ public interface FileScopeProvider {
} }
public interface AdditionalScopes { public interface AdditionalScopes {
public fun scopes(file: JetFile): List<JetScope> public val scopes: List<JetScope>
} }
} }
@@ -80,7 +80,7 @@ public class FileScopeProviderImpl(
scopeChain.add(LazyImportScope(packageFragment, allUnderImportResolver, LazyImportScope.FilteringKind.VISIBLE_CLASSES, "All under imports in $debugName (visible classes)")) scopeChain.add(LazyImportScope(packageFragment, allUnderImportResolver, LazyImportScope.FilteringKind.VISIBLE_CLASSES, "All under imports in $debugName (visible classes)"))
scopeChain.add(LazyImportScope(packageFragment, defaultAllUnderImportResolver, LazyImportScope.FilteringKind.VISIBLE_CLASSES, "Default all under imports in $debugName (visible classes)")) scopeChain.add(LazyImportScope(packageFragment, defaultAllUnderImportResolver, LazyImportScope.FilteringKind.VISIBLE_CLASSES, "Default all under imports in $debugName (visible classes)"))
scopeChain.addAll(additionalScopes.flatMap { it.scopes(file) }) scopeChain.addAll(additionalScopes.flatMap { it.scopes })
scopeChain.add(LazyImportScope(packageFragment, allUnderImportResolver, LazyImportScope.FilteringKind.INVISIBLE_CLASSES, "All under imports in $debugName (invisible classes only)")) scopeChain.add(LazyImportScope(packageFragment, allUnderImportResolver, LazyImportScope.FilteringKind.INVISIBLE_CLASSES, "All under imports in $debugName (invisible classes only)"))
scopeChain.add(LazyImportScope(packageFragment, defaultAllUnderImportResolver, LazyImportScope.FilteringKind.INVISIBLE_CLASSES, "Default all under imports in $debugName (invisible classes only)")) scopeChain.add(LazyImportScope(packageFragment, defaultAllUnderImportResolver, LazyImportScope.FilteringKind.INVISIBLE_CLASSES, "Default all under imports in $debugName (invisible classes only)"))
@@ -38,12 +38,12 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider
import org.jetbrains.kotlin.resolve.lazy.descriptors.ClassResolutionScopesSupport import org.jetbrains.kotlin.resolve.lazy.descriptors.ClassResolutionScopesSupport
import org.jetbrains.kotlin.resolve.scopes.* import org.jetbrains.kotlin.resolve.scopes.*
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
import org.jetbrains.kotlin.resolve.scopes.utils.asJetScope import org.jetbrains.kotlin.resolve.scopes.utils.asJetScope
import org.jetbrains.kotlin.resolve.scopes.utils.asLexicalScope import org.jetbrains.kotlin.resolve.scopes.utils.asLexicalScope
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsFileScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
@@ -91,9 +91,9 @@ object ReplaceWithAnnotationAnalyzer {
val explicitlyImportedSymbols = importFqNames.flatMap { resolutionFacade.resolveImportReference(symbolDescriptor.module, it) } val explicitlyImportedSymbols = importFqNames.flatMap { resolutionFacade.resolveImportReference(symbolDescriptor.module, it) }
val symbolScope = getResolutionScope(symbolDescriptor) val additionalScopes = resolutionFacade.getFrontendService(FileScopeProvider.AdditionalScopes::class.java)
val scope = LexicalChainedScope(symbolScope, symbolDescriptor, false, null, "ReplaceWith resolution scope", val scope = getResolutionScope(symbolDescriptor, symbolDescriptor,
ExplicitImportsScope(explicitlyImportedSymbols)) listOf(ExplicitImportsScope(explicitlyImportedSymbols)) + additionalScopes.scopes)
var bindingContext = analyzeInContext(expression, symbolDescriptor, scope, resolutionFacade) var bindingContext = analyzeInContext(expression, symbolDescriptor, scope, resolutionFacade)
@@ -137,7 +137,7 @@ object ReplaceWithAnnotationAnalyzer {
else else
resolvedCall.getDispatchReceiver() resolvedCall.getDispatchReceiver()
if (receiver is ThisReceiver) { if (receiver is ThisReceiver) {
val receiverExpression = receiver.asExpression(symbolScope.asJetScope(), psiFactory) val receiverExpression = receiver.asExpression(scope.asJetScope(), psiFactory)
if (receiverExpression != null) { if (receiverExpression != null) {
receiversToAdd.add(expression to receiverExpression) receiversToAdd.add(expression to receiverExpression)
} }
@@ -170,32 +170,31 @@ object ReplaceWithAnnotationAnalyzer {
return traceContext.bindingContext return traceContext.bindingContext
} }
private fun getResolutionScope(descriptor: DeclarationDescriptor): LexicalScope { private fun getResolutionScope(descriptor: DeclarationDescriptor, ownerDescriptor: DeclarationDescriptor, additionalScopes: Collection<JetScope>): LexicalScope {
return when (descriptor) { return when (descriptor) {
is PackageFragmentDescriptor -> { is PackageFragmentDescriptor -> {
val moduleDescriptor = descriptor.getContainingDeclaration() val moduleDescriptor = descriptor.containingDeclaration
getResolutionScope(moduleDescriptor.getPackage(descriptor.fqName)) getResolutionScope(moduleDescriptor.getPackage(descriptor.fqName), ownerDescriptor, additionalScopes)
} }
is PackageViewDescriptor -> is PackageViewDescriptor ->
descriptor.memberScope.memberScopeAsFileScope() ChainedScope(ownerDescriptor, "ReplaceWith resolution scope", descriptor.memberScope, *additionalScopes.toTypedArray()).asLexicalScope()
is ClassDescriptorWithResolutionScopes -> is ClassDescriptorWithResolutionScopes ->
descriptor.getScopeForMemberDeclarationResolution() descriptor.scopeForMemberDeclarationResolution
is ClassDescriptor -> { is ClassDescriptor -> {
val outerScope = getResolutionScope(descriptor.getContainingDeclaration()) val outerScope = getResolutionScope(descriptor.containingDeclaration, ownerDescriptor, additionalScopes)
ClassResolutionScopesSupport(descriptor, LockBasedStorageManager.NO_LOCKS, { outerScope }) ClassResolutionScopesSupport(descriptor, LockBasedStorageManager.NO_LOCKS, { outerScope }).scopeForMemberDeclarationResolution()
.scopeForMemberDeclarationResolution()
} }
is FunctionDescriptor -> is FunctionDescriptor ->
FunctionDescriptorUtil.getFunctionInnerScope(getResolutionScope(descriptor.getContainingDeclaration()), FunctionDescriptorUtil.getFunctionInnerScope(getResolutionScope(descriptor.containingDeclaration, ownerDescriptor, additionalScopes),
descriptor, RedeclarationHandler.DO_NOTHING) descriptor, RedeclarationHandler.DO_NOTHING)
is PropertyDescriptor -> is PropertyDescriptor ->
JetScopeUtils.getPropertyDeclarationInnerScope(descriptor, JetScopeUtils.getPropertyDeclarationInnerScope(descriptor,
getResolutionScope(descriptor.getContainingDeclaration()), getResolutionScope(descriptor.getContainingDeclaration(), ownerDescriptor, additionalScopes),
RedeclarationHandler.DO_NOTHING) RedeclarationHandler.DO_NOTHING)
is LocalVariableDescriptor -> { is LocalVariableDescriptor -> {
val declaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as JetDeclaration val declaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as JetDeclaration
@@ -0,0 +1,11 @@
// "Replace with 'absolutePath'" "true"
import java.io.File
@deprecated("", ReplaceWith("absolutePath"))
val File.prop: String
get() = absolutePath
fun foo(file: File) {
file.prop<caret>
}
@@ -0,0 +1,11 @@
// "Replace with 'absolutePath'" "true"
import java.io.File
@deprecated("", ReplaceWith("absolutePath"))
val File.prop: String
get() = absolutePath
fun foo(file: File) {
file.absolutePath
}
@@ -3121,6 +3121,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("propertyToSyntheticExtension.kt")
public void testPropertyToSyntheticExtension() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/propertyToSyntheticExtension.kt");
doTest(fileName);
}
@TestMetadata("replaceCallWithArgument.kt") @TestMetadata("replaceCallWithArgument.kt")
public void testReplaceCallWithArgument() throws Exception { public void testReplaceCallWithArgument() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithArgument.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithArgument.kt");