Support DefaultImpls in light-classes and indices
#KT-4647 Fixed
This commit is contained in:
@@ -31,6 +31,7 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.SLRUCache;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.NamePackage;
|
||||
@@ -127,7 +128,10 @@ public class JavaElementFinder extends PsiElementFinder implements KotlinFinderM
|
||||
}
|
||||
|
||||
// Finds explicitly declared classes and objects, not package classes
|
||||
// Also DefaultImpls classes of interfaces
|
||||
private void findClassesAndObjects(FqName qualifiedName, GlobalSearchScope scope, List<PsiClass> answer) {
|
||||
findInterfaceDefaultImpls(qualifiedName, scope, answer);
|
||||
|
||||
Collection<JetClassOrObject> classOrObjectDeclarations =
|
||||
lightClassGenerationSupport.findClassOrObjectDeclarations(qualifiedName, scope);
|
||||
|
||||
@@ -141,6 +145,22 @@ public class JavaElementFinder extends PsiElementFinder implements KotlinFinderM
|
||||
}
|
||||
}
|
||||
|
||||
private void findInterfaceDefaultImpls(FqName qualifiedName, GlobalSearchScope scope, List<PsiClass> answer) {
|
||||
if (!qualifiedName.shortName().asString().equals(JvmAbi.DEFAULT_IMPLS_CLASS_NAME)) return;
|
||||
|
||||
for (JetClassOrObject classOrObject : lightClassGenerationSupport.findClassOrObjectDeclarations(qualifiedName.parent(), scope)) {
|
||||
if (LightClassUtilsKt.getHasInterfaceDefaultImpls(classOrObject)) {
|
||||
PsiClass interfaceClass = LightClassUtil.INSTANCE$.getPsiClass(classOrObject);
|
||||
if (interfaceClass != null) {
|
||||
PsiClass implsClass = interfaceClass.findInnerClassByName(JvmAbi.DEFAULT_IMPLS_CLASS_NAME, false);
|
||||
if (implsClass != null) {
|
||||
answer.add(implsClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<String> getClassNames(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
|
||||
|
||||
+17
-4
@@ -50,7 +50,7 @@ import javax.swing.Icon
|
||||
|
||||
public open class KotlinLightClassForExplicitDeclaration(
|
||||
manager: PsiManager,
|
||||
private val classFqName: FqName, // FqName of (possibly inner) class
|
||||
protected val classFqName: FqName, // FqName of (possibly inner) class
|
||||
protected val classOrObject: JetClassOrObject)
|
||||
: KotlinWrappingLightClass(manager), JetJavaMirrorMarker, StubBasedPsiElement<KotlinClassOrObjectStub<out JetClassOrObject>> {
|
||||
private var delegate: PsiClass? = null
|
||||
@@ -268,7 +268,7 @@ public open class KotlinLightClassForExplicitDeclaration(
|
||||
|
||||
override fun getModifierList(): PsiModifierList = _modifierList
|
||||
|
||||
private fun computeModifiers(): Array<String> {
|
||||
protected open fun computeModifiers(): Array<String> {
|
||||
val psiModifiers = hashSetOf<String>()
|
||||
|
||||
// PUBLIC, PROTECTED, PRIVATE, ABSTRACT, FINAL
|
||||
@@ -377,7 +377,7 @@ public open class KotlinLightClassForExplicitDeclaration(
|
||||
return getDelegate().innerClasses
|
||||
.map {
|
||||
val declaration = ClsWrapperStubPsiFactory.getOriginalDeclaration(it) as JetClassOrObject?
|
||||
if (declaration != null) create(myManager, declaration) else null
|
||||
if (declaration != null) create(myManager, declaration, it) else null
|
||||
}
|
||||
.filterNotNull()
|
||||
}
|
||||
@@ -397,7 +397,12 @@ public open class KotlinLightClassForExplicitDeclaration(
|
||||
FINAL_KEYWORD to PsiModifier.FINAL)
|
||||
|
||||
|
||||
public fun create(manager: PsiManager, classOrObject: JetClassOrObject): KotlinLightClassForExplicitDeclaration? {
|
||||
@JvmOverloads
|
||||
public fun create(
|
||||
manager: PsiManager,
|
||||
classOrObject: JetClassOrObject,
|
||||
psiClass: PsiClass? = null
|
||||
): KotlinLightClassForExplicitDeclaration? {
|
||||
if (LightClassUtil.belongsToKotlinBuiltIns(classOrObject.getContainingJetFile())) {
|
||||
return null
|
||||
}
|
||||
@@ -407,6 +412,14 @@ public open class KotlinLightClassForExplicitDeclaration(
|
||||
if (classOrObject is JetObjectDeclaration && classOrObject.isObjectLiteral()) {
|
||||
return KotlinLightClassForAnonymousDeclaration(manager, fqName, classOrObject)
|
||||
}
|
||||
|
||||
if (classOrObject.hasInterfaceDefaultImpls) {
|
||||
val implsFqName = fqName.defaultImplsChild()
|
||||
if (implsFqName.asString() == psiClass?.qualifiedName) {
|
||||
return KotlinLightClassForInterfaceDefaultImpls(manager, implsFqName, classOrObject)
|
||||
}
|
||||
}
|
||||
|
||||
return KotlinLightClassForExplicitDeclaration(manager, fqName, classOrObject)
|
||||
}
|
||||
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.asJava
|
||||
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||
|
||||
public open class KotlinLightClassForInterfaceDefaultImpls(
|
||||
manager: PsiManager,
|
||||
classFqName: FqName,
|
||||
classOrObject: JetClassOrObject)
|
||||
: KotlinLightClassForExplicitDeclaration(manager, classFqName, classOrObject){
|
||||
|
||||
override fun copy(): PsiElement {
|
||||
return KotlinLightClassForInterfaceDefaultImpls(manager, classFqName, classOrObject.copy() as JetClassOrObject)
|
||||
}
|
||||
|
||||
override fun getTypeParameterList(): PsiTypeParameterList? = null
|
||||
override fun getTypeParameters(): Array<PsiTypeParameter> = emptyArray()
|
||||
|
||||
override fun computeModifiers(): Array<String> = arrayOf(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL)
|
||||
|
||||
override fun isInterface(): Boolean = false
|
||||
override fun isDeprecated(): Boolean = false
|
||||
override fun isAnnotationType(): Boolean = false
|
||||
override fun isEnum(): Boolean = false
|
||||
override fun hasTypeParameters(): Boolean = false
|
||||
override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean = false
|
||||
|
||||
@Throws(IncorrectOperationException::class)
|
||||
override fun setName(name: String): PsiElement {
|
||||
throw IncorrectOperationException("Impossible to rename DefaultImpls")
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,9 @@
|
||||
package org.jetbrains.kotlin.asJava
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
|
||||
@@ -98,3 +101,10 @@ public val PsiElement.unwrapped: PsiElement?
|
||||
|
||||
public val PsiElement.namedUnwrappedElement: PsiNamedElement?
|
||||
get() = unwrapped?.getNonStrictParentOfType<PsiNamedElement>()
|
||||
|
||||
|
||||
val JetClassOrObject.hasInterfaceDefaultImpls: Boolean
|
||||
get() = this is JetClass && isInterface()
|
||||
|
||||
private val DEFAULT_IMPLS_CLASS_NAME = Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME)
|
||||
fun FqName.defaultImplsChild() = child(DEFAULT_IMPLS_CLASS_NAME)
|
||||
|
||||
@@ -26,11 +26,13 @@ import com.intellij.util.Processor
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.util.containers.HashSet
|
||||
import org.jetbrains.kotlin.asJava.JavaElementFinder
|
||||
import org.jetbrains.kotlin.asJava.defaultImplsChild
|
||||
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
|
||||
import org.jetbrains.kotlin.idea.stubindex.JetClassShortNameIndex
|
||||
import org.jetbrains.kotlin.idea.stubindex.JetFileFacadeShortNameIndex
|
||||
import org.jetbrains.kotlin.idea.stubindex.JetFunctionShortNameIndex
|
||||
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import java.util.*
|
||||
|
||||
@@ -68,10 +70,14 @@ public class JetShortNamesCache(private val project: Project) : PsiShortNamesCac
|
||||
for (fqName in allFqNames) {
|
||||
if (fqName == null) continue
|
||||
|
||||
assert(fqName.shortName().asString() == name) {
|
||||
val isInterfaceDefaultImpl = name == JvmAbi.DEFAULT_IMPLS_CLASS_NAME && fqName.shortName().asString() != name
|
||||
assert(fqName.shortName().asString() == name || isInterfaceDefaultImpl) {
|
||||
"A declaration obtained from index has non-matching name:\nin index: $name\ndeclared: ${fqName.shortName()}($fqName)"
|
||||
}
|
||||
val psiClass = JavaElementFinder.getInstance(project).findClass(fqName.asString(), scope)
|
||||
|
||||
val fqNameToSearch = if (isInterfaceDefaultImpl) fqName.defaultImplsChild() else fqName
|
||||
|
||||
val psiClass = JavaElementFinder.getInstance(project).findClass(fqNameToSearch.asString(), scope)
|
||||
if (psiClass != null) {
|
||||
result.add(psiClass)
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.intellij.util.io.StringRef;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo;
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
@@ -35,7 +36,6 @@ import org.jetbrains.kotlin.util.TypeIndexUtilKt;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class IdeStubIndexService extends StubIndexService {
|
||||
@@ -95,6 +95,10 @@ public class IdeStubIndexService extends StubIndexService {
|
||||
}
|
||||
}
|
||||
|
||||
if (stub.isInterface()) {
|
||||
sink.occurrence(JetClassShortNameIndex.getInstance().getKey(), JvmAbi.DEFAULT_IMPLS_CLASS_NAME);
|
||||
}
|
||||
|
||||
indexSuperNames(stub, sink);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
public class Testing {
|
||||
public static void test() {
|
||||
mockLib.foo.MyInterface.<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: DefaultImpls
|
||||
@@ -0,0 +1,8 @@
|
||||
import mockLib.foo.MyInterface.DefaultImpls;
|
||||
public class Testing {
|
||||
public static void test() {
|
||||
DefaultImpls.<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: foo
|
||||
@@ -0,0 +1,7 @@
|
||||
public class Testing {
|
||||
public static void test() {
|
||||
mockLib.foo.MyInterface.DefaultImpls.<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: foo
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import static mockLib.foo.MyInterface.DefaultImpls.*;
|
||||
public class Testing {
|
||||
public static void test() {
|
||||
f<caret>
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: foo
|
||||
@@ -48,4 +48,8 @@ class F() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface MyInterface {
|
||||
fun foo() = 1
|
||||
}
|
||||
+24
@@ -71,6 +71,30 @@ public class CompiledKotlinInJavaCompletionTestGenerated extends AbstractCompile
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InterfaceDefaultImpl.java")
|
||||
public void testInterfaceDefaultImpl() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/injava/InterfaceDefaultImpl.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InterfaceDefaultImplImportedMembers.java")
|
||||
public void testInterfaceDefaultImplImportedMembers() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/injava/InterfaceDefaultImplImportedMembers.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InterfaceDefaultImplMembers.java")
|
||||
public void testInterfaceDefaultImplMembers() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/injava/InterfaceDefaultImplMembers.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InterfaceDefaultImplStaticImportedMembers.java")
|
||||
public void testInterfaceDefaultImplStaticImportedMembers() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/injava/InterfaceDefaultImplStaticImportedMembers.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("MultiFileFacade.java")
|
||||
public void testMultiFileFacade() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/injava/MultiFileFacade.java");
|
||||
|
||||
+24
@@ -71,6 +71,30 @@ public class KotlinSourceInJavaCompletionTestGenerated extends AbstractKotlinSou
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InterfaceDefaultImpl.java")
|
||||
public void testInterfaceDefaultImpl() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/injava/InterfaceDefaultImpl.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InterfaceDefaultImplImportedMembers.java")
|
||||
public void testInterfaceDefaultImplImportedMembers() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/injava/InterfaceDefaultImplImportedMembers.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InterfaceDefaultImplMembers.java")
|
||||
public void testInterfaceDefaultImplMembers() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/injava/InterfaceDefaultImplMembers.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InterfaceDefaultImplStaticImportedMembers.java")
|
||||
public void testInterfaceDefaultImplStaticImportedMembers() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/injava/InterfaceDefaultImplStaticImportedMembers.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("MultiFileFacade.java")
|
||||
public void testMultiFileFacade() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/injava/MultiFileFacade.java");
|
||||
|
||||
Reference in New Issue
Block a user