Apply LiftReturnOrAssignmentInspection on idea

This commit is contained in:
Dmitry Gridin
2019-06-14 19:55:17 +07:00
parent 05a132357b
commit 46d8f45c11
9 changed files with 592 additions and 522 deletions
@@ -60,20 +60,20 @@ import java.lang.reflect.Modifier
import java.util.*
class KotlinIndicesHelper(
private val resolutionFacade: ResolutionFacade,
private val scope: GlobalSearchScope,
visibilityFilter: (DeclarationDescriptor) -> Boolean,
private val declarationTranslator: (KtDeclaration) -> KtDeclaration? = { it },
applyExcludeSettings: Boolean = true,
private val filterOutPrivate: Boolean = true,
private val file: KtFile? = null
private val resolutionFacade: ResolutionFacade,
private val scope: GlobalSearchScope,
visibilityFilter: (DeclarationDescriptor) -> Boolean,
private val declarationTranslator: (KtDeclaration) -> KtDeclaration? = { it },
applyExcludeSettings: Boolean = true,
private val filterOutPrivate: Boolean = true,
private val file: KtFile? = null
) {
private val moduleDescriptor = resolutionFacade.moduleDescriptor
private val project = resolutionFacade.project
private val scopeWithoutKotlin = scope.excludeKotlinSources() as GlobalSearchScope
private val descriptorFilter: (DeclarationDescriptor) -> Boolean = filter@ {
private val descriptorFilter: (DeclarationDescriptor) -> Boolean = filter@{
if (resolutionFacade.frontendService<DeprecationResolver>().isHiddenInResolution(it)) return@filter false
if (!visibilityFilter(it)) return@filter false
if (applyExcludeSettings && it.isExcludedFromAutoImport(project, file)) return@filter false
@@ -85,31 +85,32 @@ class KotlinIndicesHelper(
declarations.addTopLevelNonExtensionCallablesByName(KotlinFunctionShortNameIndex.getInstance(), name)
declarations.addTopLevelNonExtensionCallablesByName(KotlinPropertyShortNameIndex.getInstance(), name)
return declarations
.flatMap { it.resolveToDescriptors<CallableDescriptor>() }
.filter { descriptorFilter(it) }
.flatMap { it.resolveToDescriptors<CallableDescriptor>() }
.filter { descriptorFilter(it) }
}
private fun MutableSet<KtNamedDeclaration>.addTopLevelNonExtensionCallablesByName(
index: StringStubIndexExtension<out KtNamedDeclaration>,
name: String
index: StringStubIndexExtension<out KtNamedDeclaration>,
name: String
) {
index.get(name, project, scope).filterTo(this) { it.parent is KtFile && it is KtCallableDeclaration && it.receiverTypeReference == null }
index.get(name, project, scope)
.filterTo(this) { it.parent is KtFile && it is KtCallableDeclaration && it.receiverTypeReference == null }
}
fun getTopLevelExtensionOperatorsByName(name: String): Collection<FunctionDescriptor> {
return KotlinFunctionShortNameIndex.getInstance().get(name, project, scope)
.filter { it.parent is KtFile && it.receiverTypeReference != null && it.hasModifier(KtTokens.OPERATOR_KEYWORD) }
.flatMap { it.resolveToDescriptors<FunctionDescriptor>() }
.filter { descriptorFilter(it) && it.extensionReceiverParameter != null }
.distinct()
.filter { it.parent is KtFile && it.receiverTypeReference != null && it.hasModifier(KtTokens.OPERATOR_KEYWORD) }
.flatMap { it.resolveToDescriptors<FunctionDescriptor>() }
.filter { descriptorFilter(it) && it.extensionReceiverParameter != null }
.distinct()
}
fun getMemberOperatorsByName(name: String): Collection<FunctionDescriptor> {
return KotlinFunctionShortNameIndex.getInstance().get(name, project, scope)
.filter { it.parent is KtClassBody && it.receiverTypeReference == null && it.hasModifier(KtTokens.OPERATOR_KEYWORD) }
.flatMap { it.resolveToDescriptors<FunctionDescriptor>() }
.filter { descriptorFilter(it) && it.extensionReceiverParameter == null }
.distinct()
.filter { it.parent is KtClassBody && it.receiverTypeReference == null && it.hasModifier(KtTokens.OPERATOR_KEYWORD) }
.flatMap { it.resolveToDescriptors<FunctionDescriptor>() }
.filter { descriptorFilter(it) && it.extensionReceiverParameter == null }
.distinct()
}
fun processTopLevelCallables(nameFilter: (String) -> Boolean, processor: (CallableDescriptor) -> Unit) {
@@ -135,21 +136,22 @@ class KotlinIndicesHelper(
}
fun getCallableTopLevelExtensions(
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
position: KtExpression,
bindingContext: BindingContext,
nameFilter: (String) -> Boolean
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
position: KtExpression,
bindingContext: BindingContext,
nameFilter: (String) -> Boolean
): Collection<CallableDescriptor> {
val receiverTypes = callTypeAndReceiver.receiverTypes(bindingContext, position, moduleDescriptor, resolutionFacade, stableSmartCastsOnly = false)
?: return emptyList()
val receiverTypes =
callTypeAndReceiver.receiverTypes(bindingContext, position, moduleDescriptor, resolutionFacade, stableSmartCastsOnly = false)
?: return emptyList()
return getCallableTopLevelExtensions(callTypeAndReceiver, receiverTypes, nameFilter)
}
fun getCallableTopLevelExtensions(
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
receiverTypes: Collection<KotlinType>,
nameFilter: (String) -> Boolean,
declarationFilter: (KtDeclaration) -> Boolean = { true }
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
receiverTypes: Collection<KotlinType>,
nameFilter: (String) -> Boolean,
declarationFilter: (KtDeclaration) -> Boolean = { true }
): Collection<CallableDescriptor> {
if (receiverTypes.isEmpty()) return emptyList()
@@ -159,13 +161,13 @@ class KotlinIndicesHelper(
val index = KotlinTopLevelExtensionsByReceiverTypeIndex.INSTANCE
val declarations = index.getAllKeys(project)
.asSequence()
.filter {
ProgressManager.checkCanceled()
KotlinTopLevelExtensionsByReceiverTypeIndex.receiverTypeNameFromKey(it) in receiverTypeNames
&& nameFilter(KotlinTopLevelExtensionsByReceiverTypeIndex.callableNameFromKey(it))
}
.flatMap { index.get(it, project, scope).asSequence() }.filter(declarationFilter)
.asSequence()
.filter {
ProgressManager.checkCanceled()
KotlinTopLevelExtensionsByReceiverTypeIndex.receiverTypeNameFromKey(it) in receiverTypeNames
&& nameFilter(KotlinTopLevelExtensionsByReceiverTypeIndex.callableNameFromKey(it))
}
.flatMap { index.get(it, project, scope).asSequence() }.filter(declarationFilter)
val suitableExtensions = findSuitableExtensions(declarations, receiverTypes, callTypeAndReceiver.callType)
@@ -234,9 +236,9 @@ class KotlinIndicesHelper(
* Check that function or property with the given qualified name can be resolved in given scope and called on given receiver
*/
private fun findSuitableExtensions(
declarations: Sequence<KtCallableDeclaration>,
receiverTypes: Collection<KotlinType>,
callType: CallType<*>
declarations: Sequence<KtCallableDeclaration>,
receiverTypes: Collection<KotlinType>,
callType: CallType<*>
): Collection<CallableDescriptor> {
val result = LinkedHashSet<CallableDescriptor>()
@@ -253,24 +255,24 @@ class KotlinIndicesHelper(
fun getJvmClassesByName(name: String): Collection<ClassDescriptor> {
return PsiShortNamesCache.getInstance(project).getClassesByName(name, scope)
.filter { it in scope && it.containingFile != null }
.mapNotNull { it.resolveToDescriptor(resolutionFacade) }
.filter(descriptorFilter)
.toSet()
.filter { it in scope && it.containingFile != null }
.mapNotNull { it.resolveToDescriptor(resolutionFacade) }
.filter(descriptorFilter)
.toSet()
}
fun getKotlinEnumsByName(name: String): Collection<DeclarationDescriptor> {
return KotlinClassShortNameIndex.getInstance()[name, project, scope]
.filter { it is KtEnumEntry && it in scope }
.mapNotNull { it.unsafeResolveToDescriptor() }
.filter(descriptorFilter)
.toSet()
.filter { it is KtEnumEntry && it in scope }
.mapNotNull { it.unsafeResolveToDescriptor() }
.filter(descriptorFilter)
.toSet()
}
fun processJvmCallablesByName(
name: String,
filter: (PsiMember) -> Boolean,
processor: (CallableDescriptor) -> Unit
name: String,
filter: (PsiMember) -> Boolean,
processor: (CallableDescriptor) -> Unit
) {
val javaDeclarations = getJavaCallables(name, PsiShortNamesCache.getInstance(project))
val processed = HashSet<CallableDescriptor>()
@@ -295,16 +297,13 @@ class KotlinIndicesHelper(
val shortNamesCache = PsiShortNamesCache.getInstance(project)
if (shortNamesCache is CompositeShortNamesCache) {
try {
fun getMyCachesField(clazz: Class<out PsiShortNamesCache>): Field {
try {
return clazz.getDeclaredField("myCaches")
}
catch (e: NoSuchFieldException) {
// In case the class is proguarded
return clazz.declaredFields.first {
Modifier.isPrivate(it.modifiers) && Modifier.isFinal(it.modifiers) && !Modifier.isStatic(it.modifiers)
&& it.type.isArray && it.type.componentType == PsiShortNamesCache::class.java
}
fun getMyCachesField(clazz: Class<out PsiShortNamesCache>): Field = try {
clazz.getDeclaredField("myCaches")
} catch (e: NoSuchFieldException) {
// In case the class is proguarded
clazz.declaredFields.first {
Modifier.isPrivate(it.modifiers) && Modifier.isFinal(it.modifiers) && !Modifier.isStatic(it.modifiers)
&& it.type.isArray && it.type.componentType == PsiShortNamesCache::class.java
}
}
@@ -315,26 +314,25 @@ class KotlinIndicesHelper(
@Suppress("UNCHECKED_CAST")
return@lazy (myCachesField.get(shortNamesCache) as Array<PsiShortNamesCache>).filter {
it !is KotlinShortNamesCache
&& it::class.java.name != "com.android.tools.idea.databinding.BrShortNamesCache"
&& it::class.java.name != "com.android.tools.idea.databinding.DataBindingComponentShortNamesCache"
&& it::class.java.name != "com.android.tools.idea.databinding.DataBindingShortNamesCache"
&& it::class.java.name != "com.android.tools.idea.databinding.BrShortNamesCache"
&& it::class.java.name != "com.android.tools.idea.databinding.DataBindingComponentShortNamesCache"
&& it::class.java.name != "com.android.tools.idea.databinding.DataBindingShortNamesCache"
}
}
finally {
} finally {
myCachesField.isAccessible = previousIsAccessible
}
}
catch (thr: Throwable) {
} catch (thr: Throwable) {
// Our dirty hack isn't working
}
}
return@lazy null
}
private fun getJavaCallables(name: String, shortNamesCache: PsiShortNamesCache): Sequence<Any> {
filteredShortNamesCaches?.let { caches -> return getCallablesByName(name, scopeWithoutKotlin, caches) }
return shortNamesCache.getFieldsByNameUnfiltered(name, scopeWithoutKotlin).asSequence() +
shortNamesCache.getMethodsByNameUnfiltered(name, scopeWithoutKotlin).asSequence()
shortNamesCache.getMethodsByNameUnfiltered(name, scopeWithoutKotlin).asSequence()
}
private fun getCallablesByName(name: String, scope: GlobalSearchScope, caches: List<PsiShortNamesCache>): Sequence<Any> {
@@ -359,9 +357,9 @@ class KotlinIndicesHelper(
}
fun processKotlinCallablesByName(
name: String,
filter: (KtNamedDeclaration) -> Boolean,
processor: (CallableDescriptor) -> Unit
name: String,
filter: (KtNamedDeclaration) -> Boolean,
processor: (CallableDescriptor) -> Unit
) {
val functions: Sequence<KtCallableDeclaration> = KotlinFunctionShortNameIndex.getInstance().get(name, project, scope).asSequence()
val properties: Sequence<KtNamedDeclaration> = KotlinPropertyShortNameIndex.getInstance().get(name, project, scope).asSequence()
@@ -377,45 +375,46 @@ class KotlinIndicesHelper(
}
fun getKotlinClasses(
nameFilter: (String) -> Boolean,
psiFilter: (KtDeclaration) -> Boolean = { true },
kindFilter: (ClassKind) -> Boolean = { true }): Collection<ClassDescriptor> {
nameFilter: (String) -> Boolean,
psiFilter: (KtDeclaration) -> Boolean = { true },
kindFilter: (ClassKind) -> Boolean = { true }
): Collection<ClassDescriptor> {
val index = KotlinFullClassNameIndex.getInstance()
return index.getAllKeys(project).asSequence()
.filter { fqName ->
ProgressManager.checkCanceled()
nameFilter(fqName.substringAfterLast('.'))
.filter { fqName ->
ProgressManager.checkCanceled()
nameFilter(fqName.substringAfterLast('.'))
}
.toList()
.flatMap { fqName ->
index[fqName, project, scope].flatMap { classOrObject ->
classOrObject.resolveToDescriptorsWithHack(psiFilter).filterIsInstance<ClassDescriptor>()
}
.toList()
.flatMap { fqName ->
index[fqName, project, scope].flatMap { classOrObject ->
classOrObject.resolveToDescriptorsWithHack(psiFilter).filterIsInstance<ClassDescriptor>()
}
}
.filter { kindFilter(it.kind) && descriptorFilter(it) }
}
.filter { kindFilter(it.kind) && descriptorFilter(it) }
}
fun getTopLevelTypeAliases(nameFilter: (String) -> Boolean): Collection<TypeAliasDescriptor> {
val index = KotlinTopLevelTypeAliasFqNameIndex.getInstance()
return index.getAllKeys(project).asSequence()
.filter {
ProgressManager.checkCanceled()
nameFilter(it.substringAfterLast('.'))
}
.toList()
.flatMap { fqName ->
index[fqName, project, scope]
.flatMap { it.resolveToDescriptors<TypeAliasDescriptor>() }
.filter {
ProgressManager.checkCanceled()
nameFilter(it.substringAfterLast('.'))
}
.toList()
.flatMap { fqName ->
index[fqName, project, scope]
.flatMap { it.resolveToDescriptors<TypeAliasDescriptor>() }
}
.filter(descriptorFilter)
}
.filter(descriptorFilter)
}
fun processObjectMembers(
descriptorKindFilter: DescriptorKindFilter,
nameFilter: (String) -> Boolean,
filter: (KtNamedDeclaration, KtObjectDeclaration) -> Boolean,
processor: (DeclarationDescriptor) -> Unit
descriptorKindFilter: DescriptorKindFilter,
nameFilter: (String) -> Boolean,
filter: (KtNamedDeclaration, KtObjectDeclaration) -> Boolean,
processor: (DeclarationDescriptor) -> Unit
) {
fun processIndex(index: StringStubIndexExtension<out KtNamedDeclaration>) {
for (name in index.getAllKeys(project)) {
@@ -445,15 +444,19 @@ class KotlinIndicesHelper(
}
fun processJavaStaticMembers(
descriptorKindFilter: DescriptorKindFilter,
nameFilter: (String) -> Boolean,
processor: (DeclarationDescriptor) -> Unit
descriptorKindFilter: DescriptorKindFilter,
nameFilter: (String) -> Boolean,
processor: (DeclarationDescriptor) -> Unit
) {
val idFilter = IdFilter.getProjectIdFilter(resolutionFacade.project, false)
val shortNamesCache = PsiShortNamesCache.getInstance(project)
val allMethodNames = hashSetOf<String>()
shortNamesCache.processAllMethodNames({ name -> if (nameFilter(name)) allMethodNames.add(name); true }, scopeWithoutKotlin, idFilter)
shortNamesCache.processAllMethodNames(
{ name -> if (nameFilter(name)) allMethodNames.add(name); true },
scopeWithoutKotlin,
idFilter
)
for (name in allMethodNames) {
ProgressManager.checkCanceled()
@@ -469,9 +472,9 @@ class KotlinIndicesHelper(
// SAM-adapter
val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java).forceEnableSamAdapters()
syntheticScopes.collectSyntheticStaticFunctions(container.staticScope, descriptor.name, NoLookupLocation.FROM_IDE)
.filterIsInstance<SamAdapterDescriptor<*>>()
.firstOrNull { it.baseDescriptorForSynthetic.original == descriptor.original }
?.let { processor(it) }
.filterIsInstance<SamAdapterDescriptor<*>>()
.firstOrNull { it.baseDescriptorForSynthetic.original == descriptor.original }
?.let { processor(it) }
}
}
}
@@ -493,15 +496,15 @@ class KotlinIndicesHelper(
}
private inline fun <reified TDescriptor : Any> KtNamedDeclaration.resolveToDescriptors(): Collection<TDescriptor> {
return resolveToDescriptorsWithHack({ true }).filterIsInstance<TDescriptor>()
return resolveToDescriptorsWithHack { true }.filterIsInstance<TDescriptor>()
}
private fun KtNamedDeclaration.resolveToDescriptorsWithHack(
psiFilter: (KtDeclaration) -> Boolean): Collection<DeclarationDescriptor> {
psiFilter: (KtDeclaration) -> Boolean
): Collection<DeclarationDescriptor> {
if (containingKtFile.isCompiled) { //TODO: it's temporary while resolveToDescriptor does not work for compiled declarations
return resolutionFacade.resolveImportReference(moduleDescriptor, fqName!!)
}
else {
} else {
val translatedDeclaration = declarationTranslator(this) ?: return emptyList()
if (!psiFilter(translatedDeclaration)) return emptyList()