mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] Look up for kotlin top level properties/functions to add module dependency
^KTIJ-24921 GitOrigin-RevId: 1418d11d928825ae2574987ac2920370404eb540
This commit is contained in:
committed by
intellij-monorepo-bot
parent
c4b1c60067
commit
a8fdc4ef88
+14
-2
@@ -28,6 +28,7 @@ import com.intellij.psi.impl.light.LightJavaModule;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.PsiShortNamesCache;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.ThreeState;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -87,8 +88,19 @@ public abstract class OrderEntryFix implements IntentionAction, LocalQuickFix {
|
||||
invoke(project, null, descriptor.getPsiElement().getContainingFile());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<@NotNull LocalQuickFix> registerFixes(@NotNull PsiReference reference, @NotNull List<? super IntentionAction> registrar) {
|
||||
return registerFixes(reference, registrar, shortReferenceName -> {
|
||||
Project project = reference.getElement().getProject();
|
||||
return PsiShortNamesCache.getInstance(project).getClassesByName(shortReferenceName, GlobalSearchScope.allScope(project));
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<@NotNull LocalQuickFix> registerFixes(
|
||||
@NotNull PsiReference reference,
|
||||
@NotNull List<? super IntentionAction> registrar,
|
||||
@NotNull Function<? super String, PsiClass[]> shortReferenceNameToClassesLookup
|
||||
) {
|
||||
PsiElement psiElement = reference.getElement();
|
||||
String shortReferenceName = reference.getRangeInElement().substring(psiElement.getText());
|
||||
|
||||
@@ -119,7 +131,7 @@ public abstract class OrderEntryFix implements IntentionAction, LocalQuickFix {
|
||||
return result;
|
||||
}
|
||||
|
||||
PsiClass[] classes = PsiShortNamesCache.getInstance(project).getClassesByName(shortReferenceName, GlobalSearchScope.allScope(project));
|
||||
PsiClass[] classes = shortReferenceNameToClassesLookup.fun(shortReferenceName);
|
||||
List<PsiClass> allowedDependencies = filterAllowedDependencies(psiElement, classes);
|
||||
if (allowedDependencies.isEmpty()) {
|
||||
return result;
|
||||
|
||||
+53
-5
@@ -5,18 +5,27 @@ package org.jetbrains.kotlin.idea.quickfix
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.PsiReferenceBase
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.PsiShortNamesCache
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMember
|
||||
import org.jetbrains.kotlin.asJava.toLightElements
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.RootKindFilter
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.matches
|
||||
import org.jetbrains.kotlin.idea.base.util.runWhenSmart
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference.ShorteningMode
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinFunctionShortNameIndex
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinPropertyShortNameIndex
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelFunctionFqnNameIndex
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelPropertyFqnNameIndex
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
|
||||
@@ -24,8 +33,10 @@ object KotlinAddOrderEntryActionFactory : KotlinIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
|
||||
val simpleExpression = diagnostic.psiElement as? KtSimpleNameExpression ?: return emptyList()
|
||||
if (!RootKindFilter.projectSources.matches(simpleExpression)) return emptyList()
|
||||
val project = simpleExpression.project
|
||||
|
||||
val refElement = simpleExpression.getQualifiedElement()
|
||||
val importDirective = PsiTreeUtil.getParentOfType(simpleExpression, KtImportDirective::class.java)
|
||||
val refElement: KtElement = simpleExpression.getQualifiedElement()
|
||||
|
||||
val reference = object : PsiReferenceBase<KtElement>(refElement) {
|
||||
override fun resolve() = null
|
||||
@@ -40,7 +51,6 @@ object KotlinAddOrderEntryActionFactory : KotlinIntentionActionsFactory() {
|
||||
override fun getCanonicalText() = refElement.text
|
||||
|
||||
override fun bindToElement(element: PsiElement): PsiElement {
|
||||
val project = element.project
|
||||
project.runWhenSmart {
|
||||
project.executeWriteCommand("") {
|
||||
simpleExpression.mainReference.bindToElement(element, ShorteningMode.FORCED_SHORTENING)
|
||||
@@ -50,7 +60,45 @@ object KotlinAddOrderEntryActionFactory : KotlinIntentionActionsFactory() {
|
||||
}
|
||||
}
|
||||
|
||||
val registerFixes = OrderEntryFix.registerFixes(reference, mutableListOf()) { shortName ->
|
||||
val scope = GlobalSearchScope.allScope(project)
|
||||
val classesByName = PsiShortNamesCache.getInstance(project).getClassesByName(shortName, scope)
|
||||
if (classesByName.isNotEmpty()) return@registerFixes classesByName
|
||||
val importedFqName = importDirective?.importedFqName
|
||||
if (importedFqName != null) {
|
||||
PsiShortNamesCache.getInstance(project).getClassesByName(importedFqName.shortName().asString(), scope)
|
||||
.takeUnless { it.isEmpty() }
|
||||
?.let { return@registerFixes it }
|
||||
}
|
||||
|
||||
val declarations =
|
||||
run {
|
||||
if (importedFqName != null && !importDirective.isAllUnder) {
|
||||
KotlinTopLevelPropertyFqnNameIndex[importedFqName.asString(), project, scope]
|
||||
}
|
||||
else {
|
||||
KotlinPropertyShortNameIndex[shortName, project, scope].filter { (it as? KtProperty)?.isTopLevel == true }
|
||||
}
|
||||
}.takeUnless { it.isEmpty() } ?: run {
|
||||
if (importedFqName != null && !importDirective.isAllUnder) {
|
||||
KotlinTopLevelFunctionFqnNameIndex[importedFqName.asString(), project, scope]
|
||||
}
|
||||
else {
|
||||
KotlinFunctionShortNameIndex[shortName, project, scope].filter { (it as? KtNamedFunction)?.isTopLevel == true }
|
||||
}
|
||||
}
|
||||
if (declarations.isNotEmpty()) {
|
||||
val lightClasses = declarations
|
||||
.flatMap { it.toLightElements() }
|
||||
.mapNotNull { (it as? KtLightMember<*>)?.containingClass }
|
||||
.toSet()
|
||||
if (lightClasses.isNotEmpty()) {
|
||||
return@registerFixes lightClasses.toTypedArray()
|
||||
}
|
||||
}
|
||||
PsiClass.EMPTY_ARRAY
|
||||
}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return OrderEntryFix.registerFixes(reference, mutableListOf()) as List<IntentionAction>? ?: emptyList()
|
||||
return registerFixes as List<IntentionAction>? ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
+23
@@ -117,6 +117,29 @@ public abstract class QuickFixMultiModuleTestGenerated extends AbstractQuickFixM
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("testData/multiModuleQuickFix/addDependency")
|
||||
public static class AddDependency extends AbstractQuickFixMultiModuleTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("class")
|
||||
public void testClass() throws Exception {
|
||||
runTest("testData/multiModuleQuickFix/addDependency/class/");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelFunction")
|
||||
public void testTopLevelFunction() throws Exception {
|
||||
runTest("testData/multiModuleQuickFix/addDependency/topLevelFunction/");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelProperty")
|
||||
public void testTopLevelProperty() throws Exception {
|
||||
runTest("testData/multiModuleQuickFix/addDependency/topLevelProperty/");
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("testData/multiModuleQuickFix/addMissingActualMembers")
|
||||
public static class AddMissingActualMembers extends AbstractQuickFixMultiModuleTest {
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
MODULE jvm { platform=[JVM] }
|
||||
MODULE main { platform=[JVM (1.8)] }
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package bar.foo
|
||||
|
||||
class Dependency
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Add dependency on module 'jvm'" "true"
|
||||
// DISABLE-ERRORS
|
||||
package bar
|
||||
|
||||
import bar.<caret>foo.Dependency
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
MODULE jvm { platform=[JVM] }
|
||||
MODULE main { platform=[JVM (1.8)] }
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package bar.foo
|
||||
|
||||
fun fooMethod(): String = "foo"
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Add dependency on module 'jvm'" "true"
|
||||
// DISABLE-ERRORS
|
||||
package bar
|
||||
|
||||
import bar.<caret>foo.fooMethod
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
MODULE jvm { platform=[JVM] }
|
||||
MODULE main { platform=[JVM (1.8)] }
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package bar.foo
|
||||
|
||||
val FOO: String = "foo"
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Add dependency on module 'jvm'" "true"
|
||||
// DISABLE-ERRORS
|
||||
package bar
|
||||
|
||||
import bar.<caret>foo.FOO
|
||||
+2
-2
@@ -278,9 +278,9 @@ private fun parseModuleId(parts: List<String>): ModuleId {
|
||||
}
|
||||
|
||||
private fun parsePlatform(parts: List<String>) =
|
||||
platformNames.entries.single { (names, _) ->
|
||||
platformNames.entries.singleOrNull { (names, _) ->
|
||||
names.any { name -> parts.any { part -> part.equals(name, ignoreCase = true) } }
|
||||
}.value
|
||||
}?.value ?: error("unable to lookup platform among $parts")
|
||||
|
||||
private fun parseModuleName(parts: List<String>) = when {
|
||||
parts.size > 1 -> parts.first()
|
||||
|
||||
Reference in New Issue
Block a user