Autoimport items from kotlinx.android.synthetic on completion
This commit is contained in:
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.getJavaFieldDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getJavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.extension.KotlinIndicesHelperExtension
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.stubindex.*
|
||||
@@ -145,7 +146,18 @@ public class KotlinIndicesHelper(
|
||||
}
|
||||
.flatMap { index.get(it, project, scope).asSequence() }
|
||||
|
||||
return findSuitableExtensions(declarations, receiverTypes, callTypeAndReceiver.callType)
|
||||
val suitableExtensions = findSuitableExtensions(declarations, receiverTypes, callTypeAndReceiver.callType)
|
||||
|
||||
val additionalDescriptors = ArrayList<CallableDescriptor>(0)
|
||||
|
||||
for (extension in KotlinIndicesHelperExtension.getInstances(project)) {
|
||||
extension.appendExtensionCallables(additionalDescriptors, moduleDescriptor, receiverTypes, nameFilter)
|
||||
}
|
||||
|
||||
return if (additionalDescriptors.isNotEmpty())
|
||||
suitableExtensions + additionalDescriptors
|
||||
else
|
||||
suitableExtensions
|
||||
}
|
||||
|
||||
private fun MutableCollection<String>.addTypeNames(type: KotlinType) {
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.core.extension
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
interface KotlinIndicesHelperExtension {
|
||||
companion object : ProjectExtensionDescriptor<KotlinIndicesHelperExtension>(
|
||||
"org.jetbrains.kotlin.kotlinIndicesHelperExtension", KotlinIndicesHelperExtension::class.java)
|
||||
|
||||
fun appendExtensionCallables(
|
||||
consumer: MutableList<in CallableDescriptor>,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
receiverTypes: Collection<KotlinType>,
|
||||
nameFilter: (String) -> Boolean)
|
||||
}
|
||||
@@ -17,5 +17,6 @@
|
||||
<classBuilderFactoryInterceptorExtension implementation="org.jetbrains.kotlin.android.synthetic.codegen.AndroidOnDestroyClassBuilderInterceptorExtension"/>
|
||||
<packageFragmentProviderExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.res.IDEAndroidPackageFragmentProviderExtension"/>
|
||||
<simpleNameReferenceExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidSimpleNameReferenceExtension"/>
|
||||
<kotlinIndicesHelperExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidIndicesHelperExtension"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
<extensionPoint name="simpleNameReferenceExtension"
|
||||
interface="org.jetbrains.kotlin.plugin.references.SimpleNameReferenceExtension"
|
||||
area="IDEA_PROJECT"/>
|
||||
<extensionPoint name="kotlinIndicesHelperExtension"
|
||||
interface="org.jetbrains.kotlin.idea.core.extension.KotlinIndicesHelperExtension"
|
||||
area="IDEA_PROJECT"/>
|
||||
<extensionPoint name="classBuilderFactoryInterceptorExtension"
|
||||
interface="org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension"
|
||||
area="IDEA_PROJECT"/>
|
||||
|
||||
+2
-4
@@ -16,10 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.android.synthetic.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -33,6 +30,7 @@ class PredefinedPackageFragmentDescriptor(
|
||||
fqName: String,
|
||||
module: ModuleDescriptor,
|
||||
private val storageManager: StorageManager,
|
||||
val subpackages: List<PackageFragmentDescriptor> = emptyList(),
|
||||
private val descriptors: (PredefinedPackageFragmentDescriptor) -> Collection<DeclarationDescriptor> = { emptyList() }
|
||||
) : PackageFragmentDescriptorImpl(module, FqName(fqName)) {
|
||||
private val calculatedDescriptors = storageManager.createLazyValue {
|
||||
|
||||
+21
-11
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import java.util.*
|
||||
|
||||
abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProviderExtension {
|
||||
protected abstract fun getLayoutXmlFileManager(project: Project, moduleInfo: ModuleInfo?): AndroidLayoutXmlFileManager?
|
||||
@@ -49,44 +50,51 @@ abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProvider
|
||||
|
||||
val lazyContext = LazySyntheticElementResolveContext(module, storageManager)
|
||||
|
||||
val packageDescriptors = arrayListOf<PackageFragmentDescriptor>()
|
||||
val allPackageDescriptors = arrayListOf<PackageFragmentDescriptor>()
|
||||
val packagesToLookupInCompletion = arrayListOf<PackageFragmentDescriptor>()
|
||||
|
||||
// Packages with synthetic properties
|
||||
for (variantData in moduleData) {
|
||||
for ((layoutName, layouts) in variantData) {
|
||||
fun createPackageFragment(fqName: String, forView: Boolean, isDeprecated: Boolean = false): PackageFragmentDescriptor {
|
||||
fun createPackageFragment(fqName: String, forView: Boolean, isDeprecated: Boolean = false) {
|
||||
val resources = layoutXmlFileManager.extractResources(layouts, module)
|
||||
val packageData = AndroidSyntheticPackageData(moduleData, forView, isDeprecated, resources)
|
||||
return AndroidSyntheticPackageFragmentDescriptor(module, FqName(fqName), packageData, lazyContext, storageManager)
|
||||
val packageDescriptor = AndroidSyntheticPackageFragmentDescriptor(
|
||||
module, FqName(fqName), packageData, lazyContext, storageManager)
|
||||
packagesToLookupInCompletion += packageDescriptor
|
||||
allPackageDescriptors += packageDescriptor
|
||||
}
|
||||
|
||||
val packageFqName = AndroidConst.SYNTHETIC_PACKAGE + '.' + variantData.variant.name + '.' + layoutName
|
||||
|
||||
packageDescriptors += createPackageFragment(packageFqName, false)
|
||||
packageDescriptors += createPackageFragment(packageFqName + ".view", true)
|
||||
createPackageFragment(packageFqName, false)
|
||||
createPackageFragment(packageFqName + ".view", true)
|
||||
|
||||
if (variantData.variant.isMainVariant && !moduleData.any { it.variant.name == layoutName }) {
|
||||
val deprecatedPackageFqName = AndroidConst.SYNTHETIC_PACKAGE + '.' + layoutName
|
||||
packageDescriptors += createPackageFragment(deprecatedPackageFqName, false, isDeprecated = true)
|
||||
packageDescriptors += createPackageFragment(deprecatedPackageFqName + ".view", true, isDeprecated = true)
|
||||
createPackageFragment(deprecatedPackageFqName, false, isDeprecated = true)
|
||||
createPackageFragment(deprecatedPackageFqName + ".view", true, isDeprecated = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Empty middle packages
|
||||
AndroidConst.SYNTHETIC_SUBPACKAGES.forEachUntilLast { s ->
|
||||
packageDescriptors += PredefinedPackageFragmentDescriptor(s, module, storageManager)
|
||||
allPackageDescriptors += PredefinedPackageFragmentDescriptor(s, module, storageManager)
|
||||
}
|
||||
|
||||
for (variantData in moduleData) {
|
||||
val fqName = AndroidConst.SYNTHETIC_PACKAGE + '.' + variantData.variant.name
|
||||
packageDescriptors += PredefinedPackageFragmentDescriptor(fqName, module, storageManager)
|
||||
allPackageDescriptors += PredefinedPackageFragmentDescriptor(fqName, module, storageManager)
|
||||
}
|
||||
|
||||
// Package with clearFindViewByIdCache()
|
||||
AndroidConst.SYNTHETIC_SUBPACKAGES.last().let { s ->
|
||||
packageDescriptors += PredefinedPackageFragmentDescriptor(s, module, storageManager) { descriptor ->
|
||||
val packageDescriptor = PredefinedPackageFragmentDescriptor(s, module, storageManager, packagesToLookupInCompletion) { descriptor ->
|
||||
lazyContext().getWidgetReceivers(false).map { genClearCacheFunction(descriptor, it) }
|
||||
}
|
||||
packagesToLookupInCompletion += packageDescriptor
|
||||
allPackageDescriptors += packageDescriptor
|
||||
}
|
||||
|
||||
val provider = AndroidSyntheticPackageFragmentProvider(allPackageDescriptors)
|
||||
@@ -95,7 +103,9 @@ abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProvider
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidSyntheticPackageFragmentProvider(val packageFragments: Collection<PackageFragmentDescriptor>) : PackageFragmentProvider {
|
||||
class AndroidSyntheticPackageFragmentProvider(
|
||||
val packageFragments: Collection<PackageFragmentDescriptor>
|
||||
) : PackageFragmentProvider {
|
||||
override fun getPackageFragments(fqName: FqName) = packageFragments.filter { it.fqName == fqName }
|
||||
|
||||
override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean) =
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<orderEntry type="library" exported="" scope="PROVIDED" name="android-plugin" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="idea-full" level="project" />
|
||||
<orderEntry type="module" module-name="idea" scope="PROVIDED" />
|
||||
<orderEntry type="module" module-name="idea-core" scope="PROVIDED" />
|
||||
<orderEntry type="module" module-name="compiler-tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="cli" scope="TEST" />
|
||||
<orderEntry type="module" module-name="light-classes" />
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.android.synthetic.idea
|
||||
|
||||
import org.jetbrains.kotlin.android.synthetic.AndroidConst
|
||||
import org.jetbrains.kotlin.android.synthetic.descriptors.AndroidSyntheticPackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.android.synthetic.descriptors.PredefinedPackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.extension.KotlinIndicesHelperExtension
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
|
||||
class AndroidIndicesHelperExtension : KotlinIndicesHelperExtension {
|
||||
|
||||
override fun appendExtensionCallables(
|
||||
consumer: MutableList<in CallableDescriptor>,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
receiverTypes: Collection<KotlinType>,
|
||||
nameFilter: (String) -> Boolean
|
||||
) {
|
||||
for (packageFragment in moduleDescriptor.getPackage(FqName(AndroidConst.SYNTHETIC_PACKAGE)).fragments) {
|
||||
if (packageFragment !is PredefinedPackageFragmentDescriptor) continue
|
||||
|
||||
fun handleScope(scope: MemberScope) {
|
||||
val descriptors = scope.getContributedDescriptors(DescriptorKindFilter.CALLABLES) { nameFilter(it.asString()) }
|
||||
for (descriptor in descriptors) {
|
||||
val receiverType = (descriptor as CallableDescriptor).extensionReceiverParameter?.type ?: continue
|
||||
if (receiverTypes.any { it.isSubtypeOf(receiverType) }) {
|
||||
consumer += descriptor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleScope(packageFragment.getMemberScope())
|
||||
for (fragment in packageFragment.subpackages) {
|
||||
if (fragment is AndroidSyntheticPackageFragmentDescriptor && fragment.packageData.isDeprecated) continue
|
||||
handleScope(fragment.getMemberScope())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</FrameLayout>
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.myapp
|
||||
|
||||
import android.app.Activity
|
||||
|
||||
class MyActivity: Activity() {
|
||||
val button = this.login<caret>
|
||||
}
|
||||
|
||||
// EXIST: login
|
||||
+6
@@ -88,4 +88,10 @@ public class AndroidCompletionTestGenerated extends AbstractAndroidCompletionTes
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-idea-plugin/testData/android/completion/propertiesSimpleView/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("withoutImport")
|
||||
public void testWithoutImport() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-idea-plugin/testData/android/completion/withoutImport/");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user