LAB-29: split general features provider into 2 separate providers

GitOrigin-RevId: 618f4d8df9c338a7540fc538186f3a9597fed659
This commit is contained in:
Svetlana.Zemlyanskaya
2020-09-03 11:24:58 +00:00
committed by intellij-monorepo-bot
parent 3af3578c41
commit 6a5aae7b94
5 changed files with 152 additions and 110 deletions
@@ -33,6 +33,7 @@
<filePrediction.candidateProvider implementation="com.intellij.filePrediction.candidates.FilePredictionRecentSessionsProvider"/>
<filePrediction.featureProvider implementation="com.intellij.filePrediction.features.FilePredictionGeneralFeatures"/>
<filePrediction.featureProvider implementation="com.intellij.filePrediction.features.FilePredictionSimilarityFeatures"/>
<filePrediction.featureProvider implementation="com.intellij.filePrediction.features.history.FilePredictionHistoryFeatures"/>
<filePrediction.featureProvider implementation="com.intellij.filePrediction.features.history.context.FilePredictionContextFeatures"/>
@@ -3,39 +3,18 @@ package com.intellij.filePrediction.features
import com.intellij.filePrediction.features.FilePredictionFeature.Companion.binary
import com.intellij.filePrediction.features.FilePredictionFeature.Companion.fileType
import com.intellij.filePrediction.features.FilePredictionFeature.Companion.numerical
import com.intellij.filePrediction.references.ExternalReferencesResult
import com.intellij.internal.statistic.collectors.fus.fileTypes.FileTypeUsagesCollector
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
import com.intellij.openapi.roots.FileIndexFacade
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.util.text.StringUtil.toLowerCase
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.testFramework.LightVirtualFile
import com.intellij.util.PathUtil
import com.intellij.util.ThreeState
import java.io.File
class FilePredictionGeneralFeatures: FilePredictionFeatureProvider {
class FilePredictionGeneralFeatures : FilePredictionFeatureProvider {
companion object {
private val FEATURES = arrayListOf(
"excluded",
"file_type",
"in_library",
"in_project",
"in_ref",
"in_source",
"light",
"name_prefix",
"path_prefix",
"prev_file_type",
"relative_path_prefix",
"same_dir",
"same_module"
"prev_file_type"
)
}
@@ -53,57 +32,10 @@ class FilePredictionGeneralFeatures: FilePredictionFeatureProvider {
result["in_ref"] = binary(isInRef == ThreeState.YES)
}
addFileTypeFeatures(result, newFile, prevFile)
ApplicationManager.getApplication().runReadAction {
if (newFile.isValid) {
val fileIndex = FileIndexFacade.getInstance(project)
result["in_project"] = binary(fileIndex.isInProjectScope(newFile))
result["in_source"] = binary(fileIndex.isInSource(newFile))
result["in_library"] = binary(fileIndex.isInLibraryClasses(newFile) || fileIndex.isInLibrarySource(newFile))
result["excluded"] = binary(fileIndex.isExcludedFile(newFile))
if (prevFile != null && prevFile.isValid) {
val newModule = fileIndex.getModuleForFile(newFile)
result["same_module"] = binary(newModule != null && newModule == fileIndex.getModuleForFile(prevFile))
}
result["light"] = binary(newFile is LightVirtualFile)
}
}
if (prevFile != null) {
val newFileName = unify(newFile.name)
val newFilePath = unify(newFile.path)
val prevFileName = unify(prevFile.name)
result["name_prefix"] = numerical(StringUtil.commonPrefixLength(newFileName, prevFileName))
val prevFilePath = unify(prevFile.path)
result["path_prefix"] = numerical(StringUtil.commonPrefixLength(newFilePath, prevFilePath))
if (!project.isDisposed) {
val baseDir = project.guessProjectDir()?.path?.let { unify(it) }
if (baseDir != null) {
val newRelativePath = FileUtil.getRelativePath(baseDir, newFilePath, File.separatorChar, false)
val prevRelativePath = FileUtil.getRelativePath(baseDir, prevFilePath, File.separatorChar, false)
if (newRelativePath != null && prevRelativePath != null) {
result["relative_path_prefix"] = numerical(StringUtil.commonPrefixLength(newRelativePath, prevRelativePath))
}
}
}
result["same_dir"] = binary(PathUtil.getParentPath(newFilePath) == PathUtil.getParentPath(prevFilePath))
}
return result
}
private fun addFileTypeFeatures(result: MutableMap<String, FilePredictionFeature>, newFile: VirtualFile, prevFile: VirtualFile?) {
result["file_type"] = fileType(FileTypeUsagesCollector.getSafeFileTypeName(newFile.fileType))
if (prevFile != null) {
result["prev_file_type"] = fileType(FileTypeUsagesCollector.getSafeFileTypeName(prevFile.fileType))
}
}
private fun unify(path: String) : String {
val caseSensitive = SystemInfo.isFileSystemCaseSensitive
return if (caseSensitive) FileUtil.getNameWithoutExtension(path) else FileUtil.getNameWithoutExtension(toLowerCase(path))
return result
}
}
@@ -0,0 +1,89 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.filePrediction.features
import com.intellij.filePrediction.features.FilePredictionFeature.Companion.binary
import com.intellij.filePrediction.features.FilePredictionFeature.Companion.numerical
import com.intellij.filePrediction.references.ExternalReferencesResult
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
import com.intellij.openapi.roots.FileIndexFacade
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.util.text.StringUtil.toLowerCase
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.testFramework.LightVirtualFile
import com.intellij.util.PathUtil
import java.io.File
class FilePredictionSimilarityFeatures : FilePredictionFeatureProvider {
companion object {
private val FEATURES = arrayListOf(
"excluded",
"in_library",
"in_project",
"in_source",
"light",
"name_prefix",
"path_prefix",
"relative_path_prefix",
"same_dir",
"same_module"
)
}
override fun getName(): String = "similarity"
override fun getFeatures(): List<String> = FEATURES
override fun calculateFileFeatures(project: Project,
newFile: VirtualFile,
prevFile: VirtualFile?,
refs: ExternalReferencesResult): Map<String, FilePredictionFeature> {
val result = HashMap<String, FilePredictionFeature>()
ApplicationManager.getApplication().runReadAction {
if (newFile.isValid) {
val fileIndex = FileIndexFacade.getInstance(project)
result["in_project"] = binary(fileIndex.isInProjectScope(newFile))
result["in_source"] = binary(fileIndex.isInSource(newFile))
result["in_library"] = binary(fileIndex.isInLibraryClasses(newFile) || fileIndex.isInLibrarySource(newFile))
result["excluded"] = binary(fileIndex.isExcludedFile(newFile))
if (prevFile != null && prevFile.isValid) {
val newModule = fileIndex.getModuleForFile(newFile)
result["same_module"] = binary(newModule != null && newModule == fileIndex.getModuleForFile(prevFile))
}
result["light"] = binary(newFile is LightVirtualFile)
}
}
if (prevFile != null) {
val newFileName = unify(newFile.name)
val newFilePath = unify(newFile.path)
val prevFileName = unify(prevFile.name)
result["name_prefix"] = numerical(StringUtil.commonPrefixLength(newFileName, prevFileName))
val prevFilePath = unify(prevFile.path)
result["path_prefix"] = numerical(StringUtil.commonPrefixLength(newFilePath, prevFilePath))
if (!project.isDisposed) {
val baseDir = project.guessProjectDir()?.path?.let { unify(it) }
if (baseDir != null) {
val newRelativePath = FileUtil.getRelativePath(baseDir, newFilePath, File.separatorChar, false)
val prevRelativePath = FileUtil.getRelativePath(baseDir, prevFilePath, File.separatorChar, false)
if (newRelativePath != null && prevRelativePath != null) {
result["relative_path_prefix"] = numerical(StringUtil.commonPrefixLength(newRelativePath, prevRelativePath))
}
}
}
result["same_dir"] = binary(PathUtil.getParentPath(newFilePath) == PathUtil.getParentPath(prevFilePath))
}
return result
}
private fun unify(path: String): String {
val caseSensitive = SystemInfo.isFileSystemCaseSensitive
return if (caseSensitive) FileUtil.getNameWithoutExtension(path) else FileUtil.getNameWithoutExtension(toLowerCase(path))
}
}
@@ -18,31 +18,52 @@ import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.java.JpsJavaExtensionService
import java.io.File
class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtureBuilder<ModuleFixture>>() {
private fun doTestGeneralFeatures(prevPath: String, newPath: String, featuresProvider: FileFeaturesProducer) {
class FilePredictionCommonFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtureBuilder<ModuleFixture>>() {
private fun doTestSimilarityFeatures(prevPath: String,
newPath: String,
expected: FileFeaturesProducer) {
doTestFeatures(
prevPath, newPath,
listOf(FilePredictionSimilarityFeatures()),
expected
)
}
private fun doTestFeatures(prevPath: String, newPath: String,
providers: List<FilePredictionFeatureProvider>,
expectedFeaturesProvider: FileFeaturesProducer) {
val prevFile = myFixture.addFileToProject(prevPath, "PREVIOUS FILE")
val nextFile = myFixture.addFileToProject(newPath, "NEXT FILE")
val provider = FilePredictionGeneralFeatures()
val actual = provider.calculateFileFeatures(
myFixture.project, nextFile.virtualFile, prevFile.virtualFile, FAILED_COMPUTATION
)
val expected = featuresProvider.produce(myFixture.project)
val actual: MutableMap<String, FilePredictionFeature> = hashMapOf()
for (provider in providers) {
val features = provider.calculateFileFeatures(
myFixture.project, nextFile.virtualFile, prevFile.virtualFile, FAILED_COMPUTATION
)
actual.putAll(features)
}
val expected = expectedFeaturesProvider.produce(myFixture.project)
for (feature in expected.entries) {
assertTrue("Cannot find feature '${feature.key}' in $actual", actual.containsKey(feature.key))
assertEquals("The value of feature '${feature.key}' is different from expected", feature.value, actual[feature.key])
}
}
private fun doTestGeneralFeatures(newPath: String, configurator: ProjectConfigurator, featuresProvider: FileFeaturesProducer) {
private fun doTestSimilarityFeatures(newPath: String, configurator: ProjectConfigurator, featuresProvider: FileFeaturesProducer) {
doTestFeatures(FilePredictionSimilarityFeatures(), newPath, configurator, featuresProvider)
}
private fun doTestFeatures(provider: FilePredictionFeatureProvider,
newPath: String, configurator: ProjectConfigurator,
expectedFeaturesProvider: FileFeaturesProducer) {
val nextFile = myFixture.addFileToProject(newPath, "NEXT FILE")
configurator.configure(myFixture.project, myModule)
val provider = FilePredictionGeneralFeatures()
val actual = provider.calculateFileFeatures(
myFixture.project, nextFile.virtualFile, null, FAILED_COMPUTATION
)
val expected = featuresProvider.produce(myFixture.project)
val expected = expectedFeaturesProvider.produce(myFixture.project)
for (feature in expected.entries) {
assertTrue("Cannot find feature '${feature.key}' in $actual", actual.containsKey(feature.key))
assertEquals("The value of feature '${feature.key}' is different from expected", feature.value, actual[feature.key])
@@ -50,7 +71,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test file name prefix for completely different files`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"prevFile.txt", "nextFile.txt",
ConstFileFeaturesProducer(
"name_prefix" to FilePredictionFeature.numerical(0)
@@ -59,7 +80,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test file name prefix for files with common prefix`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"myPrevFile.txt", "myNextFile.txt",
ConstFileFeaturesProducer(
"name_prefix" to FilePredictionFeature.numerical(2)
@@ -68,7 +89,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test file name prefix for equal files`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"file.txt", "src/file.txt",
ConstFileFeaturesProducer(
"name_prefix" to FilePredictionFeature.numerical(4)
@@ -77,7 +98,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test file name of different length`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"someFile.txt", "src/file.txt",
ConstFileFeaturesProducer(
"name_prefix" to FilePredictionFeature.numerical(0)
@@ -86,7 +107,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test file name in child directory`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"src/someFile.txt", "src/file.txt",
ConstFileFeaturesProducer(
"name_prefix" to FilePredictionFeature.numerical(0)
@@ -95,7 +116,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test file name in neighbour directories`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"src/com/site/ui/someFile.txt", "src/com/site/component/file.txt",
ConstFileFeaturesProducer(
"name_prefix" to FilePredictionFeature.numerical(0)
@@ -104,7 +125,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test files path in project root`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"prevFile.txt", "nextFile.txt",
FileFeaturesByProjectPathProducer(
"path_prefix" to FilePredictionFeature.numerical(0)
@@ -113,7 +134,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test files path in the same directory`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"src/prevFile.txt", "src/nextFile.txt",
FileFeaturesByProjectPathProducer(
"path_prefix" to FilePredictionFeature.numerical(4)
@@ -122,7 +143,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test files path in the neighbour directories`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"src/ui/prevFile.txt", "src/components/nextFile.txt",
FileFeaturesByProjectPathProducer(
"path_prefix" to FilePredictionFeature.numerical(4)
@@ -131,7 +152,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test files path of different length`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"firstFile.txt", "another/nextFile.txt",
FileFeaturesByProjectPathProducer(
"path_prefix" to FilePredictionFeature.numerical(0)
@@ -140,7 +161,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test files in the root directory`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"prevFile.txt", "nextFile.txt",
ConstFileFeaturesProducer(
"same_dir" to FilePredictionFeature.binary(true),
@@ -150,7 +171,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test files in same child directory`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"src/prevFile.txt", "src/nextFile.txt",
ConstFileFeaturesProducer(
"same_dir" to FilePredictionFeature.binary(true),
@@ -160,7 +181,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test files in different directories`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"src/prevFile.txt", "test/nextFile.txt",
ConstFileFeaturesProducer(
"same_dir" to FilePredictionFeature.binary(false),
@@ -170,7 +191,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test file not in a source root`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"file.txt",
object : ProjectConfigurator {
override fun configure(project: Project, module: Module) {
@@ -187,7 +208,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test file in source root`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"nextFile.txt",
EmptyProjectConfigurator,
ConstFileFeaturesProducer(
@@ -200,7 +221,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test file not in a custom source root`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"nextFile.txt",
object : ProjectConfigurator {
override fun configure(project: Project, module: Module) {
@@ -218,7 +239,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test file in a custom source root`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"src/nextFile.txt",
object : ProjectConfigurator {
override fun configure(project: Project, module: Module) {
@@ -236,7 +257,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test file in a library source root`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"lib/nextFile.txt",
object : ProjectConfigurator {
override fun configure(project: Project, module: Module) {
@@ -254,7 +275,7 @@ class FilePredictionGeneralFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtu
}
fun `test file in library classes`() {
doTestGeneralFeatures(
doTestSimilarityFeatures(
"lib/nextFile.txt",
object : ProjectConfigurator {
override fun configure(project: Project, module: Module) {
@@ -8,7 +8,6 @@ import com.intellij.testFramework.builders.ModuleFixtureBuilder
import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase
import com.intellij.testFramework.fixtures.ModuleFixture
import junit.framework.TestCase
import org.junit.Test
/**
* Smoke tests for a composite features provider, for provider specific checks use dedicated test class
@@ -81,15 +80,15 @@ class FilePredictionFeaturesTest : CodeInsightFixtureTestCase<ModuleFixtureBuild
doTestFeatures(
"core_file_type",
"core_prev_file_type",
"core_in_source",
"core_in_project",
"core_in_library",
"core_excluded",
"core_same_dir",
"core_same_module",
"core_name_prefix",
"core_path_prefix",
"core_relative_path_prefix",
"similarity_in_source",
"similarity_in_project",
"similarity_in_library",
"similarity_excluded",
"similarity_same_dir",
"similarity_same_module",
"similarity_name_prefix",
"similarity_path_prefix",
"similarity_relative_path_prefix",
"history_size",
"history_uni_mle",
"history_bi_mle"