Fix Sample reference to resolve cross-module packages correctly
Now @sample links to FqName in IDE will be resolved correctly Cause now we resolve packages over all modules in project #KT-14710 fixed
This commit is contained in:
+1
-1
@@ -114,7 +114,7 @@ fun createModuleResolverProvider(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun collectAllModuleInfosFromIdeaModel(project: Project): List<IdeaModuleInfo> {
|
fun collectAllModuleInfosFromIdeaModel(project: Project): List<IdeaModuleInfo> {
|
||||||
val ideaModules = ModuleManager.getInstance(project).modules.toList()
|
val ideaModules = ModuleManager.getInstance(project).modules.toList()
|
||||||
val modulesSourcesInfos = ideaModules.flatMap { listOf(it.productionSourceInfo(), it.testSourceInfo()) }
|
val modulesSourcesInfos = ideaModules.flatMap { listOf(it.productionSourceInfo(), it.testSourceInfo()) }
|
||||||
|
|
||||||
|
|||||||
+19
-3
@@ -19,8 +19,11 @@ package org.jetbrains.kotlin.idea.kdoc
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.collectAllModuleInfosFromIdeaModel
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.idea.stubindex.KotlinClassShortNameIndex
|
||||||
import org.jetbrains.kotlin.idea.stubindex.KotlinFunctionShortNameIndex
|
import org.jetbrains.kotlin.idea.stubindex.KotlinFunctionShortNameIndex
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -29,16 +32,29 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
|||||||
class IdeSampleResolutionService(val project: Project) : SampleResolutionService {
|
class IdeSampleResolutionService(val project: Project) : SampleResolutionService {
|
||||||
|
|
||||||
override fun resolveSample(context: BindingContext, fromDescriptor: DeclarationDescriptor, resolutionFacade: ResolutionFacade, qualifiedName: List<String>): Collection<DeclarationDescriptor> {
|
override fun resolveSample(context: BindingContext, fromDescriptor: DeclarationDescriptor, resolutionFacade: ResolutionFacade, qualifiedName: List<String>): Collection<DeclarationDescriptor> {
|
||||||
|
|
||||||
val allScope = GlobalSearchScope.projectScope(project)
|
val allScope = GlobalSearchScope.projectScope(project)
|
||||||
|
|
||||||
val shortName = qualifiedName.lastOrNull() ?: return emptyList()
|
val shortName = qualifiedName.lastOrNull() ?: return emptyList()
|
||||||
val functions = KotlinFunctionShortNameIndex.getInstance().get(shortName, project, allScope)
|
|
||||||
val targetFqName = FqName.fromSegments(qualifiedName)
|
val targetFqName = FqName.fromSegments(qualifiedName)
|
||||||
|
|
||||||
|
val functions = KotlinFunctionShortNameIndex.getInstance().get(shortName, project, allScope).asSequence()
|
||||||
|
val classes = KotlinClassShortNameIndex.getInstance().get(shortName, project, allScope).asSequence()
|
||||||
|
|
||||||
val descriptors = functions.asSequence()
|
val descriptors = (functions + classes)
|
||||||
.filter { it.fqName == targetFqName }
|
.filter { it.fqName == targetFqName }
|
||||||
.map { it.resolveToDescriptor(BodyResolveMode.PARTIAL) } // TODO Filter out not visible due dependencies config descriptors
|
.map { it.resolveToDescriptor(BodyResolveMode.PARTIAL) } // TODO Filter out not visible due dependencies config descriptors
|
||||||
.toList()
|
.toList()
|
||||||
return descriptors
|
if(descriptors.isNotEmpty())
|
||||||
|
return descriptors
|
||||||
|
|
||||||
|
val packageDescriptors = collectAllModuleInfosFromIdeaModel(project)
|
||||||
|
.asSequence()
|
||||||
|
.map { resolutionFacade.findModuleDescriptor(it)?.getPackage(targetFqName) }
|
||||||
|
.filterNotNull()
|
||||||
|
.filterNot { it.isEmpty() }
|
||||||
|
|
||||||
|
return packageDescriptors.toList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -148,7 +148,7 @@ class KDocNameCompletionSession(
|
|||||||
val qualifiedLink = kDocLink.getLinkText().split('.').dropLast(1)
|
val qualifiedLink = kDocLink.getLinkText().split('.').dropLast(1)
|
||||||
val nameFilter = descriptorNameFilter.toNameFilter()
|
val nameFilter = descriptorNameFilter.toNameFilter()
|
||||||
if (qualifiedLink.isNotEmpty()) {
|
if (qualifiedLink.isNotEmpty()) {
|
||||||
val parentDescriptors = resolveKDocLink(bindingContext, resolutionFacade, declarationDescriptor, null, qualifiedLink)
|
val parentDescriptors = resolveKDocLink(bindingContext, resolutionFacade, declarationDescriptor, kDocLink.getTagIfSubject(), qualifiedLink)
|
||||||
val childDescriptorsOfPartialLink = parentDescriptors.asSequence().flatMap {
|
val childDescriptorsOfPartialLink = parentDescriptors.asSequence().flatMap {
|
||||||
val scope = getKDocLinkResolutionScope(resolutionFacade, it)
|
val scope = getKDocLinkResolutionScope(resolutionFacade, it)
|
||||||
collectDescriptorsFromScope(scope, nameFilter, false)
|
collectDescriptorsFromScope(scope, nameFilter, false)
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* @sample samples.SampleGroup.mySample
|
||||||
|
* @sample samples.megasamples.MegaSamplesGroup.megaSample
|
||||||
|
* @sample samples.notindir.NotInDirSamples.sssample
|
||||||
|
* @sample smaplez.a.b.c.Samplez.sssample
|
||||||
|
*/
|
||||||
|
fun some<caret>() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//INFO: <pre><b>public</b> <b>fun</b> some(): Unit <i>defined in</i> root package</pre><br/>
|
||||||
|
//INFO: <dl><dt><b>Samples:</b></dt><dd><a href="psi_element://samples.SampleGroup.mySample"><code>samples.SampleGroup.mySample</code></a><pre><code>
|
||||||
|
//INFO: println("Hello, world")
|
||||||
|
//INFO: </code></pre></dd><dd><a href="psi_element://samples.megasamples.MegaSamplesGroup.megaSample"><code>samples.megasamples.MegaSamplesGroup.megaSample</code></a><pre><code>
|
||||||
|
//INFO: println("...---...")
|
||||||
|
//INFO: </code></pre></dd><dd><a href="psi_element://samples.notindir.NotInDirSamples.sssample"><code>samples.notindir.NotInDirSamples.sssample</code></a><pre><code>
|
||||||
|
//INFO: println("location is samplesTest/")
|
||||||
|
//INFO: </code></pre></dd><dd><a href="psi_element://smaplez.a.b.c.Samplez.sssample"><code>smaplez.a.b.c.Samplez.sssample</code></a><pre><code>// Unresolved</code></pre></dd></dl>
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package samples.notindir
|
||||||
|
|
||||||
|
object NotInDirSamples {
|
||||||
|
fun sssample() {
|
||||||
|
println("location is samplesTest/")
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package samples.megasamples
|
||||||
|
|
||||||
|
object MegaSamplesGroup {
|
||||||
|
fun megaSample() {
|
||||||
|
println("...---...")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package samples
|
||||||
|
|
||||||
|
object SampleGroup {
|
||||||
|
fun mySample() {
|
||||||
|
println("Hello, world")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package samplez.a.b.c
|
||||||
|
|
||||||
|
object Samplez {
|
||||||
|
fun sssample() {
|
||||||
|
println("samplez")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,8 +21,13 @@ import com.intellij.openapi.util.io.FileUtil
|
|||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
|
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
|
||||||
import com.intellij.rt.execution.junit.FileComparisonFailure
|
import com.intellij.rt.execution.junit.FileComparisonFailure
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.editor.quickDoc.AbstractQuickDocProviderTest.wrapToFileComparisonFailure
|
import org.jetbrains.kotlin.idea.editor.quickDoc.AbstractQuickDocProviderTest.wrapToFileComparisonFailure
|
||||||
import org.jetbrains.kotlin.idea.stubs.AbstractMultiModuleTest
|
import org.jetbrains.kotlin.idea.stubs.AbstractMultiModuleTest
|
||||||
|
import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext.DECLARATION_TO_DESCRIPTOR
|
||||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -44,10 +49,47 @@ class KDocSampleTest : AbstractMultiModuleTest() {
|
|||||||
|
|
||||||
samples.addDependency(code)
|
samples.addDependency(code)
|
||||||
|
|
||||||
doTest("simple/code/usage.kt")
|
doInfoTest("simple/code/usage.kt")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun doTest(path: String) {
|
fun testFqName() {
|
||||||
|
|
||||||
|
val code = module("code")
|
||||||
|
val samples = module("samples", hasTestRoot = true)
|
||||||
|
|
||||||
|
samples.addDependency(code)
|
||||||
|
|
||||||
|
doInfoTest("fqName/code/usage.kt")
|
||||||
|
doResolveTest("fqName/code/usage.kt", "samples")
|
||||||
|
doResolveTest("fqName/code/usage.kt", "samples.SampleGroup")
|
||||||
|
doResolveTest("fqName/code/usage.kt", "samples.megasamples")
|
||||||
|
doResolveTest("fqName/code/usage.kt", "samples.megasamples.MegaSamplesGroup")
|
||||||
|
doResolveTest("fqName/code/usage.kt", "samples.notindir")
|
||||||
|
doResolveTest("fqName/code/usage.kt", "samples.notindir.NotInDirSamples")
|
||||||
|
doResolveTest("fqName/code/usage.kt", "samplez")
|
||||||
|
doResolveTest("fqName/code/usage.kt", "samplez.a")
|
||||||
|
doResolveTest("fqName/code/usage.kt", "samplez.a.b")
|
||||||
|
doResolveTest("fqName/code/usage.kt", "samplez.a.b.c")
|
||||||
|
doResolveTest("fqName/code/usage.kt", "samplez.a.b.c.Samplez")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doResolveTest(path: String, link: String) {
|
||||||
|
|
||||||
|
configureByFile(path)
|
||||||
|
val documentationManager = DocumentationManager.getInstance(myProject)
|
||||||
|
val targetElement = documentationManager.findTargetElement(myEditor, file)
|
||||||
|
|
||||||
|
targetElement as KtElement
|
||||||
|
|
||||||
|
val bindingContext = targetElement.analyze()
|
||||||
|
val descriptor = bindingContext[DECLARATION_TO_DESCRIPTOR, targetElement]!!
|
||||||
|
val kdoc = descriptor.findKDoc()!! as KDocSection
|
||||||
|
val resolutionFacade = targetElement.getResolutionFacade()
|
||||||
|
assertNotEmpty(resolveKDocLink(bindingContext, resolutionFacade, descriptor, kdoc.findTagByName("sample")!!, link.split(".")))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doInfoTest(path: String) {
|
||||||
val testDataFile = File(testPath, path)
|
val testDataFile = File(testPath, path)
|
||||||
configureByFile(path)
|
configureByFile(path)
|
||||||
val documentationManager = DocumentationManager.getInstance(myProject)
|
val documentationManager = DocumentationManager.getInstance(myProject)
|
||||||
@@ -77,11 +119,11 @@ class KDocSampleTest : AbstractMultiModuleTest() {
|
|||||||
|
|
||||||
if (expectedInfo.endsWith("...\n")) {
|
if (expectedInfo.endsWith("...\n")) {
|
||||||
if (!info!!.startsWith(expectedInfo.removeSuffix("...\n"))) {
|
if (!info!!.startsWith(expectedInfo.removeSuffix("...\n"))) {
|
||||||
wrapToFileComparisonFailure(info, testDataPath, textData)
|
wrapToFileComparisonFailure(info, testDataFile.absolutePath, textData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (expectedInfo != info) {
|
else if (expectedInfo != info) {
|
||||||
wrapToFileComparisonFailure(info, path, textData)
|
wrapToFileComparisonFailure(info!!, testDataFile.absolutePath, textData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user