Compare commits

...

12 Commits

Author SHA1 Message Date
Nikolay Krasko
d87b4a661b Enable configuration cache 2021-07-16 01:51:46 +03:00
Nikolay Krasko
e47f986d35 Enable native 2021-07-16 01:51:46 +03:00
Nikolay Krasko
4d9bcdadd6 -- temp 2021-07-16 01:51:45 +03:00
Nikolay Krasko
f829e55bee Remove explicit registration of classFileDecompiler EP and core.xml 2021-07-16 01:51:45 +03:00
Nikolay Krasko
a076591771 Cleanup 202 bunch files
Leave 202 in .bunch file to give some time for updating build server
2021-07-16 01:51:45 +03:00
Nikolay Krasko
e012031a57 Update .bunch file after 202 -> 203 switch 2021-07-16 01:51:44 +03:00
Nikolay Krasko
06d537530f Cleanup as42 bunch files
We don't build AS42 plugin from main kotlin repo anymore.
2021-07-16 01:51:44 +03:00
Nikolay Krasko
e8ac9a60ff Drop runIdeTask 2021-07-16 01:51:44 +03:00
Nikolay Krasko
4259d5fc9e Remove runIde mentioning from README.md 2021-07-16 01:51:43 +03:00
Nikolay Krasko
96a81da851 Drop old IDEA run configurations 2021-07-16 01:51:43 +03:00
Nikolay Krasko
9fe58ed913 Revert incremental test data 2021-07-16 01:51:43 +03:00
Nikolay Krasko
42f18128e0 Remove old source code of the IDE-related modules
All IDE-related sources was moved to IntelliJ repository
https://github.com/JetBrains/intellij-community/tree/master/plugins/kotlin
2021-07-15 19:43:47 +03:00
50808 changed files with 9 additions and 1179796 deletions

5
.bunch
View File

@@ -1,3 +1,2 @@
202
203_202
as42
203
202

View File

@@ -1,20 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="IDEA" type="GradleRunConfiguration" factoryName="Gradle" singleton="true" folderName="IDEA">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="runIde" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<method />
</configuration>
</component>

View File

@@ -1,20 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="IDEA Ultimate" type="GradleRunConfiguration" factoryName="Gradle" folderName="IDEA">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="-P intellijUltimateEnabled" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="runUltimate" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<method />
</configuration>
</component>

View File

@@ -1,20 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="IDEA Ultimate (No ProcessCanceledException) " type="GradleRunConfiguration" factoryName="Gradle" folderName="IDEA">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="-PnoPCE" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="runUltimate" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<method />
</configuration>
</component>

View File

@@ -1,20 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="IDEA (No ProcessCanceledException)" type="GradleRunConfiguration" factoryName="Gradle" folderName="IDEA">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="-PnoPCE" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="runIde" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<method />
</configuration>
</component>

View File

@@ -1,19 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="IDEA (Not Internal)" type="GradleRunConfiguration" factoryName="Gradle" folderName="IDEA">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="-Pidea.is.internal=false" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="runIde" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
</configuration>
</component>

View File

@@ -152,64 +152,4 @@ fun DependencyHandlerScope.excludeInAndroidStudio(rootProject: Project, block: D
if (!rootProject.extra.has("versions.androidStudioRelease")) {
block()
}
}
fun Project.runIdeTask(name: String, ideaPluginDir: File, ideaSandboxDir: File, body: JavaExec.() -> Unit): TaskProvider<JavaExec> {
return tasks.register<JavaExec>(name) {
val ideaSandboxConfigDir = File(ideaSandboxDir, "config")
classpath = mainSourceSet.runtimeClasspath
mainClass.set("com.intellij.idea.Main")
workingDir = File(intellijRootDir(), "bin")
jvmArgs(
"-Xmx1250m",
"-XX:ReservedCodeCacheSize=240m",
"-XX:+HeapDumpOnOutOfMemoryError",
"-ea",
"-Didea.debug.mode=true",
"-Didea.system.path=$ideaSandboxDir",
"-Didea.config.path=$ideaSandboxConfigDir",
"-Didea.tooling.debug=true",
"-Dfus.internal.test.mode=true",
"-Dapple.laf.useScreenMenuBar=true",
"-Dapple.awt.graphics.UseQuartz=true",
"-Dsun.io.useCanonCaches=false",
"-Dplugin.path=${ideaPluginDir.absolutePath}"
)
jvmArgs("-Didea.platform.prefix=Idea")
if (rootProject.findProperty("versions.androidStudioRelease") != null) {
jvmArgs("-Didea.platform.prefix=AndroidStudio")
}
if (project.hasProperty("noPCE")) {
jvmArgs("-Didea.ProcessCanceledException=disabled")
}
jvmArgs("-Didea.is.internal=${project.findProperty("idea.is.internal") ?: true}")
project.findProperty("idea.args")?.let { arguments ->
jvmArgs(arguments.toString().split(" "))
}
args()
doFirst {
val disabledPluginsFile = File(ideaSandboxConfigDir, "disabled_plugins.txt")
val disabledPluginsContents = disabledPluginsFile.takeIf { it.isFile }?.readLines()
val filteredContents = disabledPluginsContents?.filterNot { it.contains("org.jetbrains.kotlin") }
if (filteredContents != null && filteredContents.size != disabledPluginsContents.size) {
with(disabledPluginsFile.printWriter()) {
filteredContents.forEach(this::println)
}
}
}
body()
}
}
}

View File

@@ -1,12 +0,0 @@
<idea-plugin>
<id>org.jetbrains.kotlin</id>
<version>1.2</version>
<!-- Don't add more extension points here! Logic in KotlinCoreEnvironment assumes that there is only one EP. -->
<!-- And this file should be removed once 202 is no longer supported -->
<extensionPoints>
<extensionPoint qualifiedName="com.intellij.psi.classFileDecompiler"
interface="com.intellij.psi.compiled.ClassFileDecompilers$Decompiler"
dynamic="true"/>
</extensionPoints>
</idea-plugin>

View File

@@ -1,10 +0,0 @@
<idea-plugin>
<id>org.jetbrains.kotlin</id>
<version>1.2</version>
<extensionPoints>
<extensionPoint qualifiedName="com.intellij.psi.classFileDecompiler"
interface="com.intellij.psi.compiled.ClassFileDecompilers$Decompiler"
dynamic="true"/>
</extensionPoints>
</idea-plugin>

View File

@@ -1,19 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.cli.jvm.compiler
import com.intellij.openapi.project.DumbUtil
@Suppress("UnstableApiUsage")
class KotlinCoreDumbUtil : DumbUtil {
override fun <T : Any?> filterByDumbAwarenessHonoringIgnoring(collection: Collection<T>): List<T> =
when (collection) {
is List<T> -> collection
else -> ArrayList(collection)
}
override fun mayUseIndices(): Boolean = false
}

View File

@@ -538,11 +538,6 @@ class KotlinCoreEnvironment private constructor(
val applicationEnvironment = KotlinCoreApplicationEnvironment.create(parentDisposable, unitTestMode)
registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/compiler.xml")
// FIX ME WHEN BUNCH 202 REMOVED: this code is required to support compiler bundled to both 202 and 203.
// Please, remove "com.intellij.psi.classFileDecompiler" EP registration once 202 is no longer supported by the compiler
if (!ApplicationManager.getApplication().extensionArea.hasExtensionPoint("com.intellij.psi.classFileDecompiler")) {
registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/core.xml")
}
registerApplicationServicesForCLI(applicationEnvironment)
registerApplicationServices(applicationEnvironment)

View File

@@ -1,722 +0,0 @@
/*
* Copyright 2010-2017 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.cli.jvm.compiler
import com.intellij.codeInsight.ExternalAnnotationsManager
import com.intellij.codeInsight.InferredAnnotationsManager
import com.intellij.core.CoreApplicationEnvironment
import com.intellij.core.CoreJavaFileManager
import com.intellij.core.JavaCoreProjectEnvironment
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.lang.java.JavaParserDefinition
import com.intellij.mock.MockProject
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.TransactionGuard
import com.intellij.openapi.application.TransactionGuardImpl
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.extensions.ExtensionsArea
import com.intellij.openapi.fileTypes.PlainTextFileType
import com.intellij.openapi.project.DumbUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.*
import com.intellij.openapi.vfs.impl.ZipHandler
import com.intellij.psi.PsiElementFinder
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.JavaClassSupersImpl
import com.intellij.psi.impl.PsiElementFinderImpl
import com.intellij.psi.impl.PsiTreeChangePreprocessor
import com.intellij.psi.impl.file.impl.JavaFileManager
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.JavaClassSupers
import com.intellij.util.io.URLUtil
import com.intellij.util.lang.UrlClassLoader
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.classes.FacadeCache
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.CliModuleVisibilityManagerImpl
import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY
import org.jetbrains.kotlin.cli.common.config.ContentRoot
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots
import org.jetbrains.kotlin.cli.common.extensions.ScriptEvaluationExtension
import org.jetbrains.kotlin.cli.common.extensions.ShellExtension
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_WARNING
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.toBooleanLenient
import org.jetbrains.kotlin.cli.jvm.JvmRuntimeVersionsConsistencyChecker
import org.jetbrains.kotlin.cli.jvm.config.*
import org.jetbrains.kotlin.cli.jvm.index.*
import org.jetbrains.kotlin.cli.jvm.javac.JavacWrapperRegistrar
import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleFinder
import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleResolver
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.extensions.*
import org.jetbrains.kotlin.extensions.internal.CandidateInterceptor
import org.jetbrains.kotlin.extensions.internal.TypeResolutionInterceptor
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.kotlin.MetadataFinderFactory
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer
import org.jetbrains.kotlin.resolve.ModuleAnnotationsResolver
import org.jetbrains.kotlin.resolve.extensions.ExtraImportsProviderExtension
import org.jetbrains.kotlin.resolve.jvm.extensions.SyntheticJavaResolveExtension
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
import org.jetbrains.kotlin.resolve.lazy.declarations.CliDeclarationProviderFactoryService
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
import org.jetbrains.kotlin.serialization.DescriptorSerializerPlugin
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
import java.nio.file.FileSystems
import java.util.zip.ZipFile
class KotlinCoreEnvironment private constructor(
val projectEnvironment: JavaCoreProjectEnvironment,
initialConfiguration: CompilerConfiguration,
configFiles: EnvironmentConfigFiles
) {
class ProjectEnvironment(
disposable: Disposable, applicationEnvironment: KotlinCoreApplicationEnvironment
) :
KotlinCoreProjectEnvironment(disposable, applicationEnvironment) {
private var extensionRegistered = false
override fun preregisterServices() {
registerProjectExtensionPoints(project.extensionArea)
}
fun registerExtensionsFromPlugins(configuration: CompilerConfiguration) {
if (!extensionRegistered) {
registerPluginExtensionPoints(project)
registerExtensionsFromPlugins(project, configuration)
extensionRegistered = true
}
}
override fun registerJavaPsiFacade() {
with(project) {
registerService(
CoreJavaFileManager::class.java,
ServiceManager.getService(this, JavaFileManager::class.java) as CoreJavaFileManager
)
registerKotlinLightClassSupport(project)
registerService(ExternalAnnotationsManager::class.java, MockExternalAnnotationsManager())
registerService(InferredAnnotationsManager::class.java, MockInferredAnnotationsManager())
}
super.registerJavaPsiFacade()
}
}
private val sourceFiles = mutableListOf<KtFile>()
private val rootsIndex: JvmDependenciesDynamicCompoundIndex
private val packagePartProviders = mutableListOf<JvmPackagePartProvider>()
private val classpathRootsResolver: ClasspathRootsResolver
private val initialRoots = ArrayList<JavaRoot>()
val configuration: CompilerConfiguration = initialConfiguration.apply { setupJdkClasspathRoots(configFiles) }.copy()
init {
PersistentFSConstants::class.java.getDeclaredField("ourMaxIntellisenseFileSize")
.apply { isAccessible = true }
.setInt(null, FileUtilRt.LARGE_FOR_CONTENT_LOADING)
val project = projectEnvironment.project
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
(projectEnvironment as? ProjectEnvironment)?.registerExtensionsFromPlugins(configuration)
// otherwise consider that project environment is properly configured before passing to the environment
// TODO: consider some asserts to check important extension points
project.registerService(DeclarationProviderFactoryService::class.java, CliDeclarationProviderFactoryService(sourceFiles))
val isJvm = configFiles == EnvironmentConfigFiles.JVM_CONFIG_FILES
project.registerService(ModuleVisibilityManager::class.java, CliModuleVisibilityManagerImpl(isJvm))
registerProjectServicesForCLI(projectEnvironment)
registerProjectServices(projectEnvironment.project)
for (extension in CompilerConfigurationExtension.getInstances(project)) {
extension.updateConfiguration(configuration)
}
sourceFiles += createKtFiles(project)
collectAdditionalSources(project)
sourceFiles.sortBy { it.virtualFile.path }
val javaFileManager = ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl
val jdkHome = configuration.get(JVMConfigurationKeys.JDK_HOME)
val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL)
val javaModuleFinder = CliJavaModuleFinder(
jdkHome?.path?.let { path ->
jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR)
},
javaFileManager
)
val outputDirectory =
configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory()
?: configuration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY)?.absolutePath
classpathRootsResolver = ClasspathRootsResolver(
PsiManager.getInstance(project),
messageCollector,
configuration.getList(JVMConfigurationKeys.ADDITIONAL_JAVA_MODULES),
this::contentRootToVirtualFile,
javaModuleFinder,
!configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE),
outputDirectory?.let(this::findLocalFile),
javaFileManager
)
val (initialRoots, javaModules) =
classpathRootsResolver.convertClasspathRoots(configuration.getList(CLIConfigurationKeys.CONTENT_ROOTS))
this.initialRoots.addAll(initialRoots)
if (!configuration.getBoolean(JVMConfigurationKeys.SKIP_RUNTIME_VERSION_CHECK) && messageCollector != null) {
JvmRuntimeVersionsConsistencyChecker.checkCompilerClasspathConsistency(
messageCollector,
configuration,
initialRoots.mapNotNull { (file, type) -> if (type == JavaRoot.RootType.BINARY) file else null }
)
}
val (roots, singleJavaFileRoots) =
initialRoots.partition { (file) -> file.isDirectory || file.extension != JavaFileType.DEFAULT_EXTENSION }
// REPL and kapt2 update classpath dynamically
rootsIndex = JvmDependenciesDynamicCompoundIndex().apply {
addIndex(JvmDependenciesIndexImpl(roots))
updateClasspathFromRootsIndex(this)
}
javaFileManager.initialize(
rootsIndex,
packagePartProviders,
SingleJavaFileRootsIndex(singleJavaFileRoots),
configuration.getBoolean(JVMConfigurationKeys.USE_PSI_CLASS_FILES_READING)
)
project.registerService(
JavaModuleResolver::class.java,
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList(), project)
)
val finderFactory = CliVirtualFileFinderFactory(rootsIndex)
project.registerService(MetadataFinderFactory::class.java, finderFactory)
project.registerService(VirtualFileFinderFactory::class.java, finderFactory)
project.putUserData(APPEND_JAVA_SOURCE_ROOTS_HANDLER_KEY, fun(roots: List<File>) {
updateClasspath(roots.map { JavaSourceRoot(it, null) })
})
}
private fun collectAdditionalSources(project: MockProject) {
var unprocessedSources: Collection<KtFile> = sourceFiles
val processedSources = HashSet<KtFile>()
val processedSourcesByExtension = HashMap<CollectAdditionalSourcesExtension, Collection<KtFile>>()
// repeat feeding extensions with sources while new sources a being added
var sourceCollectionIterations = 0
while (unprocessedSources.isNotEmpty()) {
if (sourceCollectionIterations++ > 10) { // TODO: consider using some appropriate global constant
throw IllegalStateException("Unable to collect additional sources in reasonable number of iterations")
}
processedSources.addAll(unprocessedSources)
val allNewSources = ArrayList<KtFile>()
for (extension in CollectAdditionalSourcesExtension.getInstances(project)) {
// do not feed the extension with the sources it returned on the previous iteration
val sourcesToProcess = unprocessedSources - (processedSourcesByExtension[extension] ?: emptyList())
val newSources = extension.collectAdditionalSourcesAndUpdateConfiguration(sourcesToProcess, configuration, project)
if (newSources.isNotEmpty()) {
allNewSources.addAll(newSources)
processedSourcesByExtension[extension] = newSources
}
}
unprocessedSources = allNewSources.filterNot { processedSources.contains(it) }.distinct()
sourceFiles += unprocessedSources
}
}
fun addKotlinSourceRoots(rootDirs: List<File>) {
val roots = rootDirs.map { KotlinSourceRoot(it.absolutePath, isCommon = false) }
sourceFiles += createSourceFilesFromSourceRoots(configuration, project, roots)
}
fun createPackagePartProvider(scope: GlobalSearchScope): JvmPackagePartProvider {
return JvmPackagePartProvider(configuration.languageVersionSettings, scope).apply {
addRoots(initialRoots, configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY))
packagePartProviders += this
(ModuleAnnotationsResolver.getInstance(project) as CliModuleAnnotationsResolver).addPackagePartProvider(this)
}
}
private val VirtualFile.javaFiles: List<VirtualFile>
get() = mutableListOf<VirtualFile>().apply {
VfsUtilCore.processFilesRecursively(this@javaFiles) { file ->
if (file.fileType == JavaFileType.INSTANCE) {
add(file)
}
true
}
}
private val allJavaFiles: List<File>
get() = configuration.javaSourceRoots
.mapNotNull(this::findLocalFile)
.flatMap { it.javaFiles }
.map { File(it.canonicalPath) }
fun registerJavac(
javaFiles: List<File> = allJavaFiles,
kotlinFiles: List<KtFile> = sourceFiles,
arguments: Array<String>? = null,
bootClasspath: List<File>? = null,
sourcePath: List<File>? = null
): Boolean {
return JavacWrapperRegistrar.registerJavac(
projectEnvironment.project, configuration, javaFiles, kotlinFiles, arguments, bootClasspath, sourcePath,
LightClassGenerationSupport.getInstance(project), packagePartProviders
)
}
private val applicationEnvironment: CoreApplicationEnvironment
get() = projectEnvironment.environment
val project: Project
get() = projectEnvironment.project
internal fun countLinesOfCode(sourceFiles: List<KtFile>): Int =
sourceFiles.sumBy { sourceFile ->
val text = sourceFile.text
StringUtil.getLineBreakCount(text) + (if (StringUtil.endsWithLineBreak(text)) 0 else 1)
}
private fun updateClasspathFromRootsIndex(index: JvmDependenciesIndex) {
index.indexedRoots.forEach {
projectEnvironment.addSourcesToClasspath(it.file)
}
}
fun updateClasspath(contentRoots: List<ContentRoot>): List<File>? {
// TODO: add new Java modules to CliJavaModuleResolver
val newRoots = classpathRootsResolver.convertClasspathRoots(contentRoots).roots
if (packagePartProviders.isEmpty()) {
initialRoots.addAll(newRoots)
} else {
for (packagePartProvider in packagePartProviders) {
packagePartProvider.addRoots(newRoots, configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY))
}
}
return rootsIndex.addNewIndexForRoots(newRoots)?.let { newIndex ->
updateClasspathFromRootsIndex(newIndex)
newIndex.indexedRoots.mapNotNull { (file) ->
VfsUtilCore.virtualToIoFile(VfsUtilCore.getVirtualFileForJar(file) ?: file)
}.toList()
}.orEmpty()
}
private fun contentRootToVirtualFile(root: JvmContentRoot): VirtualFile? =
when (root) {
is JvmClasspathRoot ->
if (root.file.isFile) findJarRoot(root.file) else findExistingRoot(root, "Classpath entry")
is JvmModulePathRoot ->
if (root.file.isFile) findJarRoot(root.file) else findExistingRoot(root, "Java module root")
is JavaSourceRoot ->
findExistingRoot(root, "Java source root")
else ->
throw IllegalStateException("Unexpected root: $root")
}
internal fun findLocalFile(path: String): VirtualFile? =
applicationEnvironment.localFileSystem.findFileByPath(path)
private fun findExistingRoot(root: JvmContentRoot, rootDescription: String): VirtualFile? {
return findLocalFile(root.file.absolutePath).also {
if (it == null) {
report(STRONG_WARNING, "$rootDescription points to a non-existent location: ${root.file}")
}
}
}
private fun findJarRoot(file: File): VirtualFile? =
applicationEnvironment.jarFileSystem.findFileByPath("$file${URLUtil.JAR_SEPARATOR}")
private fun getSourceRootsCheckingForDuplicates(): List<KotlinSourceRoot> {
val uniqueSourceRoots = hashSetOf<String>()
val result = mutableListOf<KotlinSourceRoot>()
for (root in configuration.kotlinSourceRoots) {
if (!uniqueSourceRoots.add(root.path)) {
report(STRONG_WARNING, "Duplicate source root: ${root.path}")
}
result.add(root)
}
return result
}
fun getSourceFiles(): List<KtFile> = sourceFiles
private fun createKtFiles(project: Project): List<KtFile> =
createSourceFilesFromSourceRoots(configuration, project, getSourceRootsCheckingForDuplicates())
internal fun report(severity: CompilerMessageSeverity, message: String) = configuration.report(severity, message)
companion object {
private val LOG = Logger.getInstance(KotlinCoreEnvironment::class.java)
private val APPLICATION_LOCK = Object()
private var ourApplicationEnvironment: KotlinCoreApplicationEnvironment? = null
private var ourProjectCount = 0
@JvmStatic
fun createForProduction(
parentDisposable: Disposable, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles
): KotlinCoreEnvironment {
setupIdeaStandaloneExecution()
val appEnv = getOrCreateApplicationEnvironmentForProduction(parentDisposable, configuration)
val projectEnv = ProjectEnvironment(parentDisposable, appEnv)
val environment = KotlinCoreEnvironment(projectEnv, configuration, configFiles)
synchronized(APPLICATION_LOCK) {
ourProjectCount++
}
return environment
}
@JvmStatic
fun createForProduction(
projectEnvironment: JavaCoreProjectEnvironment, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles
): KotlinCoreEnvironment {
val environment = KotlinCoreEnvironment(projectEnvironment, configuration, configFiles)
if (projectEnvironment.environment == applicationEnvironment) {
// accounting for core environment disposing
synchronized(APPLICATION_LOCK) {
ourProjectCount++
}
}
return environment
}
@TestOnly
@JvmStatic
fun createForTests(
parentDisposable: Disposable, initialConfiguration: CompilerConfiguration, extensionConfigs: EnvironmentConfigFiles
): KotlinCoreEnvironment {
val configuration = initialConfiguration.copy()
// Tests are supposed to create a single project and dispose it right after use
val appEnv = createApplicationEnvironment(parentDisposable, configuration, unitTestMode = true)
val projectEnv = ProjectEnvironment(parentDisposable, appEnv)
return KotlinCoreEnvironment(projectEnv, configuration, extensionConfigs)
}
@TestOnly
@JvmStatic
fun createForTests(
projectEnvironment: ProjectEnvironment, initialConfiguration: CompilerConfiguration, extensionConfigs: EnvironmentConfigFiles
): KotlinCoreEnvironment {
return KotlinCoreEnvironment(projectEnvironment, initialConfiguration, extensionConfigs)
}
@TestOnly
fun createProjectEnvironmentForTests(parentDisposable: Disposable, configuration: CompilerConfiguration): ProjectEnvironment {
val appEnv = createApplicationEnvironment(parentDisposable, configuration, unitTestMode = true)
return ProjectEnvironment(parentDisposable, appEnv)
}
// used in the daemon for jar cache cleanup
val applicationEnvironment: KotlinCoreApplicationEnvironment? get() = ourApplicationEnvironment
fun getOrCreateApplicationEnvironmentForProduction(
parentDisposable: Disposable, configuration: CompilerConfiguration
): KotlinCoreApplicationEnvironment = getOrCreateApplicationEnvironment(parentDisposable, configuration, unitTestMode = false)
fun getOrCreateApplicationEnvironmentForTests(
parentDisposable: Disposable, configuration: CompilerConfiguration
): KotlinCoreApplicationEnvironment = getOrCreateApplicationEnvironment(parentDisposable, configuration, unitTestMode = true)
private fun getOrCreateApplicationEnvironment(
parentDisposable: Disposable, configuration: CompilerConfiguration, unitTestMode: Boolean
): KotlinCoreApplicationEnvironment {
synchronized(APPLICATION_LOCK) {
if (ourApplicationEnvironment == null) {
val disposable = Disposer.newDisposable()
ourApplicationEnvironment = createApplicationEnvironment(disposable, configuration, unitTestMode)
ourProjectCount = 0
Disposer.register(disposable, Disposable {
synchronized(APPLICATION_LOCK) {
ourApplicationEnvironment = null
}
})
}
// Disposing of the environment is unsafe in production then parallel builds are enabled, but turning it off universally
// breaks a lot of tests, therefore it is disabled for production and enabled for tests
if (System.getProperty(KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY).toBooleanLenient() != true) {
// JPS may run many instances of the compiler in parallel (there's an option for compiling independent modules in parallel in IntelliJ)
// All projects share the same ApplicationEnvironment, and when the last project is disposed, the ApplicationEnvironment is disposed as well
Disposer.register(parentDisposable, Disposable {
synchronized(APPLICATION_LOCK) {
if (--ourProjectCount <= 0) {
disposeApplicationEnvironment()
}
}
})
}
return ourApplicationEnvironment!!
}
}
private fun disposeApplicationEnvironment() {
synchronized(APPLICATION_LOCK) {
val environment = ourApplicationEnvironment ?: return
ourApplicationEnvironment = null
Disposer.dispose(environment.parentDisposable)
ZipHandler.clearFileAccessorCache()
}
}
private fun createApplicationEnvironment(
parentDisposable: Disposable, configuration: CompilerConfiguration, unitTestMode: Boolean
): KotlinCoreApplicationEnvironment {
val applicationEnvironment = KotlinCoreApplicationEnvironment.create(parentDisposable, unitTestMode)
registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/compiler.xml")
registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/core.xml")
registerApplicationServicesForCLI(applicationEnvironment)
registerApplicationServices(applicationEnvironment)
return applicationEnvironment
}
private fun registerApplicationExtensionPointsAndExtensionsFrom(configuration: CompilerConfiguration, configFilePath: String) {
fun File.hasConfigFile(configFile: String): Boolean =
if (isDirectory) File(this, "META-INF" + File.separator + configFile).exists()
else try {
ZipFile(this).use {
it.getEntry("META-INF/$configFile") != null
}
} catch (e: Throwable) {
false
}
val pluginRoot: File =
configuration.get(CLIConfigurationKeys.INTELLIJ_PLUGIN_ROOT)?.let(::File)
?: PathUtil.getResourcePathForClass(this::class.java).takeIf { it.hasConfigFile(configFilePath) }
// hack for load extensions when compiler run directly from project directory (e.g. in tests)
?: File("compiler/cli/cli-common/resources").takeIf { it.hasConfigFile(configFilePath) }
?: throw IllegalStateException(
"Unable to find extension point configuration $configFilePath " +
"(cp:\n ${(Thread.currentThread().contextClassLoader as? UrlClassLoader)?.urls?.joinToString("\n ") { it.file }})"
)
CoreApplicationEnvironment.registerExtensionPointAndExtensions(
FileSystems.getDefault().getPath(pluginRoot.path),
configFilePath,
ApplicationManager.getApplication().extensionArea
)
}
@JvmStatic
@Suppress("MemberVisibilityCanPrivate") // made public for CLI Android Lint
fun registerPluginExtensionPoints(project: MockProject) {
ExpressionCodegenExtension.registerExtensionPoint(project)
SyntheticResolveExtension.registerExtensionPoint(project)
SyntheticJavaResolveExtension.registerExtensionPoint(project)
ClassBuilderInterceptorExtension.registerExtensionPoint(project)
AnalysisHandlerExtension.registerExtensionPoint(project)
PackageFragmentProviderExtension.registerExtensionPoint(project)
StorageComponentContainerContributor.registerExtensionPoint(project)
DeclarationAttributeAltererExtension.registerExtensionPoint(project)
PreprocessedVirtualFileFactoryExtension.registerExtensionPoint(project)
JsSyntheticTranslateExtension.registerExtensionPoint(project)
CompilerConfigurationExtension.registerExtensionPoint(project)
CollectAdditionalSourcesExtension.registerExtensionPoint(project)
ExtraImportsProviderExtension.registerExtensionPoint(project)
IrGenerationExtension.registerExtensionPoint(project)
ScriptEvaluationExtension.registerExtensionPoint(project)
ShellExtension.registerExtensionPoint(project)
TypeResolutionInterceptor.registerExtensionPoint(project)
CandidateInterceptor.registerExtensionPoint(project)
DescriptorSerializerPlugin.registerExtensionPoint(project)
}
internal fun registerExtensionsFromPlugins(project: MockProject, configuration: CompilerConfiguration) {
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
for (registrar in configuration.getList(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS)) {
try {
registrar.registerProjectComponents(project, configuration)
} catch (e: AbstractMethodError) {
val message = "The provided plugin ${registrar.javaClass.name} is not compatible with this version of compiler"
// Since the scripting plugin is often discovered in the compiler environment, it is often taken from the incompatible
// location, and in many cases this is not a fatal error, therefore strong warning is generated instead of exception
if (registrar.javaClass.simpleName == "ScriptingCompilerConfigurationComponentRegistrar") {
messageCollector?.report(STRONG_WARNING, "Default scripting plugin is disabled: $message")
} else {
throw IllegalStateException(message, e)
}
}
}
}
private fun registerApplicationServicesForCLI(applicationEnvironment: KotlinCoreApplicationEnvironment) {
// ability to get text from annotations xml files
applicationEnvironment.registerFileType(PlainTextFileType.INSTANCE, "xml")
applicationEnvironment.registerParserDefinition(JavaParserDefinition())
}
// made public for Upsource
@Suppress("MemberVisibilityCanBePrivate")
@JvmStatic
fun registerApplicationServices(applicationEnvironment: KotlinCoreApplicationEnvironment) {
with(applicationEnvironment) {
registerFileType(KotlinFileType.INSTANCE, "kt")
registerFileType(KotlinFileType.INSTANCE, KotlinParserDefinition.STD_SCRIPT_SUFFIX)
registerParserDefinition(KotlinParserDefinition())
application.registerService(KotlinBinaryClassCache::class.java, KotlinBinaryClassCache())
application.registerService(JavaClassSupers::class.java, JavaClassSupersImpl::class.java)
application.registerService(TransactionGuard::class.java, TransactionGuardImpl::class.java)
}
}
@JvmStatic
fun registerProjectExtensionPoints(area: ExtensionsArea) {
CoreApplicationEnvironment.registerExtensionPoint(
area, PsiTreeChangePreprocessor.EP.name, PsiTreeChangePreprocessor::class.java
)
CoreApplicationEnvironment.registerExtensionPoint(area, PsiElementFinder.EP.name, PsiElementFinder::class.java)
IdeaExtensionPoints.registerVersionSpecificProjectExtensionPoints(area)
}
// made public for Upsource
@JvmStatic
@Deprecated("Use registerProjectServices(project) instead.", ReplaceWith("registerProjectServices(projectEnvironment.project)"))
fun registerProjectServices(
projectEnvironment: JavaCoreProjectEnvironment,
@Suppress("UNUSED_PARAMETER") messageCollector: MessageCollector?
) {
registerProjectServices(projectEnvironment.project)
}
// made public for Android Lint
@JvmStatic
fun registerProjectServices(project: MockProject) {
with(project) {
registerService(KotlinJavaPsiFacade::class.java, KotlinJavaPsiFacade(this))
registerService(FacadeCache::class.java, FacadeCache(this))
registerService(ModuleAnnotationsResolver::class.java, CliModuleAnnotationsResolver())
}
}
private fun registerProjectServicesForCLI(@Suppress("UNUSED_PARAMETER") projectEnvironment: JavaCoreProjectEnvironment) {
/**
* Note that Kapt may restart code analysis process, and CLI services should be aware of that.
* Use PsiManager.getModificationTracker() to ensure that all the data you cached is still valid.
*/
}
// made public for Android Lint
@JvmStatic
fun registerKotlinLightClassSupport(project: MockProject) {
with(project) {
val traceHolder = CliTraceHolder()
val cliLightClassGenerationSupport = CliLightClassGenerationSupport(traceHolder, project)
val kotlinAsJavaSupport = CliKotlinAsJavaSupport(this, traceHolder)
registerService(LightClassGenerationSupport::class.java, cliLightClassGenerationSupport)
registerService(CliLightClassGenerationSupport::class.java, cliLightClassGenerationSupport)
registerService(KotlinAsJavaSupport::class.java, kotlinAsJavaSupport)
registerService(CodeAnalyzerInitializer::class.java, traceHolder)
@Suppress("UnstableApiUsage")
registerService(DumbUtil::class.java, KotlinCoreDumbUtil())
// We don't pass Disposable because in some tests, we manually unregister these extensions, and that leads to LOG.error
// exception from `ExtensionPointImpl.doRegisterExtension`, because the registered extension can no longer be found
// when the project is being disposed.
// For example, see the `unregisterExtension` call in `GenerationUtils.compileFilesUsingFrontendIR`.
// TODO: refactor this to avoid registering unneeded extensions in the first place, and avoid using deprecated API.
@Suppress("DEPRECATION")
PsiElementFinder.EP.getPoint(project).registerExtension(JavaElementFinder(this))
@Suppress("DEPRECATION")
PsiElementFinder.EP.getPoint(project).registerExtension(PsiElementFinderImpl(this))
}
}
private fun CompilerConfiguration.setupJdkClasspathRoots(configFiles: EnvironmentConfigFiles) {
if (getBoolean(JVMConfigurationKeys.NO_JDK)) return
val jvmTarget = configFiles == EnvironmentConfigFiles.JVM_CONFIG_FILES
if (!jvmTarget) return
val jdkHome = get(JVMConfigurationKeys.JDK_HOME)
val (javaRoot, classesRoots) = if (jdkHome == null) {
val javaHome = File(System.getProperty("java.home"))
put(JVMConfigurationKeys.JDK_HOME, javaHome)
javaHome to PathUtil.getJdkClassesRootsFromCurrentJre()
} else {
jdkHome to PathUtil.getJdkClassesRoots(jdkHome)
}
if (!CoreJrtFileSystem.isModularJdk(javaRoot)) {
if (classesRoots.isEmpty()) {
report(ERROR, "No class roots are found in the JDK path: $javaRoot")
} else {
addJvmSdkRoots(classesRoots)
}
}
}
}
}

View File

@@ -1,146 +0,0 @@
/*
* 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.psi;
import com.intellij.extapi.psi.StubBasedPsiElementBase;
import com.intellij.lang.ASTNode;
import com.intellij.lang.Language;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.psi.stubs.IStubElementType;
import com.intellij.psi.stubs.StubElement;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.KotlinLanguage;
import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementType;
import java.util.Arrays;
import java.util.List;
public class KtElementImplStub<T extends StubElement<?>> extends StubBasedPsiElementBase<T>
implements KtElement, StubBasedPsiElement<T> {
public KtElementImplStub(@NotNull T stub, @NotNull IStubElementType nodeType) {
super(stub, nodeType);
}
public KtElementImplStub(@NotNull ASTNode node) {
super(node);
}
@NotNull
@Override
public Language getLanguage() {
return KotlinLanguage.INSTANCE;
}
@Override
public String toString() {
return getElementType().toString();
}
@Override
@SuppressWarnings("unchecked")
public final void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof KtVisitor) {
accept((KtVisitor) visitor, null);
}
else {
visitor.visitElement(this);
}
}
@NotNull
@Override
public KtFile getContainingKtFile() {
PsiFile file = getContainingFile();
if (!(file instanceof KtFile)) {
// KtElementImpl.copy() might be the reason for this exception
String fileString = "";
if (file.isValid()) {
try {
fileString = " " + file.getText();
}
catch (Exception e) {
// ignore when failed to get file text
}
}
// getNode() will fail if getContainingFile() returns not PsiFileImpl instance
String nodeString = (file instanceof PsiFileImpl ? (" node = " + getNode()) : "");
throw new IllegalStateException("KtElement not inside KtFile: " +
file + fileString + " of type " + file.getClass() +
" for element " + this + " of type " + this.getClass() + nodeString);
}
return (KtFile) file;
}
@Override
public <D> void acceptChildren(@NotNull KtVisitor<Void, D> visitor, D data) {
PsiElement child = getFirstChild();
while (child != null) {
if (child instanceof KtElement) {
((KtElement) child).accept(visitor, data);
}
child = child.getNextSibling();
}
}
@Override
public <R, D> R accept(@NotNull KtVisitor<R, D> visitor, D data) {
return visitor.visitKtElement(this, data);
}
@Override
public void delete() throws IncorrectOperationException {
KtElementUtilsKt.deleteSemicolon(this);
super.delete();
}
@Override
@SuppressWarnings("deprecation")
public PsiReference getReference() {
PsiReference[] references = getReferences();
if (references.length == 1) return references[0];
else return null;
}
@NotNull
@Override
public PsiReference[] getReferences() {
return KotlinReferenceProvidersService.getReferencesFromProviders(this);
}
@NotNull
protected <PsiT extends KtElementImplStub<?>, StubT extends StubElement> List<PsiT> getStubOrPsiChildrenAsList(
@NotNull KtStubElementType<StubT, PsiT> elementType
) {
return Arrays.asList(getStubOrPsiChildren(elementType, elementType.getArrayFactory()));
}
@NotNull
@Override
public KtElement getPsiOrParent() {
return this;
}
@Override
public PsiElement getParent() {
PsiElement substitute = KtPsiUtilKt.getParentSubstitute(this);
return substitute != null ? substitute : super.getParent();
}
}

View File

@@ -1,46 +0,0 @@
/*
* 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.psi.stubs.elements
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import com.intellij.psi.stubs.StubInputStream
import com.intellij.psi.stubs.StubOutputStream
import com.intellij.util.io.StringRef
import org.jetbrains.kotlin.psi.KtAnnotationUseSiteTarget
import org.jetbrains.kotlin.psi.stubs.KotlinAnnotationUseSiteTargetStub
import org.jetbrains.kotlin.psi.stubs.impl.KotlinAnnotationUseSiteTargetStubImpl
class KtAnnotationUseSiteTargetElementType(debugName: String) :
KtStubElementType<KotlinAnnotationUseSiteTargetStub, KtAnnotationUseSiteTarget>(
debugName, KtAnnotationUseSiteTarget::class.java, KotlinAnnotationUseSiteTargetStub::class.java
) {
override fun createStub(psi: KtAnnotationUseSiteTarget, parentStub: StubElement<PsiElement>): KotlinAnnotationUseSiteTargetStub {
val useSiteTarget = psi.getAnnotationUseSiteTarget().name
return KotlinAnnotationUseSiteTargetStubImpl(parentStub, StringRef.fromString(useSiteTarget)!!)
}
override fun serialize(stub: KotlinAnnotationUseSiteTargetStub, dataStream: StubOutputStream) {
dataStream.writeName(stub.getUseSiteTarget())
}
override fun deserialize(dataStream: StubInputStream, parentStub: StubElement<PsiElement>): KotlinAnnotationUseSiteTargetStub {
val useSiteTarget = dataStream.readName()
return KotlinAnnotationUseSiteTargetStubImpl(parentStub, useSiteTarget!!)
}
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.psi.stubs.elements
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import com.intellij.psi.stubs.StubInputStream
import com.intellij.psi.stubs.StubOutputStream
import org.jetbrains.kotlin.psi.KtContractEffect
import org.jetbrains.kotlin.psi.stubs.KotlinContractEffectStub
import org.jetbrains.kotlin.psi.stubs.impl.KotlinContractEffectStubImpl
class KtContractEffectElementType(debugName: String, psiClass: Class<KtContractEffect>) :
KtStubElementType<KotlinContractEffectStub, KtContractEffect>(debugName, psiClass, KotlinContractEffectStub::class.java) {
override fun serialize(stub: KotlinContractEffectStub, dataStream: StubOutputStream) {
}
override fun deserialize(dataStream: StubInputStream, parentStub: StubElement<PsiElement>?): KotlinContractEffectStub {
return KotlinContractEffectStubImpl(parentStub, this)
}
override fun createStub(psi: KtContractEffect, parentStub: StubElement<PsiElement>?): KotlinContractEffectStub {
return KotlinContractEffectStubImpl(parentStub, this)
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright 2010-2017 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.psi.stubs.elements
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import com.intellij.psi.stubs.StubInputStream
import com.intellij.psi.stubs.StubOutputStream
import com.intellij.util.io.StringRef
import org.jetbrains.kotlin.psi.KtImportAlias
import org.jetbrains.kotlin.psi.stubs.KotlinImportAliasStub
import org.jetbrains.kotlin.psi.stubs.impl.KotlinImportAliasStubImpl
class KtImportAliasElementType(debugName: String) :
KtStubElementType<KotlinImportAliasStub, KtImportAlias>(debugName, KtImportAlias::class.java, KotlinImportAliasStub::class.java) {
override fun createStub(psi: KtImportAlias, parentStub: StubElement<PsiElement>?): KotlinImportAliasStub {
return KotlinImportAliasStubImpl(parentStub, StringRef.fromString(psi.name))
}
override fun serialize(stub: KotlinImportAliasStub, dataStream: StubOutputStream) {
dataStream.writeName(stub.getName())
}
override fun deserialize(dataStream: StubInputStream, parentStub: StubElement<PsiElement>?): KotlinImportAliasStub {
val name = dataStream.readName()
return KotlinImportAliasStubImpl(parentStub, name)
}
}

View File

@@ -1,55 +0,0 @@
/*
* 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.psi.stubs.elements;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.stubs.StubInputStream;
import com.intellij.psi.stubs.StubOutputStream;
import com.intellij.util.io.DataInputOutputUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.psi.KtModifierList;
import org.jetbrains.kotlin.psi.stubs.KotlinModifierListStub;
import org.jetbrains.kotlin.psi.stubs.impl.KotlinModifierListStubImpl;
import java.io.IOException;
import static org.jetbrains.kotlin.psi.stubs.impl.ModifierMaskUtils.computeMaskFromModifierList;
public class KtModifierListElementType<T extends KtModifierList> extends KtStubElementType<KotlinModifierListStub, T> {
public KtModifierListElementType(@NotNull @NonNls String debugName, @NotNull Class<T> psiClass) {
super(debugName, psiClass, KotlinModifierListStub.class);
}
@Override
public KotlinModifierListStub createStub(@NotNull T psi, StubElement parentStub) {
return new KotlinModifierListStubImpl(parentStub, computeMaskFromModifierList(psi), this);
}
@Override
public void serialize(@NotNull KotlinModifierListStub stub, @NotNull StubOutputStream dataStream) throws IOException {
long mask = ((KotlinModifierListStubImpl) stub).getMask();
DataInputOutputUtil.writeLONG(dataStream, mask);
}
@NotNull
@Override
public KotlinModifierListStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
long mask = DataInputOutputUtil.readLONG(dataStream);
return new KotlinModifierListStubImpl(parentStub, mask, this);
}
}

View File

@@ -1,51 +0,0 @@
/*
* 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.psi.stubs.elements;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.stubs.StubInputStream;
import com.intellij.psi.stubs.StubOutputStream;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.psi.KtElementImplStub;
import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub;
import org.jetbrains.kotlin.psi.stubs.impl.KotlinPlaceHolderStubImpl;
import java.io.IOException;
public class KtPlaceHolderStubElementType<T extends KtElementImplStub<? extends StubElement<?>>> extends
KtStubElementType<KotlinPlaceHolderStub<T>, T> {
public KtPlaceHolderStubElementType(@NotNull @NonNls String debugName, @NotNull Class<T> psiClass) {
super(debugName, psiClass, KotlinPlaceHolderStub.class);
}
@Override
public KotlinPlaceHolderStub<T> createStub(@NotNull T psi, StubElement parentStub) {
return new KotlinPlaceHolderStubImpl<>(parentStub, this);
}
@Override
public void serialize(@NotNull KotlinPlaceHolderStub<T> stub, @NotNull StubOutputStream dataStream) throws IOException {
//do nothing
}
@NotNull
@Override
public KotlinPlaceHolderStub<T> deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
return new KotlinPlaceHolderStubImpl<>(parentStub, this);
}
}

View File

@@ -1,50 +0,0 @@
/*
* 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.psi.stubs.elements
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.IndexSink
import com.intellij.psi.stubs.StubElement
import com.intellij.psi.stubs.StubInputStream
import com.intellij.psi.stubs.StubOutputStream
import com.intellij.util.io.StringRef
import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.psi.stubs.KotlinScriptStub
import org.jetbrains.kotlin.psi.stubs.impl.KotlinScriptStubImpl
class KtScriptElementType(debugName: String) : KtStubElementType<KotlinScriptStub, KtScript>(
debugName, KtScript::class.java, KotlinScriptStub::class.java
) {
override fun createStub(psi: KtScript, parentStub: StubElement<PsiElement>): KotlinScriptStub {
return KotlinScriptStubImpl(parentStub, StringRef.fromString(psi.fqName.asString()))
}
override fun serialize(stub: KotlinScriptStub, dataStream: StubOutputStream) {
dataStream.writeName(stub.getFqName().asString())
}
override fun deserialize(dataStream: StubInputStream, parentStub: StubElement<PsiElement>): KotlinScriptStub {
val fqName = dataStream.readName()
return KotlinScriptStubImpl(parentStub, fqName)
}
override fun indexStub(stub: KotlinScriptStub, sink: IndexSink) {
StubIndexService.getInstance().indexScript(stub, sink)
}
}

View File

@@ -1,119 +0,0 @@
/*
* 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.psi.stubs.elements;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.stubs.IStubElementType;
import com.intellij.psi.stubs.IndexSink;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.IStubFileElementType;
import com.intellij.util.ArrayFactory;
import com.intellij.util.ReflectionUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.KotlinLanguage;
import org.jetbrains.kotlin.psi.KtClassOrObject;
import org.jetbrains.kotlin.psi.KtElementImplStub;
import org.jetbrains.kotlin.psi.KtFunction;
import org.jetbrains.kotlin.psi.KtProperty;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
public abstract class KtStubElementType<StubT extends StubElement, PsiT extends KtElementImplStub<?>> extends IStubElementType<StubT, PsiT> {
@NotNull
private final Constructor<PsiT> byNodeConstructor;
@NotNull
private final Constructor<PsiT> byStubConstructor;
@NotNull
private final PsiT[] emptyArray;
@NotNull
private final ArrayFactory<PsiT> arrayFactory;
@SuppressWarnings("unchecked")
public KtStubElementType(@NotNull @NonNls String debugName, @NotNull Class<PsiT> psiClass, @NotNull Class<?> stubClass) {
super(debugName, KotlinLanguage.INSTANCE);
try {
byNodeConstructor = psiClass.getConstructor(ASTNode.class);
byStubConstructor = psiClass.getConstructor(stubClass);
}
catch (NoSuchMethodException e) {
throw new RuntimeException("Stub element type declaration for " + psiClass.getSimpleName() + " is missing required constructors",e);
}
emptyArray = (PsiT[]) Array.newInstance(psiClass, 0);
arrayFactory = count -> {
if (count == 0) {
return emptyArray;
}
return (PsiT[]) Array.newInstance(psiClass, count);
};
}
@NotNull
public PsiT createPsiFromAst(@NotNull ASTNode node) {
return ReflectionUtil.createInstance(byNodeConstructor, node);
}
@Override
@NotNull
public PsiT createPsi(@NotNull StubT stub) {
return ReflectionUtil.createInstance(byStubConstructor, stub);
}
@NotNull
@Override
public String getExternalId() {
return "kotlin." + toString();
}
@Override
public boolean shouldCreateStub(ASTNode node) {
PsiElement psi = node.getPsi();
if (psi instanceof KtClassOrObject || psi instanceof KtFunction) {
return true;
}
if (psi instanceof KtProperty) {
return !((KtProperty) psi).isLocal();
}
return createStubDependingOnParent(node);
}
private static boolean createStubDependingOnParent(ASTNode node) {
ASTNode parent = node.getTreeParent();
IElementType parentType = parent.getElementType();
if (parentType instanceof IStubElementType) {
return ((IStubElementType) parentType).shouldCreateStub(parent);
}
if (parentType instanceof IStubFileElementType) {
return true;
}
return false;
}
@Override
public void indexStub(@NotNull StubT stub, @NotNull IndexSink sink) {
// do not force inheritors to implement this method
}
@NotNull
public ArrayFactory<PsiT> getArrayFactory() {
return arrayFactory;
}
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.psi.stubs.elements
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import com.intellij.psi.stubs.StubInputStream
import com.intellij.psi.stubs.StubOutputStream
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.psi.stubs.KotlinValueArgumentStub
import org.jetbrains.kotlin.psi.stubs.impl.KotlinValueArgumentStubImpl
class KtValueArgumentElementType<T : KtValueArgument>(debugName: String, psiClass: Class<T>) :
KtStubElementType<KotlinValueArgumentStub<T>, T>(debugName, psiClass, KotlinValueArgumentStub::class.java) {
override fun createStub(psi: T, parentStub: StubElement<PsiElement>?): KotlinValueArgumentStub<T> {
return KotlinValueArgumentStubImpl(parentStub, this, psi.isSpread)
}
override fun serialize(stub: KotlinValueArgumentStub<T>, dataStream: StubOutputStream) {
dataStream.writeBoolean(stub.isSpread())
}
override fun deserialize(dataStream: StubInputStream, parentStub: StubElement<PsiElement>?): KotlinValueArgumentStub<T> {
val isSpread = dataStream.readBoolean()
return KotlinValueArgumentStubImpl(parentStub, this, isSpread)
}
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright 2010-2017 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.psi.stubs.impl
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import com.intellij.util.io.StringRef
import org.jetbrains.kotlin.psi.KtImportAlias
import org.jetbrains.kotlin.psi.stubs.KotlinImportAliasStub
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
class KotlinImportAliasStubImpl(
parent: StubElement<PsiElement>?,
private val name: StringRef?
) : KotlinStubBaseImpl<KtImportAlias>(parent, KtStubElementTypes.IMPORT_ALIAS), KotlinImportAliasStub {
override fun getName(): String? = StringRef.toString(name)
}

View File

@@ -88,7 +88,6 @@ public class JUnit3RunnerWithInnersForJPS extends Runner implements Filterable,
*/
private static void ensureCompilerExtensionFilesExists() {
copyCompilerResourceFile("compiler.xml");
copyCompilerResourceFile("core.xml");
}
private static void copyCompilerResourceFile(String fileName) {

View File

@@ -1,184 +0,0 @@
/*
* 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.test;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.junit.internal.MethodSorter;
import org.junit.internal.runners.JUnit38ClassRunner;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.manipulation.*;
import org.junit.runner.notification.RunNotifier;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static org.jetbrains.kotlin.test.JUnit3RunnerWithInners.isTestMethod;
/**
* This runner runs class with all inners test classes, but monitors situation when those classes are planned to be executed
* with IDEA package test runner.
*/
public class JUnit3RunnerWithInnersForJPS extends Runner implements Filterable, Sortable {
private static final Set<Class> requestedRunners = new HashSet<>();
private JUnit38ClassRunner delegateRunner;
private final Class<?> klass;
private boolean isFakeTest = false;
public JUnit3RunnerWithInnersForJPS(Class<?> klass) {
this.klass = klass;
requestedRunners.add(klass);
ensureCompilerExtensionFilesExists();
}
@Override
public void run(RunNotifier notifier) {
initialize();
delegateRunner.run(notifier);
}
@Override
public Description getDescription() {
initialize();
return isFakeTest ? Description.EMPTY : delegateRunner.getDescription();
}
@Override
public void filter(Filter filter) throws NoTestsRemainException {
initialize();
delegateRunner.filter(filter);
}
@Override
public void sort(Sorter sorter) {
initialize();
delegateRunner.sort(sorter);
}
protected void initialize() {
if (delegateRunner != null) return;
delegateRunner = new JUnit38ClassRunner(getCollectedTests());
}
/**
* compiler.xml needs to be in both compiler & ide module for tests execution.
* To avoid file duplication copy it to the out dir idea module before test execution.
*/
private static void ensureCompilerExtensionFilesExists() {
copyCompilerResourceFile("compiler.xml");
copyCompilerResourceFile("core.xml");
}
private static void copyCompilerResourceFile(String fileName) {
String compilerXmlSourcePath = "compiler/cli/cli-common/resources/META-INF/extensions/" + fileName;
String jpsTargetDirectory = "out/production/kotlin.idea.main";
String pillTargetDirectory = "out/production/idea.main";
String baseDir = Files.exists(Paths.get(jpsTargetDirectory)) ? jpsTargetDirectory : pillTargetDirectory;
String compilerXmlTargetPath = baseDir + "/META-INF/extensions/" + fileName;
try {
Path targetPath = Paths.get(compilerXmlTargetPath);
Files.createDirectories(targetPath.getParent());
Files.copy(Paths.get(compilerXmlSourcePath),targetPath, REPLACE_EXISTING);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
private Test getCollectedTests() {
List<Class> innerClasses = collectDeclaredClasses(klass, false);
Set<Class> unprocessedInnerClasses = unprocessedClasses(innerClasses);
if (unprocessedInnerClasses.isEmpty()) {
if (!innerClasses.isEmpty() && !hasTestMethods(klass)) {
isFakeTest = true;
return new JUnit3RunnerWithInners.FakeEmptyClassTest(klass);
}
else {
return new TestSuite(klass.asSubclass(TestCase.class));
}
}
else if (unprocessedInnerClasses.size() == innerClasses.size()) {
return createTreeTestSuite(klass);
}
else {
return new TestSuite(klass.asSubclass(TestCase.class));
}
}
private static Test createTreeTestSuite(Class root) {
Set<Class> classes = new LinkedHashSet<>(collectDeclaredClasses(root, true));
Map<Class, TestSuite> classSuites = new HashMap<>();
for (Class aClass : classes) {
classSuites.put(aClass, hasTestMethods(aClass) ? new TestSuite(aClass) : new TestSuite(aClass.getCanonicalName()));
}
for (Class aClass : classes) {
if (aClass.getEnclosingClass() != null && classes.contains(aClass.getEnclosingClass())) {
classSuites.get(aClass.getEnclosingClass()).addTest(classSuites.get(aClass));
}
}
return classSuites.get(root);
}
private static Set<Class> unprocessedClasses(Collection<Class> classes) {
Set<Class> result = new LinkedHashSet<>();
for (Class aClass : classes) {
if (!requestedRunners.contains(aClass)) {
result.add(aClass);
}
}
return result;
}
private static List<Class> collectDeclaredClasses(Class klass, boolean withItself) {
List<Class> result = new ArrayList<>();
if (withItself) {
result.add(klass);
}
for (Class aClass : klass.getDeclaredClasses()) {
result.addAll(collectDeclaredClasses(aClass, true));
}
return result;
}
private static boolean hasTestMethods(Class klass) {
for (Class currentClass = klass; Test.class.isAssignableFrom(currentClass); currentClass = currentClass.getSuperclass()) {
for (Method each : MethodSorter.getDeclaredMethods(currentClass)) {
if (isTestMethod(each)) return true;
}
}
return false;
}
}

View File

@@ -1,42 +0,0 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
sourceSets {
"main" { java.srcDirs("main") }
"test" { projectDefault() }
}
dependencies {
compile(kotlinStdlib("jdk8"))
testCompile(projectTests(":idea:idea-maven"))
testCompile(projectTests(":idea:idea-fir"))
testCompile(projectTests(":idea:idea-fir-performance-tests"))
testCompile(projectTests(":idea-frontend-fir"))
testCompile(projectTests(":idea-frontend-fir:idea-fir-low-level-api"))
testCompile(projectTests(":idea:idea-frontend-fir:fir-low-level-api-ide-impl"))
testCompile(projectTests(":idea:idea-fir-fe10-binding"))
testCompile(projectTests(":j2k"))
testCompile(projectTests(":nj2k"))
if (Ide.IJ()) {
testCompile(projectTests(":libraries:tools:new-project-wizard:new-project-wizard-cli"))
testCompile(projectTests(":idea:idea-new-project-wizard"))
}
testCompile(projectTests(":idea:performanceTests"))
testCompile(projectTests(":idea:scripting-support"))
testCompile(projectTests(":jps-plugin"))
testCompile(projectTests(":plugins:uast-kotlin"))
testCompile(projectTests(":plugins:uast-kotlin-fir"))
testCompile(projectTests(":idea:jvm-debugger:jvm-debugger-test"))
testCompile(projectTests(":idea"))
testCompile(projectTests(":idea:idea-android"))
testCompile(projectTests(":generators:test-generator"))
testCompile(projectTests(":plugins:parcelize:parcelize-ide"))
testCompile(projectTests(":kotlinx-serialization-ide-plugin"))
testCompile(projectTests(":compiler:tests-common"))
testCompile(projectTests(":compiler:tests-spec"))
testApiJUnit5()
}
val generateIdeaTests by generator("org.jetbrains.kotlin.generators.tests.idea.GenerateTestsKt")

View File

@@ -45,8 +45,11 @@ kotlin.stdlib.default.dependency=false
kotlin.internal.mpp12x.deprecation.suppress=true
kotlin.mpp.stability.nowarn=true
kotlin.2js.nowarn=true
kotlin.native.enabled=false
kotlin.native.enabled=true
kotlin.native.home=kotlin-native/dist
# org.gradle.dependency.verification=lenient
org.gradle.vfs.watch=true
disableKotlinPluginModules=true
org.gradle.unsafe.configuration-cache=true

View File

@@ -1,23 +0,0 @@
versions.intellijSdk=202.7660.26
versions.intellijSdk.forIde.202=202.7660.26
versions.intellijSdk.forIde.203=203.6682.168
versions.intellijSdk.forIde.211=211.7442.40
versions.idea.NodeJS=193.6494.7
versions.jar.asm-all=8.0.1
versions.jar.guava=29.0-jre
versions.jar.groovy=2.5.11
versions.jar.groovy-xml=2.5.11
versions.jar.lombok-ast=0.2.3
versions.jar.swingx-core=1.6.2-2
versions.jar.kxml2=2.3.0
versions.jar.streamex=0.7.2
versions.jar.gson=2.8.6
versions.jar.oro=2.0.8
versions.jar.picocontainer=1.2
versions.jar.serviceMessages=2019.1.4
versions.jar.lz4-java=1.7.1
ignore.jar.snappy-in-java=true
versions.gradle-api=4.5.1
versions.shadow=6.1.0
versions.junit-bom=5.7.0
versions.org.junit.platform=1.7.0

View File

@@ -1,23 +0,0 @@
versions.intellijSdk=202.6397.94
versions.idea.NodeJS=193.6494.7
versions.androidStudioRelease=4.2.0.16
versions.androidStudioBuild=202.6939830
versions.jar.asm-all=8.0.1
versions.jar.guava=29.0-jre
versions.jar.groovy=2.5.11
versions.jar.lombok-ast=0.2.3
versions.jar.swingx-core=1.6.2-2
versions.jar.kxml2=2.3.0
versions.jar.streamex=0.7.2
versions.jar.gson=2.8.6
versions.jar.oro=2.0.8
versions.jar.picocontainer=1.2
versions.jar.serviceMessages=2019.1.4
versions.jar.lz4-java=1.7.1
ignore.jar.snappy-in-java=true
versions.gradle-api=4.5.1
versions.shadow=6.1.0
ignore.jar.common=true
ignore.jar.lombok-ast=true
versions.junit-bom=5.7.0
versions.org.junit.platform=1.7.0

View File

@@ -1,3 +0,0 @@
This module exists for the sole purpose of providing the classpath for the IDEA run configuration.
This run configuration takes a plugin from the KotlinPlugin artifact instead of the project's 'out' directory, which makes it possible for our plugin to depend on other plugins such as JUnit plugin.
If you want to debug some patch to IDEA, you can add copy of IDEA class into this module and modify.

View File

@@ -1,23 +0,0 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compileOnly(project(":idea"))
compileOnly(project(":idea:idea-maven"))
compileOnly(project(":idea:idea-gradle"))
compileOnly(project(":idea:idea-jvm"))
runtimeOnly(intellijDep())
runtimeOnly(intellijRuntimeAnnotations())
runtimeOnly(toolsJar())
}
val ideaPluginDir: File by rootProject.extra
val ideaSandboxDir: File by rootProject.extra
runIdeTask("runIde", ideaPluginDir, ideaSandboxDir) {
dependsOn(":dist", ":ideaPlugin")
}

View File

@@ -1,225 +0,0 @@
import org.apache.tools.ant.filters.ReplaceTokens
plugins {
kotlin("jvm")
id("jps-compatible")
}
val kotlinVersion: String by rootProject.extra
sourceSets {
"main" {
projectDefault()
java.srcDirs(
"idea-completion/src",
"idea-live-templates/src",
"idea-repl/src"
)
resources.srcDirs(
"idea-completion/resources",
"idea-live-templates/resources",
"idea-repl/resources",
"resources-en"
)
if (kotlinBuildProperties.useFirIdeaPlugin) {
resources.srcDir("resources-fir")
} else {
resources.srcDir("resources-descriptors")
}
}
"test" {
projectDefault()
java.srcDirs(
"idea-completion/tests",
"idea-live-templates/tests"
)
}
}
dependencies {
testRuntime(intellijDep())
testRuntime(intellijRuntimeAnnotations())
compile(kotlinStdlib("jdk8"))
compileOnly(project(":kotlin-reflect-api"))
compile(project(":core:descriptors"))
compile(project(":core:descriptors.jvm"))
compile(project(":compiler:backend"))
compile(project(":compiler:frontend"))
compile(project(":compiler:frontend.common"))
compile(project(":compiler:frontend.java"))
compile(project(":compiler:ir.backend.common")) // TODO: fix import (workaround for jps build)
compile(project(":js:js.frontend"))
compile(project(":js:js.serializer"))
compile(project(":compiler:light-classes"))
compile(project(":compiler:util"))
compile(project(":kotlin-build-common"))
compile(project(":daemon-common"))
compile(project(":daemon-common-new"))
compile(projectRuntimeJar(":kotlin-daemon-client"))
compile(project(":compiler:plugin-api"))
compile(project(":idea:jvm-debugger:jvm-debugger-util"))
compile(project(":idea:jvm-debugger:jvm-debugger-core"))
compile(project(":idea:jvm-debugger:jvm-debugger-evaluation"))
compile(project(":idea:jvm-debugger:jvm-debugger-sequence"))
compile(project(":idea:jvm-debugger:jvm-debugger-coroutine"))
compile(project(":j2k"))
compile(project(":idea:idea-j2k"))
compile(project(":idea:formatter"))
compile(project(":compiler:fir:fir2ir"))
compile(project(":compiler:fir:resolve"))
compile(project(":compiler:fir:checkers"))
compile(project(":compiler:fir:checkers:checkers.jvm"))
compile(project(":compiler:fir:java"))
compile(project(":compiler:fir:jvm"))
compile(project(":idea:idea-core"))
compile(project(":idea:idea-frontend-independent"))
compile(project(":idea:ide-common"))
compile(project(":idea:idea-jps-common"))
compile(project(":idea:kotlin-gradle-tooling"))
compile(project(":idea:line-indent-provider"))
compile(project(":plugins:uast-kotlin-base"))
compile(project(":plugins:uast-kotlin"))
compile(project(":plugins:uast-kotlin-idea"))
compile(project(":plugins:uast-kotlin-idea-base"))
compile(project(":kotlin-script-util")) { isTransitive = false }
compile(project(":kotlin-scripting-intellij"))
compile(project(":compiler:backend.jvm")) // Do not delete, for Pill
compile(project(":compiler:backend.jvm:backend.jvm.entrypoint"))
compile(commonDep("org.jetbrains.kotlinx", "kotlinx-coroutines-core")) { isTransitive = false }
compileOnly(project(":kotlin-daemon-client"))
compileOnly(intellijDep())
compileOnly(intellijPluginDep("java"))
testCompileOnly(intellijPluginDep("java"))
testRuntime(intellijPluginDep("java"))
implementation(commonDep("org.jetbrains.intellij.deps.completion", "completion-ranking-kotlin"))
Ide.IJ {
implementation(intellijPluginDep("stats-collector"))
}
compileOnly(commonDep("org.jetbrains", "markdown"))
compileOnly(commonDep("com.google.code.findbugs", "jsr305"))
compileOnly(intellijPluginDep("IntelliLang"))
compileOnly(intellijPluginDep("copyright"))
compileOnly(intellijPluginDep("properties"))
compileOnly(intellijPluginDep("java-i18n"))
compileOnly(intellijPluginDep("gradle"))
testCompileOnly(toolsJar())
testCompileOnly(project(":kotlin-reflect-api")) // TODO: fix import (workaround for jps build)
testCompile(project(":kotlin-test:kotlin-test-junit"))
testCompile(projectTests(":compiler:tests-common"))
testCompile(projectTests(":idea:idea-test-framework")) { isTransitive = false }
testImplementation(projectTests(":idea:idea-frontend-independent")) { isTransitive = false }
testCompile(project(":idea:idea-jvm")) { isTransitive = false }
testCompile(project(":idea:idea-gradle")) { isTransitive = false }
testCompile(project(":idea:idea-maven")) { isTransitive = false }
testCompile(project(":idea:idea-native")) { isTransitive = false }
testCompile(project(":idea:idea-gradle-native")) { isTransitive = false }
testCompile(commonDep("junit:junit"))
testCompileOnly(intellijPluginDep("coverage"))
testRuntimeOnly(toolsJar())
testRuntime(commonDep("org.jetbrains", "markdown"))
testRuntime(project(":plugins:kapt3-idea")) { isTransitive = false }
testRuntime(project(":kotlin-reflect"))
testRuntime(project(":kotlin-preloader"))
testCompile(project(":kotlin-sam-with-receiver-compiler-plugin")) { isTransitive = false }
testRuntime(project(":plugins:android-extensions-compiler"))
testRuntimeOnly(project(":kotlin-android-extensions-runtime")) // TODO: fix import (workaround for jps build)
testRuntime(project(":plugins:android-extensions-ide")) { isTransitive = false }
testRuntime(project(":allopen-ide-plugin")) { isTransitive = false }
testRuntime(project(":kotlin-allopen-compiler-plugin"))
testRuntime(project(":noarg-ide-plugin")) { isTransitive = false }
testRuntime(project(":kotlin-noarg-compiler-plugin"))
testRuntime(project(":plugins:annotation-based-compiler-plugins-ide-support")) { isTransitive = false }
testRuntime(project(":plugins:base-compiler-plugins-ide-support")) { isTransitive = false }
testRuntime(project(":plugins:parcelize:parcelize-compiler"))
testRuntime(project(":plugins:parcelize:parcelize-ide")) { isTransitive = false }
testRuntime(project(":plugins:base-compiler-plugins-ide-support")) { isTransitive = false }
testRuntime(project(":plugins:lombok:lombok-compiler-plugin"))
testRuntime(project(":plugins:lombok:lombok-ide-plugin")) { isTransitive = false }
testRuntime(project(":kotlin-scripting-idea")) { isTransitive = false }
testRuntime(project(":kotlin-scripting-compiler-impl"))
testRuntime(project(":sam-with-receiver-ide-plugin")) { isTransitive = false }
testRuntime(project(":kotlinx-serialization-compiler-plugin"))
testRuntime(project(":kotlinx-serialization-ide-plugin")) { isTransitive = false }
testRuntime(project(":idea:idea-android")) { isTransitive = false }
testRuntime(project(":plugins:lint")) { isTransitive = false }
testRuntime(project(":plugins:uast-kotlin"))
testRuntime(project(":nj2k:nj2k-services")) { isTransitive = false }
(rootProject.extra["compilerModules"] as Array<String>).forEach {
testRuntime(project(it))
}
testCompile(intellijPluginDep("IntelliLang"))
testCompile(intellijPluginDep("copyright"))
testCompile(intellijPluginDep("properties"))
testCompile(intellijPluginDep("java-i18n"))
testCompile(intellijPluginDep("junit"))
testCompileOnly(intellijDep())
testCompileOnly(commonDep("com.google.code.findbugs", "jsr305"))
testCompileOnly(intellijPluginDep("gradle"))
testCompileOnly(intellijPluginDep("Groovy"))
if (Ide.IJ()) {
testCompileOnly(intellijPluginDep("maven"))
testRuntime(intellijPluginDep("maven"))
testRuntime(intellijPluginDep("repository-search"))
}
testRuntime(intellijPluginDep("junit"))
testRuntime(intellijPluginDep("gradle"))
testRuntime(intellijPluginDep("Groovy"))
testRuntime(intellijPluginDep("coverage"))
testRuntime(intellijPluginDep("android"))
testRuntime(intellijPluginDep("smali"))
testRuntime(intellijPluginDep("testng"))
if (kotlinBuildProperties.useFirIdeaPlugin) {
testRuntime(project(":idea:idea-fir"))
}
if (Ide.AS()) {
testRuntime(intellijPluginDep("android-layoutlib"))
testRuntime(intellijPluginDep("git4idea"))
testRuntime(intellijPluginDep("google-cloud-tools-core-as"))
testRuntime(intellijPluginDep("google-login-as"))
testRuntime(intellijPluginDep("platform-images"))
}
}
tasks.named<Copy>("processResources") {
val currentIde = IdeVersionConfigurator.currentIde
val pluginPatchNumber = findProperty("pluginPatchNumber") as String? ?: "1"
val defaultPluginVersion = "$kotlinVersion-${currentIde.displayVersion}-$pluginPatchNumber"
val pluginVersion = findProperty("pluginVersion") as String? ?: defaultPluginVersion
inputs.property("pluginVersion", pluginVersion)
filesMatching("META-INF/plugin.xml") {
filter<ReplaceTokens>("tokens" to mapOf("snapshot" to pluginVersion))
}
from(provider { project(":compiler:cli-common").mainSourceSet.resources }) {
include("META-INF/extensions/compiler.xml")
}
}
projectTest(parallel = true) {
dependsOn(":dist")
workingDir = rootDir
}
configureFormInstrumentation()
testsJar()

View File

@@ -1,18 +0,0 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compile(project(":compiler:util"))
compile(project(":compiler:frontend"))
compileOnly(intellijDep())
compileOnly(intellijPluginDep("java"))
}
sourceSets {
"main" { projectDefault() }
"test" {}
}

View File

@@ -1,196 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.core.formatter;
import com.intellij.application.options.CodeStyle;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.formatter.KotlinObsoleteCodeStyle;
import org.jetbrains.kotlin.idea.formatter.KotlinStyleGuideCodeStyle;
import org.jetbrains.kotlin.idea.util.FormatterUtilKt;
import org.jetbrains.kotlin.idea.util.ReflectionUtil;
import static com.intellij.util.ReflectionUtil.copyFields;
public class KotlinCodeStyleSettings extends CustomCodeStyleSettings {
public final KotlinPackageEntryTable PACKAGES_TO_USE_STAR_IMPORTS = new KotlinPackageEntryTable();
public final KotlinPackageEntryTable PACKAGES_IMPORT_LAYOUT = new KotlinPackageEntryTable();
public boolean SPACE_AROUND_RANGE = false;
public boolean SPACE_BEFORE_TYPE_COLON = false;
public boolean SPACE_AFTER_TYPE_COLON = true;
public boolean SPACE_BEFORE_EXTEND_COLON = true;
public boolean SPACE_AFTER_EXTEND_COLON = true;
public boolean INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD = true;
public boolean ALIGN_IN_COLUMNS_CASE_BRANCH = false;
public boolean SPACE_AROUND_FUNCTION_TYPE_ARROW = true;
public boolean SPACE_AROUND_WHEN_ARROW = true;
public boolean SPACE_BEFORE_LAMBDA_ARROW = true;
public boolean SPACE_BEFORE_WHEN_PARENTHESES = true;
public boolean LBRACE_ON_NEXT_LINE = false;
public int NAME_COUNT_TO_USE_STAR_IMPORT = ApplicationManager.getApplication().isUnitTestMode() ? Integer.MAX_VALUE : 5;
public int NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS = ApplicationManager.getApplication().isUnitTestMode() ? Integer.MAX_VALUE : 3;
public boolean IMPORT_NESTED_CLASSES = false;
public boolean CONTINUATION_INDENT_IN_PARAMETER_LISTS = true;
public boolean CONTINUATION_INDENT_IN_ARGUMENT_LISTS = true;
public boolean CONTINUATION_INDENT_FOR_EXPRESSION_BODIES = true;
public boolean CONTINUATION_INDENT_FOR_CHAINED_CALLS = true;
public boolean CONTINUATION_INDENT_IN_SUPERTYPE_LISTS = true;
public boolean CONTINUATION_INDENT_IN_IF_CONDITIONS = true;
public boolean CONTINUATION_INDENT_IN_ELVIS = true;
public int BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES = 0;
public int WRAP_EXPRESSION_BODY_FUNCTIONS = 0;
public int WRAP_ELVIS_EXPRESSIONS = 1;
public boolean IF_RPAREN_ON_NEW_LINE = false;
public boolean ALLOW_TRAILING_COMMA = false;
public boolean ALLOW_TRAILING_COMMA_ON_CALL_SITE = false;
public int BLANK_LINES_BEFORE_DECLARATION_WITH_COMMENT_OR_ANNOTATION_ON_SEPARATE_LINE = 1;
@ReflectionUtil.SkipInEquals
public String CODE_STYLE_DEFAULTS = null;
/**
* Load settings with previous IDEA defaults to have an ability to restore them.
*/
@Nullable
private KotlinCodeStyleSettings settingsAgainstPreviousDefaults = null;
private final boolean isTempForDeserialize;
public KotlinCodeStyleSettings(CodeStyleSettings container) {
this(container, false);
}
private KotlinCodeStyleSettings(CodeStyleSettings container, boolean isTempForDeserialize) {
super("JetCodeStyleSettings", container);
this.isTempForDeserialize = isTempForDeserialize;
// defaults in IDE but not in tests
if (!ApplicationManager.getApplication().isUnitTestMode()) {
PACKAGES_TO_USE_STAR_IMPORTS.addEntry(new KotlinPackageEntry("java.util", false));
PACKAGES_TO_USE_STAR_IMPORTS.addEntry(new KotlinPackageEntry("kotlinx.android.synthetic", true));
PACKAGES_TO_USE_STAR_IMPORTS.addEntry(new KotlinPackageEntry("io.ktor", true));
}
// Many of test data actually depend on this order of imports,
// that is why we put it here even for test mode
PACKAGES_IMPORT_LAYOUT.addEntry(KotlinPackageEntry.ALL_OTHER_IMPORTS_ENTRY);
PACKAGES_IMPORT_LAYOUT.addEntry(new KotlinPackageEntry("java", true));
PACKAGES_IMPORT_LAYOUT.addEntry(new KotlinPackageEntry("javax", true));
PACKAGES_IMPORT_LAYOUT.addEntry(new KotlinPackageEntry("kotlin", true));
PACKAGES_IMPORT_LAYOUT.addEntry(KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY);
}
public static KotlinCodeStyleSettings getInstance(Project project) {
return CodeStyle.getSettings(project).getCustomSettings(KotlinCodeStyleSettings.class);
}
@SuppressWarnings("MethodDoesntCallSuperMethod")
@Override
public Object clone() {
return cloneSettings();
}
@NotNull
public KotlinCodeStyleSettings cloneSettings() {
KotlinCodeStyleSettings clone = new KotlinCodeStyleSettings(getContainer());
clone.copyFrom(this);
clone.settingsAgainstPreviousDefaults = this.settingsAgainstPreviousDefaults;
return clone;
}
private void copyFrom(@NotNull KotlinCodeStyleSettings from) {
copyFields(getClass().getFields(), from, this);
PACKAGES_TO_USE_STAR_IMPORTS.copyFrom(from.PACKAGES_TO_USE_STAR_IMPORTS);
PACKAGES_IMPORT_LAYOUT.copyFrom(from.PACKAGES_IMPORT_LAYOUT);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof KotlinCodeStyleSettings)) return false;
if (!ReflectionUtil.comparePublicNonFinalFieldsWithSkip(this, obj)) return false;
return true;
}
@Override
public void writeExternal(Element parentElement, @NotNull CustomCodeStyleSettings parentSettings) throws WriteExternalException {
if (CODE_STYLE_DEFAULTS != null) {
KotlinCodeStyleSettings defaultKotlinCodeStyle = (KotlinCodeStyleSettings) parentSettings.clone();
if (KotlinStyleGuideCodeStyle.CODE_STYLE_ID.equals(CODE_STYLE_DEFAULTS)) {
KotlinStyleGuideCodeStyle.Companion.applyToKotlinCustomSettings(defaultKotlinCodeStyle, false);
}
else if (KotlinObsoleteCodeStyle.CODE_STYLE_ID.equals(CODE_STYLE_DEFAULTS)) {
KotlinObsoleteCodeStyle.Companion.applyToKotlinCustomSettings(defaultKotlinCodeStyle, false);
}
parentSettings = defaultKotlinCodeStyle;
}
super.writeExternal(parentElement, parentSettings);
}
@Override
public void readExternal(Element parentElement) throws InvalidDataException {
if (isTempForDeserialize) {
super.readExternal(parentElement);
return;
}
KotlinCodeStyleSettings tempSettings = readExternalToTemp(parentElement);
String customDefaults = tempSettings.CODE_STYLE_DEFAULTS;
if (KotlinStyleGuideCodeStyle.CODE_STYLE_ID.equals(customDefaults)) {
KotlinStyleGuideCodeStyle.Companion.applyToKotlinCustomSettings(this, true);
}
else if (KotlinObsoleteCodeStyle.CODE_STYLE_ID.equals(customDefaults)) {
KotlinObsoleteCodeStyle.Companion.applyToKotlinCustomSettings(this, true);
}
else if (customDefaults == null && FormatterUtilKt.isDefaultOfficialCodeStyle()) {
// Temporary load settings against previous defaults
settingsAgainstPreviousDefaults = new KotlinCodeStyleSettings(null, true);
KotlinObsoleteCodeStyle.Companion.applyToKotlinCustomSettings(settingsAgainstPreviousDefaults, true);
settingsAgainstPreviousDefaults.readExternal(parentElement);
}
// Actual read
super.readExternal(parentElement);
}
private static KotlinCodeStyleSettings readExternalToTemp(Element parentElement) {
// Read to temp
KotlinCodeStyleSettings tempSettings = new KotlinCodeStyleSettings(null, true);
tempSettings.readExternal(parentElement);
return tempSettings;
}
public boolean canRestore() {
return settingsAgainstPreviousDefaults != null;
}
public void restore() {
if (settingsAgainstPreviousDefaults != null) {
copyFrom(settingsAgainstPreviousDefaults);
}
}
public static KotlinCodeStyleSettings defaultSettings() {
return ServiceManager.getService(KotlinCodeStyleSettingsHolder.class).defaultSettings;
}
public static final class KotlinCodeStyleSettingsHolder {
private final KotlinCodeStyleSettings defaultSettings = new KotlinCodeStyleSettings(new CodeStyleSettings());
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.core.formatter
import com.intellij.openapi.application.ApplicationBundle
class KotlinPackageEntry(
packageName: String,
val withSubpackages: Boolean
) {
val packageName = packageName.removeSuffix(".*")
companion object {
@JvmField
val ALL_OTHER_IMPORTS_ENTRY =
KotlinPackageEntry(ApplicationBundle.message("listbox.import.all.other.imports"), withSubpackages = true)
@JvmField
val ALL_OTHER_ALIAS_IMPORTS_ENTRY = KotlinPackageEntry("<all other alias imports>", withSubpackages = true)
}
fun matchesPackageName(otherPackageName: String): Boolean {
if (otherPackageName.startsWith(packageName)) {
if (otherPackageName.length == packageName.length) return true
if (withSubpackages) {
if (otherPackageName[packageName.length] == '.') return true
}
}
return false
}
val isSpecial: Boolean get() = this == ALL_OTHER_IMPORTS_ENTRY || this == ALL_OTHER_ALIAS_IMPORTS_ENTRY
override fun toString(): String {
return packageName
}
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.core.formatter
import com.intellij.openapi.util.InvalidDataException
import com.intellij.openapi.util.JDOMExternalizable
import org.jdom.Element
class KotlinPackageEntryTable : JDOMExternalizable, Cloneable {
private val entries = mutableListOf<KotlinPackageEntry>()
val entryCount: Int get() = entries.size
public override fun clone(): KotlinPackageEntryTable {
val clone = KotlinPackageEntryTable()
clone.copyFrom(this)
return clone
}
fun copyFrom(packageTable: KotlinPackageEntryTable) {
entries.clear()
entries.addAll(packageTable.entries)
}
fun getEntries(): Array<KotlinPackageEntry> {
return entries.toTypedArray()
}
fun insertEntryAt(entry: KotlinPackageEntry, index: Int) {
entries.add(index, entry)
}
fun removeEntryAt(index: Int) {
entries.removeAt(index)
}
fun getEntryAt(index: Int): KotlinPackageEntry {
return entries[index]
}
fun setEntryAt(entry: KotlinPackageEntry, index: Int) {
entries[index] = entry
}
operator fun contains(packageName: String): Boolean {
return entries.any { !it.isSpecial && it.matchesPackageName(packageName) }
}
fun removeEmptyPackages() {
entries.removeAll { it.packageName.isBlank() }
}
fun addEntry(entry: KotlinPackageEntry) {
entries.add(entry)
}
override fun readExternal(element: Element) {
entries.clear()
element.children.forEach {
if (it.name == "package") {
val packageName = it.getAttributeValue("name") ?: throw InvalidDataException()
val alias = it.getAttributeValue("alias")?.toBoolean() ?: false
val withSubpackages = it.getAttributeValue("withSubpackages")?.toBoolean() ?: false
val entry = when {
packageName.isEmpty() && !alias -> KotlinPackageEntry.ALL_OTHER_IMPORTS_ENTRY
packageName.isEmpty() && alias -> KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY
else -> KotlinPackageEntry(packageName, withSubpackages)
}
entries.add(entry)
}
}
}
override fun writeExternal(parentNode: Element) {
for (entry in entries) {
val element = Element("package")
parentNode.addContent(element)
val name = if (entry.isSpecial) "" else entry.packageName
val alias = (entry == KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY)
element.setAttribute("name", name)
element.setAttribute("alias", alias.toString())
element.setAttribute("withSubpackages", entry.withSubpackages.toString())
}
}
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright 2010-2016 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.formatter
import com.intellij.formatting.Alignment
import com.intellij.lang.ASTNode
abstract class CommonAlignmentStrategy {
abstract fun getAlignment(node: ASTNode): Alignment?
}

View File

@@ -1,273 +0,0 @@
/*
* Copyright 2000-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter;
import com.intellij.lang.Language;
import com.intellij.openapi.util.DefaultJDOMExternalizer;
import com.intellij.openapi.util.DifferenceFilter;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
import com.intellij.psi.codeStyle.arrangement.ArrangementSettings;
import com.intellij.psi.codeStyle.arrangement.ArrangementUtil;
import com.intellij.util.xmlb.XmlSerializer;
import kotlin.collections.ArraysKt;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.KotlinLanguage;
import org.jetbrains.kotlin.idea.util.FormatterUtilKt;
import org.jetbrains.kotlin.idea.util.ReflectionUtil;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
@SuppressWarnings("UnnecessaryFinalOnLocalVariableOrParameter")
public class KotlinCommonCodeStyleSettings extends CommonCodeStyleSettings {
@ReflectionUtil.SkipInEquals
public String CODE_STYLE_DEFAULTS = null;
/**
* Load settings with previous IDEA defaults to have an ability to restore them.
*/
@Nullable
private KotlinCommonCodeStyleSettings settingsAgainstPreviousDefaults = null;
private final boolean isTempForDeserialize;
public KotlinCommonCodeStyleSettings() {
this(false);
}
private KotlinCommonCodeStyleSettings(boolean isTempForDeserialize) {
super(KotlinLanguage.INSTANCE);
this.isTempForDeserialize = isTempForDeserialize;
}
private static KotlinCommonCodeStyleSettings createForTempDeserialize() {
return new KotlinCommonCodeStyleSettings(true);
}
@Override
public void readExternal(Element element) throws InvalidDataException {
if (isTempForDeserialize) {
super.readExternal(element);
return;
}
KotlinCommonCodeStyleSettings tempDeserialize = createForTempDeserialize();
tempDeserialize.readExternal(element);
String customDefaults = tempDeserialize.CODE_STYLE_DEFAULTS;
if (KotlinStyleGuideCodeStyle.CODE_STYLE_ID.equals(customDefaults)) {
KotlinStyleGuideCodeStyle.Companion.applyToCommonSettings(this, true);
}
else if (KotlinObsoleteCodeStyle.CODE_STYLE_ID.equals(customDefaults)) {
KotlinObsoleteCodeStyle.Companion.applyToCommonSettings(this, true);
}
else if (customDefaults == null && FormatterUtilKt.isDefaultOfficialCodeStyle()) {
// Temporary load settings against previous defaults
settingsAgainstPreviousDefaults = createForTempDeserialize();
KotlinObsoleteCodeStyle.Companion.applyToCommonSettings(settingsAgainstPreviousDefaults, true);
settingsAgainstPreviousDefaults.readExternal(element);
}
readExternalBase(element);
}
@Override
public void writeExternal(Element element) throws WriteExternalException {
CommonCodeStyleSettings defaultSettings = getDefaultSettings();
if (defaultSettings != null) {
if (KotlinStyleGuideCodeStyle.CODE_STYLE_ID.equals(CODE_STYLE_DEFAULTS)) {
KotlinStyleGuideCodeStyle.Companion.applyToCommonSettings(defaultSettings, false);
}
else if (KotlinObsoleteCodeStyle.CODE_STYLE_ID.equals(CODE_STYLE_DEFAULTS)) {
KotlinObsoleteCodeStyle.Companion.applyToCommonSettings(defaultSettings, false);
}
}
writeExternalBase(element, defaultSettings);
}
//<editor-fold desc="Copied and adapted from CommonCodeStyleSettings ">
private void readExternalBase(Element element) throws InvalidDataException {
super.readExternal(element);
}
private void writeExternalBase(Element element, CommonCodeStyleSettings defaultSettings) throws WriteExternalException {
Set<String> supportedFields = getSupportedFields();
if (supportedFields != null) {
supportedFields.add("FORCE_REARRANGE_MODE");
supportedFields.add("CODE_STYLE_DEFAULTS");
}
//noinspection deprecation
DefaultJDOMExternalizer.writeExternal(this, element, new SupportedFieldsDiffFilter(this, supportedFields, defaultSettings));
List<Integer> softMargins = getSoftMargins();
serializeInto(softMargins, element);
IndentOptions myIndentOptions = getIndentOptions();
if (myIndentOptions != null) {
IndentOptions defaultIndentOptions = defaultSettings != null ? defaultSettings.getIndentOptions() : null;
Element indentOptionsElement = new Element(INDENT_OPTIONS_TAG);
myIndentOptions.serialize(indentOptionsElement, defaultIndentOptions);
if (!indentOptionsElement.getChildren().isEmpty()) {
element.addContent(indentOptionsElement);
}
}
ArrangementSettings myArrangementSettings = getArrangementSettings();
if (myArrangementSettings != null) {
Element container = new Element(ARRANGEMENT_ELEMENT_NAME);
ArrangementUtil.writeExternal(container, myArrangementSettings, myLanguage);
if (!container.getChildren().isEmpty()) {
element.addContent(container);
}
}
}
@Override
public CommonCodeStyleSettings clone(@NotNull CodeStyleSettings rootSettings) {
KotlinCommonCodeStyleSettings commonSettings = new KotlinCommonCodeStyleSettings();
commonSettings.settingsAgainstPreviousDefaults = settingsAgainstPreviousDefaults;
copyPublicFieldsOwn(this, commonSettings);
try {
Method setRootSettingsMethod = CommonCodeStyleSettings.class.getDeclaredMethod("setRootSettings", CodeStyleSettings.class);
setRootSettingsMethod.setAccessible(true);
setRootSettingsMethod.invoke(commonSettings, rootSettings);
}
catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException(e);
}
commonSettings.setForceArrangeMenuAvailable(isForceArrangeMenuAvailable());
IndentOptions indentOptions = getIndentOptions();
if (indentOptions != null) {
IndentOptions targetIndentOptions = commonSettings.initIndentOptions();
targetIndentOptions.copyFrom(indentOptions);
}
ArrangementSettings arrangementSettings = getArrangementSettings();
if (arrangementSettings != null) {
commonSettings.setArrangementSettings(arrangementSettings.clone());
}
try {
Method setRootSettingsMethod = ArraysKt.singleOrNull(
CommonCodeStyleSettings.class.getDeclaredMethods(),
method -> "setSoftMargins".equals(method.getName()));
if (setRootSettingsMethod != null) {
// Method was introduced in 173
setRootSettingsMethod.setAccessible(true);
setRootSettingsMethod.invoke(commonSettings, getSoftMargins());
}
}
catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException(e);
}
return commonSettings;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof KotlinCommonCodeStyleSettings)) {
return false;
}
if (!ReflectionUtil.comparePublicNonFinalFieldsWithSkip(this, obj)) {
return false;
}
CommonCodeStyleSettings other = (CommonCodeStyleSettings) obj;
if (!getSoftMargins().equals(other.getSoftMargins())) {
return false;
}
IndentOptions options = getIndentOptions();
if ((options == null && other.getIndentOptions() != null) ||
(options != null && !options.equals(other.getIndentOptions()))) {
return false;
}
return arrangementSettingsEqual(other);
}
// SoftMargins.serializeInfo
private void serializeInto(@NotNull List<Integer> softMargins, @NotNull Element element) {
if (softMargins.size() > 0) {
XmlSerializer.serializeInto(this, element);
}
}
//</editor-fold>
//<editor-fold desc="Copied from CommonCodeStyleSettings">
private static final String INDENT_OPTIONS_TAG = "indentOptions";
private static final String ARRANGEMENT_ELEMENT_NAME = "arrangement";
private final Language myLanguage = KotlinLanguage.INSTANCE;
@Nullable
private CommonCodeStyleSettings getDefaultSettings() {
return LanguageCodeStyleSettingsProvider.getDefaultCommonSettings(myLanguage);
}
@Nullable
private Set<String> getSupportedFields() {
final LanguageCodeStyleSettingsProvider provider = LanguageCodeStyleSettingsProvider.forLanguage(myLanguage);
return provider == null ? null : provider.getSupportedFields();
}
public boolean canRestore() {
return settingsAgainstPreviousDefaults != null;
}
public void restore() {
if (settingsAgainstPreviousDefaults != null) {
copyFrom(settingsAgainstPreviousDefaults);
}
}
private static class SupportedFieldsDiffFilter extends DifferenceFilter<CommonCodeStyleSettings> {
private final Set<String> mySupportedFieldNames;
public SupportedFieldsDiffFilter(
final CommonCodeStyleSettings object,
Set<String> supportedFiledNames,
final CommonCodeStyleSettings parentObject
) {
super(object, parentObject);
mySupportedFieldNames = supportedFiledNames;
}
@Override
public boolean isAccept(@NotNull Field field) {
if (mySupportedFieldNames == null ||
mySupportedFieldNames.contains(field.getName())) {
return super.isAccept(field);
}
return false;
}
}
// Can't use super.copyPublicFields because the method is internal in 181
private static void copyPublicFieldsOwn(Object from, Object to) {
assert from != to;
com.intellij.util.ReflectionUtil.copyFields(to.getClass().getFields(), from, to);
}
//</editor-fold>
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
class KotlinObsoleteCodeStyle : KotlinPredefinedCodeStyle(CODE_STYLE_TITLE, KotlinLanguage.INSTANCE) {
override val codeStyleId: String = CODE_STYLE_ID
override fun apply(settings: CodeStyleSettings) {
Companion.apply(settings)
}
companion object {
val INSTANCE = KotlinObsoleteCodeStyle()
const val CODE_STYLE_ID = "KOTLIN_OLD_DEFAULTS"
const val CODE_STYLE_SETTING = "obsolete"
const val CODE_STYLE_TITLE = "Kotlin obsolete IntelliJ IDEA codestyle"
fun apply(settings: CodeStyleSettings) {
applyToKotlinCustomSettings(settings.kotlinCustomSettings)
applyToCommonSettings(settings.kotlinCommonSettings)
}
fun applyToKotlinCustomSettings(kotlinCustomSettings: KotlinCodeStyleSettings, modifyCodeStyle: Boolean = true) {
kotlinCustomSettings.apply {
if (modifyCodeStyle) {
CODE_STYLE_DEFAULTS = CODE_STYLE_ID
}
CONTINUATION_INDENT_IN_PARAMETER_LISTS = true
CONTINUATION_INDENT_IN_ARGUMENT_LISTS = true
CONTINUATION_INDENT_FOR_EXPRESSION_BODIES = true
CONTINUATION_INDENT_FOR_CHAINED_CALLS = true
CONTINUATION_INDENT_IN_SUPERTYPE_LISTS = true
CONTINUATION_INDENT_IN_IF_CONDITIONS = true
CONTINUATION_INDENT_IN_ELVIS = true
WRAP_EXPRESSION_BODY_FUNCTIONS = CodeStyleSettings.DO_NOT_WRAP
IF_RPAREN_ON_NEW_LINE = false
}
}
fun applyToCommonSettings(commonSettings: CommonCodeStyleSettings, modifyCodeStyle: Boolean = true) {
commonSettings.apply {
CALL_PARAMETERS_WRAP = CodeStyleSettings.DO_NOT_WRAP
CALL_PARAMETERS_LPAREN_ON_NEXT_LINE = false
CALL_PARAMETERS_RPAREN_ON_NEXT_LINE = false
METHOD_PARAMETERS_WRAP = CodeStyleSettings.DO_NOT_WRAP
METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE = false
METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE = false
EXTENDS_LIST_WRAP = CodeStyleSettings.DO_NOT_WRAP
METHOD_CALL_CHAIN_WRAP = CodeStyleSettings.DO_NOT_WRAP
ASSIGNMENT_WRAP = CodeStyleSettings.DO_NOT_WRAP
}
if (modifyCodeStyle && commonSettings is KotlinCommonCodeStyleSettings) {
commonSettings.CODE_STYLE_DEFAULTS = CODE_STYLE_ID
}
}
}
}

View File

@@ -1,13 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter
import com.intellij.lang.Language
import com.intellij.psi.codeStyle.PredefinedCodeStyle
abstract class KotlinPredefinedCodeStyle(name: String, language: Language) : PredefinedCodeStyle(name, language) {
abstract val codeStyleId: String
}

View File

@@ -1,215 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter
import com.intellij.formatting.*
import com.intellij.formatting.DependentSpacingRule.Anchor
import com.intellij.formatting.DependentSpacingRule.Trigger
import com.intellij.lang.ASTNode
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiComment
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.idea.util.requireNode
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.psiUtil.children
import org.jetbrains.kotlin.psi.stubs.elements.KtModifierListElementType
import kotlin.math.max
fun CommonCodeStyleSettings.createSpaceBeforeRBrace(numSpacesOtherwise: Int, textRange: TextRange): Spacing? {
return Spacing.createDependentLFSpacing(
numSpacesOtherwise, numSpacesOtherwise, textRange,
KEEP_LINE_BREAKS,
KEEP_BLANK_LINES_BEFORE_RBRACE
)
}
class KotlinSpacingBuilder(val commonCodeStyleSettings: CommonCodeStyleSettings, val spacingBuilderUtil: KotlinSpacingBuilderUtil) {
private val builders = ArrayList<Builder>()
private interface Builder {
fun getSpacing(parent: ASTBlock, left: ASTBlock, right: ASTBlock): Spacing?
}
inner class BasicSpacingBuilder : SpacingBuilder(commonCodeStyleSettings), Builder {
override fun getSpacing(parent: ASTBlock, left: ASTBlock, right: ASTBlock): Spacing? {
return super.getSpacing(parent, left, right)
}
}
private data class Condition(
val parent: IElementType? = null,
val left: IElementType? = null,
val right: IElementType? = null,
val parentSet: TokenSet? = null,
val leftSet: TokenSet? = null,
val rightSet: TokenSet? = null
) : (ASTBlock, ASTBlock, ASTBlock) -> Boolean {
override fun invoke(p: ASTBlock, l: ASTBlock, r: ASTBlock): Boolean =
(parent == null || p.requireNode().elementType == parent) &&
(left == null || l.requireNode().elementType == left) &&
(right == null || r.requireNode().elementType == right) &&
(parentSet == null || parentSet.contains(p.requireNode().elementType)) &&
(leftSet == null || leftSet.contains(l.requireNode().elementType)) &&
(rightSet == null || rightSet.contains(r.requireNode().elementType))
}
private data class Rule(
val conditions: List<Condition>,
val action: (ASTBlock, ASTBlock, ASTBlock) -> Spacing?
) : (ASTBlock, ASTBlock, ASTBlock) -> Spacing? {
override fun invoke(p: ASTBlock, l: ASTBlock, r: ASTBlock): Spacing? =
if (conditions.all { it(p, l, r) }) action(p, l, r) else null
}
inner class CustomSpacingBuilder : Builder {
private val rules = ArrayList<Rule>()
private var conditions = ArrayList<Condition>()
override fun getSpacing(parent: ASTBlock, left: ASTBlock, right: ASTBlock): Spacing? {
for (rule in rules) {
val spacing = rule(parent, left, right)
if (spacing != null) {
return spacing
}
}
return null
}
fun inPosition(
parent: IElementType? = null, left: IElementType? = null, right: IElementType? = null,
parentSet: TokenSet? = null, leftSet: TokenSet? = null, rightSet: TokenSet? = null
): CustomSpacingBuilder {
conditions.add(Condition(parent, left, right, parentSet, leftSet, rightSet))
return this
}
fun lineBreakIfLineBreakInParent(numSpacesOtherwise: Int, allowBlankLines: Boolean = true) {
newRule { p, _, _ ->
Spacing.createDependentLFSpacing(
numSpacesOtherwise, numSpacesOtherwise, p.textRange,
commonCodeStyleSettings.KEEP_LINE_BREAKS,
if (allowBlankLines) commonCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE else 0
)
}
}
fun emptyLinesIfLineBreakInLeft(emptyLines: Int, numberOfLineFeedsOtherwise: Int = 1, numSpacesOtherwise: Int = 0) {
newRule { _: ASTBlock, left: ASTBlock, _: ASTBlock ->
val lastChild = left.node?.psi?.lastChild
val leftEndsWithComment = lastChild is PsiComment && lastChild.tokenType == KtTokens.EOL_COMMENT
val dependentSpacingRule = DependentSpacingRule(Trigger.HAS_LINE_FEEDS).registerData(Anchor.MIN_LINE_FEEDS, emptyLines + 1)
val textRange = left.node
?.startOfDeclaration()
?.startOffset
?.let { TextRange.create(it, left.textRange.endOffset) }
?: left.textRange
spacingBuilderUtil.createLineFeedDependentSpacing(
numSpacesOtherwise,
numSpacesOtherwise,
if (leftEndsWithComment) max(1, numberOfLineFeedsOtherwise) else numberOfLineFeedsOtherwise,
commonCodeStyleSettings.KEEP_LINE_BREAKS,
commonCodeStyleSettings.KEEP_BLANK_LINES_IN_DECLARATIONS,
textRange,
dependentSpacingRule
)
}
}
fun spacing(spacing: Spacing) {
newRule { _, _, _ -> spacing }
}
fun customRule(block: (parent: ASTBlock, left: ASTBlock, right: ASTBlock) -> Spacing?) {
newRule(block)
}
private fun newRule(rule: (ASTBlock, ASTBlock, ASTBlock) -> Spacing?) {
val savedConditions = ArrayList(conditions)
rules.add(Rule(savedConditions, rule))
conditions.clear()
}
}
fun getSpacing(parent: Block, child1: Block?, child2: Block): Spacing? {
if (parent !is ASTBlock || child1 !is ASTBlock || child2 !is ASTBlock) {
return null
}
for (builder in builders) {
val spacing = builder.getSpacing(parent, child1, child2)
if (spacing != null) {
// TODO: it's a severe hack but I don't know how to implement it in other way
if (child1.requireNode().elementType == KtTokens.EOL_COMMENT && spacing.toString().contains("minLineFeeds=0")) {
val isBeforeBlock =
child2.requireNode().elementType == KtNodeTypes.BLOCK || child2.requireNode().firstChildNode
?.elementType == KtNodeTypes.BLOCK
val keepBlankLines = if (isBeforeBlock) 0 else commonCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE
return createSpacing(0, minLineFeeds = 1, keepLineBreaks = true, keepBlankLines = keepBlankLines)
}
return spacing
}
}
return null
}
fun simple(init: BasicSpacingBuilder.() -> Unit) {
val builder = BasicSpacingBuilder()
builder.init()
builders.add(builder)
}
fun custom(init: CustomSpacingBuilder.() -> Unit) {
val builder = CustomSpacingBuilder()
builder.init()
builders.add(builder)
}
fun createSpacing(
minSpaces: Int,
maxSpaces: Int = minSpaces,
minLineFeeds: Int = 0,
keepLineBreaks: Boolean = commonCodeStyleSettings.KEEP_LINE_BREAKS,
keepBlankLines: Int = commonCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE
): Spacing {
return Spacing.createSpacing(minSpaces, maxSpaces, minLineFeeds, keepLineBreaks, keepBlankLines)
}
}
interface KotlinSpacingBuilderUtil {
fun createLineFeedDependentSpacing(
minSpaces: Int,
maxSpaces: Int,
minimumLineFeeds: Int,
keepLineBreaks: Boolean,
keepBlankLines: Int,
dependency: TextRange,
rule: DependentSpacingRule
): Spacing
fun getPreviousNonWhitespaceLeaf(node: ASTNode?): ASTNode?
fun isWhitespaceOrEmpty(node: ASTNode?): Boolean
}
fun rules(
commonCodeStyleSettings: CommonCodeStyleSettings,
builderUtil: KotlinSpacingBuilderUtil,
init: KotlinSpacingBuilder.() -> Unit
): KotlinSpacingBuilder {
val builder = KotlinSpacingBuilder(commonCodeStyleSettings, builderUtil)
builder.init()
return builder
}
internal fun ASTNode.startOfDeclaration(): ASTNode? = children().firstOrNull {
val elementType = it.elementType
elementType !is KtModifierListElementType<*> && elementType !in KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET
}

View File

@@ -1,81 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
class KotlinStyleGuideCodeStyle : KotlinPredefinedCodeStyle("Kotlin style guide", KotlinLanguage.INSTANCE) {
override val codeStyleId: String = CODE_STYLE_ID
override fun apply(settings: CodeStyleSettings) {
Companion.apply(settings)
}
companion object {
val INSTANCE = KotlinStyleGuideCodeStyle()
const val CODE_STYLE_ID = "KOTLIN_OFFICIAL"
const val CODE_STYLE_SETTING = "official"
const val CODE_STYLE_TITLE = "Kotlin Coding Conventions"
fun apply(settings: CodeStyleSettings) {
applyToKotlinCustomSettings(settings.kotlinCustomSettings)
applyToCommonSettings(settings.kotlinCommonSettings)
}
fun applyToKotlinCustomSettings(
kotlinCustomSettings: KotlinCodeStyleSettings,
modifyCodeStyle: Boolean = true
) {
kotlinCustomSettings.apply {
if (modifyCodeStyle) {
CODE_STYLE_DEFAULTS = CODE_STYLE_ID
}
CONTINUATION_INDENT_IN_PARAMETER_LISTS = false
CONTINUATION_INDENT_IN_ARGUMENT_LISTS = false
CONTINUATION_INDENT_FOR_EXPRESSION_BODIES = false
CONTINUATION_INDENT_FOR_CHAINED_CALLS = false
CONTINUATION_INDENT_IN_SUPERTYPE_LISTS = false
CONTINUATION_INDENT_IN_IF_CONDITIONS = false
CONTINUATION_INDENT_IN_ELVIS = false
WRAP_EXPRESSION_BODY_FUNCTIONS = CodeStyleSettings.WRAP_AS_NEEDED
IF_RPAREN_ON_NEW_LINE = true
ALLOW_TRAILING_COMMA = false
}
}
fun applyToCommonSettings(commonSettings: CommonCodeStyleSettings, modifyCodeStyle: Boolean = true) {
commonSettings.apply {
WHILE_ON_NEW_LINE = false
ELSE_ON_NEW_LINE = false
CATCH_ON_NEW_LINE = false
FINALLY_ON_NEW_LINE = false
CALL_PARAMETERS_WRAP = CodeStyleSettings.WRAP_AS_NEEDED + CodeStyleSettings.WRAP_ON_EVERY_ITEM
CALL_PARAMETERS_LPAREN_ON_NEXT_LINE = true
CALL_PARAMETERS_RPAREN_ON_NEXT_LINE = true
METHOD_PARAMETERS_WRAP = CodeStyleSettings.WRAP_AS_NEEDED + CodeStyleSettings.WRAP_ON_EVERY_ITEM
METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE = true
METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE = true
EXTENDS_LIST_WRAP = CodeStyleSettings.WRAP_AS_NEEDED
METHOD_CALL_CHAIN_WRAP = CodeStyleSettings.WRAP_AS_NEEDED
ASSIGNMENT_WRAP = CodeStyleSettings.WRAP_AS_NEEDED
ALIGN_MULTILINE_BINARY_OPERATION = false
}
if (modifyCodeStyle && commonSettings is KotlinCommonCodeStyleSettings) {
commonSettings.CODE_STYLE_DEFAULTS = CODE_STYLE_ID
}
}
}
}

View File

@@ -1,50 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter
import com.intellij.application.options.CodeStyle
import com.intellij.openapi.project.Project
import com.intellij.psi.codeStyle.CodeStyleSettings
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
data class KtCodeStyleSettings(
val custom: KotlinCodeStyleSettings,
val common: KotlinCommonCodeStyleSettings,
val all: CodeStyleSettings
)
fun KtCodeStyleSettings.canRestore(): Boolean {
return custom.canRestore() || common.canRestore()
}
fun KtCodeStyleSettings.hasDefaultLoadScheme(): Boolean {
return custom.CODE_STYLE_DEFAULTS == null || common.CODE_STYLE_DEFAULTS == null
}
fun KtCodeStyleSettings.restore() {
custom.restore()
common.restore()
}
fun ktCodeStyleSettings(project: Project): KtCodeStyleSettings? {
val settings = CodeStyle.getSettings(project)
val ktCommonSettings = settings.getCommonSettings(KotlinLanguage.INSTANCE) as KotlinCommonCodeStyleSettings
val ktCustomSettings = settings.getCustomSettings(KotlinCodeStyleSettings::class.java)
return KtCodeStyleSettings(ktCustomSettings, ktCommonSettings, settings)
}
val CodeStyleSettings.kotlinCommonSettings: KotlinCommonCodeStyleSettings
get() = getCommonSettings(KotlinLanguage.INSTANCE) as KotlinCommonCodeStyleSettings
val CodeStyleSettings.kotlinCustomSettings: KotlinCodeStyleSettings
get() = getCustomSettings(KotlinCodeStyleSettings::class.java)
fun CodeStyleSettings.kotlinCodeStyleDefaults(): String? {
return kotlinCustomSettings.CODE_STYLE_DEFAULTS ?: kotlinCommonSettings.CODE_STYLE_DEFAULTS
}

View File

@@ -1,144 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter
import com.intellij.formatting.Indent
import com.intellij.lang.ASTNode
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import org.jetbrains.annotations.NonNls
import kotlin.collections.ArrayList
abstract class NodeIndentStrategy {
abstract fun getIndent(node: ASTNode, settings: CodeStyleSettings): Indent?
class ConstIndentStrategy(private val indent: Indent) : NodeIndentStrategy() {
override fun getIndent(node: ASTNode, settings: CodeStyleSettings): Indent? {
return indent
}
}
class PositionStrategy(private val debugInfo: String?) : NodeIndentStrategy() {
private var indentCallback: (CodeStyleSettings) -> Indent = { Indent.getNoneIndent() }
private val within = ArrayList<IElementType>()
private var withinCallback: ((ASTNode) -> Boolean)? = null
private val notIn = ArrayList<IElementType>()
private val forElement = ArrayList<IElementType>()
private val notForElement = ArrayList<IElementType>()
private var forElementCallback: ((ASTNode) -> Boolean)? = null
override fun toString(): String {
return "PositionStrategy " + (debugInfo ?: "No debug info")
}
fun set(indent: Indent): PositionStrategy {
indentCallback = { indent }
return this
}
fun set(indentCallback: (CodeStyleSettings) -> Indent): PositionStrategy {
this.indentCallback = indentCallback
return this
}
fun within(parents: TokenSet): PositionStrategy {
val types = parents.types
if (types.isEmpty()) {
throw IllegalArgumentException("Empty token set is unexpected")
}
fillTypes(within, types[0], types.copyOfRange(1, types.size))
return this
}
fun within(parentType: IElementType, vararg orParentTypes: IElementType): PositionStrategy {
fillTypes(within, parentType, orParentTypes)
return this
}
fun within(callback: (ASTNode) -> Boolean): PositionStrategy {
withinCallback = callback
return this
}
fun notWithin(parentType: IElementType, vararg orParentTypes: IElementType): PositionStrategy {
fillTypes(notIn, parentType, orParentTypes)
return this
}
fun withinAny(): PositionStrategy {
within.clear()
notIn.clear()
return this
}
fun forType(elementType: IElementType, vararg otherTypes: IElementType): PositionStrategy {
fillTypes(forElement, elementType, otherTypes)
return this
}
fun notForType(elementType: IElementType, vararg otherTypes: IElementType): PositionStrategy {
fillTypes(notForElement, elementType, otherTypes)
return this
}
fun forAny(): PositionStrategy {
forElement.clear()
notForElement.clear()
return this
}
fun forElement(callback: (ASTNode) -> Boolean): PositionStrategy {
forElementCallback = callback
return this
}
override fun getIndent(node: ASTNode, settings: CodeStyleSettings): Indent? {
if (!isValidIndent(forElement, notForElement, node, forElementCallback)) return null
val parent = node.treeParent
if (parent != null) {
if (!isValidIndent(within, notIn, parent, withinCallback)) return null
} else if (within.isNotEmpty()) return null
return indentCallback(settings)
}
private fun fillTypes(resultCollection: MutableList<IElementType>, singleType: IElementType, otherTypes: Array<out IElementType>) {
resultCollection.clear()
resultCollection.add(singleType)
resultCollection.addAll(otherTypes)
}
}
companion object {
fun constIndent(indent: Indent): NodeIndentStrategy {
return ConstIndentStrategy(indent)
}
fun strategy(@NonNls debugInfo: String?): PositionStrategy {
return PositionStrategy(debugInfo)
}
}
}
private fun isValidIndent(
elements: ArrayList<IElementType>,
excludeElements: ArrayList<IElementType>,
node: ASTNode,
callback: ((ASTNode) -> Boolean)?
): Boolean {
if (elements.isNotEmpty() && !elements.contains(node.elementType)) return false
if (excludeElements.contains(node.elementType)) return false
if (callback?.invoke(node) == false) return false
return true
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter
import com.intellij.application.options.CodeStyle
import com.intellij.openapi.project.Project
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
object ProjectCodeStyleImporter {
fun apply(project: Project, codeStyleStr: String?): Boolean {
return when (codeStyleStr) {
KotlinObsoleteCodeStyle.CODE_STYLE_SETTING -> {
apply(project, KotlinObsoleteCodeStyle.INSTANCE)
true
}
KotlinStyleGuideCodeStyle.CODE_STYLE_SETTING -> {
apply(project, KotlinStyleGuideCodeStyle.INSTANCE)
true
}
else -> false
}
}
fun apply(project: Project, predefinedCodeStyle: KotlinPredefinedCodeStyle) {
val settingsManager = CodeStyleSettingsManager.getInstance(project)
val customSettings = CodeStyle.getSettings(project)
if (predefinedCodeStyle.codeStyleId == customSettings.kotlinCodeStyleDefaults()) {
// Don't bother user that already have correct code style
return
}
val projectSettingsUpdated: CodeStyleSettings = if (settingsManager.USE_PER_PROJECT_SETTINGS) {
customSettings.clone()
} else {
CodeStyleSettings()
}
settingsManager.USE_PER_PROJECT_SETTINGS = true
predefinedCodeStyle.apply(projectSettingsUpdated)
settingsManager.mainProjectCodeStyle = projectSettingsUpdated
}
}

View File

@@ -1,63 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter
import com.intellij.formatting.*
import com.intellij.lang.ASTNode
import com.intellij.openapi.util.TextRange
class SyntheticKotlinBlock(
private val node: ASTNode,
private val subBlocks: List<ASTBlock>,
private val alignment: Alignment?,
private val indent: Indent?,
private val wrap: Wrap?,
private val spacingBuilder: KotlinSpacingBuilder,
private val createParentSyntheticSpacingBlock: (ASTNode) -> ASTBlock
) : ASTBlock {
private val textRange = TextRange(
subBlocks.first().textRange.startOffset,
subBlocks.last().textRange.endOffset
)
override fun getTextRange(): TextRange = textRange
override fun getSubBlocks() = subBlocks
override fun getWrap() = wrap
override fun getIndent() = indent
override fun getAlignment() = alignment
override fun getChildAttributes(newChildIndex: Int) = ChildAttributes(getIndent(), null)
override fun isIncomplete() = getSubBlocks().last().isIncomplete
override fun isLeaf() = false
override fun getNode() = node
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
return spacingBuilder.getSpacing(createParentSyntheticSpacingBlock(node), child1, child2)
}
override fun toString(): String {
var child = subBlocks.first()
var treeNode: ASTNode? = null
loop@
while (treeNode == null) when (child) {
is SyntheticKotlinBlock -> child = child.getSubBlocks().first()
else -> treeNode = child.node
}
val textRange = getTextRange()
val psi = treeNode.psi
if (psi != null) {
val file = psi.containingFile
if (file != null) {
return file.text!!.subSequence(textRange.startOffset, textRange.endOffset).toString() + " " + textRange
}
}
return this::class.java.name + ": " + textRange
}
}

View File

@@ -1,690 +0,0 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter
import com.intellij.formatting.ASTBlock
import com.intellij.formatting.DependentSpacingRule
import com.intellij.formatting.Spacing
import com.intellij.formatting.SpacingBuilder
import com.intellij.formatting.SpacingBuilder.RuleBuilder
import com.intellij.lang.ASTNode
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import com.intellij.util.text.TextRangeUtil
import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.idea.formatter.KotlinSpacingBuilder.CustomSpacingBuilder
import org.jetbrains.kotlin.idea.util.requireNode
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.children
import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral
import org.jetbrains.kotlin.psi.psiUtil.siblings
import org.jetbrains.kotlin.psi.psiUtil.textRangeWithoutComments
val MODIFIERS_LIST_ENTRIES = TokenSet.orSet(TokenSet.create(ANNOTATION_ENTRY, ANNOTATION), MODIFIER_KEYWORDS)
val EXTEND_COLON_ELEMENTS =
TokenSet.create(TYPE_CONSTRAINT, CLASS, OBJECT_DECLARATION, TYPE_PARAMETER, ENUM_ENTRY, SECONDARY_CONSTRUCTOR)
val DECLARATIONS = TokenSet.create(PROPERTY, FUN, CLASS, OBJECT_DECLARATION, ENUM_ENTRY, SECONDARY_CONSTRUCTOR, CLASS_INITIALIZER)
fun SpacingBuilder.beforeInside(element: IElementType, tokenSet: TokenSet, spacingFun: RuleBuilder.() -> Unit) {
tokenSet.types.forEach { inType -> beforeInside(element, inType).spacingFun() }
}
fun SpacingBuilder.afterInside(element: IElementType, tokenSet: TokenSet, spacingFun: RuleBuilder.() -> Unit) {
tokenSet.types.forEach { inType -> afterInside(element, inType).spacingFun() }
}
fun RuleBuilder.spacesNoLineBreak(spaces: Int): SpacingBuilder? =
spacing(spaces, spaces, 0, false, 0)
fun createSpacingBuilder(settings: CodeStyleSettings, builderUtil: KotlinSpacingBuilderUtil): KotlinSpacingBuilder {
val kotlinCommonSettings = settings.kotlinCommonSettings
val kotlinCustomSettings = settings.kotlinCustomSettings
return rules(kotlinCommonSettings, builderUtil) {
simple {
before(FILE_ANNOTATION_LIST).lineBreakInCode()
between(IMPORT_DIRECTIVE, IMPORT_DIRECTIVE).lineBreakInCode()
after(IMPORT_LIST).blankLines(1)
}
custom {
fun commentSpacing(minSpaces: Int): Spacing {
if (kotlinCommonSettings.KEEP_FIRST_COLUMN_COMMENT) {
return Spacing.createKeepingFirstColumnSpacing(
minSpaces,
Int.MAX_VALUE,
settings.KEEP_LINE_BREAKS,
kotlinCommonSettings.KEEP_BLANK_LINES_IN_CODE
)
}
return Spacing.createSpacing(
minSpaces,
Int.MAX_VALUE,
0,
settings.KEEP_LINE_BREAKS,
kotlinCommonSettings.KEEP_BLANK_LINES_IN_CODE
)
}
// Several line comments happened to be generated in one line
inPosition(parent = null, left = EOL_COMMENT, right = EOL_COMMENT).customRule { _, _, right ->
val nodeBeforeRight = right.requireNode().treePrev
if (nodeBeforeRight is PsiWhiteSpace && !nodeBeforeRight.textContains('\n')) {
createSpacing(0, minLineFeeds = 1)
} else {
null
}
}
inPosition(right = BLOCK_COMMENT).spacing(commentSpacing(0))
inPosition(right = EOL_COMMENT).spacing(commentSpacing(1))
inPosition(parent = FUNCTION_LITERAL, right = BLOCK).customRule { _, _, right ->
when (right.node?.children()?.firstOrNull()?.elementType) {
BLOCK_COMMENT -> commentSpacing(0)
EOL_COMMENT -> commentSpacing(1)
else -> null
}
}
}
simple {
after(FILE_ANNOTATION_LIST).blankLines(1)
after(PACKAGE_DIRECTIVE).blankLines(1)
}
custom {
inPosition(leftSet = DECLARATIONS, rightSet = DECLARATIONS).customRule(fun(
_: ASTBlock,
_: ASTBlock,
right: ASTBlock
): Spacing? {
val node = right.node ?: return null
val elementStart = node.startOfDeclaration() ?: return null
return if (StringUtil.containsLineBreak(
node.text.subSequence(0, elementStart.startOffset - node.startOffset).trimStart()
)
)
createSpacing(0, minLineFeeds = 1 + kotlinCustomSettings.BLANK_LINES_BEFORE_DECLARATION_WITH_COMMENT_OR_ANNOTATION_ON_SEPARATE_LINE)
else
null
})
inPosition(left = CLASS, right = CLASS).emptyLinesIfLineBreakInLeft(1)
inPosition(left = CLASS, right = OBJECT_DECLARATION).emptyLinesIfLineBreakInLeft(1)
inPosition(left = OBJECT_DECLARATION, right = OBJECT_DECLARATION).emptyLinesIfLineBreakInLeft(1)
inPosition(left = OBJECT_DECLARATION, right = CLASS).emptyLinesIfLineBreakInLeft(1)
inPosition(left = FUN, right = FUN).emptyLinesIfLineBreakInLeft(1)
inPosition(left = PROPERTY, right = FUN).emptyLinesIfLineBreakInLeft(1)
inPosition(left = FUN, right = PROPERTY).emptyLinesIfLineBreakInLeft(1)
inPosition(left = SECONDARY_CONSTRUCTOR, right = SECONDARY_CONSTRUCTOR).emptyLinesIfLineBreakInLeft(1)
inPosition(left = TYPEALIAS, right = TYPEALIAS).emptyLinesIfLineBreakInLeft(1)
// Case left for alternative constructors
inPosition(left = FUN, right = CLASS).emptyLinesIfLineBreakInLeft(1)
inPosition(left = ENUM_ENTRY, right = ENUM_ENTRY).emptyLinesIfLineBreakInLeft(
emptyLines = 0, numberOfLineFeedsOtherwise = 0, numSpacesOtherwise = 1
)
inPosition(parent = CLASS_BODY, left = SEMICOLON).customRule { parent, _, right ->
val klass = parent.requireNode().treeParent.psi as? KtClass ?: return@customRule null
if (klass.isEnum() && right.requireNode().elementType in DECLARATIONS) {
createSpacing(0, minLineFeeds = 2, keepBlankLines = kotlinCommonSettings.KEEP_BLANK_LINES_IN_DECLARATIONS)
} else null
}
inPosition(parent = CLASS_BODY, left = LBRACE).customRule { parent, left, right ->
if (right.requireNode().elementType == RBRACE) {
return@customRule createSpacing(0)
}
val classBody = parent.requireNode().psi as KtClassBody
val parentPsi = classBody.parent as? KtClassOrObject ?: return@customRule null
if (kotlinCommonSettings.BLANK_LINES_AFTER_CLASS_HEADER == 0 || parentPsi.isObjectLiteral()) {
null
} else {
val minLineFeeds = if (right.requireNode().elementType == FUN || right.requireNode().elementType == PROPERTY)
kotlinCommonSettings.BLANK_LINES_AFTER_CLASS_HEADER + 1
else
0
builderUtil.createLineFeedDependentSpacing(
1,
1,
minLineFeeds,
commonCodeStyleSettings.KEEP_LINE_BREAKS,
commonCodeStyleSettings.KEEP_BLANK_LINES_IN_DECLARATIONS,
TextRange(parentPsi.textRange.startOffset, left.requireNode().psi.textRange.startOffset),
DependentSpacingRule(DependentSpacingRule.Trigger.HAS_LINE_FEEDS)
.registerData(
DependentSpacingRule.Anchor.MIN_LINE_FEEDS,
kotlinCommonSettings.BLANK_LINES_AFTER_CLASS_HEADER + 1
)
)
}
}
val parameterWithDocCommentRule = { _: ASTBlock, _: ASTBlock, right: ASTBlock ->
if (right.requireNode().firstChildNode.elementType == DOC_COMMENT) {
createSpacing(0, minLineFeeds = 1, keepLineBreaks = true, keepBlankLines = settings.KEEP_BLANK_LINES_IN_DECLARATIONS)
} else {
null
}
}
inPosition(parent = VALUE_PARAMETER_LIST, right = VALUE_PARAMETER).customRule(parameterWithDocCommentRule)
inPosition(parent = PROPERTY, right = PROPERTY_ACCESSOR).customRule { parent, _, _ ->
val startNode = parent.requireNode().psi.firstChild
.siblings()
.dropWhile { it is PsiComment || it is PsiWhiteSpace }.firstOrNull() ?: parent.requireNode().psi
Spacing.createDependentLFSpacing(
1, 1,
TextRange(startNode.textRange.startOffset, parent.textRange.endOffset),
false, 0
)
}
if (!kotlinCustomSettings.ALLOW_TRAILING_COMMA) {
inPosition(parent = VALUE_ARGUMENT_LIST, left = LPAR).customRule { parent, _, _ ->
if (kotlinCommonSettings.CALL_PARAMETERS_LPAREN_ON_NEXT_LINE && needWrapArgumentList(parent.requireNode().psi)) {
Spacing.createDependentLFSpacing(
0, 0,
excludeLambdasAndObjects(parent),
commonCodeStyleSettings.KEEP_LINE_BREAKS,
commonCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE
)
} else {
createSpacing(0)
}
}
inPosition(parent = VALUE_ARGUMENT_LIST, right = RPAR).customRule { parent, left, _ ->
when {
kotlinCommonSettings.CALL_PARAMETERS_RPAREN_ON_NEXT_LINE ->
Spacing.createDependentLFSpacing(
0, 0,
excludeLambdasAndObjects(parent),
commonCodeStyleSettings.KEEP_LINE_BREAKS,
commonCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE
)
left.requireNode().elementType == COMMA -> // incomplete call being edited
createSpacing(1)
else ->
createSpacing(0)
}
}
}
inPosition(left = CONDITION, right = RPAR).customRule { _, left, _ ->
if (kotlinCustomSettings.IF_RPAREN_ON_NEW_LINE) {
Spacing.createDependentLFSpacing(
0, 0,
excludeLambdasAndObjects(left),
commonCodeStyleSettings.KEEP_LINE_BREAKS,
commonCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE
)
} else {
createSpacing(0)
}
}
inPosition(left = VALUE_PARAMETER, right = COMMA).customRule { _, left, _ ->
if (left.node?.lastChildNode?.elementType === EOL_COMMENT)
createSpacing(0, minLineFeeds = 1)
else
null
}
inPosition(parent = LONG_STRING_TEMPLATE_ENTRY, right = LONG_TEMPLATE_ENTRY_END).lineBreakIfLineBreakInParent(0)
inPosition(parent = LONG_STRING_TEMPLATE_ENTRY, left = LONG_TEMPLATE_ENTRY_START).lineBreakIfLineBreakInParent(0)
}
simple {
// ============ Line breaks ==============
before(DOC_COMMENT).lineBreakInCode()
between(PROPERTY, PROPERTY).lineBreakInCode()
// CLASS - CLASS, CLASS - OBJECT_DECLARATION are exception
between(CLASS, DECLARATIONS).blankLines(1)
// FUN - FUN, FUN - PROPERTY, FUN - CLASS are exceptions
between(FUN, DECLARATIONS).blankLines(1)
// PROPERTY - PROPERTY, PROPERTY - FUN are exceptions
between(PROPERTY, DECLARATIONS).blankLines(1)
// OBJECT_DECLARATION - OBJECT_DECLARATION, CLASS - OBJECT_DECLARATION are exception
between(OBJECT_DECLARATION, DECLARATIONS).blankLines(1)
between(SECONDARY_CONSTRUCTOR, DECLARATIONS).blankLines(1)
between(CLASS_INITIALIZER, DECLARATIONS).blankLines(1)
// TYPEALIAS - TYPEALIAS is an exception
between(TYPEALIAS, DECLARATIONS).blankLines(1)
// ENUM_ENTRY - ENUM_ENTRY is exception
between(ENUM_ENTRY, DECLARATIONS).blankLines(1)
between(ENUM_ENTRY, SEMICOLON).spaces(0)
between(COMMA, SEMICOLON).lineBreakInCodeIf(kotlinCustomSettings.ALLOW_TRAILING_COMMA)
beforeInside(FUN, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
beforeInside(SECONDARY_CONSTRUCTOR, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
beforeInside(CLASS, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
beforeInside(OBJECT_DECLARATION, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
beforeInside(PROPERTY, WHEN).spaces(0)
beforeInside(PROPERTY, LABELED_EXPRESSION).spacesNoLineBreak(1)
before(PROPERTY).lineBreakInCode()
after(DOC_COMMENT).lineBreakInCode()
// =============== Spacing ================
between(EOL_COMMENT, COMMA).lineBreakInCode()
before(COMMA).spacesNoLineBreak(if (kotlinCommonSettings.SPACE_BEFORE_COMMA) 1 else 0)
after(COMMA).spaceIf(kotlinCommonSettings.SPACE_AFTER_COMMA)
val spacesAroundAssignment = if (kotlinCommonSettings.SPACE_AROUND_ASSIGNMENT_OPERATORS) 1 else 0
beforeInside(EQ, PROPERTY).spacesNoLineBreak(spacesAroundAssignment)
beforeInside(EQ, FUN).spacing(spacesAroundAssignment, spacesAroundAssignment, 0, false, 0)
around(
TokenSet.create(EQ, MULTEQ, DIVEQ, PLUSEQ, MINUSEQ, PERCEQ)
).spaceIf(kotlinCommonSettings.SPACE_AROUND_ASSIGNMENT_OPERATORS)
around(TokenSet.create(ANDAND, OROR)).spaceIf(kotlinCommonSettings.SPACE_AROUND_LOGICAL_OPERATORS)
around(TokenSet.create(EQEQ, EXCLEQ, EQEQEQ, EXCLEQEQEQ)).spaceIf(kotlinCommonSettings.SPACE_AROUND_EQUALITY_OPERATORS)
aroundInside(
TokenSet.create(LT, GT, LTEQ, GTEQ), BINARY_EXPRESSION
).spaceIf(kotlinCommonSettings.SPACE_AROUND_RELATIONAL_OPERATORS)
aroundInside(TokenSet.create(PLUS, MINUS), BINARY_EXPRESSION).spaceIf(kotlinCommonSettings.SPACE_AROUND_ADDITIVE_OPERATORS)
aroundInside(
TokenSet.create(MUL, DIV, PERC), BINARY_EXPRESSION
).spaceIf(kotlinCommonSettings.SPACE_AROUND_MULTIPLICATIVE_OPERATORS)
around(
TokenSet.create(PLUSPLUS, MINUSMINUS, EXCLEXCL, MINUS, PLUS, EXCL)
).spaceIf(kotlinCommonSettings.SPACE_AROUND_UNARY_OPERATOR)
before(ELVIS).spaces(1)
after(ELVIS).spacesNoLineBreak(1)
around(RANGE).spaceIf(kotlinCustomSettings.SPACE_AROUND_RANGE)
after(MODIFIER_LIST).spaces(1)
beforeInside(IDENTIFIER, CLASS).spaces(1)
beforeInside(IDENTIFIER, OBJECT_DECLARATION).spaces(1)
after(VAL_KEYWORD).spaces(1)
after(VAR_KEYWORD).spaces(1)
betweenInside(TYPE_PARAMETER_LIST, IDENTIFIER, PROPERTY).spaces(1)
betweenInside(TYPE_REFERENCE, DOT, PROPERTY).spacing(0, 0, 0, false, 0)
betweenInside(DOT, IDENTIFIER, PROPERTY).spacing(0, 0, 0, false, 0)
betweenInside(RETURN_KEYWORD, LABEL_QUALIFIER, RETURN).spaces(0)
afterInside(RETURN_KEYWORD, RETURN).spaces(1)
afterInside(LABEL_QUALIFIER, RETURN).spaces(1)
betweenInside(LABEL_QUALIFIER, EOL_COMMENT, LABELED_EXPRESSION).spacing(
0, Int.MAX_VALUE, 0, true, kotlinCommonSettings.KEEP_BLANK_LINES_IN_CODE
)
betweenInside(LABEL_QUALIFIER, BLOCK_COMMENT, LABELED_EXPRESSION).spacing(
0, Int.MAX_VALUE, 0, true, kotlinCommonSettings.KEEP_BLANK_LINES_IN_CODE
)
betweenInside(LABEL_QUALIFIER, LAMBDA_EXPRESSION, LABELED_EXPRESSION).spaces(0)
afterInside(LABEL_QUALIFIER, LABELED_EXPRESSION).spaces(1)
betweenInside(FUN_KEYWORD, VALUE_PARAMETER_LIST, FUN).spacing(0, 0, 0, false, 0)
after(FUN_KEYWORD).spaces(1)
betweenInside(TYPE_PARAMETER_LIST, TYPE_REFERENCE, FUN).spaces(1)
betweenInside(TYPE_PARAMETER_LIST, IDENTIFIER, FUN).spaces(1)
betweenInside(TYPE_REFERENCE, DOT, FUN).spacing(0, 0, 0, false, 0)
betweenInside(DOT, IDENTIFIER, FUN).spacing(0, 0, 0, false, 0)
afterInside(IDENTIFIER, FUN).spacing(0, 0, 0, false, 0)
aroundInside(DOT, USER_TYPE).spaces(0)
around(AS_KEYWORD).spaces(1)
around(AS_SAFE).spaces(1)
around(IS_KEYWORD).spaces(1)
around(NOT_IS).spaces(1)
around(IN_KEYWORD).spaces(1)
around(NOT_IN).spaces(1)
aroundInside(IDENTIFIER, BINARY_EXPRESSION).spaces(1)
// before LPAR in constructor(): this() {}
after(CONSTRUCTOR_DELEGATION_REFERENCE).spacing(0, 0, 0, false, 0)
// class A() - no space before LPAR of PRIMARY_CONSTRUCTOR
// class A private() - one space before modifier
custom {
inPosition(right = PRIMARY_CONSTRUCTOR).customRule { _, _, r ->
val spacesCount = if (r.requireNode().findLeafElementAt(0)?.elementType != LPAR) 1 else 0
createSpacing(spacesCount, minLineFeeds = 0, keepLineBreaks = true, keepBlankLines = 0)
}
}
afterInside(CONSTRUCTOR_KEYWORD, PRIMARY_CONSTRUCTOR).spaces(0)
betweenInside(IDENTIFIER, TYPE_PARAMETER_LIST, CLASS).spaces(0)
beforeInside(DOT, DOT_QUALIFIED_EXPRESSION).spaces(0)
afterInside(DOT, DOT_QUALIFIED_EXPRESSION).spacesNoLineBreak(0)
beforeInside(SAFE_ACCESS, SAFE_ACCESS_EXPRESSION).spaces(0)
afterInside(SAFE_ACCESS, SAFE_ACCESS_EXPRESSION).spacesNoLineBreak(0)
between(MODIFIERS_LIST_ENTRIES, MODIFIERS_LIST_ENTRIES).spaces(1)
after(LBRACKET).spaces(0)
before(RBRACKET).spaces(0)
afterInside(LPAR, VALUE_PARAMETER_LIST).spaces(0, kotlinCommonSettings.METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE)
beforeInside(RPAR, VALUE_PARAMETER_LIST).spaces(0, kotlinCommonSettings.METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE)
afterInside(LT, TYPE_PARAMETER_LIST).spaces(0)
beforeInside(GT, TYPE_PARAMETER_LIST).spaces(0)
afterInside(LT, TYPE_ARGUMENT_LIST).spaces(0)
beforeInside(GT, TYPE_ARGUMENT_LIST).spaces(0)
before(TYPE_ARGUMENT_LIST).spaces(0)
after(LPAR).spaces(0)
before(RPAR).spaces(0)
betweenInside(FOR_KEYWORD, LPAR, FOR).spaceIf(kotlinCommonSettings.SPACE_BEFORE_FOR_PARENTHESES)
betweenInside(IF_KEYWORD, LPAR, IF).spaceIf(kotlinCommonSettings.SPACE_BEFORE_IF_PARENTHESES)
betweenInside(WHILE_KEYWORD, LPAR, WHILE).spaceIf(kotlinCommonSettings.SPACE_BEFORE_WHILE_PARENTHESES)
betweenInside(WHILE_KEYWORD, LPAR, DO_WHILE).spaceIf(kotlinCommonSettings.SPACE_BEFORE_WHILE_PARENTHESES)
betweenInside(WHEN_KEYWORD, LPAR, WHEN).spaceIf(kotlinCustomSettings.SPACE_BEFORE_WHEN_PARENTHESES)
betweenInside(CATCH_KEYWORD, VALUE_PARAMETER_LIST, CATCH).spaceIf(kotlinCommonSettings.SPACE_BEFORE_CATCH_PARENTHESES)
betweenInside(LPAR, VALUE_PARAMETER, FOR).spaces(0)
betweenInside(LPAR, DESTRUCTURING_DECLARATION, FOR).spaces(0)
betweenInside(LOOP_RANGE, RPAR, FOR).spaces(0)
afterInside(ANNOTATION_ENTRY, ANNOTATED_EXPRESSION).spaces(1)
before(SEMICOLON).spaces(0)
beforeInside(INITIALIZER_LIST, ENUM_ENTRY).spaces(0)
beforeInside(QUEST, NULLABLE_TYPE).spaces(0)
val TYPE_COLON_ELEMENTS = TokenSet.create(PROPERTY, FUN, VALUE_PARAMETER, DESTRUCTURING_DECLARATION_ENTRY, FUNCTION_LITERAL)
beforeInside(COLON, TYPE_COLON_ELEMENTS) { spaceIf(kotlinCustomSettings.SPACE_BEFORE_TYPE_COLON) }
afterInside(COLON, TYPE_COLON_ELEMENTS) { spaceIf(kotlinCustomSettings.SPACE_AFTER_TYPE_COLON) }
afterInside(COLON, EXTEND_COLON_ELEMENTS) { spaceIf(kotlinCustomSettings.SPACE_AFTER_EXTEND_COLON) }
beforeInside(ARROW, FUNCTION_LITERAL).spaceIf(kotlinCustomSettings.SPACE_BEFORE_LAMBDA_ARROW)
aroundInside(ARROW, FUNCTION_TYPE).spaceIf(kotlinCustomSettings.SPACE_AROUND_FUNCTION_TYPE_ARROW)
before(VALUE_ARGUMENT_LIST).spaces(0)
between(VALUE_ARGUMENT_LIST, LAMBDA_ARGUMENT).spaces(1)
betweenInside(REFERENCE_EXPRESSION, LAMBDA_ARGUMENT, CALL_EXPRESSION).spaces(1)
betweenInside(TYPE_ARGUMENT_LIST, LAMBDA_ARGUMENT, CALL_EXPRESSION).spaces(1)
around(COLONCOLON).spaces(0)
around(BY_KEYWORD).spaces(1)
betweenInside(IDENTIFIER, PROPERTY_DELEGATE, PROPERTY).spaces(1)
betweenInside(TYPE_REFERENCE, PROPERTY_DELEGATE, PROPERTY).spaces(1)
before(INDICES).spaces(0)
before(WHERE_KEYWORD).spaces(1)
afterInside(GET_KEYWORD, PROPERTY_ACCESSOR).spaces(0)
afterInside(SET_KEYWORD, PROPERTY_ACCESSOR).spaces(0)
}
custom {
fun CustomSpacingBuilder.ruleForKeywordOnNewLine(
shouldBeOnNewLine: Boolean,
keyword: IElementType,
parent: IElementType,
afterBlockFilter: (wordParent: ASTNode, block: ASTNode) -> Boolean = { _, _ -> true }
) {
if (shouldBeOnNewLine) {
inPosition(parent = parent, right = keyword)
.lineBreakIfLineBreakInParent(numSpacesOtherwise = 1, allowBlankLines = false)
} else {
inPosition(parent = parent, right = keyword).customRule { _, _, right ->
val previousLeaf = builderUtil.getPreviousNonWhitespaceLeaf(right.requireNode())
val leftBlock = if (
previousLeaf != null &&
previousLeaf.elementType == RBRACE &&
previousLeaf.treeParent?.elementType == BLOCK
) {
previousLeaf.treeParent!!
} else null
val removeLineBreaks = leftBlock != null && afterBlockFilter(right.node?.treeParent!!, leftBlock)
createSpacing(1, minLineFeeds = 0, keepLineBreaks = !removeLineBreaks, keepBlankLines = 0)
}
}
}
ruleForKeywordOnNewLine(kotlinCommonSettings.ELSE_ON_NEW_LINE, keyword = ELSE_KEYWORD, parent = IF) { keywordParent, block ->
block.treeParent?.elementType == THEN && block.treeParent?.treeParent == keywordParent
}
ruleForKeywordOnNewLine(
kotlinCommonSettings.WHILE_ON_NEW_LINE,
keyword = WHILE_KEYWORD,
parent = DO_WHILE
) { keywordParent, block ->
block.treeParent?.elementType == BODY && block.treeParent?.treeParent == keywordParent
}
ruleForKeywordOnNewLine(kotlinCommonSettings.CATCH_ON_NEW_LINE, keyword = CATCH, parent = TRY)
ruleForKeywordOnNewLine(kotlinCommonSettings.FINALLY_ON_NEW_LINE, keyword = FINALLY, parent = TRY)
fun spacingForLeftBrace(block: ASTNode?, blockType: IElementType = BLOCK): Spacing? {
if (block != null && block.elementType == blockType) {
val leftBrace = block.findChildByType(LBRACE)
if (leftBrace != null) {
val previousLeaf = builderUtil.getPreviousNonWhitespaceLeaf(leftBrace)
val isAfterEolComment = previousLeaf != null && (previousLeaf.elementType == EOL_COMMENT)
val keepLineBreaks = kotlinCustomSettings.LBRACE_ON_NEXT_LINE || isAfterEolComment
val minimumLF = if (kotlinCustomSettings.LBRACE_ON_NEXT_LINE) 1 else 0
return createSpacing(1, minLineFeeds = minimumLF, keepLineBreaks = keepLineBreaks, keepBlankLines = 0)
}
}
return createSpacing(1)
}
fun leftBraceRule(blockType: IElementType = BLOCK) = { _: ASTBlock, _: ASTBlock, right: ASTBlock ->
spacingForLeftBrace(right.node, blockType)
}
val leftBraceRuleIfBlockIsWrapped = { _: ASTBlock, _: ASTBlock, right: ASTBlock ->
spacingForLeftBrace(right.requireNode().firstChildNode)
}
// Add space after a semicolon if there is another child at the same line
inPosition(left = SEMICOLON).customRule { _, left, _ ->
val nodeAfterLeft = left.requireNode().treeNext
if (nodeAfterLeft is PsiWhiteSpace && !nodeAfterLeft.textContains('\n')) {
createSpacing(1)
} else {
null
}
}
inPosition(parent = IF, right = THEN).customRule(leftBraceRuleIfBlockIsWrapped)
inPosition(parent = IF, right = ELSE).customRule(leftBraceRuleIfBlockIsWrapped)
inPosition(parent = FOR, right = BODY).customRule(leftBraceRuleIfBlockIsWrapped)
inPosition(parent = WHILE, right = BODY).customRule(leftBraceRuleIfBlockIsWrapped)
inPosition(parent = DO_WHILE, right = BODY).customRule(leftBraceRuleIfBlockIsWrapped)
inPosition(parent = TRY, right = BLOCK).customRule(leftBraceRule())
inPosition(parent = CATCH, right = BLOCK).customRule(leftBraceRule())
inPosition(parent = FINALLY, right = BLOCK).customRule(leftBraceRule())
inPosition(parent = FUN, right = BLOCK).customRule(leftBraceRule())
inPosition(parent = SECONDARY_CONSTRUCTOR, right = BLOCK).customRule(leftBraceRule())
inPosition(parent = CLASS_INITIALIZER, right = BLOCK).customRule(leftBraceRule())
inPosition(parent = PROPERTY_ACCESSOR, right = BLOCK).customRule(leftBraceRule())
inPosition(right = CLASS_BODY).customRule(leftBraceRule(blockType = CLASS_BODY))
inPosition(left = WHEN_ENTRY, right = WHEN_ENTRY).customRule { _, left, right ->
val leftEntry = left.requireNode().psi as KtWhenEntry
val rightEntry = right.requireNode().psi as KtWhenEntry
val blankLines = if (leftEntry.expression is KtBlockExpression || rightEntry.expression is KtBlockExpression)
settings.kotlinCustomSettings.BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES
else
0
createSpacing(0, minLineFeeds = blankLines + 1)
}
inPosition(parent = WHEN_ENTRY, right = BLOCK).customRule(leftBraceRule())
inPosition(parent = WHEN, right = LBRACE).customRule { parent, _, _ ->
spacingForLeftBrace(block = parent.requireNode(), blockType = WHEN)
}
inPosition(left = LBRACE, right = WHEN_ENTRY).customRule { _, _, _ ->
createSpacing(0, minLineFeeds = 1)
}
val spacesInSimpleFunction = if (kotlinCustomSettings.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD) 1 else 0
inPosition(
parent = FUNCTION_LITERAL,
left = LBRACE,
right = BLOCK
).lineBreakIfLineBreakInParent(numSpacesOtherwise = spacesInSimpleFunction)
inPosition(
parent = FUNCTION_LITERAL,
left = ARROW,
right = BLOCK
).lineBreakIfLineBreakInParent(numSpacesOtherwise = 1)
inPosition(
parent = FUNCTION_LITERAL,
left = LBRACE,
right = RBRACE
).spacing(createSpacing(minSpaces = 0, maxSpaces = 1))
inPosition(
parent = FUNCTION_LITERAL,
right = RBRACE
).lineBreakIfLineBreakInParent(numSpacesOtherwise = spacesInSimpleFunction)
inPosition(
parent = FUNCTION_LITERAL,
left = LBRACE
).customRule { _, _, right ->
val rightNode = right.requireNode()
val rightType = rightNode.elementType
if (rightType == VALUE_PARAMETER_LIST) {
createSpacing(spacesInSimpleFunction, keepLineBreaks = false)
} else {
createSpacing(spacesInSimpleFunction)
}
}
inPosition(parent = CLASS_BODY, right = RBRACE).customRule { parent, _, _ ->
kotlinCommonSettings.createSpaceBeforeRBrace(1, parent.textRange)
}
inPosition(parent = BLOCK, right = RBRACE).customRule { block, left, _ ->
val psiElement = block.requireNode().treeParent.psi
val empty = left.requireNode().elementType == LBRACE
when (psiElement) {
is KtFunction -> {
if (psiElement.name != null && !empty) return@customRule null
}
is KtPropertyAccessor ->
if (!empty) return@customRule null
else ->
return@customRule null
}
val spaces = if (empty) 0 else spacesInSimpleFunction
kotlinCommonSettings.createSpaceBeforeRBrace(spaces, psiElement.textRangeWithoutComments)
}
inPosition(parent = BLOCK, left = LBRACE).customRule { parent, _, _ ->
val psiElement = parent.requireNode().treeParent.psi
val funNode = psiElement as? KtFunction ?: return@customRule null
if (funNode.name != null) return@customRule null
// Empty block is covered in above rule
Spacing.createDependentLFSpacing(
spacesInSimpleFunction, spacesInSimpleFunction, funNode.textRangeWithoutComments,
kotlinCommonSettings.KEEP_LINE_BREAKS,
kotlinCommonSettings.KEEP_BLANK_LINES_IN_CODE
)
}
inPosition(parentSet = EXTEND_COLON_ELEMENTS, left = PRIMARY_CONSTRUCTOR, right = COLON).customRule { _, left, _ ->
val primaryConstructor = left.requireNode().psi as KtPrimaryConstructor
val rightParenthesis = primaryConstructor.valueParameterList?.rightParenthesis
val prevSibling = rightParenthesis?.prevSibling
val spaces = if (kotlinCustomSettings.SPACE_BEFORE_EXTEND_COLON) 1 else 0
// TODO This should use DependentSpacingRule, but it doesn't set keepLineBreaks to false if max LFs is 0
if ((prevSibling as? PsiWhiteSpace)?.textContains('\n') == true || kotlinCommonSettings
.METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE
) {
createSpacing(spaces, keepLineBreaks = false)
} else {
createSpacing(spaces)
}
}
inPosition(
parent = CLASS_BODY,
left = LBRACE,
right = ENUM_ENTRY
).lineBreakIfLineBreakInParent(numSpacesOtherwise = 1)
}
simple {
afterInside(LBRACE, BLOCK).lineBreakInCode()
beforeInside(RBRACE, BLOCK).spacing(
1, 0, 1,
kotlinCommonSettings.KEEP_LINE_BREAKS,
kotlinCommonSettings.KEEP_BLANK_LINES_BEFORE_RBRACE
)
between(LBRACE, ENUM_ENTRY).spacing(1, 0, 0, true, kotlinCommonSettings.KEEP_BLANK_LINES_IN_CODE)
beforeInside(RBRACE, WHEN).lineBreakInCode()
between(RPAR, BODY).spaces(1)
// if when entry has block, spacing after arrow should be set by lbrace rule
aroundInside(ARROW, WHEN_ENTRY).spaceIf(kotlinCustomSettings.SPACE_AROUND_WHEN_ARROW)
beforeInside(COLON, EXTEND_COLON_ELEMENTS) { spaceIf(kotlinCustomSettings.SPACE_BEFORE_EXTEND_COLON) }
after(EOL_COMMENT).lineBreakInCode()
}
}
}
private fun excludeLambdasAndObjects(parent: ASTBlock): List<TextRange> {
val rangesToExclude = mutableListOf<TextRange>()
parent.requireNode().psi.accept(object : KtTreeVisitorVoid() {
override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {
super.visitLambdaExpression(lambdaExpression)
rangesToExclude.add(lambdaExpression.textRange)
}
override fun visitObjectLiteralExpression(expression: KtObjectLiteralExpression) {
super.visitObjectLiteralExpression(expression)
rangesToExclude.add(expression.textRange)
}
override fun visitNamedFunction(function: KtNamedFunction) {
super.visitNamedFunction(function)
if (function.name == null) {
rangesToExclude.add(function.textRange)
}
}
})
return TextRangeUtil.excludeRanges(parent.textRange, rangesToExclude).toList()
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter.trailingComma
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
import org.jetbrains.kotlin.psi.KtElement
class TrailingCommaContext private constructor(val element: PsiElement, val state: TrailingCommaState) {
/**
* Return [KtElement] if [state] != [TrailingCommaState.NOT_APPLICABLE]
*/
val ktElement: KtElement get() = element as? KtElement ?: error("State is NOT_APPLICABLE")
companion object {
fun create(element: PsiElement): TrailingCommaContext = TrailingCommaContext(
element,
TrailingCommaState.stateForElement(element),
)
}
}
fun TrailingCommaContext.commaExistsOrMayExist(settings: KotlinCodeStyleSettings): Boolean = when (state) {
TrailingCommaState.EXISTS -> true
TrailingCommaState.MISSING -> settings.addTrailingCommaIsAllowedFor(element)
else -> false
}

View File

@@ -1,86 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter.trailingComma
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiErrorElement
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.tree.TokenSet
import com.intellij.psi.util.PsiUtil
import org.jetbrains.kotlin.idea.formatter.kotlinCustomSettings
import org.jetbrains.kotlin.idea.util.isComma
import org.jetbrains.kotlin.idea.util.isLineBreak
import org.jetbrains.kotlin.idea.util.leafIgnoringWhitespace
import org.jetbrains.kotlin.idea.util.leafIgnoringWhitespaceAndComments
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getPrevSiblingIgnoringWhitespaceAndComments
import org.jetbrains.kotlin.psi.psiUtil.prevLeaf
import org.jetbrains.kotlin.psi.psiUtil.siblings
import org.jetbrains.kotlin.utils.addToStdlib.cast
object TrailingCommaHelper {
fun findInvalidCommas(commaOwner: KtElement): List<PsiElement> = commaOwner.firstChild
?.siblings(withItself = false)
?.filter { it.isComma }
?.filter {
it.prevLeaf(true)?.isLineBreak() == true || it.leafIgnoringWhitespace(false) != it.leafIgnoringWhitespaceAndComments(false)
}?.toList().orEmpty()
fun trailingCommaExistsOrCanExist(psiElement: PsiElement, settings: CodeStyleSettings): Boolean =
TrailingCommaContext.create(psiElement).commaExistsOrMayExist(settings.kotlinCustomSettings)
fun trailingCommaExists(commaOwner: KtElement): Boolean = when (commaOwner) {
is KtFunctionLiteral -> commaOwner.valueParameterList?.trailingComma != null
is KtWhenEntry -> commaOwner.trailingComma != null
is KtDestructuringDeclaration -> commaOwner.trailingComma != null
else -> trailingCommaOrLastElement(commaOwner)?.isComma == true
}
fun trailingCommaOrLastElement(commaOwner: KtElement): PsiElement? {
val lastChild = commaOwner.lastSignificantChild ?: return null
val withSelf = when (PsiUtil.getElementType(lastChild)) {
KtTokens.COMMA -> return lastChild
in RIGHT_BARRIERS -> false
else -> true
}
return lastChild.getPrevSiblingIgnoringWhitespaceAndComments(withSelf)?.takeIf {
PsiUtil.getElementType(it) !in LEFT_BARRIERS
}?.takeIfIsNotError()
}
fun elementBeforeFirstElement(commaOwner: KtElement): PsiElement? = when (commaOwner) {
is KtParameterList -> {
val parent = commaOwner.parent
if (parent is KtFunctionLiteral) parent.lBrace else commaOwner.leftParenthesis
}
is KtWhenEntry -> commaOwner.parent.cast<KtWhenExpression>().openBrace
is KtDestructuringDeclaration -> commaOwner.lPar
else -> commaOwner.firstChild?.takeIfIsNotError()
}
fun elementAfterLastElement(commaOwner: KtElement): PsiElement? = when (commaOwner) {
is KtParameterList -> {
val parent = commaOwner.parent
if (parent is KtFunctionLiteral) parent.arrow else commaOwner.rightParenthesis
}
is KtWhenEntry -> commaOwner.arrow
is KtDestructuringDeclaration -> commaOwner.rPar
else -> commaOwner.lastChild?.takeIfIsNotError()
}
private fun PsiElement.takeIfIsNotError(): PsiElement? = takeIf { it !is PsiErrorElement }
private val RIGHT_BARRIERS = TokenSet.create(KtTokens.RBRACKET, KtTokens.RPAR, KtTokens.RBRACE, KtTokens.GT, KtTokens.ARROW)
private val LEFT_BARRIERS = TokenSet.create(KtTokens.LBRACKET, KtTokens.LPAR, KtTokens.LBRACE, KtTokens.LT)
private val PsiElement.lastSignificantChild: PsiElement?
get() = when (this) {
is KtWhenEntry -> arrow
is KtDestructuringDeclaration -> rPar
else -> lastChild
}
}

View File

@@ -1,90 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter.trailingComma
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.util.containsLineBreakInChild
import org.jetbrains.kotlin.idea.util.isMultiline
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
enum class TrailingCommaState {
/**
* The trailing comma is needed and exists
*/
EXISTS,
/**
* The trailing comma is needed and doesn't exists
*/
MISSING,
/**
* The trailing comma isn't needed and doesn't exists
*/
NOT_EXISTS,
/**
* The trailing comma isn't needed, but exists
*/
REDUNDANT,
/**
* The trailing comma isn't applicable for this element
*/
NOT_APPLICABLE,
;
companion object {
fun stateForElement(element: PsiElement): TrailingCommaState = when {
element !is KtElement || !element.canAddTrailingComma() -> NOT_APPLICABLE
isMultiline(element) ->
if (TrailingCommaHelper.trailingCommaExists(element))
EXISTS
else
MISSING
else ->
if (TrailingCommaHelper.trailingCommaExists(element))
REDUNDANT
else
NOT_EXISTS
}
}
}
private fun isMultiline(ktElement: KtElement): Boolean = when {
ktElement.parent is KtFunctionLiteral -> isMultiline(ktElement.parent as KtElement)
ktElement is KtFunctionLiteral -> ktElement.isMultiline(
startOffsetGetter = { valueParameterList?.startOffset },
endOffsetGetter = { arrow?.endOffset },
)
ktElement is KtWhenEntry -> ktElement.isMultiline(
startOffsetGetter = { startOffset },
endOffsetGetter = { arrow?.endOffset },
)
ktElement is KtDestructuringDeclaration -> ktElement.isMultiline(
startOffsetGetter = { lPar?.startOffset },
endOffsetGetter = { rPar?.endOffset },
)
else -> ktElement.isMultiline()
}
private fun <T : PsiElement> T.isMultiline(
startOffsetGetter: T.() -> Int?,
endOffsetGetter: T.() -> Int?,
): Boolean {
val startOffset = startOffsetGetter() ?: startOffset
val endOffset = endOffsetGetter() ?: endOffset
return containsLineBreakInChild(startOffset, endOffset)
}

View File

@@ -1,66 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.formatter.trailingComma
import com.intellij.lang.ASTNode
import com.intellij.openapi.util.registry.Registry
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import com.intellij.psi.util.PsiUtilCore
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.utils.addToStdlib.cast
fun trailingCommaIsAllowedOnCallSite(): Boolean = Registry.`is`("kotlin.formatter.allowTrailingCommaOnCallSite")
private val TYPES_WITH_TRAILING_COMMA_ON_DECLARATION_SITE = TokenSet.create(
KtNodeTypes.TYPE_PARAMETER_LIST,
KtNodeTypes.DESTRUCTURING_DECLARATION,
KtNodeTypes.WHEN_ENTRY,
KtNodeTypes.FUNCTION_LITERAL,
KtNodeTypes.VALUE_PARAMETER_LIST,
)
private val TYPES_WITH_TRAILING_COMMA_ON_CALL_SITE = TokenSet.create(
KtNodeTypes.COLLECTION_LITERAL_EXPRESSION,
KtNodeTypes.TYPE_ARGUMENT_LIST,
KtNodeTypes.INDICES,
KtNodeTypes.VALUE_ARGUMENT_LIST,
)
private val TYPES_WITH_TRAILING_COMMA = TokenSet.orSet(
TYPES_WITH_TRAILING_COMMA_ON_DECLARATION_SITE,
TYPES_WITH_TRAILING_COMMA_ON_CALL_SITE,
)
fun PsiElement.canAddTrailingCommaWithRegistryCheck(): Boolean {
val type = PsiUtilCore.getElementType(this) ?: return false
return type in TYPES_WITH_TRAILING_COMMA_ON_DECLARATION_SITE ||
trailingCommaIsAllowedOnCallSite() && type in TYPES_WITH_TRAILING_COMMA_ON_CALL_SITE
}
fun KotlinCodeStyleSettings.addTrailingCommaIsAllowedFor(node: ASTNode): Boolean =
addTrailingCommaIsAllowedFor(PsiUtilCore.getElementType(node))
fun KotlinCodeStyleSettings.addTrailingCommaIsAllowedFor(element: PsiElement): Boolean =
addTrailingCommaIsAllowedFor(PsiUtilCore.getElementType(element))
private fun KotlinCodeStyleSettings.addTrailingCommaIsAllowedFor(type: IElementType?): Boolean = when (type) {
null -> false
in TYPES_WITH_TRAILING_COMMA_ON_DECLARATION_SITE -> ALLOW_TRAILING_COMMA
in TYPES_WITH_TRAILING_COMMA_ON_CALL_SITE -> ALLOW_TRAILING_COMMA_ON_CALL_SITE || trailingCommaIsAllowedOnCallSite()
else -> false
}
fun PsiElement.canAddTrailingComma(): Boolean = when {
this is KtWhenEntry && (isElse || parent.cast<KtWhenExpression>().leftParenthesis == null) -> false
this is KtFunctionLiteral && arrow == null -> false
else -> PsiUtilCore.getElementType(this) in TYPES_WITH_TRAILING_COMMA
}

View File

@@ -1,68 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.util
import com.intellij.formatting.ASTBlock
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.util.PsiUtil
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.psiUtil.*
/*
* ASTBlock.node is nullable, this extension was introduced to minimize changes
*/
fun ASTBlock.requireNode() = node ?: error("ASTBlock.getNode() returned null")
/**
* Can be removed with all usages after moving master to 1.3 with new default code style settings.
*/
val isDefaultOfficialCodeStyle by lazy { !KotlinCodeStyleSettings.defaultSettings().CONTINUATION_INDENT_FOR_CHAINED_CALLS }
// Copied from idea-core
fun PsiElement.getLineCount(): Int {
val spaceRange = textRange ?: TextRange.EMPTY_RANGE
return getLineCountByDocument(spaceRange.startOffset, spaceRange.endOffset)
?: StringUtil.getLineBreakCount(text ?: error("Cannot count number of lines")) + 1
}
fun PsiElement.getLineCountByDocument(startOffset: Int, endOffset: Int): Int? {
val doc = containingFile?.let { PsiDocumentManager.getInstance(project).getDocument(it) } ?: return null
if (endOffset > doc.textLength || startOffset >= endOffset) return null
val startLine = doc.getLineNumber(startOffset)
val endLine = doc.getLineNumber(endOffset)
return endLine - startLine + 1
}
fun PsiElement.isMultiline() = getLineCount() > 1
fun PsiElement?.isLineBreak() = this is PsiWhiteSpace && StringUtil.containsLineBreak(text)
fun PsiElement.leafIgnoringWhitespace(forward: Boolean = true, skipEmptyElements: Boolean = true) =
leaf(forward) { (!skipEmptyElements || it.textLength != 0) && it !is PsiWhiteSpace }
fun PsiElement.leafIgnoringWhitespaceAndComments(forward: Boolean = true, skipEmptyElements: Boolean = true) =
leaf(forward) { (!skipEmptyElements || it.textLength != 0) && it !is PsiWhiteSpace && it !is PsiComment }
fun PsiElement.leaf(forward: Boolean = true, filter: (PsiElement) -> Boolean): PsiElement? =
if (forward) nextLeaf(filter)
else prevLeaf(filter)
val PsiElement.isComma: Boolean get() = PsiUtil.getElementType(this) == KtTokens.COMMA
fun PsiElement.containsLineBreakInChild(globalStartOffset: Int, globalEndOffset: Int): Boolean =
getLineCountByDocument(globalStartOffset, globalEndOffset)?.let { it > 1 }
?: firstChild.siblings(forward = true, withItself = true)
.dropWhile { it.startOffset < globalStartOffset }
.takeWhile { it.endOffset <= globalEndOffset }
.any { it.textContains('\n') || it.textContains('\r') }

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.util;
import com.intellij.openapi.util.Comparing;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Predicate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Set;
public class ReflectionUtil {
@Retention(RetentionPolicy.RUNTIME)
public @interface SkipInEquals {
}
public static boolean comparePublicNonFinalFieldsWithSkip(@NotNull Object first, @NotNull Object second) {
return comparePublicNonFinalFields(first, second, field -> field.getAnnotation(SkipInEquals.class) == null);
}
private static boolean comparePublicNonFinalFields(
@NotNull Object first,
@NotNull Object second,
@Nullable Predicate<Field> acceptPredicate
) {
Set<Field> firstFields = ContainerUtil.newHashSet(first.getClass().getFields());
for (Field field : second.getClass().getFields()) {
if (firstFields.contains(field)) {
if (isPublic(field) && !isFinal(field) && (acceptPredicate == null || acceptPredicate.apply(field))) {
try {
if (!Comparing.equal(field.get(first), field.get(second))) {
return false;
}
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
return true;
}
private static boolean isPublic(Field field) {
return (field.getModifiers() & Modifier.PUBLIC) != 0;
}
private static boolean isFinal(Field field) {
return (field.getModifiers() & Modifier.FINAL) != 0;
}
}

View File

@@ -1,24 +0,0 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compileOnly(project(":compiler:util"))
compileOnly(project(":compiler:frontend"))
compileOnly(project(":compiler:frontend.java"))
compileOnly(project(":idea:idea-frontend-independent"))
compileOnly(project(":js:js.frontend"))
compileOnly(project(":js:js.serializer"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "guava", rootProject = rootProject) }
}
sourceSets {
"main" { projectDefault() }
"test" {}
}
sourcesJar()
javadocJar()

View File

@@ -1,62 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.caches.project
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootModificationTracker
import com.intellij.openapi.util.UserDataHolder
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
fun <T> Module.cacheByClass(classForKey: Class<*>, vararg dependencies: Any, provider: () -> T): T {
return CachedValuesManager.getManager(project).cache(this, dependencies, classForKey, provider)
}
fun <T> Module.cacheByClassInvalidatingOnRootModifications(classForKey: Class<*>, provider: () -> T): T {
return cacheByClass(classForKey, ProjectRootModificationTracker.getInstance(project), provider = provider)
}
/**
* Note that it uses lambda's class for caching (essentially, anonymous class), which means that all invocations will be cached
* by the one and the same key.
* It is encouraged to use explicit class, just for the sake of readability.
*/
fun <T> Module.cacheInvalidatingOnRootModifications(provider: () -> T): T {
return cacheByClassInvalidatingOnRootModifications(provider::class.java, provider)
}
fun <T> Project.cacheByClass(classForKey: Class<*>, vararg dependencies: Any, provider: () -> T): T {
return CachedValuesManager.getManager(this).cache(this, dependencies, classForKey, provider)
}
fun <T> Project.cacheByClassInvalidatingOnRootModifications(classForKey: Class<*>, provider: () -> T): T {
return cacheByClass(classForKey, ProjectRootModificationTracker.getInstance(this), provider = provider)
}
/**
* Note that it uses lambda's class for caching (essentially, anonymous class), which means that all invocations will be cached
* by the one and the same key.
* It is encouraged to use explicit class, just for the sake of readability.
*/
fun <T> Project.cacheInvalidatingOnRootModifications(provider: () -> T): T {
return cacheByClassInvalidatingOnRootModifications(provider::class.java, provider)
}
private fun <T> CachedValuesManager.cache(
holder: UserDataHolder,
dependencies: Array<out Any>,
classForKey: Class<*>,
provider: () -> T
): T {
return getCachedValue(
holder,
getKeyForClass(classForKey),
{ CachedValueProvider.Result.create(provider(), dependencies) },
false
)
}

View File

@@ -1,41 +0,0 @@
/*
* 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.caches.resolve
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache
interface KotlinCacheService {
companion object {
fun getInstance(project: Project): KotlinCacheService = ServiceManager.getService(project, KotlinCacheService::class.java)!!
}
fun getResolutionFacade(elements: List<KtElement>): ResolutionFacade
fun getResolutionFacade(elements: List<KtElement>, platform: TargetPlatform): ResolutionFacade
fun getResolutionFacadeByFile(file: PsiFile, platform: TargetPlatform): ResolutionFacade?
fun getSuppressionCache(): KotlinSuppressCache
fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, platform: TargetPlatform): ResolutionFacade?
fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, settings: PlatformAnalysisSettings): ResolutionFacade?
}

View File

@@ -1,22 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.caches.resolve
/**
* Regulates which sources should be analyzed together.
*
* There are exactly two descendants, which are in strong one-to-one correspondence with [ResolutionModeComponent.Mode] (meaning
* that after checking value of ResolutionMode, it's safe to downcast settings instance to the respective type):
* - [PlatformAnalysisSettingsImpl] should be used iff we're working under [Mode.SEPARATE], and will create separate
* facade for each platforms, sdk, builtIns settings and other stuff.
* This is the old and stable mode, which should be used by default.
*
* - [CompositeAnalysisSettings] should be used iff we're working under [Mode.COMPOSITE], and will analyze all sources
* together, in one facade.
* This mode is new and experimental, and works only together with TypeRefinement facilities in the compiler's frontend.
* This mode is currently enabled only for HMPP projects
*/
interface PlatformAnalysisSettings

View File

@@ -1,110 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.analysis
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor
@JvmOverloads
@OptIn(FrontendInternals::class)
fun KtExpression.computeTypeInfoInContext(
scope: LexicalScope,
contextExpression: KtExpression = this,
trace: BindingTrace = BindingTraceContext(),
dataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY,
expectedType: KotlinType = TypeUtils.NO_EXPECTED_TYPE,
isStatement: Boolean = false,
contextDependency: ContextDependency = ContextDependency.INDEPENDENT,
expressionTypingServices: ExpressionTypingServices = contextExpression.getResolutionFacade().frontendService<ExpressionTypingServices>()
): KotlinTypeInfo {
PreliminaryDeclarationVisitor.createForExpression(this, trace, expressionTypingServices.languageVersionSettings)
return expressionTypingServices.getTypeInfo(
scope, this, expectedType, dataFlowInfo, InferenceSession.default, trace, isStatement, contextExpression, contextDependency
)
}
@JvmOverloads
@OptIn(FrontendInternals::class)
fun KtExpression.analyzeInContext(
scope: LexicalScope,
contextExpression: KtExpression = this,
trace: BindingTrace = BindingTraceContext(),
dataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY,
expectedType: KotlinType = TypeUtils.NO_EXPECTED_TYPE,
isStatement: Boolean = false,
contextDependency: ContextDependency = ContextDependency.INDEPENDENT,
expressionTypingServices: ExpressionTypingServices = contextExpression.getResolutionFacade().frontendService<ExpressionTypingServices>()
): BindingContext {
computeTypeInfoInContext(
scope,
contextExpression,
trace,
dataFlowInfo,
expectedType,
isStatement,
contextDependency,
expressionTypingServices
)
return trace.bindingContext
}
@JvmOverloads
fun KtExpression.computeTypeInContext(
scope: LexicalScope,
contextExpression: KtExpression = this,
trace: BindingTrace = BindingTraceContext(),
dataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY,
expectedType: KotlinType = TypeUtils.NO_EXPECTED_TYPE
): KotlinType? = computeTypeInfoInContext(scope, contextExpression, trace, dataFlowInfo, expectedType).type
@JvmOverloads
fun KtExpression.analyzeAsReplacement(
expressionToBeReplaced: KtExpression,
bindingContext: BindingContext,
scope: LexicalScope,
trace: BindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace for analyzeAsReplacement()"),
contextDependency: ContextDependency = ContextDependency.INDEPENDENT
): BindingContext = analyzeInContext(
scope,
expressionToBeReplaced,
dataFlowInfo = bindingContext.getDataFlowInfoBefore(expressionToBeReplaced),
expectedType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, expressionToBeReplaced] ?: TypeUtils.NO_EXPECTED_TYPE,
isStatement = expressionToBeReplaced.isUsedAsStatement(bindingContext),
trace = trace,
contextDependency = contextDependency
)
@JvmOverloads
fun KtExpression.analyzeAsReplacement(
expressionToBeReplaced: KtExpression,
bindingContext: BindingContext,
resolutionFacade: ResolutionFacade = expressionToBeReplaced.getResolutionFacade(),
trace: BindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace for analyzeAsReplacement()"),
contextDependency: ContextDependency = ContextDependency.INDEPENDENT
): BindingContext {
val scope = expressionToBeReplaced.getResolutionScope(bindingContext, resolutionFacade)
return analyzeAsReplacement(expressionToBeReplaced, bindingContext, scope, trace, contextDependency)
}

View File

@@ -1,119 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.caches.resolve
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException
/**
* This function throws exception when resolveToDescriptorIfAny returns null, otherwise works equivalently.
*/
fun KtDeclaration.unsafeResolveToDescriptor(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL
): DeclarationDescriptor =
resolveToDescriptorIfAny(resolutionFacade, bodyResolveMode) ?: throw NoDescriptorForDeclarationException(this)
/**
* This function first uses declaration resolvers to resolve this declaration and/or additional declarations (e.g. its parent),
* and then takes the relevant descriptor from binding context.
* The exact set of declarations to resolve depends on bodyResolveMode
*/
fun KtDeclaration.resolveToDescriptorIfAny(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): DeclarationDescriptor? {
//TODO: BodyResolveMode.PARTIAL is not quite safe!
val context = analyze(resolutionFacade, bodyResolveMode)
return if (this is KtParameter && hasValOrVar()) {
context.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, this)
// It is incorrect to have `val/var` parameters outside the primary constructor (e.g., `fun foo(val x: Int)`)
// but we still want to try to resolve in such cases.
?: context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, this)
} else {
context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, this)
}
}
fun KtAnnotationEntry.resolveToDescriptorIfAny(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): AnnotationDescriptor? {
//TODO: BodyResolveMode.PARTIAL is not quite safe!
val context = analyze(resolutionFacade, bodyResolveMode)
return context.get(BindingContext.ANNOTATION, this)
}
fun KtClassOrObject.resolveToDescriptorIfAny(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): ClassDescriptor? {
return (this as KtDeclaration).resolveToDescriptorIfAny(resolutionFacade, bodyResolveMode) as? ClassDescriptor
}
fun KtNamedFunction.resolveToDescriptorIfAny(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): FunctionDescriptor? {
return (this as KtDeclaration).resolveToDescriptorIfAny(resolutionFacade, bodyResolveMode) as? FunctionDescriptor
}
fun KtProperty.resolveToDescriptorIfAny(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): VariableDescriptor? {
return (this as KtDeclaration).resolveToDescriptorIfAny(resolutionFacade, bodyResolveMode) as? VariableDescriptor
}
fun KtParameter.resolveToParameterDescriptorIfAny(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): ValueParameterDescriptor? {
val context = analyze(resolutionFacade, bodyResolveMode)
return context.get(BindingContext.VALUE_PARAMETER, this) as? ValueParameterDescriptor
}
fun KtElement.resolveToCall(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): ResolvedCall<out CallableDescriptor>? =
getResolvedCall(analyze(resolutionFacade, bodyResolveMode))
@JvmOverloads
fun KtElement.analyze(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL
): BindingContext =
resolutionFacade.analyze(this, bodyResolveMode)
fun KtElement.analyzeAndGetResult(resolutionFacade: ResolutionFacade): AnalysisResult =
AnalysisResult.success(resolutionFacade.analyze(this), resolutionFacade.moduleDescriptor)
// This function is used on declarations to make analysis not only declaration itself but also it content:
// body for declaration with body, initializer & accessors for properties
fun KtElement.analyzeWithContentAndGetResult(resolutionFacade: ResolutionFacade): AnalysisResult =
resolutionFacade.analyzeWithAllCompilerChecks(listOf(this))
// This function is used on declarations to make analysis not only declaration itself but also it content:
// body for declaration with body, initializer & accessors for properties
fun KtDeclaration.analyzeWithContent(resolutionFacade: ResolutionFacade): BindingContext =
resolutionFacade.analyzeWithAllCompilerChecks(listOf(this)).bindingContext
// This function is used to make full analysis of declaration container.
// All its declarations, including their content (see above), are analyzed.
inline fun <reified T> T.analyzeWithContent(resolutionFacade: ResolutionFacade): BindingContext where T : KtDeclarationContainer, T : KtElement =
resolutionFacade.analyzeWithAllCompilerChecks(listOf(this)).bindingContext

View File

@@ -1,218 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:JvmName("ResolutionUtils")
package org.jetbrains.kotlin.idea.caches.resolve
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
fun KtElement.getResolutionFacade(): ResolutionFacade =
KotlinCacheService.getInstance(project).getResolutionFacade(listOf(this))
/**
* For local declarations is equivalent to unsafeResolveToDescriptor(bodyResolveMode)
*
* But for non-local declarations it ignores bodyResolveMode and uses LazyDeclarationResolver directly
*/
@Deprecated(
message = "This function has unclear semantics. Please use either unsafeResolveToDescriptor or resolveToDescriptorIfAny instead",
replaceWith = ReplaceWith("unsafeResolveToDescriptor")
)
fun KtDeclaration.resolveToDescriptor(bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): DeclarationDescriptor =
getResolutionFacade().resolveToDescriptor(this, bodyResolveMode)
/**
* This function throws exception when resolveToDescriptorIfAny returns null, otherwise works equivalently.
*
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtDeclaration.unsafeResolveToDescriptor(
bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL
): DeclarationDescriptor =
unsafeResolveToDescriptor(getResolutionFacade(), bodyResolveMode)
/**
* This function first uses declaration resolvers to resolve this declaration and/or additional declarations (e.g. its parent),
* and then takes the relevant descriptor from binding context.
* The exact set of declarations to resolve depends on bodyResolveMode
*
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtDeclaration.resolveToDescriptorIfAny(
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): DeclarationDescriptor? =
resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode)
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtClassOrObject.resolveToDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) =
resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode)
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtNamedFunction.resolveToDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) =
resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode)
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtProperty.resolveToDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) =
resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode)
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtParameter.resolveToParameterDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) =
resolveToParameterDescriptorIfAny(getResolutionFacade(), bodyResolveMode)
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtElement.resolveToCall(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) =
resolveToCall(getResolutionFacade(), bodyResolveMode)
fun KtFile.resolveImportReference(fqName: FqName): Collection<DeclarationDescriptor> {
val facade = getResolutionFacade()
return facade.resolveImportReference(facade.moduleDescriptor, fqName)
}
fun KtAnnotationEntry.resolveToDescriptorIfAny(
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL_NO_ADDITIONAL
): AnnotationDescriptor? =
resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode)
// This and next functions are used for 'normal' element analysis
// This analysis *should* provide all information extractable from this KtElement except:
// - for declarations, it does not analyze their bodies
// - for classes, it does not analyze their content
// - for member / top-level properties, it does not analyze initializers / accessors
// This information includes related descriptors, resolved calls (but not inside body, see above!)
// and many other binding context slices.
// Normally, the function is used on local declarations or statements / expressions
// Any usage on non-local declaration is a bit suspicious,
// consider replacing it with resolveToDescriptorIfAny and
// remember that body / content is not analyzed;
// if it's necessary, use analyzeWithContent()
//
// If you need diagnostics in result context, use BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS.
// BodyResolveMode.FULL analyzes all statements on the level of KtElement and above.
// BodyResolveMode.PARTIAL analyzes only statements necessary for this KtElement precise analysis.
//
// See also: ResolveSessionForBodies, ResolveElementCache
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
@JvmOverloads
fun KtElement.analyze(
bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL
): BindingContext =
analyze(getResolutionFacade(), bodyResolveMode)
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtElement.analyzeAndGetResult(): AnalysisResult {
return analyzeAndGetResult(getResolutionFacade())
}
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtElement.analyzeWithContentAndGetResult(): AnalysisResult =
analyzeWithContentAndGetResult(getResolutionFacade())
fun KtElement.findModuleDescriptor(): ModuleDescriptor = getResolutionFacade().moduleDescriptor
// This function is used on declarations to make analysis not only declaration itself but also it content:
// body for declaration with body, initializer & accessors for properties
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtDeclaration.analyzeWithContent(): BindingContext =
analyzeWithContent(getResolutionFacade())
// This function is used to make full analysis of declaration container.
// All its declarations, including their content (see above), are analyzed.
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
inline fun <reified T> T.analyzeWithContent(): BindingContext where T : KtDeclarationContainer, T : KtElement =
analyzeWithContent(getResolutionFacade())
/**
* This function is expected to produce the same result as compiler for the whole file content (including diagnostics,
* trace slices, descriptors, etc.).
*
* It's not recommended to call this function without real need.
*
* @ref [KotlinCacheService]
* @ref [org.jetbrains.kotlin.idea.caches.resolve.PerFileAnalysisCache]
*/
fun KtFile.analyzeWithAllCompilerChecks(vararg extraFiles: KtFile): AnalysisResult =
this.analyzeWithAllCompilerChecks(null, *extraFiles)
fun KtFile.analyzeWithAllCompilerChecks(callback: ((Diagnostic) -> Unit)?, vararg extraFiles: KtFile): AnalysisResult =
KotlinCacheService.getInstance(project).getResolutionFacade(listOf(this) + extraFiles.toList())
.analyzeWithAllCompilerChecks(listOf(this), callback)
/**
* This function is expected to produce the same result as compiler for the given element and its children (including diagnostics,
* trace slices, descriptors, etc.). For some expression element it actually performs analyze for some parent (usually declaration).
*
* It's not recommended to call this function without real need.
*
* NB: for statements / expressions, usually should be replaced with analyze(),
* for declarations, analyzeWithContent() will do what you want.
*
* @ref [KotlinCacheService]
* @ref [org.jetbrains.kotlin.idea.caches.resolve.PerFileAnalysisCache]
*/
@Deprecated(
"Use either KtFile.analyzeWithAllCompilerChecks() or KtElement.analyzeAndGetResult()",
ReplaceWith("analyzeAndGetResult()")
)
fun KtElement.analyzeWithAllCompilerChecks(): AnalysisResult = getResolutionFacade().analyzeWithAllCompilerChecks(listOf(this))
// this method don't check visibility and collect all descriptors with given fqName
@OptIn(FrontendInternals::class)
fun ResolutionFacade.resolveImportReference(
moduleDescriptor: ModuleDescriptor,
fqName: FqName
): Collection<DeclarationDescriptor> {
val importDirective = KtPsiFactory(project).createImportDirective(ImportPath(fqName, false))
val qualifiedExpressionResolver = this.getFrontendService(moduleDescriptor, QualifiedExpressionResolver::class.java)
return qualifiedExpressionResolver.processImportReference(
importDirective,
moduleDescriptor,
BindingTraceContext(),
excludedImportNames = emptyList(),
packageFragmentForVisibilityCheck = null
)?.getContributedDescriptors() ?: emptyList()
}
@Suppress("DEPRECATION")
@Deprecated(
"This method is going to be removed in 1.3.0 release",
ReplaceWith("analyzeWithAllCompilerChecks().bindingContext"),
DeprecationLevel.ERROR
)
fun KtElement.analyzeFully(): BindingContext = analyzeWithAllCompilerChecks().bindingContext

View File

@@ -1,198 +0,0 @@
/*
* 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.quickfix;
import com.intellij.extapi.psi.ASTDelegatePsiElement;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode;
import org.jetbrains.kotlin.types.DeferredType;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
public class QuickFixUtil {
private QuickFixUtil() {
}
public static boolean removePossiblyWhiteSpace(ASTDelegatePsiElement element, PsiElement possiblyWhiteSpace) {
if (possiblyWhiteSpace instanceof PsiWhiteSpace) {
element.deleteChildInternal(possiblyWhiteSpace.getNode());
return true;
}
return false;
}
@Nullable
public static <T extends PsiElement> T getParentElementOfType(Diagnostic diagnostic, Class<T> aClass) {
return PsiTreeUtil.getParentOfType(diagnostic.getPsiElement(), aClass, false);
}
@Nullable
public static KotlinType getDeclarationReturnType(KtNamedDeclaration declaration) {
PsiFile file = declaration.getContainingFile();
if (!(file instanceof KtFile)) return null;
DeclarationDescriptor descriptor = ResolutionUtils.unsafeResolveToDescriptor(declaration, BodyResolveMode.FULL);
if (!(descriptor instanceof CallableDescriptor)) return null;
KotlinType type = ((CallableDescriptor) descriptor).getReturnType();
if (type instanceof DeferredType) {
type = ((DeferredType) type).getDelegate();
}
return type;
}
@Nullable
public static KotlinType findLowerBoundOfOverriddenCallablesReturnTypes(@NotNull CallableDescriptor descriptor) {
KotlinType matchingReturnType = null;
for (CallableDescriptor overriddenDescriptor : ((CallableDescriptor) descriptor).getOverriddenDescriptors()) {
KotlinType overriddenReturnType = overriddenDescriptor.getReturnType();
if (overriddenReturnType == null) {
return null;
}
if (matchingReturnType == null || KotlinTypeChecker.DEFAULT.isSubtypeOf(overriddenReturnType, matchingReturnType)) {
matchingReturnType = overriddenReturnType;
}
else if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(matchingReturnType, overriddenReturnType)) {
return null;
}
}
return matchingReturnType;
}
@Nullable
public static PsiElement safeGetDeclaration(@Nullable CallableDescriptor descriptor) {
//do not create fix if descriptor has more than one overridden declaration
if (descriptor == null || descriptor.getOverriddenDescriptors().size() > 1) return null;
return DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
}
@Nullable
public static KtParameter getParameterDeclarationForValueArgument(
@NotNull ResolvedCall<?> resolvedCall,
@Nullable ValueArgument valueArgument
) {
PsiElement declaration = safeGetDeclaration(CallUtilKt.getParameterForArgument(resolvedCall, valueArgument));
return declaration instanceof KtParameter ? (KtParameter) declaration : null;
}
private static boolean equalOrLastInBlock(KtExpression block, KtExpression expression) {
if (block == expression) return true;
return block instanceof KtBlockExpression && expression.getParent() == block &&
PsiTreeUtil.getNextSiblingOfType(expression, KtExpression.class) == null;
}
@Nullable
public static KtIfExpression getParentIfForBranch(@Nullable KtExpression expression) {
KtIfExpression ifExpression = PsiTreeUtil.getParentOfType(expression, KtIfExpression.class, true);
if (ifExpression == null) return null;
if (equalOrLastInBlock(ifExpression.getThen(), expression)
|| equalOrLastInBlock(ifExpression.getElse(), expression)) {
return ifExpression;
}
return null;
}
@Nullable
private static KtWhenExpression getParentWhenForBranch(@Nullable KtExpression expression) {
KtWhenEntry whenEntry = PsiTreeUtil.getParentOfType(expression, KtWhenEntry.class, true);
if (whenEntry == null) return null;
KtExpression whenEntryExpression = whenEntry.getExpression();
if (whenEntryExpression == null) return null;
if (!equalOrLastInBlock(whenEntryExpression, expression)) return null;
return PsiTreeUtil.getParentOfType(whenEntry, KtWhenExpression.class, true);
}
@Nullable
private static KtExpression getParentForBranch(@Nullable KtExpression expression) {
KtExpression parent = getParentIfForBranch(expression);
if (parent != null) return parent;
return getParentWhenForBranch(expression);
}
// Returns true iff parent's value always or sometimes is evaluable to child's value, e.g.
// parent = (x), child = x;
// parent = if (...) x else y, child = x;
// parent = y.x, child = x
public static boolean canEvaluateTo(KtExpression parent, KtExpression child) {
if (parent == null || child == null) {
return false;
}
while (parent != child) {
PsiElement childParent = child.getParent();
if (childParent instanceof KtParenthesizedExpression) {
child = (KtExpression) childParent;
continue;
}
if (childParent instanceof KtDotQualifiedExpression &&
(child instanceof KtCallExpression || child instanceof KtDotQualifiedExpression)) {
child = (KtExpression) childParent;
continue;
}
child = getParentForBranch(child);
if (child == null) return false;
}
return true;
}
public static boolean canFunctionOrGetterReturnExpression(@NotNull KtDeclaration functionOrGetter, @NotNull KtExpression expression) {
if (functionOrGetter instanceof KtFunctionLiteral) {
KtBlockExpression functionLiteralBody = ((KtFunctionLiteral) functionOrGetter).getBodyExpression();
PsiElement returnedElement = null;
if (functionLiteralBody != null) {
PsiElement[] children = functionLiteralBody.getChildren();
int length = children.length;
if (length > 0) {
returnedElement = children[length - 1];
}
}
return returnedElement instanceof KtExpression && canEvaluateTo((KtExpression) returnedElement, expression);
}
else {
if (functionOrGetter instanceof KtDeclarationWithInitializer && canEvaluateTo(((KtDeclarationWithInitializer) functionOrGetter).getInitializer(), expression)) {
return true;
}
KtReturnExpression returnExpression = PsiTreeUtil.getParentOfType(expression, KtReturnExpression.class);
return returnExpression != null && canEvaluateTo(returnExpression.getReturnedExpression(), expression);
}
}
public static String renderTypeWithFqNameOnClash(KotlinType type, String nameToCheckAgainst) {
FqName fqNameToCheckAgainst = new FqName(nameToCheckAgainst);
ClassifierDescriptor typeClassifierDescriptor = type.getConstructor().getDeclarationDescriptor();
FqName typeFqName = typeClassifierDescriptor != null ? DescriptorUtils.getFqNameSafe(typeClassifierDescriptor) : fqNameToCheckAgainst;
DescriptorRenderer renderer = typeFqName.shortName().equals(fqNameToCheckAgainst.shortName())
? IdeDescriptorRenderers.SOURCE_CODE
: IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS;
return renderer.renderType(type);
}
}

View File

@@ -1,372 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.imports
import com.intellij.openapi.progress.ProgressManager
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.idea.analysis.analyzeAsReplacement
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider
import org.jetbrains.kotlin.resolve.scopes.ImportingScope
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf
import org.jetbrains.kotlin.resolve.scopes.utils.replaceImportingScopes
class OptimizedImportsBuilder(
private val file: KtFile,
private val data: InputData,
private val options: Options
) {
companion object {
@get:TestOnly
@set:TestOnly
var testLog: StringBuilder? = null
}
interface AbstractReference {
val element: KtElement
val dependsOnNames: Collection<Name>
fun resolve(bindingContext: BindingContext): Collection<DeclarationDescriptor>
}
class InputData(
val descriptorsToImport: Set<DeclarationDescriptor>,
val namesToImport: Map<FqName, Set<Name>>,
val references: Collection<AbstractReference>,
val unresolvedNames: Set<Name>,
)
class Options(
val nameCountToUseStarImport: Int,
val nameCountToUseStarImportForMembers: Int,
val isInPackagesToUseStarImport: (FqName) -> Boolean
)
private val importInsertHelper = ImportInsertHelper.getInstance(file.project)
private sealed class ImportRule {
// force presence of this import
data class Add(val importPath: ImportPath) : ImportRule() {
override fun toString() = "+$importPath"
}
// force absence of this import
data class DoNotAdd(val importPath: ImportPath) : ImportRule() {
override fun toString() = "-$importPath"
}
}
private val importRules = HashSet<ImportRule>()
fun buildOptimizedImports(): List<ImportPath>? {
val facade = file.getResolutionFacade()
file.importDirectives
.asSequence()
.filter { it.mayReferToSomeUnresolvedName() || it.isExistedUnresolvedName(facade) }
.mapNotNull { it.importPath }
.mapNotNullTo(importRules) { ImportRule.Add(it) }
while (true) {
ProgressManager.checkCanceled()
val importRulesBefore = importRules.size
val result = tryBuildOptimizedImports()
if (importRules.size == importRulesBefore) return result
testLog?.append("Trying to build import list again with import rules: ${importRules.joinToString()}\n")
}
}
private fun KtImportDirective.mayReferToSomeUnresolvedName() = isAllUnder && data.unresolvedNames.isNotEmpty()
private fun KtImportDirective.isExistedUnresolvedName(facade: ResolutionFacade) =
importedName in data.unresolvedNames && !canResolve(facade)
private fun getExpressionToAnalyze(element: KtElement): KtExpression? {
val parent = element.parent
return when {
parent is KtQualifiedExpression && element == parent.selectorExpression -> parent
parent is KtCallExpression && element == parent.calleeExpression -> getExpressionToAnalyze(parent)
parent is KtOperationExpression && element == parent.operationReference -> parent
parent is KtUserType -> null //TODO: is it always correct?
else -> element as? KtExpression //TODO: what if not expression? Example: KtPropertyDelegationMethodsReference
}
}
private fun tryBuildOptimizedImports(): List<ImportPath>? {
val importsToGenerate = hashSetOf<ImportPath>()
importRules.filterIsInstance<ImportRule.Add>().mapTo(importsToGenerate) { it.importPath }
val descriptorsByParentFqName = HashMap<FqName, MutableSet<DeclarationDescriptor>>()
for (descriptor in data.descriptorsToImport) {
val fqName = descriptor.importableFqName!!
for (name in data.namesToImport.getValue(fqName)) {
val alias = if (name != fqName.shortName()) name else null
val explicitImportPath = ImportPath(fqName, false, alias)
if (explicitImportPath in importsToGenerate) continue
val parentFqName = fqName.parent()
if (alias == null && canUseStarImport(descriptor, fqName) && ImportPath(parentFqName, true).isAllowedByRules()) {
descriptorsByParentFqName.getOrPut(parentFqName) { hashSetOf() }.add(descriptor)
} else {
importsToGenerate.add(explicitImportPath)
}
}
}
val classNamesToCheck = hashSetOf<FqName>()
for (parentFqName in descriptorsByParentFqName.keys) {
ProgressManager.checkCanceled()
val starImportPath = ImportPath(parentFqName, true)
if (starImportPath in importsToGenerate) continue
val descriptors = descriptorsByParentFqName[parentFqName]!!
val fqNames = descriptors.map { it.importableFqName!! }.toSet()
val nameCountToUseStar = descriptors.first().nameCountToUseStar()
val useExplicitImports = fqNames.size < nameCountToUseStar && !options.isInPackagesToUseStarImport(parentFqName)
|| !starImportPath.isAllowedByRules()
if (useExplicitImports) {
fqNames.filter(this::needExplicitImport).mapTo(importsToGenerate) { ImportPath(it, false) }
} else {
descriptors.asSequence()
.filterIsInstance<ClassDescriptor>()
.map { it.importableFqName!! }
.filterTo(classNamesToCheck, this::needExplicitImport)
if (fqNames.all(this::needExplicitImport)) {
importsToGenerate.add(starImportPath)
}
}
}
// now check that there are no conflicts and all classes are really imported
addExplicitImportsForClassesWhenRequired(classNamesToCheck, descriptorsByParentFqName, importsToGenerate, file)
val sortedImportsToGenerate = importsToGenerate.sortedWith(importInsertHelper.importSortComparator)
// check if no changes to imports required
val oldImports = file.importDirectives
if (oldImports.size == sortedImportsToGenerate.size && oldImports.map { it.importPath } == sortedImportsToGenerate) return null
val originalFileScope = file.getFileResolutionScope()
val newFileScope = buildScopeByImports(file, sortedImportsToGenerate)
var references = data.references
if (testLog != null) {
// to make log the same for all runs
references = references.sortedBy { it.toString() }
}
for ((names, refs) in references.groupBy { it.dependsOnNames }) {
if (!areScopeSlicesEqual(originalFileScope, newFileScope, names)) {
for (ref in refs) {
ProgressManager.checkCanceled()
val element = ref.element
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
val expressionToAnalyze = getExpressionToAnalyze(element) ?: continue
val newScope = element.getResolutionScope(
bindingContext,
file.getResolutionFacade()
).replaceImportingScopes(newFileScope)
val newBindingContext = expressionToAnalyze.analyzeAsReplacement(
expressionToAnalyze,
bindingContext,
newScope,
trace = BindingTraceContext()
)
testLog?.append("Additional checking of reference $ref\n")
val oldTargets = ref.resolve(bindingContext)
val newTargets = ref.resolve(newBindingContext)
if (!areTargetsEqual(oldTargets, newTargets)) {
testLog?.append("Changed resolve of $ref\n")
(oldTargets + newTargets).forEach {
lockImportForDescriptor(it, names)
}
}
}
}
}
return sortedImportsToGenerate
}
private fun lockImportForDescriptor(descriptor: DeclarationDescriptor, existingNames: Collection<Name>) {
val fqName = descriptor.importableFqName ?: return
val names = data.namesToImport.getOrElse(fqName) { listOf(descriptor.name) }.intersect(existingNames)
val starImportPath = ImportPath(fqName.parent(), true)
val importPaths = file.importDirectives.map { it.importPath }
for (name in names) {
val alias = if (name != fqName.shortName()) name else null
val explicitImportPath = ImportPath(fqName, false, alias)
when {
explicitImportPath in importPaths ->
importRules.add(ImportRule.Add(explicitImportPath))
alias == null && starImportPath in importPaths ->
importRules.add(ImportRule.Add(starImportPath))
else -> // there is no import for this descriptor in the original import list, so do not allow to import it by star-import
importRules.add(ImportRule.DoNotAdd(starImportPath))
}
}
}
private fun addExplicitImportsForClassesWhenRequired(
classNamesToCheck: Collection<FqName>,
descriptorsByParentFqName: Map<FqName, MutableSet<DeclarationDescriptor>>,
importsToGenerate: MutableSet<ImportPath>,
originalFile: KtFile
) {
val scope = buildScopeByImports(originalFile, importsToGenerate.filter { it.isAllUnder })
for (fqName in classNamesToCheck) {
if (scope.findClassifier(fqName.shortName(), NoLookupLocation.FROM_IDE)?.importableFqName != fqName) {
// add explicit import if failed to import with * (or from current package)
importsToGenerate.add(ImportPath(fqName, false))
val parentFqName = fqName.parent()
val siblingsToImport = descriptorsByParentFqName.getValue(parentFqName)
for (descriptor in siblingsToImport.filter { it.importableFqName == fqName }) {
siblingsToImport.remove(descriptor)
}
if (siblingsToImport.isEmpty()) { // star import is not really needed
importsToGenerate.remove(ImportPath(parentFqName, true))
}
}
}
}
private fun buildScopeByImports(originalFile: KtFile, importsToGenerate: Collection<ImportPath>): ImportingScope {
val fileText = buildString {
append("package ")
append(originalFile.packageFqName.toUnsafe().render())
append("\n")
for (importPath in importsToGenerate) {
append("import ")
append(importPath.pathStr)
if (importPath.hasAlias()) {
append("=")
append(importPath.alias!!.render())
}
append("\n")
}
}
val fileWithImports = KtPsiFactory(originalFile).createAnalyzableFile("Dummy_" + originalFile.name, fileText, originalFile)
if (file.isScript()) {
fileWithImports.originalFile = originalFile
}
return fileWithImports.getFileResolutionScope()
}
@OptIn(FrontendInternals::class)
private fun KtFile.getFileResolutionScope() =
getResolutionFacade().frontendService<FileScopeProvider>().getFileScopes(this).importingScope
private fun areScopeSlicesEqual(scope1: ImportingScope, scope2: ImportingScope, names: Collection<Name>): Boolean {
val tower1 = scope1.extractSliceTower(names)
val tower2 = scope2.extractSliceTower(names)
val iterator1 = tower1.iterator()
val iterator2 = tower2.iterator()
while (true) {
when {
!iterator1.hasNext() -> return !iterator2.hasNext()
!iterator2.hasNext() -> return false
else -> if (!areTargetsEqual(iterator1.next(), iterator2.next())) return false
}
}
}
private fun ImportingScope.extractSliceTower(names: Collection<Name>): Sequence<Collection<DeclarationDescriptor>> {
return parentsWithSelf
.map { scope ->
names.flatMap { name ->
ProgressManager.checkCanceled()
val contributedFunctions = scope.getContributedFunctions(name, NoLookupLocation.FROM_IDE)
ProgressManager.checkCanceled()
val contributedVariables = scope.getContributedVariables(name, NoLookupLocation.FROM_IDE)
ProgressManager.checkCanceled()
val contributedClassifier = scope.getContributedClassifier(name, NoLookupLocation.FROM_IDE)
contributedFunctions + contributedVariables + listOfNotNull(contributedClassifier)
}
}
.filter { it.isNotEmpty() }
}
private fun canUseStarImport(descriptor: DeclarationDescriptor, fqName: FqName): Boolean = when {
fqName.parent().isRoot -> false
(descriptor.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.OBJECT -> false
else -> true
}
private fun needExplicitImport(fqName: FqName): Boolean = hasAlias(fqName) || !isImportedByDefault(fqName)
private fun hasAlias(fqName: FqName) = data.namesToImport[fqName]?.let {
it.singleOrNull() == null
} ?: false
private fun isImportedByDefault(fqName: FqName) = importInsertHelper.isImportedWithDefault(ImportPath(fqName, false), file)
private fun isImportedByLowPriorityDefault(fqName: FqName) =
importInsertHelper.isImportedWithLowPriorityDefaultImport(ImportPath(fqName, false), file)
private fun DeclarationDescriptor.nameCountToUseStar(): Int {
val isMember = containingDeclaration is ClassDescriptor
return if (isMember)
options.nameCountToUseStarImportForMembers
else
options.nameCountToUseStarImport
}
private fun areTargetsEqual(descriptors1: Collection<DeclarationDescriptor>, descriptors2: Collection<DeclarationDescriptor>): Boolean {
return descriptors1.size == descriptors2.size &&
descriptors1.zip(descriptors2).all { (first, second) -> areTargetsEqual(first, second) } //TODO: can have different order?
}
private fun areTargetsEqual(first: DeclarationDescriptor, second: DeclarationDescriptor): Boolean {
if (first == second) return true
val firstFqName = first.importableFqName
val secondFqName = second.importableFqName
return firstFqName == secondFqName ||
(first.isAliasTo(second) && secondFqName != null && isImportedByLowPriorityDefault(secondFqName)) ||
(second.isAliasTo(first) && firstFqName != null && isImportedByLowPriorityDefault(firstFqName))
}
private fun DeclarationDescriptor.isAliasTo(other: DeclarationDescriptor): Boolean =
this is TypeAliasDescriptor && classDescriptor == other ||
this is TypeAliasConstructorDescriptor && underlyingConstructorDescriptor == other
private fun ImportPath.isAllowedByRules(): Boolean = importRules.none { it is ImportRule.DoNotAdd && it.importPath == this }
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.kdoc
import com.intellij.openapi.components.ServiceManager
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.resolve.BindingContext
interface SampleResolutionService {
fun resolveSample(
context: BindingContext,
fromDescriptor: DeclarationDescriptor,
resolutionFacade: ResolutionFacade,
qualifiedName: List<String>
): Collection<DeclarationDescriptor>
companion object {
/**
* It's internal implementation, please use [resolveKDocSampleLink], or [resolveKDocLink]
*/
internal fun resolveSample(
context: BindingContext,
fromDescriptor: DeclarationDescriptor,
resolutionFacade: ResolutionFacade,
qualifiedName: List<String>
): Collection<DeclarationDescriptor> {
val instance = ServiceManager.getService(resolutionFacade.project, SampleResolutionService::class.java)
return instance?.resolveSample(context, fromDescriptor, resolutionFacade, qualifiedName) ?: emptyList()
}
}
}

View File

@@ -1,110 +0,0 @@
/*
* Copyright 2010-2016 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.kdoc
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
import org.jetbrains.kotlin.kdoc.psi.api.KDoc
import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
fun DeclarationDescriptor.findKDoc(
descriptorToPsi: (DeclarationDescriptorWithSource) -> PsiElement? = { DescriptorToSourceUtils.descriptorToDeclaration(it) }
): KDocTag? {
if (this is DeclarationDescriptorWithSource) {
val psiDeclaration = descriptorToPsi(this)?.navigationElement
return (psiDeclaration as? KtElement)?.findKDoc(descriptorToPsi)
}
return null
}
private typealias DescriptorToPsi = (DeclarationDescriptorWithSource) -> PsiElement?
fun KtElement.findKDoc(descriptorToPsi: DescriptorToPsi): KDocTag? {
return this.lookupOwnedKDoc()
?: this.lookupKDocInContainer()
?: this.lookupInheritedKDoc(descriptorToPsi)
}
private fun KtElement.lookupOwnedKDoc(): KDocTag? {
// KDoc for primary constructor is located inside of its class KDoc
val psiDeclaration = when (this) {
is KtPrimaryConstructor -> getContainingClassOrObject()
else -> this
}
if (psiDeclaration is KtDeclaration) {
val kdoc = psiDeclaration.docComment
if (kdoc != null) {
if (this is KtConstructor<*>) {
// ConstructorDescriptor resolves to the same JetDeclaration
val constructorSection = kdoc.findSectionByTag(KDocKnownTag.CONSTRUCTOR)
if (constructorSection != null) {
return constructorSection
}
}
return kdoc.getDefaultSection()
}
}
return null
}
private fun KtElement.lookupKDocInContainer(): KDocTag? {
val subjectName = name
val containingDeclaration =
PsiTreeUtil.findFirstParent(this, true) {
it is KtDeclarationWithBody && it !is KtPrimaryConstructor
|| it is KtClassOrObject
}
val containerKDoc = containingDeclaration?.getChildOfType<KDoc>()
if (containerKDoc == null || subjectName == null) return null
val propertySection = containerKDoc.findSectionByTag(KDocKnownTag.PROPERTY, subjectName)
val paramTag = containerKDoc.findDescendantOfType<KDocTag> { it.knownTag == KDocKnownTag.PARAM && it.getSubjectName() == subjectName }
return when {
this is KtParameter && this.isPropertyParameter() -> propertySection ?: paramTag
this is KtParameter || this is KtTypeParameter -> paramTag
this is KtProperty && containingDeclaration is KtClassOrObject -> propertySection
else -> null
}
}
private fun KtElement.lookupInheritedKDoc(descriptorToPsi: DescriptorToPsi): KDocTag? {
if (this is KtCallableDeclaration) {
val descriptor = this.resolveToDescriptorIfAny() as? CallableDescriptor ?: return null
for (baseDescriptor in descriptor.overriddenDescriptors) {
val baseKDoc = baseDescriptor.original.findKDoc(descriptorToPsi)
if (baseKDoc != null) {
return baseKDoc
}
}
}
return null
}

View File

@@ -1,287 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.kdoc
import com.intellij.openapi.components.ServiceManager
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.getFileResolutionScope
import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtQualifiedExpression
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil
import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.*
import org.jetbrains.kotlin.resolve.scopes.utils.*
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addIfNotNull
fun resolveKDocLink(
context: BindingContext,
resolutionFacade: ResolutionFacade,
fromDescriptor: DeclarationDescriptor,
fromSubjectOfTag: KDocTag?,
qualifiedName: List<String>
): Collection<DeclarationDescriptor> = when (fromSubjectOfTag?.knownTag) {
KDocKnownTag.PARAM -> resolveParamLink(fromDescriptor, qualifiedName)
KDocKnownTag.SAMPLE -> resolveKDocSampleLink(context, resolutionFacade, fromDescriptor, qualifiedName)
else -> resolveDefaultKDocLink(context, resolutionFacade, fromDescriptor, qualifiedName)
}
fun getParamDescriptors(fromDescriptor: DeclarationDescriptor): List<DeclarationDescriptor> {
// TODO resolve parameters of functions passed as parameters
when (fromDescriptor) {
is CallableDescriptor -> {
return fromDescriptor.valueParameters + fromDescriptor.typeParameters
}
is ClassifierDescriptor -> {
val typeParams = fromDescriptor.typeConstructor.parameters
if (fromDescriptor is ClassDescriptor) {
val constructorDescriptor = fromDescriptor.unsubstitutedPrimaryConstructor
if (constructorDescriptor != null) {
return typeParams + constructorDescriptor.valueParameters
}
}
return typeParams
}
else -> {
return emptyList()
}
}
}
private fun resolveParamLink(fromDescriptor: DeclarationDescriptor, qualifiedName: List<String>): List<DeclarationDescriptor> {
val name = qualifiedName.singleOrNull() ?: return emptyList()
return getParamDescriptors(fromDescriptor).filter { it.name.asString() == name }
}
fun resolveKDocSampleLink(
context: BindingContext,
resolutionFacade: ResolutionFacade,
fromDescriptor: DeclarationDescriptor,
qualifiedName: List<String>
): Collection<DeclarationDescriptor> {
val resolvedViaService = SampleResolutionService.resolveSample(context, fromDescriptor, resolutionFacade, qualifiedName)
if (resolvedViaService.isNotEmpty()) return resolvedViaService
return resolveDefaultKDocLink(context, resolutionFacade, fromDescriptor, qualifiedName)
}
private fun resolveDefaultKDocLink(
context: BindingContext,
resolutionFacade: ResolutionFacade,
fromDescriptor: DeclarationDescriptor,
qualifiedName: List<String>
): Collection<DeclarationDescriptor> {
val contextScope = getKDocLinkResolutionScope(resolutionFacade, fromDescriptor)
if (qualifiedName.size == 1) {
val shortName = Name.identifier(qualifiedName.single())
val descriptorsByName = SmartList<DeclarationDescriptor>()
descriptorsByName.addIfNotNull(contextScope.findClassifier(shortName, NoLookupLocation.FROM_IDE))
descriptorsByName.addIfNotNull(contextScope.findPackage(shortName))
descriptorsByName.addAll(contextScope.collectFunctions(shortName, NoLookupLocation.FROM_IDE))
descriptorsByName.addAll(contextScope.collectVariables(shortName, NoLookupLocation.FROM_IDE))
if (fromDescriptor is FunctionDescriptor && fromDescriptor.isExtension && shortName.asString() == "this") {
return listOfNotNull(fromDescriptor.extensionReceiverParameter)
}
// Try to find a matching local descriptor (parameter or type parameter) first
val localDescriptors = descriptorsByName.filter { it.containingDeclaration == fromDescriptor }
if (localDescriptors.isNotEmpty()) return localDescriptors
return descriptorsByName
}
val moduleDescriptor = fromDescriptor.module
@OptIn(FrontendInternals::class)
val qualifiedExpressionResolver = resolutionFacade.getFrontendService(moduleDescriptor, QualifiedExpressionResolver::class.java)
val contextElement = DescriptorToSourceUtils.descriptorToDeclaration(fromDescriptor)
val factory = KtPsiFactory(resolutionFacade.project)
// TODO escape identifiers
val codeFragment = factory.createExpressionCodeFragment(qualifiedName.joinToString("."), contextElement)
val qualifiedExpression =
codeFragment.findElementAt(codeFragment.textLength - 1)?.getStrictParentOfType<KtQualifiedExpression>() ?: return emptyList()
val (descriptor, memberName) = qualifiedExpressionResolver.resolveClassOrPackageInQualifiedExpression(
qualifiedExpression,
contextScope,
context
)
if (descriptor == null) return emptyList()
if (memberName != null) {
val memberScope = getKDocLinkMemberScope(descriptor, contextScope)
return memberScope.getContributedFunctions(memberName, NoLookupLocation.FROM_IDE) +
memberScope.getContributedVariables(memberName, NoLookupLocation.FROM_IDE) +
listOfNotNull(memberScope.getContributedClassifier(memberName, NoLookupLocation.FROM_IDE))
}
return listOf(descriptor)
}
private fun getPackageInnerScope(descriptor: PackageFragmentDescriptor): MemberScope {
return descriptor.containingDeclaration.getPackage(descriptor.fqName).memberScope
}
private fun getClassInnerScope(outerScope: LexicalScope, descriptor: ClassDescriptor): LexicalScope {
val headerScope = LexicalScopeImpl(
outerScope, descriptor, false, descriptor.thisAsReceiverParameter,
LexicalScopeKind.SYNTHETIC
) {
descriptor.declaredTypeParameters.forEach { addClassifierDescriptor(it) }
descriptor.constructors.forEach { addFunctionDescriptor(it) }
}
return LexicalChainedScope.create(
headerScope, descriptor, false, null, LexicalScopeKind.SYNTHETIC,
descriptor.defaultType.memberScope,
descriptor.staticScope,
descriptor.companionObjectDescriptor?.defaultType?.memberScope
)
}
fun getKDocLinkResolutionScope(resolutionFacade: ResolutionFacade, contextDescriptor: DeclarationDescriptor): LexicalScope {
return when (contextDescriptor) {
is PackageFragmentDescriptor ->
LexicalScope.Base(getPackageInnerScope(contextDescriptor).memberScopeAsImportingScope(), contextDescriptor)
is PackageViewDescriptor ->
LexicalScope.Base(contextDescriptor.memberScope.memberScopeAsImportingScope(), contextDescriptor)
is ClassDescriptor ->
getClassInnerScope(getOuterScope(contextDescriptor, resolutionFacade), contextDescriptor)
is FunctionDescriptor -> FunctionDescriptorUtil.getFunctionInnerScope(
getOuterScope(contextDescriptor, resolutionFacade),
contextDescriptor, LocalRedeclarationChecker.DO_NOTHING
)
is PropertyDescriptor ->
ScopeUtils.makeScopeForPropertyHeader(getOuterScope(contextDescriptor, resolutionFacade), contextDescriptor)
is DeclarationDescriptorNonRoot ->
getOuterScope(contextDescriptor, resolutionFacade)
else -> throw IllegalArgumentException("Cannot find resolution scope for root $contextDescriptor")
}
}
private fun getOuterScope(descriptor: DeclarationDescriptorWithSource, resolutionFacade: ResolutionFacade): LexicalScope {
val parent = descriptor.containingDeclaration!!
if (parent is PackageFragmentDescriptor) {
val containingFile = (descriptor.source as? PsiSourceElement)?.psi?.containingFile as? KtFile ?: return LexicalScope.Base(
ImportingScope.Empty,
parent
)
val kotlinCacheService = ServiceManager.getService(containingFile.project, KotlinCacheService::class.java)
val facadeToUse = kotlinCacheService?.getResolutionFacade(listOf(containingFile)) ?: resolutionFacade
return facadeToUse.getFileResolutionScope(containingFile)
} else {
return getKDocLinkResolutionScope(resolutionFacade, parent)
}
}
fun getKDocLinkMemberScope(descriptor: DeclarationDescriptor, contextScope: LexicalScope): MemberScope {
return when (descriptor) {
is PackageFragmentDescriptor -> getPackageInnerScope(descriptor)
is PackageViewDescriptor -> descriptor.memberScope
is ClassDescriptor -> {
ChainedMemberScope.create(
"Member scope for KDoc resolve", listOfNotNull(
descriptor.unsubstitutedMemberScope,
descriptor.staticScope,
descriptor.companionObjectDescriptor?.unsubstitutedMemberScope,
ExtensionsScope(descriptor, contextScope)
)
)
}
else -> MemberScope.Empty
}
}
private class ExtensionsScope(
private val receiverClass: ClassDescriptor,
private val contextScope: LexicalScope
) : MemberScope {
private val receiverTypes = listOf(receiverClass.defaultType)
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> {
return contextScope.collectFunctions(name, location).flatMap {
if (it is SimpleFunctionDescriptor && it.isExtension) it.substituteExtensionIfCallable(
receiverTypes,
CallType.DOT
) else emptyList()
}
}
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> {
return contextScope.collectVariables(name, location).flatMap {
if (it is PropertyDescriptor && it.isExtension) it.substituteExtensionIfCallable(
receiverTypes,
CallType.DOT
) else emptyList()
}
}
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null
override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
if (DescriptorKindExclude.Extensions in kindFilter.excludes) return emptyList()
return contextScope.collectDescriptorsFiltered(
kindFilter exclude DescriptorKindExclude.NonExtensions,
nameFilter,
changeNamesForAliased = true
).flatMap {
if (it is CallableDescriptor && it.isExtension) it.substituteExtensionIfCallable(
receiverTypes,
CallType.DOT
) else emptyList()
}
}
override fun getFunctionNames(): Set<Name> =
getContributedDescriptors(kindFilter = DescriptorKindFilter.FUNCTIONS).map { it.name }.toSet()
override fun getVariableNames(): Set<Name> =
getContributedDescriptors(kindFilter = DescriptorKindFilter.VARIABLES).map { it.name }.toSet()
override fun getClassifierNames() = null
override fun printScopeStructure(p: Printer) {
p.println("Extensions for ${receiverClass.name} in:")
contextScope.printStructure(p)
}
}

View File

@@ -1,93 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.refactoring.introduce
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.resolve.getLanguageVersionSettings
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.nextSiblingOfSameType
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
class ExtractableSubstringInfo(
val startEntry: KtStringTemplateEntry,
val endEntry: KtStringTemplateEntry,
val prefix: String,
val suffix: String,
type: KotlinType? = null
) {
private fun guessLiteralType(literal: String): KotlinType {
val facade = template.getResolutionFacade()
val module = facade.moduleDescriptor
val stringType = module.builtIns.stringType
if (startEntry != endEntry || startEntry !is KtLiteralStringTemplateEntry) return stringType
val expr = KtPsiFactory(startEntry).createExpressionIfPossible(literal) ?: return stringType
val context = facade.analyze(template, BodyResolveMode.PARTIAL)
val scope = template.getResolutionScope(context, facade)
val tempContext = expr.analyzeInContext(scope, template)
val trace = DelegatingBindingTrace(tempContext, "Evaluate '$literal'")
val languageVersionSettings = facade.getLanguageVersionSettings()
val value = ConstantExpressionEvaluator(module, languageVersionSettings, facade.project).evaluateExpression(expr, trace)
if (value == null || value.isError) return stringType
return value.toConstantValue(TypeUtils.NO_EXPECTED_TYPE).getType(module)
}
val template: KtStringTemplateExpression = startEntry.parent as KtStringTemplateExpression
val content = with(entries.map { it.text }.joinToString(separator = "")) { substring(prefix.length, length - suffix.length) }
val type = type ?: guessLiteralType(content)
val contentRange: TextRange
get() = TextRange(startEntry.startOffset + prefix.length, endEntry.endOffset - suffix.length)
val relativeContentRange: TextRange
get() = contentRange.shiftRight(-template.startOffset)
val entries: Sequence<KtStringTemplateEntry>
get() = generateSequence(startEntry) { if (it != endEntry) it.nextSiblingOfSameType() else null }
fun createExpression(): KtExpression {
val quote = template.firstChild.text
val literalValue = if (KotlinBuiltIns.isString(type)) "$quote$content$quote" else content
return KtPsiFactory(startEntry).createExpression(literalValue).apply { extractableSubstringInfo = this@ExtractableSubstringInfo }
}
fun copy(newTemplate: KtStringTemplateExpression): ExtractableSubstringInfo {
val oldEntries = template.entries
val newEntries = newTemplate.entries
val startIndex = oldEntries.indexOf(startEntry)
val endIndex = oldEntries.indexOf(endEntry)
if (startIndex < 0 || startIndex >= newEntries.size || endIndex < 0 || endIndex >= newEntries.size) {
throw AssertionError("Old template($startIndex..$endIndex): ${template.text}, new template: ${newTemplate.text}")
}
return ExtractableSubstringInfo(newEntries[startIndex], newEntries[endIndex], prefix, suffix, type)
}
}
var KtExpression.extractableSubstringInfo: ExtractableSubstringInfo? by UserDataProperty(Key.create("EXTRACTED_SUBSTRING_INFO"))
val KtExpression.substringContextOrThis: KtExpression
get() = extractableSubstringInfo?.template ?: this
val PsiElement.substringContextOrThis: PsiElement
get() = (this as? KtExpression)?.extractableSubstringInfo?.template ?: this

View File

@@ -1,29 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.util
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.command.CommandProcessor
enum class ActionRunningMode {
RUN_IN_CURRENT_THREAD,
RUN_IN_EDT
}
inline fun <T> ActionRunningMode.runAction(crossinline action: () -> T): T = when (this) {
ActionRunningMode.RUN_IN_CURRENT_THREAD -> {
action()
}
ActionRunningMode.RUN_IN_EDT -> {
var result: T? = null
ApplicationManager.getApplication().invokeAndWait {
CommandProcessor.getInstance().runUndoTransparentAction {
result = ApplicationManager.getApplication().runWriteAction<T> { action() }
}
}
result!!
}
}

View File

@@ -1,108 +0,0 @@
/*
* Copyright 2010-2016 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.util
import org.jetbrains.kotlin.descriptors.annotations.BuiltInAnnotationDescriptor
import org.jetbrains.kotlin.renderer.AnnotationArgumentsRenderingPolicy
import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.DescriptorRenderer.Companion.FQ_NAMES_IN_TYPES
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
import org.jetbrains.kotlin.renderer.OverrideRenderingPolicy
import org.jetbrains.kotlin.resolve.calls.inference.isCaptured
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.kotlin.types.typeUtil.builtIns
object IdeDescriptorRenderers {
@JvmField
val APPROXIMATE_FLEXIBLE_TYPES: (KotlinType) -> KotlinType = { it.approximateFlexibleTypes(preferNotNull = false) }
@JvmField
val APPROXIMATE_FLEXIBLE_TYPES_NOT_NULL: (KotlinType) -> KotlinType = { it.approximateFlexibleTypes(preferNotNull = true) }
private fun unwrapAnonymousType(type: KotlinType): KotlinType {
if (type.isDynamic()) return type
if (type.constructor is NewCapturedTypeConstructor) return type
val classifier = type.constructor.declarationDescriptor
if (classifier != null && !classifier.name.isSpecial) return type
type.constructor.supertypes.singleOrNull()?.let { return it }
val builtIns = type.builtIns
return if (type.isMarkedNullable)
builtIns.nullableAnyType
else
builtIns.anyType
}
private val BASE: DescriptorRenderer = DescriptorRenderer.withOptions {
normalizedVisibilities = true
withDefinedIn = false
renderDefaultVisibility = false
overrideRenderingPolicy = OverrideRenderingPolicy.RENDER_OVERRIDE
unitReturnType = false
enhancedTypes = true
modifiers = DescriptorRendererModifier.ALL
renderUnabbreviatedType = false
annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY
}
@JvmField
val SOURCE_CODE: DescriptorRenderer = BASE.withOptions {
classifierNamePolicy = ClassifierNamePolicy.SOURCE_CODE_QUALIFIED
typeNormalizer = { APPROXIMATE_FLEXIBLE_TYPES(unwrapAnonymousType(it)) }
}
@JvmField
val FQ_NAMES_IN_TYPES_WITH_NORMALIZER: DescriptorRenderer = FQ_NAMES_IN_TYPES.withOptions {
typeNormalizer = { APPROXIMATE_FLEXIBLE_TYPES(unwrapAnonymousType(it)) }
}
@JvmField
val SOURCE_CODE_TYPES: DescriptorRenderer = BASE.withOptions {
classifierNamePolicy = ClassifierNamePolicy.SOURCE_CODE_QUALIFIED
typeNormalizer = { APPROXIMATE_FLEXIBLE_TYPES(unwrapAnonymousType(it)) }
annotationFilter = { it !is BuiltInAnnotationDescriptor }
parameterNamesInFunctionalTypes = false
}
@JvmField
val SOURCE_CODE_TYPES_WITH_SHORT_NAMES: DescriptorRenderer = BASE.withOptions {
classifierNamePolicy = ClassifierNamePolicy.SHORT
typeNormalizer = { APPROXIMATE_FLEXIBLE_TYPES(unwrapAnonymousType(it)) }
modifiers -= DescriptorRendererModifier.ANNOTATIONS
parameterNamesInFunctionalTypes = false
}
@JvmField
val SOURCE_CODE_NOT_NULL_TYPE_APPROXIMATION: DescriptorRenderer = BASE.withOptions {
classifierNamePolicy = ClassifierNamePolicy.SOURCE_CODE_QUALIFIED
typeNormalizer = { APPROXIMATE_FLEXIBLE_TYPES_NOT_NULL(unwrapAnonymousType(it)) }
presentableUnresolvedTypes = true
informativeErrorType = false
}
@JvmField
val SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS: DescriptorRenderer = BASE.withOptions {
classifierNamePolicy = ClassifierNamePolicy.SHORT
typeNormalizer = { APPROXIMATE_FLEXIBLE_TYPES(unwrapAnonymousType(it)) }
modifiers -= DescriptorRendererModifier.ANNOTATIONS
}
}

View File

@@ -1,56 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.util
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.ImportPath
import java.util.*
abstract class ImportInsertHelper {
/*TODO: implementation is not quite correct*/
abstract fun isImportedWithDefault(importPath: ImportPath, contextFile: KtFile): Boolean
abstract fun isImportedWithLowPriorityDefaultImport(importPath: ImportPath, contextFile: KtFile): Boolean
abstract fun mayImportOnShortenReferences(descriptor: DeclarationDescriptor): Boolean
abstract val importSortComparator: Comparator<ImportPath>
abstract fun importDescriptor(
file: KtFile,
descriptor: DeclarationDescriptor,
actionRunningMode: ActionRunningMode = ActionRunningMode.RUN_IN_CURRENT_THREAD,
forceAllUnderImport: Boolean = false
): ImportDescriptorResult
fun importDescriptor(
file: KtFile,
descriptor: DeclarationDescriptor,
forceAllUnderImport: Boolean = false
): ImportDescriptorResult = importDescriptor(
file,
descriptor,
ActionRunningMode.RUN_IN_CURRENT_THREAD,
forceAllUnderImport
)
companion object {
@JvmStatic
fun getInstance(project: Project): ImportInsertHelper =
ServiceManager.getService<ImportInsertHelper>(project, ImportInsertHelper::class.java)
}
}
enum class ImportDescriptorResult {
FAIL,
IMPORT_ADDED,
ALREADY_IMPORTED
}

View File

@@ -1,16 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:JvmName("CidrUtil")
package org.jetbrains.kotlin.idea.util
import com.intellij.util.PlatformUtils
// Currently CIDR IDEs (CLion and AppCode) have no Java support.
// Use this property to bypass Java-specific logic in CIDR.
val isRunningInCidrIde: Boolean by lazy(LazyThreadSafetyMode.PUBLICATION) {
PlatformUtils.isCidr()
}

View File

@@ -1,87 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.util.psi.patternMatching
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
import org.jetbrains.kotlin.psi.psiUtil.siblings
import java.util.*
private val SIGNIFICANT_FILTER = { e: PsiElement -> e !is PsiWhiteSpace && e !is PsiComment && e.textLength > 0 }
interface KotlinPsiRange {
object Empty : KotlinPsiRange {
override val elements: List<PsiElement> get() = Collections.emptyList<PsiElement>()
override fun getTextRange(): TextRange = TextRange.EMPTY_RANGE
}
class ListRange(override val elements: List<PsiElement>) : KotlinPsiRange {
val startElement: PsiElement = elements.first()
val endElement: PsiElement = elements.last()
override fun getTextRange(): TextRange {
val startRange = startElement.textRange
val endRange = endElement.textRange
if (startRange == null || endRange == null) return TextRange.EMPTY_RANGE
return TextRange(startRange.startOffset, endRange.endOffset)
}
}
val elements: List<PsiElement>
fun getTextRange(): TextRange
fun isValid(): Boolean = elements.all { it.isValid }
val empty: Boolean get() = this is Empty
operator fun contains(element: PsiElement): Boolean = getTextRange().contains(element.textRange ?: TextRange.EMPTY_RANGE)
fun match(scope: PsiElement, unifier: KotlinPsiUnifier): List<UnificationResult.Matched> {
val elements = elements.filter(SIGNIFICANT_FILTER)
if (elements.isEmpty()) return Collections.emptyList()
val matches = ArrayList<UnificationResult.Matched>()
scope.accept(
object : KtTreeVisitorVoid() {
override fun visitKtElement(element: KtElement) {
val range = element
.siblings()
.filter(SIGNIFICANT_FILTER)
.take(elements.size)
.toList()
.toRange()
val result = unifier.unify(range, this@KotlinPsiRange)
if (result is UnificationResult.StronglyMatched) {
matches.add(result)
} else {
val matchCountSoFar = matches.size
super.visitKtElement(element)
if (result is UnificationResult.WeaklyMatched && matches.size == matchCountSoFar) {
matches.add(result)
}
}
}
}
)
return matches
}
}
fun List<PsiElement>.toRange(significantOnly: Boolean = true): KotlinPsiRange {
val elements = if (significantOnly) filter(SIGNIFICANT_FILTER) else this
return if (elements.isEmpty()) KotlinPsiRange.Empty else KotlinPsiRange.ListRange(elements)
}
fun PsiElement?.toRange(): KotlinPsiRange = this?.let { KotlinPsiRange.ListRange(Collections.singletonList(it)) } ?: KotlinPsiRange.Empty

View File

@@ -1,623 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.lazy
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiRecursiveElementVisitor
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.StatementFilter
import org.jetbrains.kotlin.util.isProbablyNothing
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.swap
import java.util.*
//TODO: do resolve anonymous object's body
class PartialBodyResolveFilter(
elementsToResolve: Collection<KtElement>,
private val declaration: KtDeclaration,
forCompletion: Boolean
) : StatementFilter() {
private val statementMarks = StatementMarks()
private val globalProbablyNothingCallableNames = ProbablyNothingCallableNames.getInstance(declaration.project)
private val globalProbablyContractedCallableNames = ProbablyContractedCallableNames.getInstance(declaration.project)
private val contextNothingFunctionNames = HashSet<String>()
private val contextNothingVariableNames = HashSet<String>()
override val filter: ((KtExpression) -> Boolean)? = { statementMarks.statementMark(it) != MarkLevel.NONE }
val allStatementsToResolve: Collection<KtExpression>
get() = statementMarks.allMarkedStatements()
init {
elementsToResolve.forEach { assert(declaration.isAncestor(it)) }
assert(!KtPsiUtil.isLocal(declaration)) { "Should never be invoked on local declaration otherwise we may miss some local declarations with type Nothing" }
declaration.forEachDescendantOfType<KtCallableDeclaration> { declaration ->
if (declaration.typeReference.containsProbablyNothing()) {
val name = declaration.name
if (name != null) {
if (declaration is KtNamedFunction) {
contextNothingFunctionNames.add(name)
} else {
contextNothingVariableNames.add(name)
}
}
}
}
elementsToResolve.forEach {
statementMarks.mark(it, if (forCompletion) MarkLevel.NEED_COMPLETION else MarkLevel.NEED_REFERENCE_RESOLVE)
}
declaration.forTopLevelBlocksInside { processBlock(it) }
}
//TODO: do..while is special case
private fun processBlock(block: KtBlockExpression): NameFilter {
if (isValueNeeded(block)) {
block.lastStatement()?.let { statementMarks.mark(it, MarkLevel.NEED_REFERENCE_RESOLVE) }
}
val nameFilter = NameFilter()
val startStatement = statementMarks.lastMarkedStatement(block, MarkLevel.NEED_REFERENCE_RESOLVE) ?: return nameFilter
for (statement in startStatement.siblings(forward = false)) {
if (statement !is KtExpression) continue
if (statement is KtNamedDeclaration) {
val name = statement.getName()
if (name != null && nameFilter(name)) {
statementMarks.mark(statement, MarkLevel.NEED_REFERENCE_RESOLVE)
}
} else if (statement is KtDestructuringDeclaration) {
if (statement.entries.any {
val name = it.name
name != null && nameFilter(name)
}) {
statementMarks.mark(statement, MarkLevel.NEED_REFERENCE_RESOLVE)
}
}
fun updateNameFilter() {
when (statementMarks.statementMark(statement)) {
MarkLevel.NONE, MarkLevel.TAKE -> {
}
MarkLevel.NEED_REFERENCE_RESOLVE -> nameFilter.addUsedNames(statement)
MarkLevel.NEED_COMPLETION -> nameFilter.addAllNames()
}
}
updateNameFilter()
if (!nameFilter.isEmpty) {
val smartCastPlaces = potentialSmartCastPlaces(statement, { it.affectsNames(nameFilter) })
if (!smartCastPlaces.isEmpty()) {
//TODO: do we really need correct resolve for ALL smart cast places?
smartCastPlaces.values
.flatten()
.forEach { statementMarks.mark(it, MarkLevel.NEED_REFERENCE_RESOLVE) }
updateNameFilter()
}
}
val level = statementMarks.statementMark(statement)
if (level > MarkLevel.TAKE) { // otherwise there are no statements inside that need processBlock which only works when reference resolve needed
statement.forTopLevelBlocksInside { nestedBlock ->
val childFilter = processBlock(nestedBlock)
nameFilter.addNamesFromFilter(childFilter)
}
}
}
return nameFilter
}
/**
* Finds places within the given statement that may affect smart-casts after it.
* That is, such places whose containing statements must be left in code to keep the smart-casts.
* Returns map from smart-cast expression names (variable name or qualified variable name) to places.
*/
private fun potentialSmartCastPlaces(
statement: KtExpression,
filter: (SmartCastName) -> Boolean = { true }
): Map<SmartCastName, List<KtExpression>> {
val map = HashMap<SmartCastName, ArrayList<KtExpression>>(0)
fun addPlace(name: SmartCastName, place: KtExpression) {
map.getOrPut(name, { ArrayList(1) }).add(place)
}
fun addPlaces(name: SmartCastName, places: Collection<KtExpression>) {
if (places.isNotEmpty()) {
map.getOrPut(name, { ArrayList(places.size) }).addAll(places)
}
}
fun addIfCanBeSmartCast(expression: KtExpression) {
val name = expression.smartCastExpressionName() ?: return
if (filter(name)) {
addPlace(name, expression)
}
}
statement.accept(object : ControlFlowVisitor() {
override fun visitPostfixExpression(expression: KtPostfixExpression) {
expression.acceptChildren(this)
if (expression.operationToken == KtTokens.EXCLEXCL) {
addIfCanBeSmartCast(expression.baseExpression ?: return)
}
}
override fun visitCallExpression(expression: KtCallExpression) {
super.visitCallExpression(expression)
val nameReference = expression.calleeExpression as? KtNameReferenceExpression ?: return
if (!globalProbablyContractedCallableNames.isProbablyContractedCallableName(nameReference.getReferencedName())) return
val mentionedSmartCastName = expression.findMentionedName(filter)
if (mentionedSmartCastName != null) {
addPlace(mentionedSmartCastName, expression)
}
}
override fun visitBinaryWithTypeRHSExpression(expression: KtBinaryExpressionWithTypeRHS) {
expression.acceptChildren(this)
if (expression.operationReference.getReferencedNameElementType() == KtTokens.AS_KEYWORD) {
addIfCanBeSmartCast(expression.left)
}
}
override fun visitBinaryExpression(expression: KtBinaryExpression) {
expression.acceptChildren(this)
if (expression.operationToken == KtTokens.ELVIS) {
val left = expression.left
val right = expression.right
if (left != null && right != null) {
val smartCastName = left.smartCastExpressionName()
if (smartCastName != null && filter(smartCastName)) {
val exits = collectAlwaysExitPoints(right)
addPlaces(smartCastName, exits)
}
}
}
}
override fun visitIfExpression(expression: KtIfExpression) {
val condition = expression.condition
val thenBranch = expression.then
val elseBranch = expression.`else`
val (thenSmartCastNames, elseSmartCastNames) = possiblySmartCastInCondition(condition)
fun processBranchExits(smartCastNames: Collection<SmartCastName>, branch: KtExpression?) {
if (branch == null) return
val filteredNames = smartCastNames.filter(filter)
if (filteredNames.isNotEmpty()) {
val exits = collectAlwaysExitPoints(branch)
if (exits.isNotEmpty()) {
for (name in filteredNames) {
addPlaces(name, exits)
}
}
}
}
processBranchExits(thenSmartCastNames, elseBranch)
processBranchExits(elseSmartCastNames, thenBranch)
condition?.accept(this)
if (thenBranch != null && elseBranch != null) {
val thenCasts = potentialSmartCastPlaces(thenBranch, filter)
if (thenCasts.isNotEmpty()) {
val elseCasts = potentialSmartCastPlaces(elseBranch) { filter(it) && thenCasts.containsKey(it) }
if (elseCasts.isNotEmpty()) {
for ((name, places) in thenCasts) {
if (elseCasts.containsKey(name)) { // need filtering by cast names in else-branch
addPlaces(name, places)
}
}
for ((name, places) in elseCasts) { // already filtered by cast names in then-branch
addPlaces(name, places)
}
}
}
}
}
override fun visitForExpression(expression: KtForExpression) {
// analyze only the loop-range expression, do not enter the loop body
expression.loopRange?.accept(this)
}
override fun visitWhileExpression(expression: KtWhileExpression) {
val condition = expression.condition
// we need to enter the body only for "while(true)"
if (condition.isTrueConstant()) {
expression.acceptChildren(this)
} else {
condition?.accept(this)
}
}
//TODO: when
})
return map
}
private fun KtExpression.findMentionedName(filter: (SmartCastName) -> Boolean): SmartCastName? {
var foundMentionedName: SmartCastName? = null
val visitor = object : PsiRecursiveElementVisitor() {
override fun visitElement(element: PsiElement) {
if (foundMentionedName != null) return
if (element !is KtSimpleNameExpression) super.visitElement(element)
if (element !is KtExpression) return
element.smartCastExpressionName()?.takeIf(filter)?.let { foundMentionedName = it }
}
}
accept(visitor)
return foundMentionedName
}
/**
* Returns names of expressions that would possibly be smart cast
* in then (first component) and else (second component)
* branches of an if-statement with such condition
*/
private fun possiblySmartCastInCondition(condition: KtExpression?): Pair<Set<SmartCastName>, Set<SmartCastName>> {
val emptyResult = Pair(setOf<SmartCastName>(), setOf<SmartCastName>())
when (condition) {
is KtBinaryExpression -> {
val operation = condition.operationToken
val left = condition.left ?: return emptyResult
val right = condition.right ?: return emptyResult
fun smartCastInEq(): Pair<Set<SmartCastName>, Set<SmartCastName>> = when {
left.isNullLiteral() -> {
Pair(setOf(), right.smartCastExpressionName().singletonOrEmptySet())
}
right.isNullLiteral() -> {
Pair(setOf(), left.smartCastExpressionName().singletonOrEmptySet())
}
else -> {
val leftName = left.smartCastExpressionName()
val rightName = right.smartCastExpressionName()
val names = listOfNotNull(leftName, rightName).toSet()
Pair(names, setOf())
}
}
when (operation) {
KtTokens.EQEQ, KtTokens.EQEQEQ -> return smartCastInEq()
KtTokens.EXCLEQ, KtTokens.EXCLEQEQEQ -> return smartCastInEq().swap()
KtTokens.ANDAND -> {
val casts1 = possiblySmartCastInCondition(left)
val casts2 = possiblySmartCastInCondition(right)
return Pair(casts1.first.union(casts2.first), casts1.second.intersect(casts2.second))
}
KtTokens.OROR -> {
val casts1 = possiblySmartCastInCondition(left)
val casts2 = possiblySmartCastInCondition(right)
return Pair(casts1.first.intersect(casts2.first), casts1.second.union(casts2.second))
}
}
}
is KtIsExpression -> {
val cast = condition.leftHandSide.smartCastExpressionName().singletonOrEmptySet()
return if (condition.isNegated) Pair(setOf(), cast) else Pair(cast, setOf())
}
is KtPrefixExpression -> {
if (condition.operationToken == KtTokens.EXCL) {
val operand = condition.baseExpression ?: return emptyResult
return possiblySmartCastInCondition(operand).swap()
}
}
is KtParenthesizedExpression -> {
val operand = condition.expression ?: return emptyResult
return possiblySmartCastInCondition(operand)
}
}
return emptyResult
}
/**
* If it's possible that the given statement never passes the execution to the next statement (that is, always exits somewhere)
* then this function returns a collection of all places in code that are necessary to be kept to preserve this behaviour.
*/
private fun collectAlwaysExitPoints(statement: KtExpression?): Collection<KtExpression> {
val result = ArrayList<KtExpression>()
statement?.accept(object : ControlFlowVisitor() {
var insideLoopLevel: Int = 0
override fun visitReturnExpression(expression: KtReturnExpression) {
result.add(expression)
}
override fun visitThrowExpression(expression: KtThrowExpression) {
result.add(expression)
}
override fun visitIfExpression(expression: KtIfExpression) {
expression.condition?.accept(this)
val thenBranch = expression.then
val elseBranch = expression.`else`
if (thenBranch != null && elseBranch != null) { // if we have only one branch it makes no sense to search exits in it
val thenExits = collectAlwaysExitPoints(thenBranch)
if (thenExits.isNotEmpty()) {
val elseExits = collectAlwaysExitPoints(elseBranch)
if (elseExits.isNotEmpty()) {
result.addAll(thenExits)
result.addAll(elseExits)
}
}
}
}
override fun visitForExpression(loop: KtForExpression) {
loop.loopRange?.accept(this)
// do not make sense to search exits inside for as not necessary enter it at all
}
override fun visitWhileExpression(loop: KtWhileExpression) {
val condition = loop.condition ?: return
if (condition.isTrueConstant()) {
insideLoopLevel++
loop.body?.accept(this)
insideLoopLevel--
} else {
// do not make sense to search exits inside while-loop as not necessary enter it at all
condition.accept(this)
}
}
override fun visitDoWhileExpression(loop: KtDoWhileExpression) {
loop.condition?.accept(this)
insideLoopLevel++
loop.body?.accept(this)
insideLoopLevel--
}
override fun visitBreakExpression(expression: KtBreakExpression) {
if (insideLoopLevel == 0 || expression.getLabelName() != null) {
result.add(expression)
}
}
override fun visitContinueExpression(expression: KtContinueExpression) {
if (insideLoopLevel == 0 || expression.getLabelName() != null) {
result.add(expression)
}
}
override fun visitCallExpression(expression: KtCallExpression) {
val name = (expression.calleeExpression as? KtSimpleNameExpression)?.getReferencedName()
if (name != null && (name in globalProbablyNothingCallableNames.functionNames() || name in contextNothingFunctionNames)) {
result.add(expression)
}
super.visitCallExpression(expression)
}
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
val name = expression.getReferencedName()
if (name in globalProbablyNothingCallableNames.propertyNames() || name in contextNothingVariableNames) {
result.add(expression)
}
}
override fun visitBinaryExpression(expression: KtBinaryExpression) {
if (expression.operationToken == KtTokens.ELVIS) {
// do not search exits after "?:"
expression.left?.accept(this)
} else {
super.visitBinaryExpression(expression)
}
}
})
return result
}
/**
* Recursively visits code but does not enter constructs that may not affect smart casts/control flow
*/
private abstract class ControlFlowVisitor : KtVisitorVoid() {
override fun visitKtElement(element: KtElement) {
if (element.noControlFlowInside()) return
element.acceptChildren(this)
}
private fun KtElement.noControlFlowInside() = this is KtFunction || this is KtClass || this is KtClassBody
}
private data class SmartCastName(
private val receiverName: SmartCastName?,
private val selectorName: String? /* null means "this" (and receiverName should be null */
) {
init {
if (selectorName == null) {
assert(receiverName == null) { "selectorName is allowed to be null only when receiverName is also null (which means 'this')" }
}
}
override fun toString(): String = if (receiverName != null) "$receiverName.$selectorName" else selectorName ?: "this"
fun affectsNames(nameFilter: (String) -> Boolean): Boolean {
if (selectorName == null) return true
if (!nameFilter(selectorName)) return false
return receiverName == null || receiverName.affectsNames(nameFilter)
}
}
private fun KtExpression.smartCastExpressionName(): SmartCastName? {
return when (this) {
is KtSimpleNameExpression -> SmartCastName(null, this.getReferencedName())
is KtQualifiedExpression -> {
val selector = selectorExpression as? KtSimpleNameExpression ?: return null
val selectorName = selector.getReferencedName()
val receiver = receiverExpression
if (receiver is KtThisExpression) {
return SmartCastName(null, selectorName)
}
val receiverName = receiver.smartCastExpressionName() ?: return null
return SmartCastName(receiverName, selectorName)
}
is KtThisExpression -> SmartCastName(null, null)
else -> null
}
}
//TODO: declarations with special names (e.g. "get")
private class NameFilter : (String) -> Boolean {
private var names: MutableSet<String>? = HashSet()
override fun invoke(name: String) = names == null || name in names!!
val isEmpty: Boolean
get() = names?.isEmpty() ?: false
fun addUsedNames(statement: KtExpression) {
if (names != null) {
statement.forEachDescendantOfType<KtSimpleNameExpression>(canGoInside = { it !is KtBlockExpression }) {
names!!.add(it.getReferencedName())
}
}
}
fun addNamesFromFilter(filter: NameFilter) {
if (names == null) return
if (filter.names == null) {
names = null
} else {
names!!.addAll(filter.names!!)
}
}
fun addAllNames() {
names = null
}
}
private enum class MarkLevel {
NONE,
TAKE,
NEED_REFERENCE_RESOLVE,
NEED_COMPLETION
}
companion object {
fun findStatementToResolve(element: KtElement, declaration: KtDeclaration): KtExpression? {
return element.parentsWithSelf.takeWhile { it != declaration }.firstOrNull { it.isStatement() } as KtExpression?
}
private fun KtElement.forTopLevelBlocksInside(action: (KtBlockExpression) -> Unit) {
forEachDescendantOfType(canGoInside = { it !is KtBlockExpression }, action = action)
}
private fun KtExpression?.isNullLiteral() = this?.node?.elementType == KtNodeTypes.NULL
private fun KtExpression?.isTrueConstant() = this != null && node?.elementType == KtNodeTypes.BOOLEAN_CONSTANT && text == "true"
private fun <T : Any> T?.singletonOrEmptySet(): Set<T> = if (this != null) setOf(this) else setOf()
//TODO: review logic
private fun isValueNeeded(expression: KtExpression): Boolean = when (val parent = expression.parent) {
is KtBlockExpression -> expression == parent.lastStatement() && isValueNeeded(parent)
is KtContainerNode -> { //TODO - not quite correct
val pparent = parent.parent as? KtExpression
pparent != null && isValueNeeded(pparent)
}
is KtDeclarationWithBody -> {
if (expression == parent.bodyExpression)
!parent.hasBlockBody() && !parent.hasDeclaredReturnType()
else
true
}
is KtAnonymousInitializer -> false
else -> true
}
private fun KtBlockExpression.lastStatement(): KtExpression? =
lastChild?.siblings(forward = false)?.firstIsInstanceOrNull<KtExpression>()
private fun PsiElement.isStatement() = this is KtExpression && parent is KtBlockExpression
private fun KtTypeReference?.containsProbablyNothing() =
this?.typeElement?.anyDescendantOfType<KtUserType> { it.isProbablyNothing() } ?: false
}
private inner class StatementMarks {
private val statementMarks = HashMap<KtExpression, MarkLevel>()
private val blockLevels = HashMap<KtBlockExpression, MarkLevel>()
fun mark(element: PsiElement, level: MarkLevel) {
var e = element
while (e != declaration) {
if (e.isStatement()) {
markStatement(e as KtExpression, level)
}
e = e.parent!!
}
}
private fun markStatement(statement: KtExpression, level: MarkLevel) {
val currentLevel = statementMark(statement)
if (currentLevel < level) {
statementMarks[statement] = level
val block = statement.parent as KtBlockExpression
val currentBlockLevel = blockLevels[block] ?: MarkLevel.NONE
if (currentBlockLevel < level) {
blockLevels[block] = level
}
}
}
fun statementMark(statement: KtExpression): MarkLevel = statementMarks[statement] ?: MarkLevel.NONE
fun allMarkedStatements(): Collection<KtExpression> = statementMarks.keys
fun lastMarkedStatement(block: KtBlockExpression, minLevel: MarkLevel): KtExpression? {
val level = blockLevels[block] ?: MarkLevel.NONE
if (level < minLevel) return null // optimization
return block.lastChild.siblings(forward = false)
.filterIsInstance<KtExpression>()
.first { statementMark(it) >= minLevel }
}
}
}

View File

@@ -1,18 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.lazy
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
interface ProbablyContractedCallableNames {
fun isProbablyContractedCallableName(name: String): Boolean
companion object {
fun getInstance(project: Project): ProbablyContractedCallableNames =
ServiceManager.getService(project, ProbablyContractedCallableNames::class.java)!!
}
}

View File

@@ -1,29 +0,0 @@
/*
* 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.resolve.lazy
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
interface ProbablyNothingCallableNames {
fun functionNames(): Collection<String>
fun propertyNames(): Collection<String>
companion object {
fun getInstance(project: Project) = ServiceManager.getService(project, ProbablyNothingCallableNames::class.java)!!
}
}

View File

@@ -1,78 +0,0 @@
/*
* 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.util
import com.google.common.collect.HashMultimap
import com.google.common.collect.Multimap
import com.intellij.openapi.util.Key
import com.intellij.psi.stubs.PsiFileStub
import com.intellij.psi.stubs.StubElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.psi.KtUserType
fun KtUserType.aliasImportMap(): Multimap<String, String> {
// we need to access containing file via stub because getPsi() may return null when indexing and getContainingFile() will crash
val file = stub?.getContainingFileStub()?.psi ?: return HashMultimap.create()
return (file as KtFile).aliasImportMap()
}
fun KtFile.aliasImportMap(): Multimap<String, String> {
val cached = getUserData(ALIAS_IMPORT_DATA_KEY)
val modificationStamp = modificationStamp
if (cached != null && modificationStamp == cached.fileModificationStamp) {
return cached.map
}
val data = CachedAliasImportData(buildAliasImportMap(), modificationStamp)
putUserData(ALIAS_IMPORT_DATA_KEY, data)
return data.map
}
private fun KtFile.buildAliasImportMap(): Multimap<String, String> {
val map = HashMultimap.create<String, String>()
val importList = importList ?: return map
for (import in importList.imports) {
val aliasName = import.aliasName ?: continue
val name = import.importPath?.fqName?.shortName()?.asString() ?: continue
map.put(aliasName, name)
}
return map
}
private class CachedAliasImportData(val map: Multimap<String, String>, val fileModificationStamp: Long)
private val ALIAS_IMPORT_DATA_KEY = Key<CachedAliasImportData>("ALIAS_IMPORT_MAP_KEY")
fun KtTypeReference?.isProbablyNothing(): Boolean {
val userType = this?.typeElement as? KtUserType ?: return false
return userType.isProbablyNothing()
}
//TODO: support type aliases
fun KtUserType?.isProbablyNothing(): Boolean {
if (this == null) return false
val referencedName = referencedName
return referencedName == "Nothing" || aliasImportMap()[referencedName].contains("Nothing")
}
private fun StubElement<*>.getContainingFileStub(): PsiFileStub<*> {
return if (this is PsiFileStub)
this
else
parentStub.getContainingFileStub()
}

View File

@@ -1,49 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.types.substitutions
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedure
import java.util.*
fun getTypeSubstitution(baseType: KotlinType, derivedType: KotlinType): LinkedHashMap<TypeConstructor, TypeProjection>? {
val substitutedType = TypeCheckingProcedure.findCorrespondingSupertype(derivedType, baseType) ?: return null
val substitution = LinkedHashMap<TypeConstructor, TypeProjection>(substitutedType.arguments.size)
for ((param, arg) in baseType.constructor.parameters.zip(substitutedType.arguments)) {
substitution[param.typeConstructor] = arg
}
return substitution
}
fun getCallableSubstitution(
baseCallable: CallableDescriptor,
derivedCallable: CallableDescriptor
): MutableMap<TypeConstructor, TypeProjection>? {
val baseClass = baseCallable.containingDeclaration as? ClassDescriptor ?: return null
val derivedClass = derivedCallable.containingDeclaration as? ClassDescriptor ?: return null
val substitution = getTypeSubstitution(baseClass.defaultType, derivedClass.defaultType) ?: return null
for ((baseParam, derivedParam) in baseCallable.typeParameters.zip(derivedCallable.typeParameters)) {
substitution[baseParam.typeConstructor] = TypeProjectionImpl(derivedParam.defaultType)
}
return substitution
}
fun getCallableSubstitutor(
baseCallable: CallableDescriptor,
derivedCallable: CallableDescriptor
): TypeSubstitutor? {
return getCallableSubstitution(baseCallable, derivedCallable)?.let { TypeSubstitutor.create(it) }
}
fun getTypeSubstitutor(baseType: KotlinType, derivedType: KotlinType): TypeSubstitutor? {
return getTypeSubstitution(baseType, derivedType)?.let { TypeSubstitutor.create(it) }
}

View File

@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="backend" />
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="frontend.java" />
<orderEntry type="module" module-name="light-classes" />
<orderEntry type="module" module-name="eval4j" />
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../ideaSDK/core/annotations.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="library" name="guava" level="project" />
<orderEntry type="module" module-name="js.frontend" />
<orderEntry type="module" module-name="js.serializer" />
<orderEntry type="library" name="trove4j" level="project" />
<orderEntry type="module" module-name="ide-common" exported="" />
<orderEntry type="module" module-name="util" />
<orderEntry type="module" module-name="idea-core" />
<orderEntry type="module" module-name="idea-jps-common" />
<orderEntry type="module" module-name="cli-common" />
<orderEntry type="module" module-name="descriptors" />
<orderEntry type="library" exported="" name="idea-full" level="project" />
<orderEntry type="library" name="uast-java" level="project" />
<orderEntry type="module" module-name="frontend.script" />
</component>
</module>

View File

@@ -1,95 +0,0 @@
found.space=found:\u0020
html.0.has.no.corresponding.expected.declaration.1.html={0} has no corresponding expected declaration{1}
html.0.is.not.abstract.and.does.not.implement.abstract.base.class.member.br.1.html={0} is not abstract and does not implement abstract base class member<br/>{1}
html.0.is.not.abstract.and.does.not.implement.abstract.member.br.1.html={0} is not abstract and does not implement abstract member<br/>{1}
html.0.method.may.be.missing.none.of.the.following.functions.will.be.called.ul.1.ul.html=''{0}'' method may be missing. None of the following functions will be called: <ul>{1}</ul>
html.candidate.resolution.will.be.changed.soon.please.use.fully.qualified.name.to.invoke.the.following.closer.candidate.explicitly.ul.0.ul.html=Candidate resolution will be changed soon, please use fully qualified name to invoke the following closer candidate explicitly: <ul>{0}</ul>
html.expected.0.has.no.actual.declaration.in.module.1.2.html=Expected {0} has no actual declaration in module {1}{2}
html.accidental.override.0.html=Accidental override: {0}
html.method.contains.from.concurrenthashmap.may.have.unexpected.semantics.it.calls.containsvalue.instead.of.containskey.br.use.explicit.form.of.the.call.to.containskey.containsvalue.contains.or.cast.the.value.to.kotlin.collections.map.instead.br.see.https.youtrack.jetbrains.com.issue.kt.18053.for.more.details.html=Method ''contains'' from ConcurrentHashMap may have unexpected semantics: it calls ''containsValue'' instead of ''containsKey''.<br/>Use explicit form of the call to ''containsKey''/''containsValue''/''contains'' or cast the value to kotlin.collections.Map instead.<br/>See https://youtrack.jetbrains.com/issue/KT-18053 for more details
html.javascript.0.html=JavaScript: {0}
html.platform.declaration.clash.0.html=Platform declaration clash: {0}
html.internal.error.occurred.while.analyzing.this.expression.br.table.cellspacing.0.cellpadding.0.tr.td.strong.please.use.the.strong.td.td.img.src.0.td.td.strong.icon.in.the.bottom.right.corner.to.report.this.error.strong.td.tr.table.br.pre.0.pre.html=Internal Error occurred while analyzing this expression <br/><table cellspacing="0" cellpadding="0"><tr><td>(<strong>Please use the "</strong></td><td><img src="{0}"/></td><td><strong>" icon in the bottom-right corner to report this error</strong>):</td></tr></table><br/><pre>{0}</pre>
html.property.delegate.must.have.a.0.method.none.of.the.following.functions.are.suitable.ul.1.ul.html=Property delegate must have a ''{0}'' method. None of the following functions are suitable. <ul>{1}</ul>
html.overload.resolution.ambiguity.on.method.0.all.these.functions.match.ul.1.ul.html=Overload resolution ambiguity on method ''{0}''. All these functions match. <ul>{1}</ul>
html.unresolved.reference.br.none.of.the.following.candidates.is.applicable.because.of.receiver.type.mismatch.ul.0.ul.html=Unresolved reference. <br/> None of the following candidates is applicable because of receiver type mismatch: <ul>{0}</ul>
html.cannot.choose.among.the.following.candidates.without.completing.type.inference.ul.0.ul.html=Cannot choose among the following candidates without completing type inference: <ul>{0}</ul>
html.none.of.the.following.functions.can.be.called.with.the.arguments.supplied.ul.0.ul.html=None of the following functions can be called with the arguments supplied. <ul>{0}</ul>
html.overload.resolution.ambiguity.all.these.functions.match.ul.0.ul.html=Overload resolution ambiguity. All these functions match. <ul>{0}</ul>
html.function.return.type.mismatch.table.tr.td.expected.td.td.1.td.tr.tr.td.found.td.td.2.td.tr.table.html=Function return type mismatch.<table><tr><td>Expected:</td><td>{1}</td></tr><tr><td>Found:</td><td>{2}</td></tr></table>
html.0.must.override.1.br.because.it.inherits.many.implementations.of.it.html={0} must override {1}<br />because it inherits many implementations of it
html.types.of.inherited.var.properties.do.not.match.br.0.br.1.html=Types of inherited var-properties do not match:<br/>{0},<br/>{1}
html.types.of.inherited.properties.are.incompatible.br.0.br.1.html=Types of inherited properties are incompatible:<br/>{0},<br/>{1}
html.actual.class.0.has.no.corresponding.members.for.expected.class.members.1.html=Actual class ''{0}'' has no corresponding members for expected class members:{1}
html.val.property.cannot.override.var.property.br.1.html=Val-property cannot override var-property<br />{1}
html.var.property.type.is.0.which.is.not.a.type.of.overridden.br.1.html=Var-property type is {0}, which is not a type of overridden<br/>{1}
required.space=required:\u0020
type.inference.failed.expected.type.mismatch=Type inference failed. Expected type mismatch:\u0020
html.setter.parameter.type.must.be.equal.to.the.type.of.the.property.table.tr.td.expected.td.td.0.td.tr.tr.td.found.td.td.1.td.tr.table.html=Setter parameter type must be equal to the type of the property.<table><tr><td>Expected:</td><td>{0}</td></tr><tr><td>Found:</td><td>{1}</td></tr></table>
html.property.type.is.0.which.is.not.a.subtype.type.of.overridden.br.1.html=Property type is {0}, which is not a subtype type of overridden<br/>{1}
html.return.types.of.inherited.members.are.incompatible.br.0.br.1.html=Return types of inherited members are incompatible:<br/>{0},<br/>{1}
html.return.type.is.0.which.is.not.a.subtype.of.overridden.br.1.html=Return type is ''{0}'', which is not a subtype of overridden<br/>{1}
html.loop.parameter.type.mismatch.table.tr.td.iterated.values.td.td.0.td.tr.tr.td.parameter.td.td.1.td.tr.table.html=Loop parameter type mismatch.<table><tr><td>Iterated values:</td><td>{0}</td></tr><tr><td>Parameter:</td><td>{1}</td></tr></table>
html.type.argument.is.not.within.its.bounds.table.tr.td.expected.td.td.0.td.tr.tr.td.found.td.td.1.td.tr.table.html=Type argument is not within its bounds.<table><tr><td>Expected:</td><td>{0}</td></tr><tr><td>Found:</td><td>{1}</td></tr></table>
html.method.iterator.is.ambiguous.for.this.expression.ul.0.ul.html=Method ''iterator()'' is ambiguous for this expression.<ul>{0}</ul>
html.getter.return.type.must.be.equal.to.the.type.of.the.property.table.tr.td.expected.td.td.0.td.tr.tr.td.found.td.td.1.td.tr.table.html=Getter return type must be equal to the type of the property.<table><tr><td>Expected:</td><td>{0}</td></tr><tr><td>Found:</td><td>{1}</td></tr></table>
html.type.inference.failed.0.html=Type inference failed: {0}
html.assignment.operators.ambiguity.all.these.functions.match.ul.0.ul.table.html=Assignment operators ambiguity. All these functions match.<ul>{0}</ul></table>
html.type.mismatch.table.tr.td.required.td.td.0.td.tr.tr.td.found.td.td.1.td.tr.table.br.projected.type.2.restricts.use.of.br.3.html=Type mismatch.<table><tr><td>Required:</td><td>{0}</td></tr><tr><td>Found:</td><td>{1}</td></tr></table><br />\nProjected type {2} restricts use of <br />\n{3}\n
html.type.mismatch.table.tr.td.required.td.td.0.td.tr.tr.td.found.td.td.1.td.tr.table.html=Type mismatch.<table><tr><td>Required:</td><td>{0}</td></tr><tr><td>Found:</td><td>{1}</td></tr></table>
intention.suppress.family=Suppress Warnings
intention.suppress.text=Suppress ''{0}'' for {1} {2}
intention.calculating.text=Quick fix is being calculated ...
special.module.for.files.not.under.source.root=<special module for files not under source root>
sdk.0=<sdk {0}>
sources.for.library.0=<sources for library {0}>
library.0=<library {0}>
source.for.script.dependencies=<Source for script dependencies>
script.dependencies=<Script dependencies>
script.0.1=<script {0} {1}>
module.name.0.test={0} (test)
platform.module.0.including.1=<Platform module {0} including {1}>
the.following.declarations.have.the.same.jvm.signature.code.0.1.code.br.ul.2.ul=The following declarations have the same JVM signature (<code>{0}{1}</code>):<br/>\n<ul>\n{2}</ul>
declaration.kind.object=object
declaration.kind.companion.object=companion object
declaration.kind.initializer=initializer
declaration.kind.statement=statement
declaration.kind.file=file
declaration.name.0.of.1={0} of {1}
declaration.kind.secondary.constructor.of=secondary constructor of
declaration.kind.enum.entry=enum entry
declaration.kind.type.parameter=type parameter
declaration.kind.class=class
declaration.kind.interface=interface
declaration.kind.fun=fun
declaration.kind.parameter=parameter
type.parameters.where=where
cannot.be.inferred=cannot be inferred
i.for.i.br.0=<i> for </i><br/>{0}
defined.in=defined in
root.package=root package
automatically.declared.based.on.the.expected.type=Automatically declared based on the expected type
0.smart.cast.to.1={0} smart cast to {1}
unknown.receiver=Unknown receiver
implicit.receiver=Implicit receiver
extension.implicit.receiver=Extension implicit receiver
always.null=Always null
value.captured.in.a.closure=Value captured in a closure
wrapped.into.a.reference.object.to.be.modified.when.captured.in.a.closure=Wrapped into a reference object to be modified when captured in a closure
smart.cast.to.0.for.1.call=Smart cast to {0} (for {1} call)
smart.cast.to.0=Smart cast to {0}
replace.overloaded.operator.with.function.call=Replace overloaded operator with function call
class.initializer=<class initializer>
object.0=object{0}
show.non.public=Show non-public
show.properties=Show properties
klib.metadata.short=Klib Metadata
function.arguments=arguments:\u0020
function.receiver.0=receiver: {0}
kotlin.built.in.declarations=Kotlin built-in declarations
kotlin.javascript.meta.file=Kotlin JavaScript meta file
framework.name.kotlin.sdk=Kotlin SDK

View File

@@ -1,139 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.caches.resolve
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.PathUtil
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters
import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
import org.jetbrains.kotlin.idea.klib.AbstractKlibLibraryInfo
import org.jetbrains.kotlin.idea.klib.createKlibPackageFragmentProvider
import org.jetbrains.kotlin.idea.klib.isKlibLibraryRootForPlatform
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
import org.jetbrains.kotlin.library.metadata.NullFlexibleTypeDeserializer
import org.jetbrains.kotlin.platform.CommonPlatforms
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind
import org.jetbrains.kotlin.resolve.TargetEnvironment
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
import org.jetbrains.kotlin.serialization.konan.impl.KlibMetadataModuleDescriptorFactoryImpl
import org.jetbrains.kotlin.storage.StorageManager
class CommonPlatformKindResolution : IdePlatformKindResolution {
override fun isLibraryFileForPlatform(virtualFile: VirtualFile): Boolean {
return virtualFile.extension == MetadataPackageFragment.METADATA_FILE_EXTENSION ||
virtualFile.isKlibLibraryRootForPlatform(CommonPlatforms.defaultCommonPlatform)
}
override val libraryKind: PersistentLibraryKind<*>?
get() = CommonLibraryKind
override val kind get() = CommonIdePlatformKind
override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?, stdlibInfo: LibraryInfo?): BuiltInsCacheKey =
BuiltInsCacheKey.DefaultBuiltInsKey
override fun createBuiltIns(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo?,
stdlibDependency: LibraryInfo?,
): KotlinBuiltIns {
return DefaultBuiltIns.Instance
}
override fun createLibraryInfo(project: Project, library: Library): List<LibraryInfo> {
val klibFiles = library.getFiles(OrderRootType.CLASSES).filter {
it.isKlibLibraryRootForPlatform(CommonPlatforms.defaultCommonPlatform)
}
return if (klibFiles.isNotEmpty()) {
klibFiles.mapNotNull {
val path = PathUtil.getLocalPath(it) ?: return@mapNotNull null
CommonKlibLibraryInfo(project, library, path)
}
} else {
// No klib files <=> old metadata-library <=> create usual LibraryInfo
listOf(CommonMetadataLibraryInfo(project, library))
}
}
override fun createKlibPackageFragmentProvider(
moduleInfo: ModuleInfo,
storageManager: StorageManager,
languageVersionSettings: LanguageVersionSettings,
moduleDescriptor: ModuleDescriptor
): PackageFragmentProvider? {
return (moduleInfo as? CommonKlibLibraryInfo)
?.resolvedKotlinLibrary
?.createKlibPackageFragmentProvider(
storageManager = storageManager,
metadataModuleDescriptorFactory = metadataModuleDescriptorFactory,
languageVersionSettings = languageVersionSettings,
moduleDescriptor = moduleDescriptor,
lookupTracker = LookupTracker.DO_NOTHING
)
}
override fun createResolverForModuleFactory(
settings: PlatformAnalysisParameters,
environment: TargetEnvironment,
platform: TargetPlatform
): ResolverForModuleFactory {
return CommonResolverForModuleFactory(
settings as CommonAnalysisParameters,
environment,
platform,
shouldCheckExpectActual = true
)
}
companion object {
private val metadataFactories = KlibMetadataFactories({ DefaultBuiltIns.Instance }, NullFlexibleTypeDeserializer)
private val metadataModuleDescriptorFactory = KlibMetadataModuleDescriptorFactoryImpl(
metadataFactories.DefaultDescriptorFactory,
metadataFactories.DefaultPackageFragmentsFactory,
metadataFactories.flexibleTypeDeserializer,
metadataFactories.platformDependentTypeTransformer
)
}
}
class CommonKlibLibraryInfo(
project: Project,
library: Library,
libraryRoot: String
) : AbstractKlibLibraryInfo(project, library, libraryRoot) {
override val platform: TargetPlatform
get() = CommonPlatforms.defaultCommonPlatform
}
class CommonMetadataLibraryInfo(project: Project, library: Library) : LibraryInfo(project, library) {
override val platform: TargetPlatform
get() = CommonPlatforms.defaultCommonPlatform
}

View File

@@ -1,276 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("Duplicates")
package org.jetbrains.kotlin.caches.resolve
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.containers.addIfNotNull
import org.jetbrains.kotlin.analyzer.*
import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters
import org.jetbrains.kotlin.analyzer.common.configureCommonSpecificComponents
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltInsPackageFragmentProvider
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.container.*
import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.frontend.di.configureModule
import org.jetbrains.kotlin.frontend.di.configureStandardResolveComponents
import org.jetbrains.kotlin.frontend.java.di.configureJavaSpecificComponents
import org.jetbrains.kotlin.frontend.java.di.initializeJavaSpecificComponents
import org.jetbrains.kotlin.idea.compiler.IdeSealedClassInheritorsProvider
import org.jetbrains.kotlin.idea.configuration.IdeBuiltInsLoadingState
import org.jetbrains.kotlin.idea.project.IdeaEnvironment
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolverImpl
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.platform.*
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.js.isJs
import org.jetbrains.kotlin.platform.jvm.JvmPlatform
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.platform.konan.NativePlatform
import org.jetbrains.kotlin.platform.konan.NativePlatforms
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.checkers.ExperimentalMarkerDeclarationAnnotationChecker
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragmentProvider
import org.jetbrains.kotlin.serialization.deserialization.MetadataPartProvider
import org.jetbrains.kotlin.storage.StorageManager
class CompositeResolverForModuleFactory(
private val commonAnalysisParameters: CommonAnalysisParameters,
private val jvmAnalysisParameters: JvmPlatformParameters,
private val targetPlatform: TargetPlatform,
private val compilerServices: CompositeAnalyzerServices
) : ResolverForModuleFactory() {
override fun <M : ModuleInfo> createResolverForModule(
moduleDescriptor: ModuleDescriptorImpl,
moduleContext: ModuleContext,
moduleContent: ModuleContent<M>,
resolverForProject: ResolverForProject<M>,
languageVersionSettings: LanguageVersionSettings,
sealedInheritorsProvider: SealedClassInheritorsProvider
): ResolverForModule {
val (moduleInfo, syntheticFiles, moduleContentScope) = moduleContent
val project = moduleContext.project
val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory(
project, moduleContext.storageManager, syntheticFiles,
moduleContentScope,
moduleInfo
)
val metadataPartProvider = commonAnalysisParameters.metadataPartProviderFactory(moduleContent)
val trace = CodeAnalyzerInitializer.getInstance(project).createTrace()
val moduleClassResolver = ModuleClassResolverImpl { javaClass ->
val referencedClassModule = jvmAnalysisParameters.moduleByJavaClass(javaClass)
// We don't have full control over idea resolve api so we allow for a situation which should not happen in Kotlin.
// For example, type in a java library can reference a class declared in a source root (is valid but rare case)
// Providing a fallback strategy in this case can hide future problems, so we should at least log to be able to diagnose those
@Suppress("UNCHECKED_CAST")
val resolverForReferencedModule = referencedClassModule?.let { resolverForProject.tryGetResolverForModule(it as M) }
val resolverForModule = resolverForReferencedModule?.takeIf {
referencedClassModule.platform.has<JvmPlatform>()
} ?: run {
// in case referenced class lies outside of our resolver, resolve the class as if it is inside our module
// this leads to java class being resolved several times
resolverForProject.resolverForModule(moduleInfo)
}
resolverForModule.componentProvider.get<JavaDescriptorResolver>()
}
val packagePartProvider = jvmAnalysisParameters.packagePartProviderFactory(moduleContent)
val container = createContainerForCompositePlatform(
moduleContext, moduleContentScope, languageVersionSettings, targetPlatform,
compilerServices, trace, declarationProviderFactory, metadataPartProvider,
moduleClassResolver, packagePartProvider
)
val packageFragmentProviders = sequence {
yield(container.get<ResolveSession>().packageFragmentProvider)
yieldAll(getCommonProvidersIfAny(moduleInfo, moduleContext, moduleDescriptor, container)) // todo: module context
yieldAll(getJsProvidersIfAny(moduleInfo, moduleContext, moduleDescriptor, container))
yieldAll(getJvmProvidersIfAny(container))
yieldAll(getNativeProvidersIfAny(moduleInfo, container))
}.toList()
return ResolverForModule(
CompositePackageFragmentProvider(
packageFragmentProviders,
"CompositeProvider@CompositeResolver for $moduleDescriptor"
),
container
)
}
private fun getCommonProvidersIfAny(
moduleInfo: ModuleInfo,
moduleContext: ModuleContext,
moduleDescriptor: ModuleDescriptor,
container: StorageComponentContainer
): List<PackageFragmentProvider> {
if (!targetPlatform.isCommon()) return emptyList()
val metadataProvider = container.get<MetadataPackageFragmentProvider>()
val klibMetadataProvider = CommonPlatforms.defaultCommonPlatform.idePlatformKind.resolution.createKlibPackageFragmentProvider(
moduleInfo,
moduleContext.storageManager,
container.get<LanguageVersionSettings>(),
moduleDescriptor
)
return listOfNotNull(metadataProvider, klibMetadataProvider)
}
@OptIn(ExperimentalStdlibApi::class)
private fun getJvmProvidersIfAny(container: StorageComponentContainer): List<PackageFragmentProvider> =
buildList {
if (targetPlatform.has<JvmPlatform>()) add(container.get<JavaDescriptorResolver>().packageFragmentProvider)
// Use JVM built-ins only for completely-JVM modules
addIfNotNull(container.tryGetService(JvmBuiltInsPackageFragmentProvider::class.java))
}
private fun getNativeProvidersIfAny(moduleInfo: ModuleInfo, container: StorageComponentContainer): List<PackageFragmentProvider> {
if (!targetPlatform.has<NativePlatform>()) return emptyList()
return listOfNotNull(
NativePlatforms.unspecifiedNativePlatform.idePlatformKind.resolution.createKlibPackageFragmentProvider(
moduleInfo,
container.get<StorageManager>(),
container.get<LanguageVersionSettings>(),
container.get<ModuleDescriptor>()
)
)
}
private fun getJsProvidersIfAny(
moduleInfo: ModuleInfo,
moduleContext: ModuleContext,
moduleDescriptor: ModuleDescriptorImpl,
container: StorageComponentContainer
): List<PackageFragmentProvider> {
if (moduleInfo !is LibraryModuleInfo || !moduleInfo.platform.isJs()) return emptyList()
return createPackageFragmentProvider(moduleInfo, container, moduleContext, moduleDescriptor)
}
fun createContainerForCompositePlatform(
moduleContext: ModuleContext,
moduleContentScope: GlobalSearchScope,
languageVersionSettings: LanguageVersionSettings,
targetPlatform: TargetPlatform,
analyzerServices: CompositeAnalyzerServices,
trace: BindingTrace,
declarationProviderFactory: DeclarationProviderFactory,
metadataPartProvider: MetadataPartProvider,
// Guaranteed to be non-null for modules with JVM
moduleClassResolver: ModuleClassResolver?,
packagePartProvider: PackagePartProvider?
): StorageComponentContainer = composeContainer("CompositePlatform") {
// Shared by all PlatformConfigurators
configureDefaultCheckers()
// Specific for each PlatformConfigurator
for (configurator in analyzerServices.services.map { it.platformConfigurator as PlatformConfiguratorBase }) {
configurator.configureExtensionsAndCheckers(this)
}
// Called by all normal containers set-ups
configureModule(moduleContext, targetPlatform, analyzerServices, trace, languageVersionSettings, IdeSealedClassInheritorsProvider)
configureStandardResolveComponents()
useInstance(moduleContentScope)
useInstance(declarationProviderFactory)
// Probably, should be in StandardResolveComponents, but
useInstance(VirtualFileFinderFactory.getInstance(moduleContext.project).create(moduleContentScope))
useInstance(packagePartProvider!!)
// JVM-specific
if (targetPlatform.has<JvmPlatform>()) {
configureJavaSpecificComponents(
moduleContext, moduleClassResolver!!,
languageVersionSettings,
configureJavaClassFinder = null,
javaClassTracker = null,
useBuiltInsProvider = IdeBuiltInsLoadingState.isFromDependenciesForJvm && targetPlatform.isJvm() // use JVM BuiltIns only for completely JVM modules
)
}
// Common-specific
if (targetPlatform.isCommon()) {
configureCommonSpecificComponents()
}
IdeaEnvironment.configure(this)
}.apply {
if (targetPlatform.has<JvmPlatform>()) {
initializeJavaSpecificComponents(trace)
}
}
}
class CompositeAnalyzerServices(val services: List<PlatformDependentAnalyzerServices>) : PlatformDependentAnalyzerServices() {
override val platformConfigurator: PlatformConfigurator = CompositePlatformConfigurator(services.map { it.platformConfigurator })
override fun computePlatformSpecificDefaultImports(storageManager: StorageManager, result: MutableList<ImportPath>) {
val intersectionOfDefaultImports = services.map { service ->
mutableListOf<ImportPath>()
.apply { service.computePlatformSpecificDefaultImports(storageManager, this) }
.toSet()
}.safeIntersect()
result.addAll(intersectionOfDefaultImports)
}
override val defaultLowPriorityImports: List<ImportPath> = services.map { it.defaultLowPriorityImports.toSet() }.safeIntersect()
override val excludedImports: List<FqName> = services.map { it.excludedImports.toSet() }.safeUnion()
private fun <T> List<Set<T>>.safeUnion(): List<T> =
if (isEmpty()) emptyList() else reduce { first, second -> first.union(second) }.toList()
private fun <T> List<Set<T>>.safeIntersect(): List<T> =
if (isEmpty()) emptyList() else reduce { first, second -> first.intersect(second) }.toList()
}
class CompositePlatformConfigurator(private val componentConfigurators: List<PlatformConfigurator>) : PlatformConfigurator {
override val platformSpecificContainer: StorageComponentContainer
get() = composeContainer(this::class.java.simpleName) {
configureDefaultCheckers()
for (configurator in componentConfigurators) {
(configurator as PlatformConfiguratorBase).configureExtensionsAndCheckers(this)
}
}
override fun configureModuleComponents(container: StorageComponentContainer, languageVersionSettings: LanguageVersionSettings) {
componentConfigurators.forEach { it.configureModuleComponents(container, languageVersionSettings) }
}
override fun configureModuleDependentCheckers(container: StorageComponentContainer) {
// We (ab)use the fact that currently, platforms don't use that method, so the only injected compnent will be
// ExperimentalMarkerDeclarationAnnotationChecker.
// Unfortunately, it is declared in base class, so repeating call to 'configureModuleDependentCheckers' will lead
// to multiple registrrations.
container.useImpl<ExperimentalMarkerDeclarationAnnotationChecker>()
}
}

View File

@@ -1,99 +0,0 @@
/*
* Copyright 2010-2017 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.caches.resolve
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.extensions.ApplicationExtensionDescriptor
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
import org.jetbrains.kotlin.platform.IdePlatformKind
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.resolve.TargetEnvironment
import org.jetbrains.kotlin.storage.StorageManager
interface IdePlatformKindResolution {
val kind: IdePlatformKind<*>
fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?, stdlibInfo: LibraryInfo?): BuiltInsCacheKey
fun createBuiltIns(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo?,
stdlibDependency: LibraryInfo?
): KotlinBuiltIns
fun createResolverForModuleFactory(
settings: PlatformAnalysisParameters,
environment: TargetEnvironment,
platform: TargetPlatform
): ResolverForModuleFactory
fun isLibraryFileForPlatform(virtualFile: VirtualFile): Boolean
fun createKlibPackageFragmentProvider(
moduleInfo: ModuleInfo,
storageManager: StorageManager,
languageVersionSettings: LanguageVersionSettings,
moduleDescriptor: ModuleDescriptor
): PackageFragmentProvider? = null
val libraryKind: PersistentLibraryKind<*>?
fun createLibraryInfo(project: Project, library: Library): List<LibraryInfo>
companion object : ApplicationExtensionDescriptor<IdePlatformKindResolution>(
"org.jetbrains.kotlin.idePlatformKindResolution", IdePlatformKindResolution::class.java
) {
private val CACHED_RESOLUTION_SUPPORT by lazy {
val allPlatformKinds = IdePlatformKind.ALL_KINDS
val groupedResolution = getInstances().groupBy { it.kind }.mapValues { it.value.single() }
for (kind in allPlatformKinds) {
if (kind !in groupedResolution) {
throw IllegalStateException(
"Resolution support for the platform '$kind' is missing. " +
"Implement 'IdePlatformKindResolution' for it."
)
}
}
groupedResolution
}
fun getResolution(kind: IdePlatformKind<*>): IdePlatformKindResolution {
return CACHED_RESOLUTION_SUPPORT[kind] ?: error("Unknown platform $this")
}
}
}
val IdePlatformKind<*>.resolution: IdePlatformKindResolution
get() = IdePlatformKindResolution.getResolution(this)

View File

@@ -1,127 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.caches.resolve
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.PathUtil
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
import org.jetbrains.kotlin.idea.framework.JSLibraryKind
import org.jetbrains.kotlin.idea.klib.AbstractKlibLibraryInfo
import org.jetbrains.kotlin.idea.klib.createKlibPackageFragmentProvider
import org.jetbrains.kotlin.idea.klib.isKlibLibraryRootForPlatform
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.impl.JsIdePlatformKind
import org.jetbrains.kotlin.platform.js.JsPlatforms
import org.jetbrains.kotlin.resolve.TargetEnvironment
import org.jetbrains.kotlin.serialization.js.DynamicTypeDeserializer
import org.jetbrains.kotlin.serialization.konan.impl.KlibMetadataModuleDescriptorFactoryImpl
import org.jetbrains.kotlin.storage.StorageManager
class JsPlatformKindResolution : IdePlatformKindResolution {
override fun isLibraryFileForPlatform(virtualFile: VirtualFile): Boolean {
return virtualFile.extension == "js"
|| virtualFile.extension == "kjsm"
|| virtualFile.isKlibLibraryRootForPlatform(JsPlatforms.defaultJsPlatform)
}
override val libraryKind: PersistentLibraryKind<*>?
get() = JSLibraryKind
override val kind get() = JsIdePlatformKind
override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?, stdlibInfo: LibraryInfo?): BuiltInsCacheKey {
return BuiltInsCacheKey.DefaultBuiltInsKey
}
override fun createBuiltIns(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo?,
stdlibDependency: LibraryInfo?,
): KotlinBuiltIns {
return DefaultBuiltIns.Instance
}
override fun createResolverForModuleFactory(
settings: PlatformAnalysisParameters,
environment: TargetEnvironment,
platform: TargetPlatform
): ResolverForModuleFactory = JsResolverForModuleFactory(environment)
override fun createLibraryInfo(project: Project, library: Library): List<LibraryInfo> {
val klibFiles = library.getFiles(OrderRootType.CLASSES).filter {
it.isKlibLibraryRootForPlatform(JsPlatforms.defaultJsPlatform)
}
return if (klibFiles.isNotEmpty()) {
klibFiles.mapNotNull {
// TODO report error?
val path = PathUtil.getLocalPath(it) ?: return@mapNotNull null
JsKlibLibraryInfo(project, library, path)
}
} else {
listOf(JsMetadataLibraryInfo(project, library))
}
}
override fun createKlibPackageFragmentProvider(
moduleInfo: ModuleInfo,
storageManager: StorageManager,
languageVersionSettings: LanguageVersionSettings,
moduleDescriptor: ModuleDescriptor
): PackageFragmentProvider? {
return (moduleInfo as? JsKlibLibraryInfo)
?.resolvedKotlinLibrary
?.createKlibPackageFragmentProvider(
storageManager = storageManager,
metadataModuleDescriptorFactory = metadataModuleDescriptorFactory,
languageVersionSettings = languageVersionSettings,
moduleDescriptor = moduleDescriptor,
lookupTracker = LookupTracker.DO_NOTHING
)
}
companion object {
private val metadataFactories = KlibMetadataFactories({ DefaultBuiltIns.Instance }, DynamicTypeDeserializer)
private val metadataModuleDescriptorFactory = KlibMetadataModuleDescriptorFactoryImpl(
metadataFactories.DefaultDescriptorFactory,
metadataFactories.DefaultPackageFragmentsFactory,
metadataFactories.flexibleTypeDeserializer,
metadataFactories.platformDependentTypeTransformer
)
}
}
class JsKlibLibraryInfo(project: Project, library: Library, libraryRoot: String) : AbstractKlibLibraryInfo(project, library, libraryRoot) {
override val platform: TargetPlatform
get() = JsPlatforms.defaultJsPlatform
}
class JsMetadataLibraryInfo(project: Project, library: Library) : LibraryInfo(project, library) {
override val platform: TargetPlatform
get() = JsPlatforms.defaultJsPlatform
}

View File

@@ -1,117 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.caches.resolve
import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.kotlin.analyzer.*
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.container.StorageComponentContainer
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.frontend.di.createContainerForLazyResolve
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices
import org.jetbrains.kotlin.platform.idePlatformKind
import org.jetbrains.kotlin.platform.js.JsPlatforms
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.SealedClassInheritorsProvider
import org.jetbrains.kotlin.resolve.TargetEnvironment
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
import org.jetbrains.kotlin.serialization.js.createKotlinJavascriptPackageFragmentProvider
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
import java.io.File
private val LOG = Logger.getInstance(JsResolverForModuleFactory::class.java)
class JsResolverForModuleFactory(
private val targetEnvironment: TargetEnvironment
) : ResolverForModuleFactory() {
override fun <M : ModuleInfo> createResolverForModule(
moduleDescriptor: ModuleDescriptorImpl,
moduleContext: ModuleContext,
moduleContent: ModuleContent<M>,
resolverForProject: ResolverForProject<M>,
languageVersionSettings: LanguageVersionSettings,
sealedInheritorsProvider: SealedClassInheritorsProvider
): ResolverForModule {
val (moduleInfo, syntheticFiles, moduleContentScope) = moduleContent
val project = moduleContext.project
val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory(
project,
moduleContext.storageManager,
syntheticFiles,
moduleContentScope,
moduleInfo
)
val container = createContainerForLazyResolve(
moduleContext,
declarationProviderFactory,
BindingTraceContext(/* allowSliceRewrite = */ true),
moduleDescriptor.platform!!,
JsPlatformAnalyzerServices,
targetEnvironment,
languageVersionSettings
)
var packageFragmentProvider = container.get<ResolveSession>().packageFragmentProvider
val libraryProviders = createPackageFragmentProvider(moduleInfo, container, moduleContext, moduleDescriptor)
if (libraryProviders.isNotEmpty()) {
packageFragmentProvider = CompositePackageFragmentProvider(
listOf(packageFragmentProvider) + libraryProviders,
"CompositeProvider@JsResolver for $moduleDescriptor"
)
}
return ResolverForModule(packageFragmentProvider, container)
}
}
internal fun <M : ModuleInfo> createPackageFragmentProvider(
moduleInfo: M,
container: StorageComponentContainer,
moduleContext: ModuleContext,
moduleDescriptor: ModuleDescriptorImpl
): List<PackageFragmentProvider> = when (moduleInfo) {
is JsKlibLibraryInfo -> {
listOfNotNull(
JsPlatforms.defaultJsPlatform.idePlatformKind.resolution.createKlibPackageFragmentProvider(
moduleInfo,
moduleContext.storageManager,
container.get<LanguageVersionSettings>(),
moduleDescriptor
)
)
}
is LibraryModuleInfo -> {
moduleInfo.getLibraryRoots()
.flatMap {
if (File(it).exists()) {
KotlinJavascriptMetadataUtils.loadMetadata(it)
} else {
// TODO can/should we warn a user about a problem in a library root? If so how?
LOG.error("Library $it not found")
emptyList()
}
}
.filter { it.version.isCompatible() }
.map { metadata ->
val (header, packageFragmentProtos) =
KotlinJavascriptSerializationUtil.readModuleAsProto(metadata.body, metadata.version)
createKotlinJavascriptPackageFragmentProvider(
moduleContext.storageManager, moduleDescriptor, header, packageFragmentProtos, metadata.version,
container.get(), LookupTracker.DO_NOTHING
)
}
}
else -> emptyList()
}

View File

@@ -1,138 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.caches.resolve
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
import org.jetbrains.kotlin.idea.configuration.IdeBuiltInsLoadingState
import org.jetbrains.kotlin.idea.caches.resolve.supportsAdditionalBuiltInsMembers
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.resolve.TargetEnvironment
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
import org.jetbrains.kotlin.resolve.jvm.JvmResolverForModuleFactory
private val LOG = Logger.getInstance(JvmPlatformKindResolution::class.java)
class JvmPlatformKindResolution : IdePlatformKindResolution {
override fun isLibraryFileForPlatform(virtualFile: VirtualFile): Boolean {
return false // TODO: No library kind for JVM
}
override fun createResolverForModuleFactory(
settings: PlatformAnalysisParameters,
environment: TargetEnvironment,
platform: TargetPlatform
): ResolverForModuleFactory {
return JvmResolverForModuleFactory(settings as JvmPlatformParameters, environment, platform)
}
override val libraryKind: PersistentLibraryKind<*>?
get() = null
override fun createLibraryInfo(project: Project, library: Library): List<LibraryInfo> =
listOf(JvmLibraryInfo(project, library))
override val kind get() = JvmIdePlatformKind
override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?, stdlibInfo: LibraryInfo?): BuiltInsCacheKey {
if (IdeBuiltInsLoadingState.isFromClassLoader && stdlibInfo != null) {
LOG.error("Standard library ${stdlibInfo.displayedName} provided for built-ins, but loading from dependencies is disabled")
}
return if (sdkInfo != null)
CacheKeyByBuiltInsDependencies(sdkInfo.sdk, stdlibInfo)
else BuiltInsCacheKey.DefaultBuiltInsKey
}
override fun createBuiltIns(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo?,
stdlibDependency: LibraryInfo?,
): KotlinBuiltIns {
return when {
sdkDependency == null -> DefaultBuiltIns.Instance
stdlibDependency == null || moduleInfo is SdkInfo ->
createBuiltInsFromClassLoader(moduleInfo, projectContext, resolverForProject, sdkDependency)
else -> createBuiltinsFromModuleDependencies(moduleInfo, projectContext, resolverForProject, sdkDependency, stdlibDependency)
}
}
private fun createBuiltInsFromClassLoader(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo,
): JvmBuiltIns {
return JvmBuiltIns(projectContext.storageManager, JvmBuiltIns.Kind.FROM_CLASS_LOADER).apply {
setPostponedSettingsComputation {
// SDK should be present, otherwise we wouldn't have created JvmBuiltIns in createBuiltIns
val sdkDescriptor = resolverForProject.descriptorForModule(sdkDependency)
val isAdditionalBuiltInsFeaturesSupported =
moduleInfo.supportsAdditionalBuiltInsMembers(projectContext.project)
JvmBuiltIns.Settings(sdkDescriptor, isAdditionalBuiltInsFeaturesSupported)
}
}
}
private fun createBuiltinsFromModuleDependencies(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo,
stdlibDependency: LibraryInfo,
): JvmBuiltIns {
if (IdeBuiltInsLoadingState.isFromClassLoader) {
LOG.error("Incorrect attempt to create built-ins from module dependencies")
}
return JvmBuiltIns(projectContext.storageManager, JvmBuiltIns.Kind.FROM_DEPENDENCIES).apply {
setPostponedBuiltinsModuleComputation {
val stdlibDescriptor = resolverForProject.descriptorForModule(stdlibDependency)
@Suppress("unchecked_cast")
stdlibDescriptor as ModuleDescriptorImpl
}
setPostponedSettingsComputation {
val sdkDescriptor = resolverForProject.descriptorForModule(sdkDependency)
val isAdditionalBuiltInsFeaturesSupported =
moduleInfo.supportsAdditionalBuiltInsMembers(projectContext.project)
JvmBuiltIns.Settings(sdkDescriptor, isAdditionalBuiltInsFeaturesSupported)
}
}
}
data class CacheKeyByBuiltInsDependencies(val sdk: Sdk, val stdlib: LibraryInfo?) : BuiltInsCacheKey
}
class JvmLibraryInfo(project: Project, library: Library) : LibraryInfo(project, library) {
override val platform: TargetPlatform
get() = JvmPlatforms.defaultJvmPlatform
}

View File

@@ -1,155 +0,0 @@
/*
* 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;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Iconable;
import com.intellij.psi.PsiElement;
import com.intellij.ui.RowIcon;
import com.intellij.util.PlatformIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
import org.jetbrains.kotlin.psi.KtElement;
import javax.swing.*;
public final class KotlinDescriptorIconProvider {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.KotlinDescriptorIconProvider");
private KotlinDescriptorIconProvider() {
}
@Nullable
public static Icon getIcon(@NotNull DeclarationDescriptor descriptor, @Nullable PsiElement declaration, @Iconable.IconFlags int flags) {
if (declaration != null && !(declaration instanceof KtElement)) {
return declaration.getIcon(flags);
}
Icon result = getBaseIcon(descriptor);
if ((flags & Iconable.ICON_FLAG_VISIBILITY) > 0) {
RowIcon rowIcon = new RowIcon(2);
rowIcon.setIcon(result, 0);
rowIcon.setIcon(getVisibilityIcon(descriptor), 1);
result = rowIcon;
}
return result;
}
private static Icon getVisibilityIcon(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof DeclarationDescriptorWithVisibility) {
DeclarationDescriptorWithVisibility descriptorWithVisibility = (DeclarationDescriptorWithVisibility) descriptor;
DescriptorVisibility visibility = descriptorWithVisibility.getVisibility().normalize();
if (visibility == DescriptorVisibilities.PUBLIC) {
return PlatformIcons.PUBLIC_ICON;
}
if (visibility == DescriptorVisibilities.PROTECTED) {
return PlatformIcons.PROTECTED_ICON;
}
if (DescriptorVisibilities.isPrivate(visibility)) {
return PlatformIcons.PRIVATE_ICON;
}
if (visibility == DescriptorVisibilities.INTERNAL) {
return PlatformIcons.PACKAGE_LOCAL_ICON;
}
}
return null;
}
private static Modality getModalitySafe(@NotNull MemberDescriptor descriptor) {
try {
return descriptor.getModality();
}
catch (InvalidModuleException ex) {
return Modality.FINAL;
}
}
private static Icon getBaseIcon(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof PackageFragmentDescriptor || descriptor instanceof PackageViewDescriptor) {
return PlatformIcons.PACKAGE_ICON;
}
if (descriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
if (functionDescriptor.getExtensionReceiverParameter() != null) {
return Modality.ABSTRACT == getModalitySafe(functionDescriptor)
? KotlinIcons.ABSTRACT_EXTENSION_FUNCTION
: KotlinIcons.EXTENSION_FUNCTION;
}
if (descriptor.getContainingDeclaration() instanceof ClassDescriptor) {
return Modality.ABSTRACT == getModalitySafe(functionDescriptor)
? PlatformIcons.ABSTRACT_METHOD_ICON
: PlatformIcons.METHOD_ICON;
}
else {
return KotlinIcons.FUNCTION;
}
}
if (descriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
switch (classDescriptor.getKind()) {
case INTERFACE:
return KotlinIcons.INTERFACE;
case ENUM_CLASS:
return KotlinIcons.ENUM;
case ENUM_ENTRY:
return KotlinIcons.ENUM;
case ANNOTATION_CLASS:
return KotlinIcons.ANNOTATION;
case OBJECT:
return KotlinIcons.OBJECT;
case CLASS:
return Modality.ABSTRACT == getModalitySafe(classDescriptor) ?
KotlinIcons.ABSTRACT_CLASS :
KotlinIcons.CLASS;
default:
LOG.warn("No icon for descriptor: " + descriptor);
return null;
}
}
if (descriptor instanceof ValueParameterDescriptor) {
return KotlinIcons.PARAMETER;
}
if (descriptor instanceof LocalVariableDescriptor) {
return ((VariableDescriptor) descriptor).isVar() ? KotlinIcons.VAR : KotlinIcons.VAL;
}
if (descriptor instanceof PropertyDescriptor) {
return ((VariableDescriptor) descriptor).isVar() ? KotlinIcons.FIELD_VAR : KotlinIcons.FIELD_VAL;
}
if (descriptor instanceof TypeParameterDescriptor) {
return PlatformIcons.CLASS_ICON;
}
if (descriptor instanceof TypeAliasDescriptor) {
return KotlinIcons.TYPE_ALIAS;
}
LOG.warn("No icon for descriptor: " + descriptor);
return null;
}
}

View File

@@ -1,14 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea
import org.jetbrains.kotlin.idea.util.hasMatchingExpected
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
class KotlinIconProvider : KotlinIconProviderBase() {
override fun KtDeclaration.isMatchingExpected() = hasActualModifier() && hasMatchingExpected()
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.PropertyKey
import org.jetbrains.kotlin.util.AbstractKotlinBundle
@NonNls
private const val BUNDLE = "messages.KotlinIdeaAnalysisBundle"
object KotlinIdeaAnalysisBundle : AbstractKotlinBundle(BUNDLE) {
@JvmStatic
fun message(@NonNls @PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): String = getMessage(key, *params)
@JvmStatic
fun htmlMessage(@NonNls @PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): String =
getMessage(key, *params).withHtml()
@JvmStatic
fun lazyMessage(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): () -> String = { getMessage(key, *params) }
}

View File

@@ -1,71 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea
import com.intellij.ide.plugins.IdeaPluginDescriptor
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.openapi.extensions.PluginId
import java.io.File
object KotlinPluginUtil {
private class KotlinPluginInfo(val id: PluginId, val version: String, val path: File) {
constructor(plugin: IdeaPluginDescriptor) : this(plugin.pluginId, plugin.version, plugin.path)
}
private val KNOWN_KOTLIN_PLUGIN_IDS = listOf(
"org.jetbrains.kotlin",
"org.jetbrains.kotlin.native.clion",
"org.jetbrains.kotlin.native.appcode"
)
private val KOTLIN_PLUGIN_INFO: KotlinPluginInfo by lazy {
val plugin = PluginManagerCore.getPlugins().firstOrNull { it.pluginId.idString in KNOWN_KOTLIN_PLUGIN_IDS }
?: error("Kotlin plugin not found: " + PluginManagerCore.getPlugins().contentToString())
KotlinPluginInfo(plugin)
}
val KOTLIN_PLUGIN_ID: PluginId
get() = KOTLIN_PLUGIN_INFO.id
private const val PATCHED_PLUGIN_VERSION_KEY = "kotlin.plugin.version"
private val PATCHED_PLUGIN_VERSION: String? = System.getProperty(PATCHED_PLUGIN_VERSION_KEY, null)
@JvmStatic
fun getPluginVersion(): String {
if (PATCHED_PLUGIN_VERSION != null) {
assert(isPatched())
return PATCHED_PLUGIN_VERSION
}
@Suppress("DEPRECATION")
return getPluginVersionFromIdea()
}
@Deprecated("This method returns original plugin version. Please use getPluginVersion() instead.")
@JvmStatic
fun getPluginVersionFromIdea(): String {
return KOTLIN_PLUGIN_INFO.version
}
@JvmStatic
fun isPatched(): Boolean {
return PATCHED_PLUGIN_VERSION != null
}
@JvmStatic
fun isSnapshotVersion(): Boolean {
return "@snapshot@" == getPluginVersion()
}
fun isDevVersion(): Boolean {
return getPluginVersion().contains("-dev-")
}
fun getPluginPath(): File {
return KOTLIN_PLUGIN_INFO.path
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.api.fe10.impl
import org.jetbrains.kotlin.idea.api.ResolveAllowanceService
class ResolveAllowanceServiceFE10Impl: ResolveAllowanceService() {
override fun switchOnAllowingResolveInEdtInCurrentThread(): SwitchResult {
return SwitchResult.ALREADY_SWITCHED
}
override fun isResolveOnEdtInCurrentThreadAllowed(): Boolean = true
override fun switchOffAllowingResolveInEdtInCurrentThread() {}
override fun switchOnForbidResolveInCurrentThread(actionName: String): SwitchResult {
return SwitchResult.ALREADY_SWITCHED
}
override fun switchOffForbidResolveInCurrentThread() {
}
override fun getResolveInCurrentThreadForbiddenReason(): String? = null
}

View File

@@ -1,41 +0,0 @@
/*
* 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.caches
import com.intellij.openapi.vfs.VirtualFile
import java.io.DataInput
import java.io.DataOutput
data class CachedAttributeData<out T>(val value: T, val timeStamp: Long)
interface FileAttributeService {
fun register(id: String, version: Int, fixedSize: Boolean = true) {}
fun <T : Enum<T>> writeEnumAttribute(id: String, file: VirtualFile, value: T): CachedAttributeData<T> =
CachedAttributeData(value, timeStamp = file.timeStamp)
fun <T : Enum<T>> readEnumAttribute(id: String, file: VirtualFile, klass: Class<T>): CachedAttributeData<T>? = null
fun writeBooleanAttribute(id: String, file: VirtualFile, value: Boolean): CachedAttributeData<Boolean> =
CachedAttributeData(value, timeStamp = file.timeStamp)
fun readBooleanAttribute(id: String, file: VirtualFile): CachedAttributeData<Boolean>? = null
fun <T> write(file: VirtualFile, id: String, value: T, writeValueFun: (DataOutput, T) -> Unit): CachedAttributeData<T>
fun <T> read(file: VirtualFile, id: String, readValueFun: (DataInput) -> T): CachedAttributeData<T>?
}

View File

@@ -1,140 +0,0 @@
/*
* Copyright 2010-2016 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.caches
import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.components.service
import com.intellij.openapi.util.Key
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileWithId
import com.intellij.reference.SoftReference
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.name.ClassId
class IDEKotlinBinaryClassCache {
class KotlinBinaryClassHeaderData(
val classId: ClassId,
val kind: KotlinClassHeader.Kind,
val metadataVersion: JvmMetadataVersion,
val partNamesIfMultifileFacade: List<String>,
val packageName: String?
)
data class KotlinBinaryData(val isKotlinBinary: Boolean, val timestamp: Long, val headerData: KotlinBinaryClassHeaderData?)
/**
* Checks if this file is a compiled Kotlin class file (not necessarily ABI-compatible with the current plugin)
*/
fun isKotlinJvmCompiledFile(file: VirtualFile, fileContent: ByteArray? = null): Boolean {
if (file.extension != JavaClassFileType.INSTANCE!!.defaultExtension) {
return false
}
val cached = getKotlinBinaryFromCache(file)
if (cached != null) {
return cached.isKotlinBinary
}
return getKotlinBinaryClass(file, fileContent) != null
}
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
val cached = getKotlinBinaryFromCache(file)
if (cached != null && !cached.isKotlinBinary) {
return null
}
val kotlinBinaryClass = KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file, fileContent)?.toKotlinJvmBinaryClass()
val isKotlinBinaryClass = kotlinBinaryClass != null
if (file is VirtualFileWithId) {
attributeService.writeBooleanAttribute(KOTLIN_IS_COMPILED_FILE_ATTRIBUTE, file, isKotlinBinaryClass)
}
if (isKotlinBinaryClass) {
val headerInfo = createHeaderInfo(kotlinBinaryClass)
file.putUserData(KOTLIN_BINARY_DATA_KEY, SoftReference(KotlinBinaryData(isKotlinBinaryClass, file.timeStamp, headerInfo)))
}
return kotlinBinaryClass
}
fun getKotlinBinaryClassHeaderData(file: VirtualFile, fileContent: ByteArray? = null): KotlinBinaryClassHeaderData? {
val cached = getKotlinBinaryFromCache(file)
if (cached != null) {
if (!cached.isKotlinBinary) {
return null
}
if (cached.headerData != null) {
return cached.headerData
}
}
val kotlinBinaryClass = getKotlinBinaryClass(file, fileContent)
return createHeaderInfo(kotlinBinaryClass)
}
private val attributeService = ServiceManager.getService(FileAttributeService::class.java)
private fun createHeaderInfo(kotlinBinaryClass: KotlinJvmBinaryClass?): KotlinBinaryClassHeaderData? {
val classId = kotlinBinaryClass?.classId ?: return null
return kotlinBinaryClass.classHeader.toLightHeader(classId)
}
private fun KotlinClassHeader.toLightHeader(classId: ClassId) =
KotlinBinaryClassHeaderData(
classId, kind, metadataVersion, multifilePartNames, packageName
)
private val KOTLIN_IS_COMPILED_FILE_ATTRIBUTE: String = "kotlin-is-binary-compiled".apply {
ServiceManager.getService(FileAttributeService::class.java)?.register(this, 2)
}
private val KOTLIN_BINARY_DATA_KEY = Key.create<SoftReference<KotlinBinaryData>>(KOTLIN_IS_COMPILED_FILE_ATTRIBUTE)
private fun getKotlinBinaryFromCache(file: VirtualFile): KotlinBinaryData? {
val userData = file.getUserData(KOTLIN_BINARY_DATA_KEY)?.get()
if (userData != null && userData.timestamp == file.timeStamp) {
return userData
}
val isKotlinBinaryAttribute = if (file is VirtualFileWithId)
attributeService.readBooleanAttribute(KOTLIN_IS_COMPILED_FILE_ATTRIBUTE, file)
else
null
if (isKotlinBinaryAttribute != null) {
val isKotlinBinary = isKotlinBinaryAttribute.value
val kotlinBinaryData = KotlinBinaryData(isKotlinBinary, file.timeStamp, null)
if (isKotlinBinary) {
file.putUserData(KOTLIN_BINARY_DATA_KEY, SoftReference(kotlinBinaryData))
}
return kotlinBinaryData
}
return null
}
companion object {
fun getInstance(): IDEKotlinBinaryClassCache = service()
}
}

View File

@@ -1,348 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.caches
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiField
import com.intellij.psi.PsiMethod
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.PsiShortNamesCache
import com.intellij.psi.stubs.StubIndex
import com.intellij.util.ArrayUtil
import com.intellij.util.Processor
import com.intellij.util.Processors
import com.intellij.util.containers.ContainerUtil
import com.intellij.util.indexing.IdFilter
import gnu.trove.THashSet
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.defaultImplsChild
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
import org.jetbrains.kotlin.asJava.getAccessorLightMethods
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInFileType
import org.jetbrains.kotlin.idea.stubindex.*
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.getPropertyNamesCandidatesByAccessorName
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() {
companion object {
private val LOG = Logger.getInstance(KotlinShortNamesCache::class.java)
}
//hacky way to avoid searches for Kotlin classes, when looking for Java (from Kotlin)
val disableSearch: ThreadLocal<Boolean> = object : ThreadLocal<Boolean>() {
override fun initialValue(): Boolean = false
}
//region Classes
override fun processAllClassNames(processor: Processor<in String>): Boolean {
if (disableSearch.get()) return true
return KotlinClassShortNameIndex.getInstance().processAllKeys(project, processor) &&
KotlinFileFacadeShortNameIndex.INSTANCE.processAllKeys(project, processor)
}
override fun processAllClassNames(processor: Processor<in String>, scope: GlobalSearchScope, filter: IdFilter?): Boolean {
if (disableSearch.get()) return true
return processAllClassNames(processor)
}
/**
* Return kotlin class names from project sources which should be visible from java.
*/
override fun getAllClassNames(): Array<String> {
if (disableSearch.get()) return ArrayUtil.EMPTY_STRING_ARRAY
return withArrayProcessor(ArrayUtil.EMPTY_STRING_ARRAY) { processor ->
processAllClassNames(processor)
}
}
override fun processClassesWithName(
name: String,
processor: Processor<in PsiClass>,
scope: GlobalSearchScope,
filter: IdFilter?
): Boolean {
if (disableSearch.get()) return true
val effectiveScope = kotlinDeclarationsVisibleFromJavaScope(scope)
val fqNameProcessor = Processor<FqName> { fqName: FqName? ->
if (fqName == null) return@Processor true
val isInterfaceDefaultImpl = name == JvmAbi.DEFAULT_IMPLS_CLASS_NAME && fqName.shortName().asString() != name
if (fqName.shortName().asString() != name && !isInterfaceDefaultImpl) {
LOG.error(
"A declaration obtained from index has non-matching name:" +
"\nin index: $name" +
"\ndeclared: ${fqName.shortName()}($fqName)"
)
return@Processor true
}
val fqNameToSearch = if (isInterfaceDefaultImpl) fqName.defaultImplsChild() else fqName
val psiClass = JavaElementFinder.getInstance(project).findClass(fqNameToSearch.asString(), effectiveScope)
?: return@Processor true
return@Processor processor.process(psiClass)
}
val allKtClassOrObjectsProcessed = StubIndex.getInstance().processElements(
KotlinClassShortNameIndex.getInstance().key,
name,
project,
effectiveScope,
filter,
KtClassOrObject::class.java
) { ktClassOrObject ->
fqNameProcessor.process(ktClassOrObject.fqName)
}
if (!allKtClassOrObjectsProcessed) {
return false
}
return StubIndex.getInstance().processElements(
KotlinFileFacadeShortNameIndex.getInstance().key,
name,
project,
effectiveScope,
filter,
KtFile::class.java
) { ktFile ->
fqNameProcessor.process(ktFile.javaFileFacadeFqName)
}
}
/**
* Return class names form kotlin sources in given scope which should be visible as Java classes.
*/
override fun getClassesByName(name: String, scope: GlobalSearchScope): Array<PsiClass> {
if (disableSearch.get()) return PsiClass.EMPTY_ARRAY
return withArrayProcessor(PsiClass.EMPTY_ARRAY) { processor ->
processClassesWithName(name, processor, scope, null)
}
}
private fun kotlinDeclarationsVisibleFromJavaScope(scope: GlobalSearchScope): GlobalSearchScope {
val noBuiltInsScope: GlobalSearchScope = object : GlobalSearchScope(project) {
override fun isSearchInModuleContent(aModule: Module) = true
override fun compare(file1: VirtualFile, file2: VirtualFile) = 0
override fun isSearchInLibraries() = true
override fun contains(file: VirtualFile) = file.fileType != KotlinBuiltInFileType
}
return KotlinSourceFilterScope.sourceAndClassFiles(scope, project).intersectWith(noBuiltInsScope)
}
//endregion
//region Methods
override fun processAllMethodNames(
processor: Processor<in String>,
scope: GlobalSearchScope,
filter: IdFilter?
): Boolean {
if (disableSearch.get()) return true
return processAllMethodNames(processor)
}
override fun getAllMethodNames(): Array<String> {
if (disableSearch.get()) ArrayUtil.EMPTY_STRING_ARRAY
return withArrayProcessor(ArrayUtil.EMPTY_STRING_ARRAY) { processor ->
processAllMethodNames(processor)
}
}
private fun processAllMethodNames(processor: Processor<in String>): Boolean {
if (disableSearch.get()) return true
if (!KotlinFunctionShortNameIndex.getInstance().processAllKeys(project, processor)) {
return false
}
return KotlinPropertyShortNameIndex.getInstance().processAllKeys(project) { name ->
return@processAllKeys processor.process(JvmAbi.setterName(name)) && processor.process(JvmAbi.getterName(name))
}
}
override fun processMethodsWithName(
name: String,
processor: Processor<in PsiMethod>,
scope: GlobalSearchScope,
filter: IdFilter?
): Boolean {
if (disableSearch.get()) return true
val allFunctionsProcessed = StubIndex.getInstance().processElements(
KotlinFunctionShortNameIndex.getInstance().key,
name,
project,
scope,
filter,
KtNamedFunction::class.java
) { ktNamedFunction ->
val methods = LightClassUtil.getLightClassMethodsByName(ktNamedFunction, name)
return@processElements methods.all { method ->
processor.process(method)
}
}
if (!allFunctionsProcessed) {
return false
}
for (propertyName in getPropertyNamesCandidatesByAccessorName(Name.identifier(name))) {
val allProcessed = StubIndex.getInstance().processElements(
KotlinPropertyShortNameIndex.getInstance().key,
propertyName.asString(),
project,
scope,
filter,
KtNamedDeclaration::class.java
) { ktNamedDeclaration ->
val methods: Sequence<PsiMethod> = ktNamedDeclaration.getAccessorLightMethods()
.asSequence()
.filter { it.name == name }
return@processElements methods.all { method ->
processor.process(method)
}
}
if (!allProcessed) {
return false
}
}
return true
}
override fun getMethodsByName(name: String, scope: GlobalSearchScope): Array<PsiMethod> {
if (disableSearch.get()) return PsiMethod.EMPTY_ARRAY
return withArrayProcessor(PsiMethod.EMPTY_ARRAY) { processor ->
processMethodsWithName(name, processor, scope, null)
}
}
override fun getMethodsByNameIfNotMoreThan(name: String, scope: GlobalSearchScope, maxCount: Int): Array<PsiMethod> {
if (disableSearch.get()) return PsiMethod.EMPTY_ARRAY
require(maxCount >= 0)
return withArrayProcessor(PsiMethod.EMPTY_ARRAY) { processor ->
processMethodsWithName(
name,
{ psiMethod ->
processor.size != maxCount && processor.process(psiMethod)
},
scope,
null
)
}
}
override fun processMethodsWithName(
name: String,
scope: GlobalSearchScope,
processor: Processor<in PsiMethod>
): Boolean {
if (disableSearch.get()) return true
return ContainerUtil.process(getMethodsByName(name, scope), processor)
}
//endregion
//region Fields
override fun processAllFieldNames(processor: Processor<in String>, scope: GlobalSearchScope, filter: IdFilter?): Boolean {
if (disableSearch.get()) return true
return processAllFieldNames(processor)
}
override fun getAllFieldNames(): Array<String> {
if (disableSearch.get()) return ArrayUtil.EMPTY_STRING_ARRAY
return withArrayProcessor(ArrayUtil.EMPTY_STRING_ARRAY) { processor ->
processAllFieldNames(processor)
}
}
private fun processAllFieldNames(processor: Processor<in String>): Boolean {
if (disableSearch.get()) return true
return KotlinPropertyShortNameIndex.getInstance().processAllKeys(project, processor)
}
override fun processFieldsWithName(
name: String,
processor: Processor<in PsiField>,
scope: GlobalSearchScope,
filter: IdFilter?
): Boolean {
if (disableSearch.get()) return true
return StubIndex.getInstance().processElements(
KotlinPropertyShortNameIndex.getInstance().key,
name,
project,
scope,
filter,
KtNamedDeclaration::class.java
) { ktNamedDeclaration ->
val field = LightClassUtil.getLightClassBackingField(ktNamedDeclaration)
?: return@processElements true
return@processElements processor.process(field)
}
}
override fun getFieldsByName(name: String, scope: GlobalSearchScope): Array<PsiField> {
if (disableSearch.get()) return PsiField.EMPTY_ARRAY
return withArrayProcessor(PsiField.EMPTY_ARRAY) { processor ->
processFieldsWithName(name, processor, scope, null)
}
}
override fun getFieldsByNameIfNotMoreThan(name: String, scope: GlobalSearchScope, maxCount: Int): Array<PsiField> {
if (disableSearch.get()) return PsiField.EMPTY_ARRAY
require(maxCount >= 0)
return withArrayProcessor(PsiField.EMPTY_ARRAY) { processor ->
processFieldsWithName(
name,
{ psiField ->
processor.size != maxCount && processor.process(psiField)
},
scope,
null
)
}
}
//endregion
private inline fun <T> withArrayProcessor(
result: Array<T>,
process: (CancelableArrayCollectProcessor<T>) -> Unit
): Array<T> {
return CancelableArrayCollectProcessor<T>().also { processor ->
process(processor)
}.toArray(result)
}
private class CancelableArrayCollectProcessor<T> : Processor<T> {
val troveSet = THashSet<T>()
private val processor = Processors.cancelableCollectProcessor<T>(troveSet)
override fun process(value: T): Boolean {
return processor.process(value)
}
val size: Int get() = troveSet.size
fun toArray(a: Array<T>): Array<T> = troveSet.toArray(a)
}
}

View File

@@ -1,418 +0,0 @@
/*
* Copyright 2000-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.caches
import com.intellij.ProjectTopics
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.module.Module
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.rootManager
import com.intellij.openapi.roots.ModuleRootEvent
import com.intellij.openapi.roots.ModuleRootListener
import com.intellij.openapi.startup.StartupActivity
import com.intellij.openapi.util.Key
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.newvfs.BulkFileListener
import com.intellij.openapi.vfs.newvfs.events.*
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.PsiManagerEx
import com.intellij.psi.impl.PsiTreeChangeEventImpl
import com.intellij.psi.impl.PsiTreeChangePreprocessor
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.caches.PerModulePackageCacheService.Companion.DEBUG_LOG_ENABLE_PerModulePackageCache
import org.jetbrains.kotlin.idea.caches.PerModulePackageCacheService.Companion.FULL_DROP_THRESHOLD
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.project.getModuleInfoByVirtualFile
import org.jetbrains.kotlin.idea.caches.project.getNullableModuleInfo
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
import org.jetbrains.kotlin.idea.util.getSourceRoot
import org.jetbrains.kotlin.idea.util.sourceRoot
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPackageDirective
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
class KotlinPackageContentModificationListener : StartupActivity {
companion object {
val LOG = Logger.getInstance(this::class.java)
}
override fun runActivity(project: Project) {
val connection = project.messageBus.connect(project)
connection.subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener {
override fun before(events: MutableList<out VFileEvent>) = onEvents(events, false)
override fun after(events: List<VFileEvent>) = onEvents(events, true)
private fun isRelevant(event: VFileEvent): Boolean = when (event) {
is VFilePropertyChangeEvent -> false
is VFileCreateEvent -> true
is VFileMoveEvent -> true
is VFileDeleteEvent -> true
is VFileContentChangeEvent -> true
is VFileCopyEvent -> true
else -> {
LOG.warn("Unknown vfs event: ${event.javaClass}")
false
}
}
fun onEvents(events: List<VFileEvent>, isAfter: Boolean) {
val service = PerModulePackageCacheService.getInstance(project)
val fileManager = PsiManagerEx.getInstanceEx(project).fileManager
if (events.size >= FULL_DROP_THRESHOLD) {
service.onTooComplexChange()
} else {
events.asSequence()
.filter(::isRelevant)
.filter {
(it.isValid || it !is VFileCreateEvent) && it.file != null
}
.filter {
val vFile = it.file!!
vFile.isDirectory || vFile.fileType == KotlinFileType.INSTANCE
}
.filter {
// It expected that content change events will be duplicated with more precise PSI events and processed
// in KotlinPackageStatementPsiTreeChangePreprocessor, but events might have been missing if PSI view provider
// is absent.
if (it is VFileContentChangeEvent) {
isAfter && fileManager.findCachedViewProvider(it.file) == null
} else {
true
}
}
.filter {
when (val origin = it.requestor) {
is Project -> origin == project
is PsiManager -> origin.project == project
else -> true
}
}
.forEach { event -> service.notifyPackageChange(event) }
}
}
})
connection.subscribe(ProjectTopics.PROJECT_ROOTS, object : ModuleRootListener {
override fun rootsChanged(event: ModuleRootEvent) {
PerModulePackageCacheService.getInstance(project).onTooComplexChange()
}
})
}
}
class KotlinPackageStatementPsiTreeChangePreprocessor(private val project: Project) : PsiTreeChangePreprocessor {
override fun treeChanged(event: PsiTreeChangeEventImpl) {
val eFile = event.file ?: event.child as? PsiFile
if (eFile == null) {
LOG.debugIfEnabled(project, true) { "Got PsiEvent: $event without file" }
}
val file = eFile as? KtFile ?: return
when (event.code) {
PsiTreeChangeEventImpl.PsiEventType.CHILD_ADDED,
PsiTreeChangeEventImpl.PsiEventType.CHILD_MOVED,
PsiTreeChangeEventImpl.PsiEventType.CHILD_REPLACED,
PsiTreeChangeEventImpl.PsiEventType.CHILD_REMOVED -> {
val child = event.child ?: run {
LOG.debugIfEnabled(project, true) { "Got PsiEvent: $event without child" }
return
}
if (child.getParentOfType<KtPackageDirective>(false) != null)
ServiceManager.getService(project, PerModulePackageCacheService::class.java).notifyPackageChange(file)
}
PsiTreeChangeEventImpl.PsiEventType.CHILDREN_CHANGED -> {
val parent = event.parent ?: run {
LOG.debugIfEnabled(project, true) { "Got PsiEvent: $event without parent" }
return
}
val childrenOfType = parent.getChildrenOfType<KtPackageDirective>()
if (
(!event.isGenericChange && (childrenOfType.any() || parent is KtPackageDirective)) ||
(childrenOfType.any { it.name.isEmpty() } && parent is KtFile)
) {
ServiceManager.getService(project, PerModulePackageCacheService::class.java).notifyPackageChange(file)
}
}
else -> {
}
}
}
companion object {
val LOG = Logger.getInstance(this::class.java)
}
}
private typealias ImplicitPackageData = MutableMap<FqName, MutableList<VirtualFile>>
class ImplicitPackagePrefixCache(private val project: Project) {
private val implicitPackageCache = ConcurrentHashMap<VirtualFile, ImplicitPackageData>()
fun getPrefix(sourceRoot: VirtualFile): FqName {
val implicitPackageMap = implicitPackageCache.getOrPut(sourceRoot) { analyzeImplicitPackagePrefixes(sourceRoot) }
return implicitPackageMap.keys.singleOrNull() ?: FqName.ROOT
}
internal fun clear() {
implicitPackageCache.clear()
}
private fun analyzeImplicitPackagePrefixes(sourceRoot: VirtualFile): MutableMap<FqName, MutableList<VirtualFile>> {
val result = mutableMapOf<FqName, MutableList<VirtualFile>>()
val ktFiles = sourceRoot.children.filter { it.fileType == KotlinFileType.INSTANCE }
for (ktFile in ktFiles) {
result.addFile(ktFile)
}
return result
}
private fun ImplicitPackageData.addFile(ktFile: VirtualFile) {
synchronized(this) {
val psiFile = PsiManager.getInstance(project).findFile(ktFile) as? KtFile ?: return
addPsiFile(psiFile, ktFile)
}
}
private fun ImplicitPackageData.addPsiFile(
psiFile: KtFile,
ktFile: VirtualFile
) = getOrPut(psiFile.packageFqName) { mutableListOf() }.add(ktFile)
private fun ImplicitPackageData.removeFile(file: VirtualFile) {
synchronized(this) {
for ((key, value) in this) {
if (value.remove(file)) {
if (value.isEmpty()) remove(key)
break
}
}
}
}
private fun ImplicitPackageData.updateFile(file: KtFile) {
synchronized(this) {
removeFile(file.virtualFile)
addPsiFile(file, file.virtualFile)
}
}
internal fun update(event: VFileEvent) {
when (event) {
is VFileCreateEvent -> checkNewFileInSourceRoot(event.file)
is VFileDeleteEvent -> checkDeletedFileInSourceRoot(event.file)
is VFileCopyEvent -> {
val newParent = event.newParent
if (newParent.isValid) {
checkNewFileInSourceRoot(newParent.findChild(event.newChildName))
}
}
is VFileMoveEvent -> {
checkNewFileInSourceRoot(event.file)
if (event.oldParent.getSourceRoot(project) == event.oldParent) {
implicitPackageCache[event.oldParent]?.removeFile(event.file)
}
}
}
}
private fun checkNewFileInSourceRoot(file: VirtualFile?) {
if (file == null) return
if (file.getSourceRoot(project) == file.parent) {
implicitPackageCache[file.parent]?.addFile(file)
}
}
private fun checkDeletedFileInSourceRoot(file: VirtualFile?) {
val directory = file?.parent
if (directory == null || !directory.isValid) return
if (directory.getSourceRoot(project) == directory) {
implicitPackageCache[directory]?.removeFile(file)
}
}
internal fun update(ktFile: KtFile) {
val parent = ktFile.virtualFile?.parent ?: return
if (ktFile.sourceRoot == parent) {
implicitPackageCache[parent]?.updateFile(ktFile)
}
}
}
class PerModulePackageCacheService(private val project: Project) : Disposable {
/*
* Actually an WeakMap<Module, SoftMap<ModuleSourceInfo, SoftMap<FqName, Boolean>>>
*/
private val cache = ContainerUtil.createConcurrentWeakMap<Module, ConcurrentMap<ModuleSourceInfo, ConcurrentMap<FqName, Boolean>>>()
private val implicitPackagePrefixCache = ImplicitPackagePrefixCache(project)
private val pendingVFileChanges: MutableSet<VFileEvent> = mutableSetOf()
private val pendingKtFileChanges: MutableSet<KtFile> = mutableSetOf()
private val projectScope = GlobalSearchScope.projectScope(project)
internal fun onTooComplexChange() {
clear()
}
private fun clear() {
synchronized(this) {
pendingVFileChanges.clear()
pendingKtFileChanges.clear()
cache.clear()
implicitPackagePrefixCache.clear()
}
}
internal fun notifyPackageChange(file: VFileEvent): Unit = synchronized(this) {
pendingVFileChanges += file
}
internal fun notifyPackageChange(file: KtFile): Unit = synchronized(this) {
pendingKtFileChanges += file
}
private fun invalidateCacheForModuleSourceInfo(moduleSourceInfo: ModuleSourceInfo) {
LOG.debugIfEnabled(project) { "Invalidated cache for $moduleSourceInfo" }
val perSourceInfoData = cache[moduleSourceInfo.module] ?: return
val dataForSourceInfo = perSourceInfoData[moduleSourceInfo] ?: return
dataForSourceInfo.clear()
}
private fun checkPendingChanges() = synchronized(this) {
if (pendingVFileChanges.size + pendingKtFileChanges.size >= FULL_DROP_THRESHOLD) {
onTooComplexChange()
} else {
pendingVFileChanges.processPending { event ->
val vfile = event.file ?: return@processPending
// When VirtualFile !isValid (deleted for example), it impossible to use getModuleInfoByVirtualFile
// For directory we must check both is it in some sourceRoot, and is it contains some sourceRoot
if (vfile.isDirectory || !vfile.isValid) {
for ((module, data) in cache) {
val sourceRootUrls = module.rootManager.sourceRootUrls
if (sourceRootUrls.any { url ->
vfile.containedInOrContains(url)
}) {
LOG.debugIfEnabled(project) { "Invalidated cache for $module" }
data.clear()
}
}
} else {
val infoByVirtualFile = getModuleInfoByVirtualFile(project, vfile)
if (infoByVirtualFile == null || infoByVirtualFile !is ModuleSourceInfo) {
LOG.debugIfEnabled(project) { "Skip $vfile as it has mismatched ModuleInfo=$infoByVirtualFile" }
}
(infoByVirtualFile as? ModuleSourceInfo)?.let {
invalidateCacheForModuleSourceInfo(it)
}
}
implicitPackagePrefixCache.update(event)
}
pendingKtFileChanges.processPending { file ->
if (file.virtualFile != null && file.virtualFile !in projectScope) {
LOG.debugIfEnabled(project) {
"Skip $file without vFile, or not in scope: ${file.virtualFile?.let { it !in projectScope }}"
}
return@processPending
}
val nullableModuleInfo = file.getNullableModuleInfo()
(nullableModuleInfo as? ModuleSourceInfo)?.let { invalidateCacheForModuleSourceInfo(it) }
if (nullableModuleInfo == null || nullableModuleInfo !is ModuleSourceInfo) {
LOG.debugIfEnabled(project) { "Skip $file as it has mismatched ModuleInfo=$nullableModuleInfo" }
}
implicitPackagePrefixCache.update(file)
}
}
}
private inline fun <T> MutableCollection<T>.processPending(crossinline body: (T) -> Unit) {
this.removeIf { value ->
try {
body(value)
} catch (pce: ProcessCanceledException) {
throw pce
} catch (exc: Exception) {
// Log and proceed. Otherwise pending object processing won't be cleared and exception will be thrown forever.
LOG.error(exc)
}
return@removeIf true
}
}
private fun VirtualFile.containedInOrContains(root: String) =
(VfsUtilCore.isEqualOrAncestor(url, root)
|| isDirectory && VfsUtilCore.isEqualOrAncestor(root, url))
fun packageExists(packageFqName: FqName, moduleInfo: ModuleSourceInfo): Boolean {
val module = moduleInfo.module
checkPendingChanges()
val perSourceInfoCache = cache.getOrPut(module) {
ContainerUtil.createConcurrentSoftMap()
}
val cacheForCurrentModuleInfo = perSourceInfoCache.getOrPut(moduleInfo) {
ContainerUtil.createConcurrentSoftMap()
}
return cacheForCurrentModuleInfo.getOrPut(packageFqName) {
val packageExists = PackageIndexUtil.packageExists(packageFqName, moduleInfo.contentScope(), project)
LOG.debugIfEnabled(project) { "Computed cache value for $packageFqName in $moduleInfo is $packageExists" }
packageExists
}
}
fun getImplicitPackagePrefix(sourceRoot: VirtualFile): FqName {
checkPendingChanges()
return implicitPackagePrefixCache.getPrefix(sourceRoot)
}
override fun dispose() {
clear()
}
companion object {
const val FULL_DROP_THRESHOLD = 1000
private val LOG = Logger.getInstance(this::class.java)
fun getInstance(project: Project): PerModulePackageCacheService =
ServiceManager.getService(project, PerModulePackageCacheService::class.java)
var Project.DEBUG_LOG_ENABLE_PerModulePackageCache: Boolean
by NotNullableUserDataProperty<Project, Boolean>(Key.create("debug.PerModulePackageCache"), false)
}
}
private fun Logger.debugIfEnabled(project: Project, withCurrentTrace: Boolean = false, message: () -> String) {
if (ApplicationManager.getApplication().isUnitTestMode && project.DEBUG_LOG_ENABLE_PerModulePackageCache) {
val msg = message()
if (withCurrentTrace) {
val e = Exception().apply { fillInStackTrace() }
this.debug(msg, e)
} else {
this.debug(msg)
}
}
}

View File

@@ -1,68 +0,0 @@
/*
* Copyright 2010-2017 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.caches.lightClasses
import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.impl.compiled.ClsFileImpl
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl
import com.intellij.util.cls.ClsFormatException
import com.intellij.util.containers.ContainerUtil
import java.io.IOException
class ClsJavaStubByVirtualFileCache {
private class CachedJavaStub(val modificationStamp: Long, val javaFileStub: PsiJavaFileStubImpl)
private val cache = ContainerUtil.createConcurrentWeakKeySoftValueMap<VirtualFile, CachedJavaStub>()
fun get(classFile: VirtualFile): PsiJavaFileStubImpl? {
val cached = cache.get(classFile)
val fileModificationStamp = classFile.modificationStamp
if (cached != null && cached.modificationStamp == fileModificationStamp) {
return cached.javaFileStub
}
val stub = createStub(classFile) as PsiJavaFileStubImpl? ?: return null
cache.put(classFile, CachedJavaStub(fileModificationStamp, stub))
return stub
}
private fun createStub(file: VirtualFile): PsiJavaFileStub? {
if (file.fileType !== JavaClassFileType.INSTANCE) return null
try {
return ClsFileImpl.buildFileStub(file, file.contentsToByteArray(false))
} catch (e: ClsFormatException) {
LOG.error("Failed to build java cls class for " + file.canonicalPath!!, e)
} catch (e: IOException) {
LOG.error("Failed to build java cls class for " + file.canonicalPath!!, e)
}
return null
}
companion object {
private val LOG = Logger.getInstance(ClsJavaStubByVirtualFileCache::class.java)
fun getInstance(project: Project): ClsJavaStubByVirtualFileCache {
return ServiceManager.getService(project, ClsJavaStubByVirtualFileCache::class.java)
}
}
}

View File

@@ -1,474 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.caches.lightClasses
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
import com.intellij.psi.search.EverythingGlobalScope
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.StubIndex
import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.container.useImpl
import org.jetbrains.kotlin.container.useInstance
import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.frontend.di.configureModule
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.idea.caches.lightClasses.IDELightClassConstructionContext.Mode.EXACT
import org.jetbrains.kotlin.idea.caches.lightClasses.IDELightClassConstructionContext.Mode.LIGHT
import org.jetbrains.kotlin.idea.caches.lightClasses.annotations.KOTLINX_SERIALIZABLE_FQ_NAME
import org.jetbrains.kotlin.idea.caches.lightClasses.annotations.KOTLINX_SERIALIZER_FQ_NAME
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider
import org.jetbrains.kotlin.idea.project.IdeaEnvironment
import org.jetbrains.kotlin.idea.project.ResolveElementCache
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.stubindex.KotlinOverridableInternalMembersShortNameIndex
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.CallResolver
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
import org.jetbrains.kotlin.resolve.lazy.FileScopeProviderImpl
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.WrappedTypeFactory
import org.jetbrains.kotlin.utils.sure
class IDELightClassConstructionContext(
bindingContext: BindingContext,
module: ModuleDescriptor,
languageVersionSettings: LanguageVersionSettings,
jvmTarget: JvmTarget,
val mode: Mode
) : LightClassConstructionContext(bindingContext, module, languageVersionSettings, jvmTarget) {
enum class Mode {
LIGHT,
EXACT
}
override fun toString() = "${this.javaClass.simpleName}:$mode"
}
internal object IDELightClassContexts {
private val LOG = Logger.getInstance(this::class.java)
fun contextForNonLocalClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
val resolutionFacade = classOrObject.getResolutionFacade()
val bindingContext = if (classOrObject is KtClass && classOrObject.isAnnotation()) {
// need to make sure default values for parameters are resolved
// because java resolve depends on whether there is a default value for an annotation attribute
@OptIn(FrontendInternals::class)
resolutionFacade.getFrontendService(ResolveElementCache::class.java)
.resolvePrimaryConstructorParametersDefaultValues(classOrObject)
} else {
resolutionFacade.analyze(classOrObject)
}
val classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject).sure {
"Class descriptor was not found for ${classOrObject.getElementTextWithContext()}"
}
ForceResolveUtil.forceResolveAllContents(classDescriptor)
return IDELightClassConstructionContext(
bindingContext,
resolutionFacade.moduleDescriptor,
classOrObject.languageVersionSettings,
resolutionFacade.jvmTarget,
EXACT
)
}
fun contextForLocalClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
val resolutionFacade = classOrObject.getResolutionFacade()
val bindingContext = resolutionFacade.analyze(classOrObject)
val descriptor = bindingContext.get(BindingContext.CLASS, classOrObject)
if (descriptor == null) {
LOG.warn("No class descriptor in context for class: " + classOrObject.getElementTextWithContext())
return IDELightClassConstructionContext(
bindingContext,
resolutionFacade.moduleDescriptor,
classOrObject.languageVersionSettings,
resolutionFacade.jvmTarget,
EXACT
)
}
ForceResolveUtil.forceResolveAllContents(descriptor)
return IDELightClassConstructionContext(
bindingContext,
resolutionFacade.moduleDescriptor,
classOrObject.languageVersionSettings,
resolutionFacade.jvmTarget,
EXACT
)
}
fun contextForFacade(files: List<KtFile>): LightClassConstructionContext {
val resolutionFacade = files.first().getResolutionFacade()
@OptIn(FrontendInternals::class)
val resolveSession = resolutionFacade.getFrontendService(ResolveSession::class.java)
forceResolvePackageDeclarations(files, resolveSession)
return IDELightClassConstructionContext(
resolveSession.bindingContext,
resolveSession.moduleDescriptor,
files.first().languageVersionSettings,
resolutionFacade.jvmTarget,
EXACT
)
}
fun contextForScript(script: KtScript): LightClassConstructionContext {
val resolutionFacade = script.getResolutionFacade()
val bindingContext = resolutionFacade.analyze(script)
val descriptor = bindingContext[BindingContext.SCRIPT, script]
if (descriptor == null) {
LOG.warn("No script descriptor in context for script: " + script.getElementTextWithContext())
return IDELightClassConstructionContext(
bindingContext,
resolutionFacade.moduleDescriptor,
script.languageVersionSettings,
resolutionFacade.jvmTarget,
EXACT
)
}
ForceResolveUtil.forceResolveAllContents(descriptor)
return IDELightClassConstructionContext(
bindingContext, resolutionFacade.moduleDescriptor, script.languageVersionSettings, resolutionFacade.jvmTarget,
EXACT
)
}
fun lightContextForClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext? {
if (!isDummyResolveApplicable(classOrObject)) return null
val resolutionFacade = classOrObject.getResolutionFacade()
val resolveSession = setupAdHocResolve(
classOrObject.project,
resolutionFacade.moduleDescriptor,
listOf(classOrObject.containingKtFile)
)
val descriptor = resolveSession.resolveToDescriptor(classOrObject) as? ClassDescriptor ?: return null
if (!isDummyResolveApplicableByDescriptor(descriptor)) return null
ForceResolveUtil.forceResolveAllContents(descriptor)
return IDELightClassConstructionContext(
resolveSession.bindingContext,
resolveSession.moduleDescriptor,
classOrObject.languageVersionSettings,
resolutionFacade.jvmTarget,
LIGHT
)
}
fun lightContextForFacade(files: List<KtFile>): LightClassConstructionContext {
val representativeFile = files.first()
val resolutionFacade = representativeFile.getResolutionFacade()
val resolveSession = setupAdHocResolve(representativeFile.project, resolutionFacade.moduleDescriptor, files)
forceResolvePackageDeclarations(files, resolveSession)
return IDELightClassConstructionContext(
resolveSession.bindingContext,
resolveSession.moduleDescriptor,
files.first().languageVersionSettings,
resolutionFacade.jvmTarget,
LIGHT
)
}
@OptIn(FrontendInternals::class)
private val ResolutionFacade.jvmTarget: JvmTarget
get() = getFrontendService(JvmTarget::class.java)
private fun isDummyResolveApplicable(classOrObject: KtClassOrObject): Boolean {
if (classOrObject.hasModifier(KtTokens.INLINE_KEYWORD)) return false
if (classOrObject.hasLightClassMatchingErrors) return false
if (hasDelegatedSupertypes(classOrObject)) return false
if (isDataClassWithGeneratedMembersOverridden(classOrObject)) return false
if (isDataClassWhichExtendsOtherClass(classOrObject)) return false
if (hasMembersOverridingInternalMembers(classOrObject)) return false
if (hasSerializationLikeAnnotations(classOrObject)) return false
if (hasJvmSyntheticMembers(classOrObject)) return false
return classOrObject.declarations.filterIsInstance<KtClassOrObject>().all { isDummyResolveApplicable(it) }
}
private fun hasSerializationLikeAnnotations(classOrObject: KtClassOrObject) =
classOrObject.annotationEntries.any { isSerializableOrSerializerShortName(it.shortName) }
private fun isDummyResolveApplicableByDescriptor(classDescriptor: ClassDescriptor): Boolean {
if (classDescriptor.annotations.any { isSerializableOrSerializerFqName(it.fqName) }) return false
return classDescriptor
.unsubstitutedInnerClassesScope
.getContributedDescriptors()
.filterIsInstance<ClassDescriptor>()
.all(::isDummyResolveApplicableByDescriptor)
}
private fun isSerializableOrSerializerShortName(shortName: Name?) =
shortName == KOTLINX_SERIALIZABLE_FQ_NAME.shortName() || shortName == KOTLINX_SERIALIZER_FQ_NAME.shortName()
private fun isSerializableOrSerializerFqName(fqName: FqName?) =
fqName == KOTLINX_SERIALIZABLE_FQ_NAME || fqName == KOTLINX_SERIALIZER_FQ_NAME
private fun hasJvmSyntheticMembers(classOrObject: KtClassOrObject) =
classOrObject.declarations.filterIsInstance<KtFunction>().any { isJvmSynthetic(it) }
private fun isJvmSynthetic(fn: KtFunction) =
fn.annotationEntries.any { it.shortName == JVM_SYNTHETIC_ANNOTATION_FQ_NAME.shortName() }
private fun hasDelegatedSupertypes(classOrObject: KtClassOrObject) =
classOrObject.superTypeListEntries.any { it is KtDelegatedSuperTypeEntry }
private fun isDataClassWithGeneratedMembersOverridden(classOrObject: KtClassOrObject): Boolean {
return classOrObject.hasModifier(KtTokens.DATA_KEYWORD) &&
classOrObject.declarations.filterIsInstance<KtFunction>().any {
isGeneratedForDataClass(it.nameAsSafeName)
}
}
private fun isGeneratedForDataClass(name: Name): Boolean {
return name == FunctionsFromAny.EQUALS_METHOD_NAME ||
// known failure is related to equals override, checking for other methods 'just in case'
name == DataClassDescriptorResolver.COPY_METHOD_NAME ||
name == FunctionsFromAny.HASH_CODE_METHOD_NAME ||
name == FunctionsFromAny.TO_STRING_METHOD_NAME ||
DataClassDescriptorResolver.isComponentLike(name)
}
private fun isDataClassWhichExtendsOtherClass(classOrObject: KtClassOrObject): Boolean {
return classOrObject.hasModifier(KtTokens.DATA_KEYWORD) &&
classOrObject.superTypeListEntries.isNotEmpty()
}
private fun hasMembersOverridingInternalMembers(classOrObject: KtClassOrObject): Boolean {
return classOrObject.declarations.filterIsInstance<KtCallableDeclaration>().any {
possiblyOverridesInternalMember(it)
}
}
private fun possiblyOverridesInternalMember(declaration: KtCallableDeclaration): Boolean {
if (!declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return false
return declaration.name?.let { anyInternalMembersWithThisName(it, declaration.project) } ?: false
}
private fun anyInternalMembersWithThisName(name: String, project: Project): Boolean {
var result = false
StubIndex.getInstance().processElements(
KotlinOverridableInternalMembersShortNameIndex.Instance.key, name, project,
EverythingGlobalScope(project), KtCallableDeclaration::class.java
) {
result = true
false // stop processing at first matching result
}
return result
}
fun forceResolvePackageDeclarations(files: Collection<KtFile>, session: ResolveSession) {
for (file in files) {
if (file.isScript()) continue
val packageFqName = file.packageFqName
// make sure we create a package descriptor
val packageDescriptor = session.moduleDescriptor.getPackage(packageFqName)
if (packageDescriptor.isEmpty()) {
LOG.warn("No descriptor found for package " + packageFqName + " in file " + file.name + "\n" + file.text)
session.forceResolveAll()
continue
}
for (declaration in file.declarations) {
when (declaration) {
is KtFunction -> {
val name = declaration.nameAsSafeName
val functions = packageDescriptor.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_IDE)
for (descriptor in functions) {
ForceResolveUtil.forceResolveAllContents(descriptor)
}
}
is KtProperty -> {
val name = declaration.nameAsSafeName
val properties = packageDescriptor.memberScope.getContributedVariables(name, NoLookupLocation.FROM_IDE)
for (descriptor in properties) {
ForceResolveUtil.forceResolveAllContents(descriptor)
}
}
is KtClassOrObject, is KtTypeAlias, is KtDestructuringDeclaration -> {
// Do nothing: we are not interested in classes or type aliases,
// and all destructuring declarations are erroneous at top level
}
else -> LOG.error("Unsupported declaration kind: " + declaration + " in file " + file.name + "\n" + file.text)
}
}
ForceResolveUtil.forceResolveAllContents(session.getFileAnnotations(file))
}
}
private fun setupAdHocResolve(project: Project, realWorldModule: ModuleDescriptor, files: List<KtFile>): ResolveSession {
val trace = BindingTraceContext()
val sm = LockBasedStorageManager.NO_LOCKS
val moduleDescriptor =
ModuleDescriptorImpl(realWorldModule.name, sm, realWorldModule.builtIns, stableName = realWorldModule.stableName)
moduleDescriptor.setDependencies(moduleDescriptor, moduleDescriptor.builtIns.builtInsModule)
val moduleInfo = files.first().getModuleInfo()
val container = createContainer("LightClassStub", JvmPlatformAnalyzerServices) {
val jvmTarget = IDELanguageSettingsProvider.getTargetPlatform(moduleInfo, project) as? JvmTarget ?: JvmTarget.DEFAULT
configureModule(
ModuleContext(moduleDescriptor, project, "ad hoc resolve"), JvmPlatforms.jvmPlatformByTargetVersion(jvmTarget),
JvmPlatformAnalyzerServices, trace,
IDELanguageSettingsProvider.getLanguageVersionSettings(moduleInfo, project)
)
useInstance(GlobalSearchScope.EMPTY_SCOPE)
useInstance(LookupTracker.DO_NOTHING)
useInstance(ExpectActualTracker.DoNothing)
useImpl<FileScopeProviderImpl>()
useInstance(FileBasedDeclarationProviderFactory(sm, files))
useInstance(CodegenAffectingAnnotations(realWorldModule))
useImpl<AdHocAnnotationResolver>()
useInstance(object : WrappedTypeFactory(sm) {
override fun createDeferredType(trace: BindingTrace, computation: () -> KotlinType) = errorType()
override fun createRecursionIntolerantDeferredType(trace: BindingTrace, computation: () -> KotlinType) = errorType()
private fun errorType() = ErrorUtils.createErrorType("Error type in ad hoc resolve for lighter classes")
})
IdeaEnvironment.configure(this)
useImpl<ResolveSession>()
}
val resolveSession = container.get<ResolveSession>()
moduleDescriptor.initialize(
CompositePackageFragmentProvider(
listOf(resolveSession.packageFragmentProvider),
"CompositeProvider@IDELightClassContexts for $moduleDescriptor"
)
)
return resolveSession
}
class CodegenAffectingAnnotations(private val realModule: ModuleDescriptor) {
fun get(name: String): ClassDescriptor? {
val annotationFqName = annotationsThatAffectCodegen.firstOrNull { it.shortName().asString() == name } ?: return null
return realModule.getPackage(annotationFqName.parent()).memberScope
.getContributedClassifier(annotationFqName.shortName(), NoLookupLocation.FROM_IDE) as? ClassDescriptor
}
// see JvmPlatformAnnotations.kt, JvmFlagAnnotations.kt, also PsiModifier.MODIFIERS
private val annotationsThatAffectCodegen = listOf(
"JvmField", "JvmOverloads", "JvmName", "JvmStatic",
"Synchronized", "Transient", "Volatile", "Strictfp"
).map { FqName("kotlin.jvm").child(Name.identifier(it)) } +
FqName("kotlin.PublishedApi") +
FqName("kotlin.Deprecated") +
FqName("kotlin.internal.InlineOnly") +
FqName("kotlinx.android.parcel.Parcelize") +
KOTLINX_SERIALIZABLE_FQ_NAME +
KOTLINX_SERIALIZER_FQ_NAME
}
class AdHocAnnotationResolver(
private val codegenAffectingAnnotations: CodegenAffectingAnnotations,
private val callResolver: CallResolver,
private val languageVersionSettings: LanguageVersionSettings,
private val dataFlowValueFactory: DataFlowValueFactory, constantExpressionEvaluator: ConstantExpressionEvaluator,
storageManager: StorageManager
) : AnnotationResolverImpl(callResolver, constantExpressionEvaluator, storageManager) {
override fun resolveAnnotationType(scope: LexicalScope, entryElement: KtAnnotationEntry, trace: BindingTrace): KotlinType {
return annotationClassByEntry(entryElement)?.defaultType ?: super.resolveAnnotationType(scope, entryElement, trace)
}
private fun annotationClassByEntry(entryElement: KtAnnotationEntry): ClassDescriptor? {
val annotationTypeReferencePsi = entryElement.calleeExpression?.constructorReferenceExpression ?: return null
val referencedName = annotationTypeReferencePsi.getReferencedName()
return codegenAffectingAnnotations.get(referencedName)
}
override fun resolveAnnotationCall(
annotationEntry: KtAnnotationEntry,
scope: LexicalScope,
trace: BindingTrace
): OverloadResolutionResults<FunctionDescriptor> {
val annotationConstructor = annotationClassByEntry(annotationEntry)?.constructors?.singleOrNull()
?: return super.resolveAnnotationCall(annotationEntry, scope, trace)
@Suppress("UNCHECKED_CAST")
return callResolver.resolveConstructorCall(
BasicCallResolutionContext.create(
trace, scope, CallMaker.makeCall(null, null, annotationEntry), TypeUtils.NO_EXPECTED_TYPE,
DataFlowInfoFactory.EMPTY, ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
true, languageVersionSettings,
dataFlowValueFactory
),
annotationEntry.calleeExpression!!.constructorReferenceExpression!!,
annotationConstructor.returnType
) as OverloadResolutionResults<FunctionDescriptor>
}
}
}

Some files were not shown because too many files have changed in this diff Show More