[Analysis API] Generify 'KtCodeFragmentModule' to support ordinary files
This commit introduces dangling file modules, which may be either code fragments or ordinary Kotlin files. As before, code fragments are analyzed against some context element, however ordinary files only have a context module. Code fragments can also have a dangling file module as a contextual one, including other code fragment. This is done to support potential usages in completion, intentions and refactorings.
This commit is contained in:
+14
-7
@@ -10,7 +10,6 @@ import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.psi.KtCodeFragment
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
|
||||
import java.nio.file.Path
|
||||
@@ -216,21 +215,29 @@ public interface KtScriptDependencyModule : KtModule {
|
||||
}
|
||||
|
||||
/**
|
||||
* A module for a Kotlin code fragment – a piece of code analyzed against a specific context element.
|
||||
* A module for a dangling file. Such files are usually temporary and are stored in-memory.
|
||||
* Dangling files may be created for various purposes, such as: a code fragment for the evaluator, a sandbox for testing code modification
|
||||
* applicability, etc.
|
||||
*/
|
||||
public interface KtCodeFragmentModule : KtModule {
|
||||
public interface KtDanglingFileModule : KtModule {
|
||||
/**
|
||||
* A code fragment PSI.
|
||||
* A temporary file PSI.
|
||||
*/
|
||||
public val codeFragment: KtCodeFragment
|
||||
public val file: KtFile
|
||||
|
||||
/**
|
||||
* Module of the context element.
|
||||
* The module against which the [file] is analyzed.
|
||||
*/
|
||||
public val contextModule: KtModule
|
||||
|
||||
/**
|
||||
* True if the [file] is a code fragment.
|
||||
* Useful to recognize code fragments when their PSI was collected.
|
||||
*/
|
||||
public val isCodeFragment: Boolean
|
||||
|
||||
override val moduleDescription: String
|
||||
get() = "Code fragment"
|
||||
get() = "Temporary file"
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+26
-13
@@ -7,22 +7,35 @@ package org.jetbrains.kotlin.analysis.project.structure.impl
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtCodeFragmentModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.psi.KtCodeFragment
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
||||
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
|
||||
import java.util.Objects
|
||||
|
||||
public class KtCodeFragmentModuleImpl(
|
||||
codeFragment: KtCodeFragment,
|
||||
public class KtDanglingFileModuleImpl(
|
||||
file: KtFile,
|
||||
override val contextModule: KtModule
|
||||
) : KtCodeFragmentModule {
|
||||
private val codeFragmentRef = codeFragment.createSmartPointer()
|
||||
) : KtDanglingFileModule {
|
||||
override val isCodeFragment: Boolean = file is KtCodeFragment
|
||||
|
||||
override val codeFragment: KtCodeFragment
|
||||
get() = codeFragmentRef.element?.takeIf { it.isValid } ?: error("Code fragment module is invalid")
|
||||
private val fileRef = file.createSmartPointer()
|
||||
|
||||
init {
|
||||
require(contextModule != this)
|
||||
|
||||
if (contextModule is KtDanglingFileModule) {
|
||||
// Only code fragments can depend on dangling files.
|
||||
// This is needed for completion, inspections and refactorings.
|
||||
require(file is KtCodeFragment)
|
||||
}
|
||||
}
|
||||
|
||||
override val file: KtFile
|
||||
get() = fileRef.element?.takeIf { it.isValid } ?: error("Dangling file module is invalid")
|
||||
|
||||
override val project: Project
|
||||
get() = contextModule.project
|
||||
@@ -34,7 +47,7 @@ public class KtCodeFragmentModuleImpl(
|
||||
get() = contextModule.analyzerServices
|
||||
|
||||
override val contentScope: GlobalSearchScope
|
||||
get() = GlobalSearchScope.fileScope(codeFragment)
|
||||
get() = GlobalSearchScope.fileScope(file)
|
||||
|
||||
override val directRegularDependencies: List<KtModule>
|
||||
get() = contextModule.directRegularDependencies
|
||||
@@ -51,16 +64,16 @@ public class KtCodeFragmentModuleImpl(
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
|
||||
if (other is KtCodeFragmentModuleImpl) {
|
||||
val selfCodeFragment = this.codeFragmentRef.element
|
||||
val otherCodeFragment = other.codeFragmentRef.element
|
||||
return selfCodeFragment != null && selfCodeFragment == otherCodeFragment && contextModule == other.contextModule
|
||||
if (other is KtDanglingFileModuleImpl) {
|
||||
val selfFile = this.fileRef.element
|
||||
val otherFile = other.fileRef.element
|
||||
return selfFile != null && selfFile == otherFile && contextModule == other.contextModule
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return Objects.hash(codeFragmentRef.element, contextModule)
|
||||
return Objects.hash(fileRef.element, contextModule)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user