Skip to content

Commit 14afe91

Browse files
committed
Merge branch 'master' into ktlint-migration
2 parents f5b1e93 + 2a519b2 commit 14afe91

File tree

173 files changed

+352
-37242
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

173 files changed

+352
-37242
lines changed

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/annotations/Plugin.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,18 @@ public annotation class Import
2828
@Target(AnnotationTarget.PROPERTY)
2929
public annotation class Order(val order: Int)
3030

31+
/**
32+
* For internal use
33+
* Compiler plugin materializes schemas as classes.
34+
* These classes have two kinds of properties:
35+
* 1. Scope properties that only serve as a reference for internal property resolution
36+
* 2. Schema properties that reflect dataframe structure
37+
* Scope properties need
38+
* to be excluded in IDE plugin and in [org.jetbrains.kotlinx.dataframe.codeGen.MarkersExtractor.get]
39+
* This annotation serves to distinguish between the two where needed
40+
*/
41+
@Target(AnnotationTarget.PROPERTY)
42+
public annotation class ScopeProperty
43+
3144
@Target(AnnotationTarget.FUNCTION)
3245
internal annotation class Check

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/codeGen/MarkersExtractor.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import org.jetbrains.kotlinx.dataframe.DataFrame
44
import org.jetbrains.kotlinx.dataframe.DataRow
55
import org.jetbrains.kotlinx.dataframe.annotations.ColumnName
66
import org.jetbrains.kotlinx.dataframe.annotations.DataSchema
7+
import org.jetbrains.kotlinx.dataframe.annotations.ScopeProperty
78
import org.jetbrains.kotlinx.dataframe.impl.schema.getPropertyOrderFromPrimaryConstructor
89
import org.jetbrains.kotlinx.dataframe.schema.ColumnSchema
910
import kotlin.reflect.KClass
@@ -56,7 +57,8 @@ internal object MarkersExtractor {
5657

5758
private fun getFields(markerClass: KClass<*>, nullableProperties: Boolean): List<GeneratedField> {
5859
val order = getPropertyOrderFromPrimaryConstructor(markerClass) ?: emptyMap()
59-
return markerClass.memberProperties.sortedBy { order[it.name] ?: Int.MAX_VALUE }.mapIndexed { _, it ->
60+
val structuralProperties = markerClass.memberProperties.filter { !it.hasAnnotation<ScopeProperty>() }
61+
return structuralProperties.sortedBy { order[it.name] ?: Int.MAX_VALUE }.mapIndexed { _, it ->
6062
val fieldName = ValidFieldName.of(it.name)
6163
val columnName = it.findAnnotation<ColumnName>()?.name ?: fieldName.unquoted
6264
val type = it.returnType

core/generated-sources/src/test/kotlin/org/jetbrains/kotlinx/dataframe/testSets/person/DataColumnTests.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package org.jetbrains.kotlinx.dataframe.testSets.person
22

33
import io.kotest.matchers.shouldBe
4+
import org.jetbrains.kotlinx.dataframe.api.columnOf
5+
import org.jetbrains.kotlinx.dataframe.api.count
46
import org.jetbrains.kotlinx.dataframe.api.sort
57
import org.jetbrains.kotlinx.dataframe.api.sortBy
68
import org.jetbrains.kotlinx.dataframe.api.sortByDesc
79
import org.jetbrains.kotlinx.dataframe.api.sortDesc
10+
import org.jetbrains.kotlinx.dataframe.api.valueCounts
811
import org.junit.Test
912

1013
class DataColumnTests : BaseTest() {
@@ -14,4 +17,12 @@ class DataColumnTests : BaseTest() {
1417
typed.age.sort() shouldBe typed.sortBy { age }.age
1518
typed.age.sortDesc() shouldBe typed.sortByDesc { age }.age
1619
}
20+
21+
@Test
22+
fun `value counts`() {
23+
val languages by columnOf("Kotlin", "Kotlin", null, null, "C++")
24+
val languageCounts = languages.valueCounts()
25+
languageCounts[languages].values() shouldBe listOf("Kotlin", "C++")
26+
languageCounts.count.values() shouldBe listOf(2, 1)
27+
}
1728
}

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/annotations/Plugin.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,18 @@ public annotation class Import
2828
@Target(AnnotationTarget.PROPERTY)
2929
public annotation class Order(val order: Int)
3030

31+
/**
32+
* For internal use
33+
* Compiler plugin materializes schemas as classes.
34+
* These classes have two kinds of properties:
35+
* 1. Scope properties that only serve as a reference for internal property resolution
36+
* 2. Schema properties that reflect dataframe structure
37+
* Scope properties need
38+
* to be excluded in IDE plugin and in [org.jetbrains.kotlinx.dataframe.codeGen.MarkersExtractor.get]
39+
* This annotation serves to distinguish between the two where needed
40+
*/
41+
@Target(AnnotationTarget.PROPERTY)
42+
public annotation class ScopeProperty
43+
3144
@Target(AnnotationTarget.FUNCTION)
3245
internal annotation class Check

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/codeGen/MarkersExtractor.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import org.jetbrains.kotlinx.dataframe.DataFrame
44
import org.jetbrains.kotlinx.dataframe.DataRow
55
import org.jetbrains.kotlinx.dataframe.annotations.ColumnName
66
import org.jetbrains.kotlinx.dataframe.annotations.DataSchema
7+
import org.jetbrains.kotlinx.dataframe.annotations.ScopeProperty
78
import org.jetbrains.kotlinx.dataframe.impl.schema.getPropertyOrderFromPrimaryConstructor
89
import org.jetbrains.kotlinx.dataframe.schema.ColumnSchema
910
import kotlin.reflect.KClass
@@ -56,7 +57,8 @@ internal object MarkersExtractor {
5657

5758
private fun getFields(markerClass: KClass<*>, nullableProperties: Boolean): List<GeneratedField> {
5859
val order = getPropertyOrderFromPrimaryConstructor(markerClass) ?: emptyMap()
59-
return markerClass.memberProperties.sortedBy { order[it.name] ?: Int.MAX_VALUE }.mapIndexed { _, it ->
60+
val structuralProperties = markerClass.memberProperties.filter { !it.hasAnnotation<ScopeProperty>() }
61+
return structuralProperties.sortedBy { order[it.name] ?: Int.MAX_VALUE }.mapIndexed { _, it ->
6062
val fieldName = ValidFieldName.of(it.name)
6163
val columnName = it.findAnnotation<ColumnName>()?.name ?: fieldName.unquoted
6264
val type = it.returnType

core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/testSets/person/DataColumnTests.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package org.jetbrains.kotlinx.dataframe.testSets.person
22

33
import io.kotest.matchers.shouldBe
4+
import org.jetbrains.kotlinx.dataframe.api.columnOf
5+
import org.jetbrains.kotlinx.dataframe.api.count
46
import org.jetbrains.kotlinx.dataframe.api.sort
57
import org.jetbrains.kotlinx.dataframe.api.sortBy
68
import org.jetbrains.kotlinx.dataframe.api.sortByDesc
79
import org.jetbrains.kotlinx.dataframe.api.sortDesc
10+
import org.jetbrains.kotlinx.dataframe.api.valueCounts
811
import org.junit.Test
912

1013
class DataColumnTests : BaseTest() {
@@ -14,4 +17,12 @@ class DataColumnTests : BaseTest() {
1417
typed.age.sort() shouldBe typed.sortBy { age }.age
1518
typed.age.sortDesc() shouldBe typed.sortByDesc { age }.age
1619
}
20+
21+
@Test
22+
fun `value counts`() {
23+
val languages by columnOf("Kotlin", "Kotlin", null, null, "C++")
24+
val languageCounts = languages.valueCounts()
25+
languageCounts[languages].values() shouldBe listOf("Kotlin", "C++")
26+
languageCounts.count.values() shouldBe listOf(2, 1)
27+
}
1728
}

plugins/kotlin-dataframe/src/org/jetbrains/kotlinx/dataframe/plugin/extensions/ReturnTypeBasedReceiverInjector.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package org.jetbrains.kotlinx.dataframe.plugin.extensions
33
import org.jetbrains.kotlin.fir.FirSession
44
import org.jetbrains.kotlinx.dataframe.plugin.utils.Names
55
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
6+
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
67
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
78
import org.jetbrains.kotlin.fir.extensions.FirExpressionResolutionExtension
89
import org.jetbrains.kotlin.fir.scopes.collectAllProperties
@@ -21,7 +22,7 @@ class ReturnTypeBasedReceiverInjector(session: FirSession) : FirExpressionResolu
2122
val symbol = generatedTokenOrNull(functionCall) ?: return emptyList()
2223
return symbol.declaredMemberScope(session, FirResolvePhase.DECLARATIONS).collectAllProperties()
2324
.filterIsInstance<FirPropertySymbol>()
24-
.filter { it.resolvedReturnType.classId?.shortClassName?.asString()?.startsWith("Scope") ?: false }
25+
.filter { it.getAnnotationByClassId(Names.SCOPE_PROPERTY_ANNOTATION, session) != null }
2526
.map { it.resolvedReturnType }
2627
}
2728

plugins/kotlin-dataframe/src/org/jetbrains/kotlinx/dataframe/plugin/extensions/TokenGenerator.kt

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.caches.getValue
1212
import org.jetbrains.kotlinx.dataframe.plugin.utils.Names
1313
import org.jetbrains.kotlinx.dataframe.plugin.utils.generateExtensionProperty
1414
import org.jetbrains.kotlin.fir.declarations.FirProperty
15+
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
1516
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation
1617
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationArgumentMapping
1718
import org.jetbrains.kotlin.fir.expressions.builder.buildLiteralExpression
@@ -51,8 +52,7 @@ class TokenGenerator(session: FirSession) : FirDeclarationGenerationExtension(se
5152
}
5253
is CallShapeData.RefinedType -> callShapeData.scopes.associate {
5354
val propertyName = Name.identifier(it.name.identifier.replaceFirstChar { it.lowercaseChar() })
54-
// making them var appeared to be the easiest way to filter
55-
propertyName to listOf(buildProperty(it.defaultType().toFirResolvedTypeRef(), propertyName, k, isVal = false))
55+
propertyName to listOf(buildProperty(it.defaultType().toFirResolvedTypeRef(), propertyName, k, isScopeProperty = true))
5656
}
5757
is CallShapeData.Scope -> callShapeData.columns.associate { schemaProperty ->
5858
val propertyName = Name.identifier(schemaProperty.name)
@@ -89,7 +89,6 @@ class TokenGenerator(session: FirSession) : FirDeclarationGenerationExtension(se
8989

9090
@OptIn(SymbolInternals::class)
9191
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>, context: MemberGenerationContext): Set<Name> {
92-
// maybe Init needed not for everything
9392
val destination = mutableSetOf<Name>()
9493
when (classSymbol.fir.callShapeData) {
9594
is CallShapeData.RefinedType -> destination.add(SpecialNames.INIT)
@@ -110,28 +109,33 @@ class TokenGenerator(session: FirSession) : FirDeclarationGenerationExtension(se
110109
resolvedTypeRef: FirResolvedTypeRef,
111110
propertyName: Name,
112111
k: FirClassSymbol<*>,
113-
isVal: Boolean = true,
112+
isScopeProperty: Boolean = false,
114113
order: Int? = null,
115114
): FirProperty {
116-
return createMemberProperty(k, Key, propertyName, resolvedTypeRef.type, isVal) {
115+
return createMemberProperty(k, Key, propertyName, resolvedTypeRef.type) {
117116
modality = Modality.ABSTRACT
118117
visibility = Visibilities.Public
119118
}.apply {
119+
val annotations = mutableListOf<FirAnnotation>()
120120
if (order != null) {
121-
val orderAnnotation = buildAnnotation {
121+
annotations += buildAnnotation {
122122
annotationTypeRef = buildResolvedTypeRef {
123-
type = ConeClassLikeTypeImpl(
124-
ConeClassLikeLookupTagImpl(Names.ORDER_ANNOTATION),
125-
arrayOf(),
126-
isNullable = false
127-
)
123+
type = Names.ORDER_ANNOTATION.defaultType(emptyList())
128124
}
129125
argumentMapping = buildAnnotationArgumentMapping {
130126
mapping[Names.ORDER_ARGUMENT] = buildLiteralExpression(null, ConstantValueKind.Int, order, setType = true)
131127
}
132128
}
133-
replaceAnnotations(listOf(orderAnnotation))
134129
}
130+
if (isScopeProperty) {
131+
annotations += buildAnnotation {
132+
annotationTypeRef = buildResolvedTypeRef {
133+
type = Names.SCOPE_PROPERTY_ANNOTATION.defaultType(emptyList())
134+
}
135+
argumentMapping = buildAnnotationArgumentMapping()
136+
}
137+
}
138+
replaceAnnotations(annotations)
135139
}
136140
}
137141

plugins/kotlin-dataframe/src/org/jetbrains/kotlinx/dataframe/plugin/impl/SimpleCol.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
package org.jetbrains.kotlinx.dataframe.plugin.impl
44

5+
import org.jetbrains.kotlin.fir.analysis.checkers.fullyExpandedClassId
56
import org.jetbrains.kotlin.fir.types.ConeKotlinType
67
import org.jetbrains.kotlin.fir.types.ConeNullability
7-
import org.jetbrains.kotlin.fir.types.classId
88
import org.jetbrains.kotlin.fir.types.isNullable
99
import org.jetbrains.kotlinx.dataframe.impl.api.DataFrameLikeContainer
1010
import org.jetbrains.kotlinx.dataframe.impl.api.GenericColumn
@@ -101,17 +101,17 @@ data class SimpleColumnGroup(
101101
}
102102

103103
fun KotlinTypeFacade.simpleColumnOf(name: String, type: ConeKotlinType): SimpleCol {
104-
return if (type.classId == Names.DATA_ROW_CLASS_ID) {
105-
val schema = pluginDataFrameSchema(type)
104+
return if (type.fullyExpandedClassId(session) == Names.DATA_ROW_CLASS_ID) {
105+
val schema = pluginDataFrameSchema(type.typeArguments[0])
106106
val group = SimpleColumnGroup(name, schema.columns())
107107
val column = if (type.isNullable) {
108108
makeNullable(group)
109109
} else {
110110
group
111111
}
112112
column
113-
} else if (type.classId == Names.DF_CLASS_ID && type.nullability == ConeNullability.NOT_NULL) {
114-
val schema = pluginDataFrameSchema(type)
113+
} else if (type.fullyExpandedClassId(session) == Names.DF_CLASS_ID && type.nullability == ConeNullability.NOT_NULL) {
114+
val schema = pluginDataFrameSchema(type.typeArguments[0])
115115
SimpleFrameColumn(name, schema.columns())
116116
} else {
117117
SimpleDataColumn(name, type.wrap())
@@ -121,7 +121,7 @@ fun KotlinTypeFacade.simpleColumnOf(name: String, type: ConeKotlinType): SimpleC
121121
private fun KotlinTypeFacade.makeNullable(column: SimpleCol): SimpleCol {
122122
return when (column) {
123123
is SimpleColumnGroup -> {
124-
SimpleColumnGroup(column.name, column.columns().map { makeNullable(column) })
124+
SimpleColumnGroup(column.name, column.columns().map { makeNullable(it) })
125125
}
126126
is SimpleFrameColumn -> column
127127
is SimpleDataColumn -> SimpleDataColumn(column.name, column.type.changeNullability { true })

plugins/kotlin-dataframe/src/org/jetbrains/kotlinx/dataframe/plugin/impl/api/add.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import org.jetbrains.kotlinx.dataframe.plugin.impl.Arguments
77
import org.jetbrains.kotlinx.dataframe.plugin.impl.Interpreter
88
import org.jetbrains.kotlinx.dataframe.plugin.impl.PluginDataFrameSchema
99
import org.jetbrains.kotlinx.dataframe.plugin.impl.SimpleCol
10-
import org.jetbrains.kotlinx.dataframe.plugin.impl.SimpleDataColumn
1110
import org.jetbrains.kotlinx.dataframe.plugin.impl.dataFrame
11+
import org.jetbrains.kotlinx.dataframe.plugin.impl.simpleColumnOf
1212
import org.jetbrains.kotlinx.dataframe.plugin.impl.string
1313
import org.jetbrains.kotlinx.dataframe.plugin.impl.type
1414

@@ -20,7 +20,7 @@ class Add : AbstractSchemaModificationInterpreter() {
2020
val Arguments.type: TypeApproximation by type(name("expression"))
2121

2222
override fun Arguments.interpret(): PluginDataFrameSchema {
23-
return PluginDataFrameSchema(receiver.columns() + SimpleDataColumn(name, type))
23+
return PluginDataFrameSchema(receiver.columns() + simpleColumnOf(name, type.type))
2424
}
2525
}
2626

@@ -30,7 +30,7 @@ class From : AbstractInterpreter<Unit>() {
3030
val Arguments.type: TypeApproximation by type(name("expression"))
3131

3232
override fun Arguments.interpret() {
33-
dsl.columns += SimpleDataColumn(receiver, type)
33+
dsl.columns += simpleColumnOf(receiver, type.type)
3434
}
3535
}
3636

@@ -40,7 +40,7 @@ class Into : AbstractInterpreter<Unit>() {
4040
val Arguments.name: String by string()
4141

4242
override fun Arguments.interpret() {
43-
dsl.columns += SimpleDataColumn(name, receiver)
43+
dsl.columns += simpleColumnOf(name, receiver.type)
4444
}
4545
}
4646

0 commit comments

Comments
 (0)