[workspace model] IDEA-297350 Remove old gradle modules

GitOrigin-RevId: 0a7a8b7032ee8ca24345599d8cdd7b5eaae4a9d3
This commit is contained in:
Mikhail Mazurkevich
2023-03-22 15:46:17 +00:00
committed by intellij-monorepo-bot
parent 0895a246f8
commit 95d8f4d808
48 changed files with 0 additions and 3935 deletions
@@ -1,42 +0,0 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store
@@ -1,42 +0,0 @@
plugins {
id("maven-publish")
// Java support
id("java")
// Kotlin support
id("org.jetbrains.kotlin.jvm") version "1.8.0"
}
group = "com.jetbrains.intellij.platform"
version = "0.0.4"
repositories {
mavenCentral()
maven {
url = uri("https://www.jetbrains.com/intellij-repository/releases")
}
maven {
url = uri("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies")
}
}
publishing {
repositories {
maven {
url = uri("https://packages.jetbrains.team/maven/p/ide-accessibility-assistant/codegen-test")
credentials {
username = System.getProperty("intellij.workspace.codegen.repository.user")
password = System.getProperty("intellij.workspace.codegen.repository.password")
}
}
}
publications {
register("mavenJava", MavenPublication::class) {
from(components["java"])
}
}
}
dependencies {
implementation("org.jetbrains:annotations:24.0.0")
implementation("com.jetbrains.intellij.platform:workspace-model-storage:223.8836.34")
}
@@ -1,6 +0,0 @@
#Fri Mar 10 15:23:48 AMT 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-234
View File
@@ -1,234 +0,0 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# 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
#
# https://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.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
-89
View File
@@ -1,89 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@@ -1,2 +0,0 @@
rootProject.name = "workspace-model-codegen"
@@ -1,8 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.deft.annotations
@Target(
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.FUNCTION
)
annotation class Cached
@@ -1,11 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.deft.annotations
/**
* Name property values acts as implicit field of parent object.
*
* By setting name of some object, you are actually declare implicit field
* of parent object with same name and this object as value.
*/
@Target(AnnotationTarget.PROPERTY)
annotation class Name
@@ -1,4 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.deft.annotations
annotation class Parent
@@ -1,7 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.deft.meta
interface CompiledObjModule : ObjModule {
fun objClass(typeId: Int): ObjClass<*>
fun <T : Obj, V> extField(receiver: ObjClass<*>, name: String, default: T.() -> V): ExtProperty<T, V>
}
@@ -1,43 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.deft.meta
interface Obj {
val objType: ObjType<*>
}
/**
* Mutable, possibly not fully initialized [Obj].
*
* Implementation of that interface is generated by the Deft compiler,
* inside each [Obj]. It will contain `var`s for all final fields.
*
* [ObjBuilder] inherits all corresponding builders of [Obj] supertypes.
*
* Doesn't have `var`s for open field, as open setters contravariance
* contradicts open getter invariance. [ObjFinalBuilder] contains rest fields,
* but **not** inherits supertypes Builders.
*/
interface ObjBuilder<T : Obj> : Obj {
val isInitialized: Boolean
fun isInitialized(field: OwnProperty<T, *>): Boolean
fun isInitialized(field: ExtProperty<T, *>): Boolean
fun <V> setValue(field: OwnProperty<T, V>, value: V)
fun <V> setValue(field: ExtProperty<T, V>, value: V)
fun <V : Obj> setValue(type: ObjClass<V>, value: V)
fun remove(field: ExtProperty<T, *>): Boolean
fun remove(type: ObjClass<*>): Boolean
fun build(): T
}
/**
* See [ObjBuilder].
*
* Contains rest open fields, and not inherits supertypes Builders
* (as open setters contravariance contradicts open getter invariance).
*/
interface ObjFinalBuilder<T : Obj> : ObjBuilder<T>
@@ -1,49 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.deft.meta
import com.intellij.workspaceModel.codegen.deft.annotations.Name
import org.jetbrains.deft.annotations.Child
interface ObjModule : Obj {
@Name
val name: String
val moduleId: Id
get() = Id(name)
val dependencies: List<ObjModule>
val types: List<@Child ObjClass<*>>
val extensions: List<@Child ExtProperty<*, *>>
/**
* Example: `org.jetbrains.deft.obj.intellijWs`
* will be parsed as:
* - `org.jetbrains.deft.obj.intellijWs` package
* - `org.jetbrains.deft.obj.intellijWs.IntellijWs` object name
**/
@JvmInline
value class Id(private val notation: String) {
private val javaPackage: String
get() = notation
private val objName: String
get() = notation.substringAfterLast(".")
.replaceFirstChar { it.titlecaseChar() }
val objFqn: String
get() = "$javaPackage.$objName"
fun check() {
check(objName.first().isUpperCase()) {
"`$notation` should be an id notation like `org.jetbrains.deft.obj.IntellijWs`.\n" +
"Will be parsed as:\n" +
"- `org.jetbrains.deft.obj.intellijWs` package\n" +
"- `IntellijWs` object name"
}
}
override fun toString(): String = "ObjModule.Id($notation)"
}
}
@@ -1,61 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.deft.meta
import com.intellij.workspaceModel.codegen.deft.annotations.Name
import com.intellij.workspaceModel.codegen.deft.annotations.Parent
/**
* Same as [kotlin.reflect.KProperty]
*/
interface ObjProperty<T : Obj, V> : Obj {
val suspend: Boolean
val open: Boolean
val mutable: Boolean
val receiver: ObjClass<T>
@Name
val name: String
val valueType: ValueType<V>
val valueKind: ValueKind
sealed interface ValueKind {
object Plain : ValueKind
class Computable(val expression: String) : ValueKind
class WithDefault(val value: String) : ValueKind
}
////// Kotlin DSL
val content: Boolean
}
/**
* Same as [kotlin.reflect.KProperty1]
*/
interface OwnProperty<T : Obj, V> : ObjProperty<T, V> {
@Parent
override val receiver: ObjClass<T>
val constructorParameter: Boolean
val classLocalId: Int
val isKey: Boolean
}
/**
* Same as [kotlin.reflect.KProperty1]
*/
interface ExtProperty<T : Obj, V> : ObjProperty<T, V> {
@Parent
val module: ObjModule
override val receiver: ObjClass<T>
val moduleLocalId: Int
}
@@ -1,78 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.deft.meta
import com.intellij.workspaceModel.codegen.deft.annotations.Cached
import com.intellij.workspaceModel.codegen.deft.annotations.Parent
import org.jetbrains.deft.annotations.Child
interface ObjType<T> : Obj {
val classifier: ObjType<T>
val arguments: List<ObjType<*>>
}
/**
* Describes parameterized type of [Objects][Obj].
*
* Read first: "Values, References and Objects" in [Obj] docs.
*
* For implementation simplicity, [ObjClass] is used to define both [ObjClass]
* itself and [asStructure], even when you need [asStructure] only.
*
* Objects can have [own][OwnProperty] and [extension][ExtProperty] fields.
*/
interface ObjClass<T : Obj> : ObjType<T> {
val typeParameters: List<@Child TypeParameter>
val superTypes: List<ObjType<*>>
@Parent
val module: ObjModule
val name: String
val openness: Openness
enum class Openness(
val instantiatable: Boolean = false,
val extendable: Boolean = false,
val openHierarchy: Boolean = extendable
) {
/** Single instance */
`const`,
/** Can't be extended */
`final`(instantiatable = true),
/** Should be extended (can't be instantiated directly) */
`abstract`(extendable = true),
/** Should be extended with sealed hierarchy */
`enum`(extendable = true, openHierarchy = false),
/** Can be extended and can be instantiated */
`open`(instantiatable = true, extendable = true)
}
val fields: List<@Child OwnProperty<T, *>>
val parentField: OwnProperty<T, *>?
val nameField: OwnProperty<T, *>?
val fieldsByName: Map<String, OwnProperty<in T, *>>
@Cached get() = fields.associateBy { it.name }
val fieldsByLocalId: Map<Int, OwnProperty<in T, *>>
@Cached get() = fields.associateBy { it.classLocalId }
val asStructure: ValueType.Structure<T>
@Cached get() = ValueType.Structure(fields.mapTo(mutableListOf()) { it.valueType })
companion object
}
interface TypeParameter : Obj {
val name: String
val lowerBound: ObjType<*>
}
@@ -1,191 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.deft.meta
/**
* [ValueType] is used to describe the set of suitable values.
*/
sealed class ValueType<T> {
sealed class Primitive<T> : ValueType<T>()
/**
* `true` or `false`. Actually, the shorthand for `OneOf(Const(true), Const(false))`.
*
* Same as Kotlin [kotlin.Boolean] and Java primitive `boolean` ([java.lang.Boolean])
*/
object Boolean : Primitive<kotlin.Boolean>()
/**
* 8-bit signed integer with the least significant bit.
*
* Same as Kotlin [kotlin.Byte] and Java primitive `byte`([java.lang.Byte]).
*/
object Byte : Primitive<kotlin.Byte>()
/**
* 16-bit signed, big endian integer with the least significant bit.
*
* Same as Kotlin [kotlin.Short] and Java primitive `short`([java.lang.Short]).
*/
object Short : Primitive<kotlin.Short>()
/**
* 32-bit signed, big endian integer with the least significant bit.
*
* Same as Kotlin [kotlin.Int] and Java primitive `int`([java.lang.Integer])
*/
object Int : Primitive<kotlin.Int>()
/**
* 64-bit signed, big endian integer with the least significant bit.
*
* Same as Kotlin [kotlin.Long] and Java primitive `long`([java.lang.Long])
*/
object Long : Primitive<kotlin.Long>()
/**
* Represents a double-precision 32-bit [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) floating point number.
*
* Same as Kotlin [kotlin.Float] and Java primitive `float`([java.lang.Float])
*/
object Float : Primitive<kotlin.Float>()
/**
* Represents a double-precision 64-bit [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) floating point number.
*
* Same as Kotlin [kotlin.Double] and Java primitive `double`([java.lang.Double])
*/
object Double : Primitive<kotlin.Double>()
/**
* 8-bit unsigned integer.
*
* Same as Kotlin [UByte]. Not available in Java.
*/
object UByte : Primitive<kotlin.UByte>()
/**
* 16-bit unsigned, big endian integer.
*
* Same as Kotlin [UShort]. Not available in Java.
*/
object UShort : Primitive<kotlin.UShort>()
/**
* 32-bit unsigned, big endian integer.
*
* Same as Kotlin [UInt]. Not available in Java.
*/
object UInt : Primitive<kotlin.UInt>()
/**
* 64-bit unsigned, big endian integer.
*
* Same as Kotlin [ULong]. Not available in Java.
*/
object ULong : Primitive<kotlin.ULong>()
/**
* 16-bit Unicode character encoded by [UShort].
*
* Same as Kotlin [kotlin.Char] and Java [java.lang.Character]
*/
object Char : Primitive<kotlin.Char>()
/**
* Behaves as [List] of [Char].
*
* Unlike all other [ValueType]s, requires decoding on read and encoding on write,
* thus should be cached on client side. The actual binary representation is
* implementation detail.
*
* Translated to [kotlin.String] and Java [java.lang.String].
*/
object String : Primitive<kotlin.String>()
/**
* Polymorphic reference to [Obj] of [target] [ObjClass].
**/
data class ObjRef<T : Obj>(
val child: kotlin.Boolean,
val target: ObjClass<T>
) : ValueType<T>()
sealed class JvmClass<T>(
val javaClassName: kotlin.String,
val javaSuperClasses: kotlin.collections.List<kotlin.String>,
) : ValueType<T>()
class DataClass<T>(
javaClassName: kotlin.String,
javaSuperClasses: kotlin.collections.List<kotlin.String>,
val properties: kotlin.collections.List<DataClassProperty>
) : JvmClass<T>(javaClassName, javaSuperClasses)
data class DataClassProperty(val name: kotlin.String, val type: ValueType<*>)
class SealedClass<T>(
javaClassName: kotlin.String,
javaSuperClasses: kotlin.collections.List<kotlin.String>,
val subclasses: kotlin.collections.List<JvmClass<*>>
) : JvmClass<T>(javaClassName, javaSuperClasses)
class Blob<T>(
javaClassName: kotlin.String,
javaSuperClasses: kotlin.collections.List<kotlin.String>,
) : JvmClass<T>(javaClassName, javaSuperClasses)
class Enum<T>(
javaClassName: kotlin.String,
) : JvmClass<T>(javaClassName, emptyList())
class Object<T>(
javaClassName: kotlin.String,
javaSuperClasses: kotlin.collections.List<kotlin.String>,
) : JvmClass<T>(javaClassName, javaSuperClasses)
/**
* Tuple of fields with fixed [ValueType]s.
*
* [Structure] is [ValueType] itself, thus can be nested (but without recursion)
* and compared by value.
*
* Use [ObjClass] to define your own structure.
*
* Read "Values, References and Objects" in [Obj] to understand differences
* between [ValueType] (which [Structure] is) and [ObjClass].
*
* Unlike [ObjProperty], [Structure] fields are not nominal.
* Thus, two structures with same set of field types considered equal.
*/
data class Structure<T>(val fields: kotlin.collections.List<ValueType<*>>) : ValueType<T>()
sealed class Collection<E, T : kotlin.collections.Collection<E>> : ValueType<T>() {
abstract val elementType: ValueType<E>
}
data class List<T>(override val elementType: ValueType<T>) : Collection<T, kotlin.collections.List<T>>()
data class Set<T>(override val elementType: ValueType<T>) : Collection<T, kotlin.collections.Set<T>>()
data class Map<K, V>(
val keyType: ValueType<K>,
val valueType: ValueType<V>
) : ValueType<Map<K, V>>()
data class Optional<T>(val type: ValueType<T>) : ValueType<T?>()
/**
* Any possible value.
* Valid inside [ValueRef] only.
*
* Logical representation: [AnyOf]`(...all value kinds)`.
*/
object Any : ValueType<kotlin.Any>()
/**
* Nothing has no possible values.
* Used to denote [Optional] values.
*
* Logical representation: [Both]`(...all value kinds, except Any)`.
*/
object Nothing : ValueType<kotlin.Nothing>()
}
@@ -1,8 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
/**
* Contains interfaces which describe structure of {@link com.intellij.workspaceModel.storage.WorkspaceEntity workspace entities}.
*/
@ApiStatus.Experimental
package com.intellij.workspaceModel.codegen.deft.meta;
import org.jetbrains.annotations.ApiStatus;
@@ -1,51 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.engine
import com.intellij.workspaceModel.codegen.deft.meta.*
import com.intellij.workspaceModel.storage.WorkspaceEntity
import com.intellij.workspaceModel.storage.WorkspaceEntityWithSymbolicId
val SKIPPED_TYPES: Set<String> = setOfNotNull(WorkspaceEntity::class.simpleName,
WorkspaceEntity.Builder::class.simpleName,
WorkspaceEntityWithSymbolicId::class.simpleName)
interface CodeGenerator {
fun generate(module: CompiledObjModule): GenerationResult
}
class GenerationResult(val generatedCode: List<GeneratedCode>, val problems: List<GenerationProblem>)
class GenerationProblem(
val message: String,
val level: Level,
val location: ProblemLocation
) {
enum class Level { ERROR, WARNING }
}
sealed interface ProblemLocation {
val objModule: ObjModule
class Class(val objClass: ObjClass<*>) : ProblemLocation {
override val objModule: ObjModule
get() = objClass.module
override fun toString(): String = objClass.name
}
class Property(val property: ObjProperty<*, *>) : ProblemLocation {
override val objModule: ObjModule
get() = when (property) {
is ExtProperty<*, *> -> property.module
else -> property.receiver.module
}
override fun toString(): String = property.toString()
}
}
class GeneratedCode(
val target: ObjClass<*>,
val builderInterface: String,
val companionObject: String,
val topLevelCode: String?,
val implementationClass: String?
)
@@ -1,42 +0,0 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store
@@ -1,43 +0,0 @@
plugins {
id("maven-publish")
// Java support
id("java")
// Kotlin support
id("org.jetbrains.kotlin.jvm") version "1.8.0"
}
group = "com.jetbrains.intellij.platform"
version = "0.0.6"
repositories {
mavenCentral()
maven {
url = uri("https://www.jetbrains.com/intellij-repository/releases")
}
maven {
url = uri("https://www.jetbrains.com/intellij-repository/nightly")
}
}
publishing {
repositories {
maven {
url = uri("https://packages.jetbrains.team/maven/p/ide-accessibility-assistant/codegen-test")
credentials {
username = System.getProperty("intellij.workspace.codegen.repository.user")
password = System.getProperty("intellij.workspace.codegen.repository.password")
}
}
}
publications {
register("mavenJava", MavenPublication::class) {
from(components["java"])
}
}
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("com.jetbrains.intellij.platform:workspace-model-codegen:LATEST-TRUNK-SNAPSHOT")
implementation("com.jetbrains.intellij.platform:workspace-model-storage:223.8836.34")
}
@@ -1,6 +0,0 @@
#Fri Mar 10 15:27:35 AMT 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-234
View File
@@ -1,234 +0,0 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# 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
#
# https://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.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
-89
View File
@@ -1,89 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@@ -1,2 +0,0 @@
rootProject.name = "workspace-model-codegen-impl"
@@ -1,343 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen
import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
import com.intellij.workspaceModel.codegen.deft.meta.OwnProperty
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
import com.intellij.workspaceModel.codegen.writer.fields.javaType
import com.intellij.workspaceModel.codegen.writer.LinesBuilder
import com.intellij.workspaceModel.codegen.writer.isRefType
class InterfaceTraverser {
fun traverse(myInterface: ObjClass<*>, visitor: InterfaceVisitor): Boolean {
for (field in myInterface.fields) {
val res = traverseField(field, visitor, field.name)
if (!res) return false
}
return true
}
private fun traverseField(field: OwnProperty<*, *>, visitor: InterfaceVisitor, varName: String): Boolean {
return traverseType(field.valueType, visitor, varName)
}
private fun traverseType(type: ValueType<*>, visitor: InterfaceVisitor, varName: String): Boolean {
when (type) {
is ValueType.Boolean -> return visitor.visitBoolean(varName)
is ValueType.Int -> return visitor.visitInt(varName)
is ValueType.String -> return visitor.visitString(varName)
is ValueType.Collection<*, *> -> {
val itemVarName = "_$varName"
val shouldProcessList = visitor.visitListStart(varName, itemVarName, type.elementType)
if (!shouldProcessList) return false
val traversingResult = traverseType(type.elementType, visitor, itemVarName)
return visitor.visitListEnd(varName, itemVarName, traversingResult, type.elementType)
}
is ValueType.Map<*, *> -> {
val keyVarName = "key_$varName"
val valueVarName = "value_$varName"
val shouldProcessMap = visitor.visitMapStart(varName, keyVarName, valueVarName, type.keyType, type.valueType)
if (!shouldProcessMap) return false
val keyTraverseResult = traverseType(type.keyType, visitor, keyVarName)
val valueTraverseResult = traverseType(type.valueType, visitor, valueVarName)
return visitor.visitMapEnd(varName, keyVarName, valueVarName, type.keyType, type.valueType,
keyTraverseResult && valueTraverseResult)
}
is ValueType.Optional<*> -> {
val notNullVarName = "_$varName"
var continueProcess = visitor.visitOptionalStart(varName, notNullVarName, type.type)
if (!continueProcess) return false
continueProcess = traverseType(type.type, visitor, notNullVarName)
return visitor.visitOptionalEnd(varName, notNullVarName, type.type, continueProcess)
}
is ValueType.Blob<*> -> {
return visitor.visitUnknownBlob(varName, type.javaClassName)
/*
var process = visitor.visitKnownBlobStart(varName, type.javaSimpleName)
if (!process) return false
process = traverse(foundType, visitor)
return visitor.visitKnownBlobFinish(varName, type.javaSimpleName, process)
*/
}
is ValueType.DataClass<*> -> {
var process = visitor.visitDataClassStart(varName, type)
if (!process) return false
//process = traverse(type, visitor)
return visitor.visitDataClassEnd(varName, type, process)
}
else -> {}
}
return true
}
}
class DeserializationVisitor(linesBuilder: LinesBuilder) : InterfaceVisitor {
private val builders: ArrayDeque<LinesBuilder> = ArrayDeque<LinesBuilder>().also { it.add(linesBuilder) }
private val builder: LinesBuilder
get() = builders.last()
private var countersCounter = 0
override fun visitBoolean(varName: String): Boolean {
builder.line("$varName = de.readBoolean()")
return true
}
override fun visitInt(varName: String): Boolean {
builder.line("$varName = de.readInt()")
return true
}
override fun visitString(varName: String): Boolean {
builder.line("$varName = de.readString()")
return true
}
override fun visitListStart(varName: String, itemVarName: String, listArgumentType: ValueType<*>): Boolean {
if (listArgumentType.isRefType()) return true
val sub = LinesBuilder(StringBuilder(), builder.indentLevel + 1)
builders.add(sub)
return true
}
override fun visitListEnd(varName: String, itemVarName: String, traverseResult: Boolean, listArgumentType: ValueType<*>): Boolean {
if (listArgumentType.isRefType()) return true
val myInListBuilder = builders.removeLast()
if (myInListBuilder.result.isNotBlank()) {
val varCounter = "counter" + counter()
val varCollector = "collector" + counter()
builder.line("val $varCounter = de.readInt()")
builder.line("val $varCollector = ArrayList<${listArgumentType.javaType}>()")
builder.line("var $itemVarName: ${listArgumentType.javaType}")
builder.line("repeat($varCounter) {")
myInListBuilder.line("$varCollector.add($itemVarName)")
builder.result.append(myInListBuilder.result)
builder.line("}")
builder.line("$varName = $varCollector")
}
return true
}
override fun visitMapStart(varName: String,
keyVarName: String,
valueVarName: String,
keyType: ValueType<*>,
valueType: ValueType<*>): Boolean {
return false
}
override fun visitMapEnd(varName: String,
keyVarName: String,
valueVarName: String,
keyType: ValueType<*>,
valueType: ValueType<*>,
traverseResult: Boolean): Boolean {
return false
}
override fun visitOptionalStart(varName: String, notNullVarName: String, type: ValueType<*>): Boolean {
if (type.isRefType()) return true
val sub = LinesBuilder(StringBuilder(), builder.indentLevel + 1)
builders.add(sub)
return true
}
override fun visitOptionalEnd(varName: String, notNullVarName: String, type: ValueType<*>, traverseResult: Boolean): Boolean {
if (type.isRefType()) return true
val popLast = builders.removeLast()
builder.section("if (de.acceptNull())") {
line("$varName = null")
}
builder.section("else") {
if (popLast.result.isNotBlank()) {
line("val $notNullVarName: ${type.javaType}")
result.append(popLast.result)
line("$varName = $notNullVarName")
}
}
return true
}
override fun visitUnknownBlob(varName: String, javaSimpleName: String): Boolean {
return false
}
override fun visitKnownBlobStart(varName: String, javaSimpleName: String): Boolean {
return false
}
override fun visitKnownBlobFinish(varName: String, javaSimpleName: String, traverseResult: Boolean): Boolean {
return false
}
override fun visitDataClassStart(varName: String, dataClass: ValueType.DataClass<*>): Boolean {
TODO("Not yet implemented")
}
override fun visitDataClassEnd(varName: String, dataClass: ValueType.DataClass<*>, traverseResult: Boolean): Boolean {
TODO("Not yet implemented")
}
private fun counter(): Int {
return countersCounter++
}
}
class SerializatorVisitor private constructor(private val linesBuilder: ArrayDeque<LinesBuilder>) : InterfaceVisitor {
constructor(linesBuilder: LinesBuilder) : this(ArrayDeque<LinesBuilder>().also { it.add(linesBuilder) })
val builder: LinesBuilder
get() = linesBuilder.last()
override fun visitBoolean(varName: String): Boolean {
builder.line("ser.saveBoolean($varName)")
return true
}
override fun visitInt(varName: String): Boolean {
builder.line("ser.saveInt($varName)")
return true
}
override fun visitString(varName: String): Boolean {
builder.line("ser.saveString($varName)")
return true
}
override fun visitListStart(varName: String, itemVarName: String, listArgumentType: ValueType<*>): Boolean {
if (listArgumentType.isRefType()) return true
val sub = LinesBuilder(StringBuilder(), builder.indentLevel + 1)
linesBuilder.add(sub)
return true
}
override fun visitListEnd(varName: String, itemVarName: String, traverseResult: Boolean, listArgumentType: ValueType<*>): Boolean {
if (listArgumentType.isRefType()) return true
val myInListBuilder = linesBuilder.removeLast()
if (myInListBuilder.result.isNotBlank()) {
builder.line("ser.saveInt($varName.size)")
builder.line("for ($itemVarName in $varName) {")
builder.result.append(myInListBuilder.result)
builder.line("}")
}
return true
}
override fun visitMapStart(varName: String,
keyVarName: String,
valueVarName: String,
keyType: ValueType<*>,
valueType: ValueType<*>): Boolean {
if (keyType.isRefType() || valueType.isRefType()) return true
val sub = LinesBuilder(StringBuilder(), builder.indentLevel + 1)
linesBuilder.add(sub)
return true
}
override fun visitMapEnd(varName: String,
keyVarName: String,
valueVarName: String,
keyType: ValueType<*>,
valueType: ValueType<*>,
traverseResult: Boolean): Boolean {
if (keyType.isRefType() || valueType.isRefType()) return true
val inMapBuilder = linesBuilder.removeLast()
if (inMapBuilder.result.isNotBlank()) {
builder.line("ser.saveInt($varName.size)")
builder.line("for (($keyVarName, $valueVarName) in $varName) {")
builder.result.append(inMapBuilder.result)
builder.line("}")
}
return true
}
override fun visitOptionalStart(varName: String, notNullVarName: String, type: ValueType<*>): Boolean {
if (type.isRefType()) return true
val sub = LinesBuilder(StringBuilder(), builder.indentLevel + 1)
linesBuilder.add(sub)
return true
}
override fun visitOptionalEnd(varName: String, notNullVarName: String, type: ValueType<*>, traverseResult: Boolean): Boolean {
if (type.isRefType()) return true
val inMapBuilder = linesBuilder.removeLast()
if (inMapBuilder.result.isNotBlank()) {
builder.line("val $notNullVarName = $varName")
builder.line("if ($notNullVarName != null) {")
builder.result.append(inMapBuilder.result)
builder.line("} else {")
builder.line(" ser.saveNull()")
builder.line("}")
}
return true
}
override fun visitUnknownBlob(varName: String, javaSimpleName: String): Boolean {
if (javaSimpleName == "EntitySource") return true
builder.line("ser.saveBlob($varName, \"$javaSimpleName\")")
return true
}
override fun visitKnownBlobStart(varName: String, javaSimpleName: String): Boolean {
return true
}
override fun visitKnownBlobFinish(varName: String, javaSimpleName: String, traverseResult: Boolean): Boolean {
return true
}
override fun visitDataClassStart(varName: String, dataClass: ValueType.DataClass<*>): Boolean {
TODO("Not yet implemented")
}
override fun visitDataClassEnd(varName: String, dataClass: ValueType.DataClass<*>, traverseResult: Boolean): Boolean {
TODO("Not yet implemented")
}
}
interface InterfaceVisitor {
fun visitBoolean(varName: String): Boolean
fun visitInt(varName: String): Boolean
fun visitString(varName: String): Boolean
fun visitListStart(varName: String, itemVarName: String, listArgumentType: ValueType<*>): Boolean
fun visitListEnd(varName: String, itemVarName: String, traverseResult: Boolean, listArgumentType: ValueType<*>): Boolean
fun visitMapStart(varName: String, keyVarName: String, valueVarName: String, keyType: ValueType<*>, valueType: ValueType<*>): Boolean
fun visitMapEnd(varName: String,
keyVarName: String,
valueVarName: String,
keyType: ValueType<*>,
valueType: ValueType<*>,
traverseResult: Boolean): Boolean
fun visitOptionalStart(varName: String, notNullVarName: String, type: ValueType<*>): Boolean
fun visitOptionalEnd(varName: String, notNullVarName: String, type: ValueType<*>, traverseResult: Boolean): Boolean
fun visitUnknownBlob(varName: String, javaSimpleName: String): Boolean
fun visitKnownBlobStart(varName: String, javaSimpleName: String): Boolean
fun visitKnownBlobFinish(varName: String, javaSimpleName: String, traverseResult: Boolean): Boolean
fun visitDataClassStart(varName: String, dataClass: ValueType.DataClass<*>): Boolean
fun visitDataClassEnd(varName: String, dataClass: ValueType.DataClass<*>, traverseResult: Boolean): Boolean
}
@@ -1,42 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.engine.impl
import com.intellij.workspaceModel.codegen.deft.meta.CompiledObjModule
import com.intellij.workspaceModel.codegen.engine.CodeGenerator
import com.intellij.workspaceModel.codegen.engine.GeneratedCode
import com.intellij.workspaceModel.codegen.engine.GenerationProblem
import com.intellij.workspaceModel.codegen.engine.GenerationResult
import com.intellij.workspaceModel.codegen.writer.generateBuilderCode
import com.intellij.workspaceModel.codegen.writer.generateCompanionObject
import com.intellij.workspaceModel.codegen.writer.generateExtensionCode
import com.intellij.workspaceModel.codegen.writer.implWsCode
class CodeGeneratorImpl : CodeGenerator {
override fun generate(module: CompiledObjModule): GenerationResult {
val problems = ArrayList<GenerationProblem>()
val reporter = ProblemReporter { problems.add(it) }
val objClassToBuilderInterface = module.types.associateWith {
val builderInterface = it.generateBuilderCode(reporter)
builderInterface
}
// If there is at least one error, report them and stop any further calculations and
if (problems.any { it.level == GenerationProblem.Level.ERROR }) {
return GenerationResult(emptyList(), problems)
}
val code = objClassToBuilderInterface.map { (objClass, builderInterface) ->
GeneratedCode(
target = objClass,
builderInterface = builderInterface,
companionObject = objClass.generateCompanionObject(),
topLevelCode = objClass.generateExtensionCode(),
implementationClass = objClass.implWsCode()
)
}
return GenerationResult(code, problems)
}
}
fun interface ProblemReporter {
fun reportProblem(problem: GenerationProblem)
}
@@ -1,54 +0,0 @@
package com.intellij.workspaceModel.codegen.writer
class LinesBuilder(
val result: StringBuilder,
val indentLevel: Int,
val indentSize: Int = 4
) {
var first = true
fun line(str: String = "") {
lineNoNl(str)
result.append('\n')
}
fun lineNoNl(str: String) {
if (first) {
first = false
}
result.append(" ".repeat(indentLevel * indentSize))
result.append(str)
}
fun <T> list(c: Collection<T>, f: T.() -> String = { "$this" }) {
c.forEach {
line(it.f())
}
}
fun section(s: LinesBuilder.() -> Unit) {
LinesBuilder(result, indentLevel + 1, indentSize).s()
}
fun section(head: String, s: LinesBuilder.() -> Unit) {
lineNoNl(head)
val sub = LinesBuilder(result, indentLevel+1, indentSize)
sub.result.append(" {\n")
sub.s()
line("}")
}
fun sectionNoBrackets(head: String, s: LinesBuilder.() -> Unit) {
lineNoNl(head)
val sub = LinesBuilder(result, indentLevel+1, indentSize)
sub.result.append("\n")
sub.s()
}
}
inline fun lines(level: Int = 0, lines: LinesBuilder.() -> Unit): String {
val result = StringBuilder()
LinesBuilder(result, level).lines()
return result.toString()
}
@@ -1,79 +0,0 @@
package com.intellij.workspaceModel.codegen.writer
import com.intellij.workspaceModel.storage.EntityStorage
import com.intellij.workspaceModel.storage.MutableEntityStorage
import com.intellij.workspaceModel.storage.WorkspaceEntity
import com.intellij.workspaceModel.storage.impl.ConnectionId
import com.intellij.workspaceModel.storage.impl.ModifiableWorkspaceEntityBase
import kotlin.reflect.*
import kotlin.reflect.jvm.javaMethod
private const val fqnEscape = "#uC03o#"
fun fqn(function: KProperty1<KClass<*>, Collection<Any>>): QualifiedName = function.fqn
fun fqn1(function: KFunction3<EntityStorage, ConnectionId, WorkspaceEntity, WorkspaceEntity?>): QualifiedName = function.fqn
fun fqn2(function: KFunction3<EntityStorage, ConnectionId, WorkspaceEntity, Sequence<Any>>): QualifiedName = function.fqn
fun fqn3(function: KFunction4<EntityStorage, ConnectionId, WorkspaceEntity, WorkspaceEntity?, Unit>): QualifiedName = function.fqn
fun fqn4(function: KFunction4<EntityStorage, ConnectionId, WorkspaceEntity, List<WorkspaceEntity>, Unit>): QualifiedName = function.fqn
fun fqn5(function: KFunction4<EntityStorage, ConnectionId, WorkspaceEntity, Sequence<WorkspaceEntity>, Unit>): QualifiedName = function.fqn
fun fqn6(function: KFunction2<ModifiableWorkspaceEntityBase<*, *>, MutableEntityStorage, Unit>): QualifiedName = function.fqn
fun fqn7(function: KFunction1<Collection<*>, Collection<*>>): QualifiedName = function.fqn
private val KProperty<*>.fqn: QualifiedName
get() {
val declaringClass = this.getter.javaMethod?.declaringClass ?: return "".toQualifiedName()
return fqn(declaringClass.packageName, this.name)
}
private val KFunction<*>.fqn: QualifiedName
get() {
val declaringClass = this.javaMethod?.declaringClass ?: return "".toQualifiedName()
return fqn(declaringClass.packageName, this.name)
}
@JvmInline
value class QualifiedName(val encodedString: String) {
override fun toString(): String {
return encodedString
}
val decoded: String
get() = encodedString.removePrefix(fqnEscape).substringBefore("#").replace("@@", ".")
fun appendInner(innerClassPath: String): QualifiedName = QualifiedName("$encodedString.$innerClassPath")
fun appendSuffix(suffix: String): QualifiedName = QualifiedName("$encodedString$suffix")
}
/**
* Temporary string for adding to imports
*/
fun fqn(packageName: String?, name: String): QualifiedName {
if (packageName.isNullOrEmpty()) return QualifiedName(name)
val outerClassName = name.substringBefore(".")
return QualifiedName("$fqnEscape$packageName@@$outerClassName#$name")
}
fun String.toQualifiedName(): QualifiedName {
val classNameMatch = Regex("\\.[A-Z]").find(this) ?: return QualifiedName(this)
return fqn(substring(0, classNameMatch.range.first), substring(classNameMatch.range.last))
}
val KClass<*>.fqn: QualifiedName
get() = java.fqn
val Class<*>.fqn: QualifiedName
get() {
val name = name
val packageName = name.substringBeforeLast(".")
val className = name.substringAfterLast(".")
.replace('$', '.')
if (className.contains(".")) {
val outerClassName = className.substringBefore(".")
val innerClassPath = className.substringAfter(".")
return fqn(packageName, outerClassName).appendInner(innerClassPath)
}
else {
return fqn(packageName, className)
}
}
@@ -1,15 +0,0 @@
package com.intellij.workspaceModel.codegen.writer
import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
val ObjClass<*>.javaFullName: QualifiedName
get() = fqn(module.name, name)
val ObjClass<*>.javaBuilderName: String
get() = "$name.Builder"
val ObjClass<*>.javaImplName: String
get() = "${name.replace(".", "")}Impl"
val ObjClass<*>.javaImplBuilderName
get() = "${javaImplName}.Builder"
@@ -1,208 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.writer
import com.intellij.workspaceModel.codegen.writer.classes.*
import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
import com.intellij.workspaceModel.codegen.deft.meta.ObjProperty
import com.intellij.workspaceModel.codegen.deft.meta.OwnProperty
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
import com.intellij.workspaceModel.codegen.engine.GenerationProblem
import com.intellij.workspaceModel.codegen.engine.ProblemLocation
import com.intellij.workspaceModel.codegen.engine.SKIPPED_TYPES
import com.intellij.workspaceModel.codegen.engine.impl.ProblemReporter
import com.intellij.workspaceModel.codegen.writer.fields.javaMutableType
import com.intellij.workspaceModel.codegen.writer.fields.javaType
import com.intellij.workspaceModel.codegen.writer.fields.wsCode
import com.intellij.workspaceModel.codegen.writer.fqn
import com.intellij.workspaceModel.codegen.writer.fqn7
import com.intellij.workspaceModel.codegen.writer.lines
import com.intellij.workspaceModel.codegen.writer.*
import com.intellij.workspaceModel.storage.*
import com.intellij.workspaceModel.storage.impl.containers.toMutableWorkspaceList
import com.intellij.workspaceModel.storage.impl.containers.toMutableWorkspaceSet
import com.intellij.workspaceModel.storage.url.VirtualFileUrl
import org.jetbrains.deft.ObjBuilder
import org.jetbrains.deft.Type
fun ObjClass<*>.generateBuilderCode(reporter: ProblemReporter): String = lines {
checkSuperTypes(this@generateBuilderCode, reporter)
checkSymbolicId(this@generateBuilderCode, reporter)
line("@${GeneratedCodeApiVersion::class.fqn}(${CodeGeneratorVersions.API_VERSION})")
val (typeParameter, typeDeclaration) =
if (openness.extendable) "T" to "<T: $javaFullName>" else javaFullName to ""
val superBuilders = superTypes.filterIsInstance<ObjClass<*>>().filter { !it.isStandardInterface }.joinToString {
", ${it.name}.Builder<$typeParameter>"
}
val header = "interface Builder$typeDeclaration: $javaFullName$superBuilders, ${WorkspaceEntity.Builder::class.fqn}<$typeParameter>, ${ObjBuilder::class.fqn}<$typeParameter>"
section(header) {
list(allFields.noSymbolicId()) {
checkProperty(this, reporter)
wsBuilderApi
}
}
}
fun checkSuperTypes(objClass: ObjClass<*>, reporter: ProblemReporter) {
objClass.superTypes.filterIsInstance<ObjClass<*>>().forEach {superClass ->
if (!superClass.openness.extendable) {
reporter.reportProblem(GenerationProblem("Class '${superClass.name}' cannot be extended", GenerationProblem.Level.ERROR,
ProblemLocation.Class(objClass)))
}
else if (!superClass.openness.openHierarchy && superClass.module != objClass.module) {
reporter.reportProblem(GenerationProblem("Class '${superClass.name}' cannot be extended from other modules",
GenerationProblem.Level.ERROR, ProblemLocation.Class(objClass)))
}
}
}
private fun checkSymbolicId(objClass: ObjClass<*>, reporter: ProblemReporter) {
if (!objClass.isEntityWithSymbolicId) return
if (objClass.openness == ObjClass.Openness.abstract) return
if (objClass.fields.none { it.name == "symbolicId" }) {
reporter.reportProblem(GenerationProblem("Class extends '${WorkspaceEntityWithSymbolicId::class.simpleName}' but " +
"doesn't override 'WorkspaceEntityWithSymbolicId.getSymbolicId' property",
GenerationProblem.Level.ERROR, ProblemLocation.Class(objClass)))
}
}
private fun checkProperty(objProperty: ObjProperty<*, *>, reporter: ProblemReporter) {
checkInheritance(objProperty, reporter)
checkAllImmutable(objProperty, reporter)
checkPropertyType(objProperty, reporter)
}
fun checkInheritance(objProperty: ObjProperty<*, *>, reporter: ProblemReporter) {
objProperty.receiver.allSuperClasses.mapNotNull { it.fieldsByName[objProperty.name] }.forEach { overriddenField ->
if (!overriddenField.open) {
reporter.reportProblem(
GenerationProblem("Property '${overriddenField.receiver.name}::${overriddenField.name}' cannot be overridden",
GenerationProblem.Level.ERROR, ProblemLocation.Property(objProperty)))
}
}
}
private fun checkPropertyType(objProperty: ObjProperty<*, *>, reporter: ProblemReporter) {
val errorMessage = when (val type = objProperty.valueType) {
is ValueType.ObjRef<*> -> {
if (type.child) "Child references should always be nullable"
else null
}
else -> checkType(type)
}
if (errorMessage != null) {
reporter.reportProblem(GenerationProblem(errorMessage, GenerationProblem.Level.ERROR, ProblemLocation.Property(objProperty)))
}
}
fun checkAllImmutable(objProperty: ObjProperty<*, *>, reporter: ProblemReporter) {
if (objProperty.mutable) {
reporter.reportProblem(GenerationProblem("An immutable interface can't contain mutable properties", GenerationProblem.Level.ERROR, ProblemLocation.Property(objProperty)))
}
}
private fun checkType(type: ValueType<*>): String? = when (type) {
is ValueType.Optional -> when (type.type) {
is ValueType.List<*> -> "Optional lists aren't supported"
is ValueType.Set<*> -> "Optional sets aren't supported"
else -> checkType(type.type)
}
is ValueType.Set<*> -> {
if (type.elementType.isRefType()) {
"Set of references isn't supported"
}
else checkType(type.elementType)
}
is ValueType.Map<*, *> -> {
checkType(type.keyType) ?: checkType(type.valueType)
}
is ValueType.Blob<*> -> {
if (!keepUnknownFields && type.javaClassName !in knownInterfaces) {
"Unsupported type '${type.javaClassName}'"
}
else null
}
else -> null
}
private val keepUnknownFields: Boolean
get() = java.lang.Boolean.getBoolean("workspace.model.generator.keep.unknown.fields")
private val knownInterfaces = setOf(
VirtualFileUrl::class.qualifiedName!!,
EntitySource::class.qualifiedName!!,
SymbolicEntityId::class.qualifiedName!!,
)
fun ObjClass<*>.generateCompanionObject(): String = lines {
val builderGeneric = if (openness.extendable) "<$javaFullName>" else ""
val companionObjectHeader = buildString {
append("companion object: ${Type::class.fqn}<$javaFullName, Builder$builderGeneric>(")
val base = superTypes.filterIsInstance<ObjClass<*>>().firstOrNull()
if (base != null && base.name !in SKIPPED_TYPES)
append(base.javaFullName)
append(")")
}
val mandatoryFields = allFields.mandatoryFields()
if (mandatoryFields.isNotEmpty()) {
val fields = mandatoryFields.joinToString { "${it.name}: ${it.valueType.javaType}" }
section(companionObjectHeader) {
line("@${JvmOverloads::class.fqn}")
line("@${JvmStatic::class.fqn}")
line("@${JvmName::class.fqn}(\"create\")")
section("operator fun invoke($fields, init: (Builder$builderGeneric.() -> Unit)? = null): $javaFullName") {
line("val builder = builder()")
list(mandatoryFields) {
if (this.valueType is ValueType.Set<*> && !this.valueType.isRefType()) {
"builder.$name = $name.${fqn7(Collection<*>::toMutableWorkspaceSet)}()"
} else if (this.valueType is ValueType.List<*> && !this.valueType.isRefType()) {
"builder.$name = $name.${fqn7(Collection<*>::toMutableWorkspaceList)}()"
} else {
"builder.$name = $name"
}
}
line("init?.invoke(builder)")
line("return builder")
}
}
}
else {
section(companionObjectHeader) {
line("@${JvmOverloads::class.fqn}")
line("@${JvmStatic::class.fqn}")
line("@${JvmName::class.fqn}(\"create\")")
section("operator fun invoke(init: (Builder$builderGeneric.() -> Unit)? = null): $javaFullName") {
line("val builder = builder()")
line("init?.invoke(builder)")
line("return builder")
}
}
}
}
fun List<OwnProperty<*, *>>.mandatoryFields(): List<ObjProperty<*, *>> {
var fields = this.noRefs().noOptional().noSymbolicId().noDefaultValue()
if (fields.isNotEmpty()) {
fields = fields.noEntitySource() + fields.single { it.name == "entitySource" }
}
return fields
}
fun ObjClass<*>.generateExtensionCode(): String? {
val fields = module.extensions.filter { it.receiver == this || it.receiver.module != module && it.valueType.isRefType() && it.valueType.getRefType().target == this }
if (openness.extendable && fields.isEmpty()) return null
return lines {
if (!openness.extendable) {
line("fun ${MutableEntityStorage::class.fqn}.modifyEntity(entity: $name, modification: $name.Builder.() -> Unit) = modifyEntity($name.Builder::class.java, entity, modification)")
}
fields.sortedWith(compareBy({ it.receiver.name }, { it.name })).forEach { line(it.wsCode) }
}
}
val ObjProperty<*, *>.wsBuilderApi: String
get() {
val returnType = if (valueType is ValueType.Collection<*, *> && !valueType.isRefType()) valueType.javaMutableType else valueType.javaType
return "override var $javaName: $returnType"
}
@@ -1,316 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.writer.classes
import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
import com.intellij.workspaceModel.codegen.deft.meta.ObjProperty
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
import com.intellij.workspaceModel.codegen.writer.fields.javaMutableType
import com.intellij.workspaceModel.codegen.writer.isRefType
import com.intellij.workspaceModel.codegen.writer.LinesBuilder
import com.intellij.workspaceModel.codegen.writer.fqn
import com.intellij.workspaceModel.codegen.writer.lines
import com.intellij.workspaceModel.codegen.writer.toQualifiedName
import com.intellij.workspaceModel.codegen.writer.allFields
import com.intellij.workspaceModel.storage.SymbolicEntityId
import com.intellij.workspaceModel.storage.impl.indices.WorkspaceMutableIndex
internal fun ObjClass<*>.softLinksCode(context: LinesBuilder, hasSoftLinks: Boolean) {
context.conditionalLine({ hasSoftLinks }, "override fun getLinks(): Set<${SymbolicEntityId::class.fqn}<*>>") {
line("val result = HashSet<${SymbolicEntityId::class.fqn}<*>>()")
operate(this) { line("result.add($it)") }
line("return result")
}
context.conditionalLine(
{ hasSoftLinks },
"override fun index(index: ${WorkspaceMutableIndex::class.fqn}<${SymbolicEntityId::class.fqn}<*>>)"
) {
operate(this) { line("index.index(this, $it)") }
}
context.conditionalLine(
{ hasSoftLinks },
"override fun updateLinksIndex(prev: Set<${SymbolicEntityId::class.fqn}<*>>, index: ${WorkspaceMutableIndex::class.fqn}<${SymbolicEntityId::class.fqn}<*>>)"
) {
line("// TODO verify logic")
line("val mutablePreviousSet = HashSet(prev)")
operate(this) {
line("val removedItem_${it.clean()} = mutablePreviousSet.remove($it)")
section("if (!removedItem_${it.clean()})") {
line("index.index(this, $it)")
}
}
section("for (removed in mutablePreviousSet)") {
line("index.remove(this, removed)")
}
}
context.conditionalLine(
{ hasSoftLinks },
"override fun updateLink(oldLink: ${SymbolicEntityId::class.fqn}<*>, newLink: ${SymbolicEntityId::class.fqn}<*>): Boolean"
) {
line("var changed = false")
operateUpdateLink(this)
line("return changed")
}
}
internal fun ObjClass<*>.hasSoftLinks(): Boolean {
return fields.noSymbolicId().noRefs().any { field ->
field.hasSoftLinks()
}
}
internal fun ObjProperty<*, *>.hasSoftLinks(): Boolean {
if (name == "symbolicId") return false
return valueType.hasSoftLinks()
}
internal fun ValueType<*>.hasSoftLinks(): Boolean = when (this) {
is ValueType.Blob -> isSymbolicId
is ValueType.Collection<*, *> -> elementType.hasSoftLinks()
is ValueType.Optional<*> -> type.hasSoftLinks()
is ValueType.SealedClass<*> -> isSymbolicId || subclasses.any { it.hasSoftLinks() }
is ValueType.DataClass<*> -> isSymbolicId || properties.any { it.type.hasSoftLinks() }
else -> false
}
val ValueType.JvmClass<*>.isSymbolicId: Boolean
get() = SymbolicEntityId::class.java.name in javaSuperClasses
private fun ObjClass<*>.operate(
context: LinesBuilder,
operation: LinesBuilder.(String) -> Unit
) {
allFields.noSymbolicId().noRefs().forEach { field ->
field.valueType.operate(field.name, context, operation)
}
}
private fun ValueType<*>.operate(
varName: String,
context: LinesBuilder,
operation: LinesBuilder.(String) -> Unit,
generateNewName: Boolean = true,
) {
when (this) {
is ValueType.JvmClass -> {
when {
isSymbolicId -> context.operation(varName)
this is ValueType.SealedClass<*> -> processSealedClass(this, varName, context, operation, generateNewName)
this is ValueType.DataClass<*> -> processDataClassProperties(varName, context, properties, operation)
}
}
is ValueType.Collection<*, *> -> {
val elementType = elementType
context.section("for (item in ${varName})") {
elementType.operate("item", this@section, operation, false)
}
}
is ValueType.Optional<*> -> {
if (type is ValueType.JvmClass && (type as ValueType.JvmClass<*>).isSymbolicId) {
context.line("val optionalLink_${varName.clean()} = $varName")
context.`if`("optionalLink_${varName.clean()} != null") label@{
type.operate("optionalLink_${varName.clean()}", this@label, operation)
}
}
}
else -> Unit
}
}
private fun processDataClassProperties(varName: String,
context: LinesBuilder,
dataClassProperties: List<ValueType.DataClassProperty>,
operation: LinesBuilder.(String) -> Unit) {
for (property in dataClassProperties) {
property.type.operate("$varName.${property.name}", context, operation)
}
}
private fun processSealedClass(thisClass: ValueType.SealedClass<*>,
varName: String,
context: LinesBuilder,
operation: LinesBuilder.(String) -> Unit,
generateNewName: Boolean = true) {
val newVarName = if (generateNewName) "_${varName.clean()}" else varName
if (generateNewName) context.line("val $newVarName = $varName")
context.section("when ($newVarName)") {
listBuilder(thisClass.subclasses) { item ->
val linesBuilder = LinesBuilder(StringBuilder(), context.indentLevel+1, context.indentSize).wrapper()
if (item is ValueType.SealedClass) {
processSealedClass(item, newVarName, linesBuilder, operation, generateNewName)
}
else if (item is ValueType.DataClass) {
processDataClassProperties(newVarName, linesBuilder, item.properties, operation)
}
section("is ${item.javaClassName.toQualifiedName()} -> ") {
result.append(linesBuilder.result)
}
}
}
}
private fun ObjClass<*>.operateUpdateLink(context: LinesBuilder) {
allFields.noSymbolicId().noRefs().forEach { field ->
val retType = field.valueType.processType(context, field.name)
if (retType != null) {
context.`if`("$retType != null") {
if (field.valueType is ValueType.Set<*> && !field.valueType.isRefType()) {
line("${field.name} = $retType as ${field.valueType.javaMutableType}")
} else if (field.valueType is ValueType.List<*> && !field.valueType.isRefType()) {
line("${field.name} = $retType as ${field.valueType.javaMutableType}")
} else {
line("${field.name} = $retType")
}
}
}
}
}
private fun ValueType<*>.processType(
context: LinesBuilder,
varName: String,
): String? {
return when (this) {
is ValueType.JvmClass -> {
when {
isSymbolicId -> {
val name = "${varName.clean()}_data"
context.lineNoNl("val $name = ")
context.ifElse("$varName == oldLink", {
line("changed = true")
line("newLink as ${javaClassName.toQualifiedName()}")
}) { line("null") }
name
}
this is ValueType.SealedClass<*> -> {
processSealedClass(this, varName, context)
}
this is ValueType.DataClass<*> -> {
val updates = properties.mapNotNull label@{
val retVar = it.type.processType(
context,
"$varName.${it.name}"
)
if (retVar != null) it.name to retVar else null
}
if (updates.isEmpty()) {
null
}
else {
val name = "${varName.clean()}_data"
context.line("var $name = $varName")
updates.forEach { (fieldName, update) ->
context.`if`("$update != null") {
line("$name = $name.copy($fieldName = $update)")
}
}
name
}
}
else -> null
}
}
is ValueType.Collection<*, *> -> {
var name: String? = "${varName.clean()}_data"
val builder = lines(context.indentLevel) {
section("val $name = $varName.map") label@{
val returnVar = elementType.processType(
this@label,
"it"
)
if (returnVar != null) {
ifElse("$returnVar != null", {
line(returnVar)
}) { line("it") }
}
else {
name = null
}
}
}
if (name != null) {
context.result.append(builder)
}
name
}
is ValueType.Optional<*> -> {
var name: String? = "${varName.clean()}_data_optional"
val builder = lines(context.indentLevel) {
lineNoNl("var $name = ")
ifElse("$varName != null", labelIf@{
val returnVar = type.processType(
this@labelIf,
"$varName!!"
)
if (returnVar != null) {
line(returnVar)
}
else {
name = null
}
}) { line("null") }
}
if (name != null) {
context.result.append(builder)
}
name
}
else -> return null
}
}
private fun processSealedClass(thisClass: ValueType.SealedClass<*>,
varName: String,
context: LinesBuilder): String {
val newVarName = "_${varName.clean()}"
val resVarName = "res_${varName.clean()}"
context.line("val $newVarName = $varName")
context.lineNoNl("val $resVarName = ")
context.section("when ($newVarName)") {
listBuilder(thisClass.subclasses) { item ->
section("is ${item.javaClassName.toQualifiedName()} -> ") label@{
var sectionVarName = newVarName
val properties: List<ValueType.DataClassProperty>
if (item is ValueType.SealedClass) {
sectionVarName = processSealedClass(item, sectionVarName, this)
properties = emptyList()
}
else if (item is ValueType.DataClass) {
properties = item.properties
}
else {
properties = emptyList()
}
val updates = properties.mapNotNull {
val retVar = it.type.processType(
this@label,
"$sectionVarName.${it.name}"
)
if (retVar != null) it.name to retVar else null
}
if (updates.isEmpty()) {
line(sectionVarName)
}
else {
val name = "${sectionVarName.clean()}_data"
line("var $name = $sectionVarName")
updates.forEach { (fieldName, update) ->
`if`("$update != null") {
line("$name = $name.copy($fieldName = $update)")
}
}
line(name)
}
}
}
}
return resVarName
}
private fun String.clean(): String {
return this.replace(".", "_").replace('!', '_')
}
@@ -1,335 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.writer.classes
import com.intellij.workspaceModel.codegen.*
import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
import com.intellij.workspaceModel.codegen.deft.meta.ObjProperty
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
import com.intellij.workspaceModel.codegen.writer.fields.implWsDataFieldCode
import com.intellij.workspaceModel.codegen.writer.fields.implWsDataFieldInitializedCode
import com.intellij.workspaceModel.codegen.writer.fields.javaType
import com.intellij.workspaceModel.codegen.writer.*
import com.intellij.workspaceModel.codegen.writer.allFields
import com.intellij.workspaceModel.storage.*
import com.intellij.workspaceModel.storage.impl.SoftLinkable
import com.intellij.workspaceModel.storage.impl.UsedClassesCollector
import com.intellij.workspaceModel.storage.impl.WorkspaceEntityData
import com.intellij.workspaceModel.storage.impl.containers.toMutableWorkspaceList
import com.intellij.workspaceModel.storage.impl.containers.toMutableWorkspaceSet
import com.intellij.workspaceModel.storage.url.VirtualFileUrl
/**
* - Soft links
* - with SymbolicId
*/
val ObjClass<*>.javaDataName
get() = "${name.replace(".", "")}Data"
val ObjClass<*>.isEntityWithSymbolicId: Boolean
get() = superTypes.any {
it is ObjClass<*> && (it.javaFullName.decoded == WorkspaceEntityWithSymbolicId::class.java.name || it.isEntityWithSymbolicId)
}
fun ObjClass<*>.implWsDataClassCode(): String {
val entityDataBaseClass = if (isEntityWithSymbolicId) {
"${WorkspaceEntityData::class.fqn}.WithCalculableSymbolicId<$javaFullName>()"
}
else {
"${WorkspaceEntityData::class.fqn}<$javaFullName>()"
}
val hasSoftLinks = hasSoftLinks()
val softLinkable = if (hasSoftLinks) SoftLinkable::class.fqn else null
return lines {
section("class $javaDataName : ${sups(entityDataBaseClass, softLinkable?.encodedString)}") label@{
listNl(allFields.noRefs().noEntitySource().noSymbolicId()) { implWsDataFieldCode }
listNl(allFields.noRefs().noEntitySource().noSymbolicId().noOptional().noDefaultValue()) { implWsDataFieldInitializedCode }
this@implWsDataClassCode.softLinksCode(this, hasSoftLinks)
sectionNl(
"override fun wrapAsModifiable(diff: ${MutableEntityStorage::class.fqn}): ${WorkspaceEntity.Builder::class.fqn}<$javaFullName>") {
line("val modifiable = $javaImplBuilderName(null)")
line("modifiable.diff = diff")
line("modifiable.snapshot = diff")
line("modifiable.id = createEntityId()")
line("return modifiable")
}
// --- createEntity
sectionNl("override fun createEntity(snapshot: ${EntityStorage::class.fqn}): $javaFullName") {
section("return getCached(snapshot)") {
line("val entity = $javaImplName(this)")
line("entity.snapshot = snapshot")
line("entity.id = createEntityId()")
line("entity")
}
}
val collectionFields = allFields.noRefs().filter { it.valueType is ValueType.Collection<*, *> }
if (collectionFields.isNotEmpty()) {
sectionNl("override fun clone(): $javaDataName") {
val fieldName = "clonedEntity"
line("val $fieldName = super.clone()")
line("$fieldName as $javaDataName")
collectionFields.forEach { field ->
if (field.valueType is ValueType.Set<*>) {
line("$fieldName.${field.name} = $fieldName.${field.name}.${fqn7(Collection<*>::toMutableWorkspaceSet)}()")
} else {
line("$fieldName.${field.name} = $fieldName.${field.name}.${fqn7(Collection<*>::toMutableWorkspaceList)}()")
}
}
line("return $fieldName")
}
}
if (isEntityWithSymbolicId) {
val symbolicIdField = fields.first { it.name == "symbolicId" }
val valueKind = symbolicIdField.valueKind
val methodBody = (valueKind as ObjProperty.ValueKind.Computable).expression
if (methodBody.contains("return")) {
if (methodBody.startsWith("{")) {
line("override fun symbolicId(): ${SymbolicEntityId::class.fqn}<*> $methodBody \n")
} else {
sectionNl("override fun symbolicId(): ${SymbolicEntityId::class.fqn}<*>") {
line(methodBody)
}
}
} else {
sectionNl("override fun symbolicId(): ${SymbolicEntityId::class.fqn}<*>") {
if (methodBody.startsWith("=")) {
line("return ${methodBody.substring(2)}")
}
else {
line("return $methodBody")
}
}
}
}
// --- getEntityInterface method
sectionNl("override fun getEntityInterface(): Class<out ${WorkspaceEntity::class.fqn}>") {
line("return $name::class.java")
}
sectionNl("override fun serialize(ser: ${EntityInformation.Serializer::class.fqn})") {
//InterfaceTraverser(simpleTypes).traverse(this@implWsDataClassCode, SerializatorVisitor(this@sectionNl))
}
sectionNl("override fun deserialize(de: ${EntityInformation.Deserializer::class.fqn})") {
//InterfaceTraverser(simpleTypes).traverse(this@implWsDataClassCode, DeserializationVisitor(this@sectionNl))
}
sectionNl("override fun createDetachedEntity(parents: List<${WorkspaceEntity::class.fqn}>): ${WorkspaceEntity::class.fqn}") {
val noRefs = allFields.noRefs().noSymbolicId()
val mandatoryFields = allFields.mandatoryFields()
val constructor = mandatoryFields.joinToString(", ") { it.name }.let { if (it.isNotBlank()) "($it)" else "" }
val optionalFields = noRefs.filterNot { it in mandatoryFields }
section("return $javaFullName$constructor") {
optionalFields.forEach {
line("this.${it.name} = this@$javaDataName.${it.name}")
}
allRefsFields.filterNot { it.valueType.getRefType().child }.forEach {
val parentType = it.valueType
if (parentType is ValueType.Optional) {
line("this.${it.name} = parents.filterIsInstance<${parentType.type.javaType}>().singleOrNull()")
} else {
line("parents.filterIsInstance<${parentType.javaType}>().singleOrNull()?.let { this.${it.name} = it }")
}
}
}
}
sectionNl("override fun getRequiredParents(): List<Class<out WorkspaceEntity>>") {
line("val res = mutableListOf<Class<out WorkspaceEntity>>()")
allRefsFields.filterNot { it.valueType.getRefType().child }.forEach {
val parentType = it.valueType
if (parentType !is ValueType.Optional) {
line("res.add(${parentType.javaType}::class.java)")
}
}
line("return res")
}
// --- equals
val keyFields = allFields.filter { it.isKey }
sectionNl("override fun equals(other: Any?): Boolean") {
line("if (other == null) return false")
line("if (this.javaClass != other.javaClass) return false")
lineWrapped("other as $javaDataName")
list(allFields.noRefs().noSymbolicId()) {
"if (this.$name != other.$name) return false"
}
line("return true")
}
// --- equalsIgnoringEntitySource
sectionNl("override fun equalsIgnoringEntitySource(other: Any?): Boolean") {
line("if (other == null) return false")
line("if (this.javaClass != other.javaClass) return false")
lineWrapped("other as $javaDataName")
list(allFields.noRefs().noEntitySource().noSymbolicId()) {
"if (this.$name != other.$name) return false"
}
line("return true")
}
// --- hashCode
section("override fun hashCode(): Int") {
line("var result = entitySource.hashCode()")
list(allFields.noRefs().noEntitySource().noSymbolicId()) {
"result = 31 * result + $name.hashCode()"
}
line("return result")
}
// --- hashCodeIgnoringEntitySource
section("override fun hashCodeIgnoringEntitySource(): Int") {
line("var result = javaClass.hashCode()")
list(allFields.noRefs().noEntitySource().noSymbolicId()) {
"result = 31 * result + $name.hashCode()"
}
line("return result")
}
if (keyFields.isNotEmpty()) {
line()
section("override fun equalsByKey(other: Any?): Boolean") {
line("if (other == null) return false")
line("if (this.javaClass != other.javaClass) return false")
lineWrapped("other as $javaDataName")
list(keyFields) {
"if (this.$name != other.$name) return false"
}
line("return true")
}
line()
section("override fun hashCodeByKey(): Int") {
line("var result = javaClass.hashCode()")
list(keyFields) {
"result = 31 * result + $name.hashCode()"
}
line("return result")
}
}
cacheCollector(this@lines)
}
}
}
fun List<ObjProperty<*, *>>.noRefs(): List<ObjProperty<*, *>> = this.filterNot { it.valueType.isRefType() }
fun List<ObjProperty<*, *>>.noEntitySource() = this.filter { it.name != "entitySource" }
fun List<ObjProperty<*, *>>.noSymbolicId() = this.filter { it.name != "symbolicId" }
fun List<ObjProperty<*, *>>.noOptional() = this.filter { it.valueType !is ValueType.Optional<*> }
fun List<ObjProperty<*, *>>.noDefaultValue() = this.filter { it.valueKind == ObjProperty.ValueKind.Plain }
private fun ObjClass<*>.cacheCollector(linesBuilder: LinesBuilder) {
val clazzes = HashSet<String>()
val accessors = HashSet<String>()
val objects = HashSet<String>()
val res = allFields.map {
it.valueType.getClasses(it.name, clazzes, accessors, objects)
}.all{ it }
linesBuilder.section("override fun collectClassUsagesData(collector: ${UsedClassesCollector::class.fqn})") {
clazzes.forEach {
line("collector.add(${it.toQualifiedName()}::class.java)")
}
objects.forEach {
line("collector.addObject(${it.toQualifiedName()}::class.java)")
}
accessors.forEach {
line(it)
}
line("collector.sameForAllEntities = $res")
}
}
private fun ValueType<*>.getClasses(fieldName: String, clazzes: HashSet<String>, accessors: HashSet<String>, objects: HashSet<String>): Boolean {
var res = true
when (this) {
is ValueType.List<*> -> {
if (!this.isRefType()) {
accessors.add("this.$fieldName?.let { collector.add(it::class.java) }")
res = false
}
this.elementType.getClasses(fieldName, clazzes, accessors, objects)
return res
}
is ValueType.Set<*> -> {
if (!this.isRefType()) {
accessors.add("this.$fieldName?.let { collector.add(it::class.java) }")
res = false
}
this.elementType.getClasses(fieldName, clazzes, accessors, objects)
return res
}
is ValueType.Blob -> {
val className = this.javaClassName
if (className !in setOf(VirtualFileUrl::class.java.name, EntitySource::class.java.name, SymbolicEntityId::class.java.name)) {
accessors.add("this.$fieldName?.let { collector.addDataToInspect(it) }")
return res
}
if (className == VirtualFileUrl::class.java.name) {
accessors.add("this.$fieldName?.let { collector.add(it::class.java) }")
return false
}
return true
}
is ValueType.Enum -> {
val className = this.javaClassName
clazzes.add(className)
return res
}
is ValueType.DataClass -> {
// Here we might filter SymbolicIds and get them from the index, but in this case we would need to inspect their fields on the fly
// Here we have all the information about the symbolic ids and it's fields, so let's keep them here (at least for a while).
clazzes.add(javaClassName)
properties.forEach { property ->
property.type.getClasses(fieldName, clazzes, accessors, objects)
}
return true
}
is ValueType.SealedClass -> {
clazzes.add(javaClassName)
this.subclasses.forEach { subclass ->
subclass.getClasses(fieldName, clazzes, accessors, objects)
}
return true
}
is ValueType.Map<*, *> -> {
if (!this.isRefType()) {
accessors.add("this.$fieldName?.let { collector.add(it::class.java) }")
res = false
}
this.keyType.getClasses(fieldName, clazzes, accessors, objects)
this.valueType.getClasses(fieldName, clazzes, accessors, objects)
return res
}
is ValueType.Optional -> {
return this.type.getClasses(fieldName, clazzes, accessors, objects)
}
is ValueType.Structure -> {
this.fields.forEach {
it.getClasses(fieldName, clazzes, accessors, objects)
}
return true
}
is ValueType.Object<*> -> {
objects.add(javaClassName)
return true
}
else -> return true
}
}
@@ -1,132 +0,0 @@
package com.intellij.workspaceModel.codegen.writer.classes
import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
import com.intellij.workspaceModel.codegen.writer.*
import com.intellij.workspaceModel.codegen.writer.fields.implWsBuilderFieldCode
import com.intellij.workspaceModel.codegen.writer.fields.implWsBuilderIsInitializedCode
import com.intellij.workspaceModel.storage.MutableEntityStorage
import com.intellij.workspaceModel.storage.WorkspaceEntity
import com.intellij.workspaceModel.storage.bridgeEntities.LibraryEntity
import com.intellij.workspaceModel.storage.impl.ConnectionId
import com.intellij.workspaceModel.storage.impl.ModifiableWorkspaceEntityBase
import com.intellij.workspaceModel.storage.impl.containers.MutableWorkspaceList
import com.intellij.workspaceModel.storage.impl.containers.MutableWorkspaceSet
fun ObjClass<*>.implWsEntityBuilderCode(): String {
return """
class Builder(result: $javaDataName?): ${ModifiableWorkspaceEntityBase::class.fqn}<$javaFullName, $javaDataName>(result), $javaBuilderName {
constructor(): this($javaDataName())
${
lines(2) {
section("override fun applyToBuilder(builder: ${MutableEntityStorage::class.fqn})") {
`if`("this.diff != null") {
ifElse("existsInBuilder(builder)", {
line("this.diff = builder")
line("return")
}) {
line("error(\"Entity $name is already created in a different builder\")")
}
}
line()
line("this.diff = builder")
line("this.snapshot = builder")
line("addToBuilder()")
line("this.id = getEntityData().createEntityId()")
lineComment("After adding entity data to the builder, we need to unbind it and move the control over entity data to builder")
lineComment("Builder may switch to snapshot at any moment and lock entity data to modification")
line("this.currentEntityData = null")
line()
list(vfuFields) {
"index(this, \"$name\", this.$name)"
}
if (name == LibraryEntity::class.simpleName) {
line("indexLibraryRoots(${LibraryEntity::roots.name})")
}
lineComment("Process linked entities that are connected without a builder")
line("processLinkedEntities(builder)")
//------------
line("checkInitialization() // TODO uncomment and check failed tests")
}
result.append("\n")
section("fun checkInitialization()") {
line("val _diff = diff")
list(allFields.noSymbolicId().noOptional().noDefaultValue()) { lineBuilder, field ->
lineBuilder.implWsBuilderIsInitializedCode(field)
}
}
line()
section("override fun connectionIdList(): List<${ConnectionId::class.fqn}>") {
line("return connections")
}
line()
val collectionFields = allFields.noRefs().filter { it.valueType is ValueType.Collection<*,*> }
if (collectionFields.isNotEmpty()) {
section("override fun afterModification()") {
collectionFields.forEach { field ->
line("val collection_${field.javaName} = getEntityData().${field.javaName}")
if (field.valueType is ValueType.List<*>) {
`if`("collection_${field.javaName} is ${MutableWorkspaceList::class.fqn}<*>") {
line("collection_${field.javaName}.cleanModificationUpdateAction()")
}
}
if (field.valueType is ValueType.Set<*>) {
`if`("collection_${field.javaName} is ${MutableWorkspaceSet::class.fqn}<*>") {
line("collection_${field.javaName}.cleanModificationUpdateAction()")
}
}
}
}
line()
}
lineComment("Relabeling code, move information from dataSource to this builder")
section("override fun relabel(dataSource: ${WorkspaceEntity::class.fqn}, parents: Set<WorkspaceEntity>?)") {
line("dataSource as $javaFullName")
list(allFields.noSymbolicId().noRefs()) { lineBuilder, field ->
var type = field.valueType
var qm = ""
if (type is ValueType.Optional<*>) {
qm = "?"
type = type.type
}
when (type) {
is ValueType.List<*> -> lineBuilder.line("if (this.${field.name} != dataSource${qm}.${field.name}) this.${field.name} = dataSource${qm}.${field.name}${qm}.toMutableList()")
is ValueType.Set<*> -> lineBuilder.line("if (this.${field.name} != dataSource${qm}.${field.name}) this.${field.name} = dataSource${qm}.${field.name}${qm}.toMutableSet()")
is ValueType.Map<*, *> -> lineBuilder.line("if (this.${field.name} != dataSource${qm}.${field.name}) this.${field.name} = dataSource${qm}.${field.name}${qm}.toMutableMap()")
else -> lineBuilder.line("if (this.${field.name} != dataSource${qm}.${field.name}) this.${field.name} = dataSource.${field.name}")
}
}
line("updateChildToParentReferences(parents)")
}
if (name == LibraryEntity::class.simpleName) {
section("private fun indexLibraryRoots(libraryRoots: List<LibraryRoot>)") {
line("val jarDirectories = mutableSetOf<VirtualFileUrl>()")
line("val libraryRootList = libraryRoots.map {")
line(" if (it.inclusionOptions != LibraryRoot.InclusionOptions.ROOT_ITSELF) {")
line(" jarDirectories.add(it.url)")
line(" }")
line(" it.url")
line("}.toHashSet()")
line("index(this, \"roots\", libraryRootList)")
line("indexJarDirectories(this, jarDirectories)")
}
}
}
}
${allFields.filter { it.name != "symbolicId" }.lines(" ") { implWsBuilderFieldCode }.trimEnd()}
override fun getEntityClass(): Class<$javaFullName> = $javaFullName::class.java
}
""".trimIndent()
}
@@ -1,52 +0,0 @@
package com.intellij.workspaceModel.codegen.writer.classes
import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
import com.intellij.workspaceModel.codegen.writer.*
import com.intellij.workspaceModel.codegen.writer.fields.implWsEntityFieldCode
import com.intellij.workspaceModel.codegen.writer.fields.refsConnectionId
import com.intellij.workspaceModel.codegen.writer.fields.refsConnectionIdCode
import com.intellij.workspaceModel.storage.CodeGeneratorVersions
import com.intellij.workspaceModel.storage.GeneratedCodeApiVersion
import com.intellij.workspaceModel.storage.GeneratedCodeImplVersion
import com.intellij.workspaceModel.storage.impl.ConnectionId
import com.intellij.workspaceModel.storage.impl.WorkspaceEntityBase
fun ObjClass<*>.implWsEntityCode(): String {
return """
package ${module.name}
@${GeneratedCodeApiVersion::class.fqn}(${CodeGeneratorVersions.API_VERSION})
@${GeneratedCodeImplVersion::class.fqn}(${CodeGeneratorVersions.IMPL_VERSION})
${if (openness.instantiatable) "open" else "abstract"} class $javaImplName(val dataSource: $javaDataName): $javaFullName, ${WorkspaceEntityBase::class.fqn}() {
${
"""
companion object {
${allRefsFields.lines(" ") { refsConnectionIdCode }.trimEnd()}
${getLinksOfConnectionIds(this)}
}"""
}
${allFields.filter { it.name !in listOf("entitySource", "symbolicId") }.lines(" ") { implWsEntityFieldCode }.trimEnd()}
override val entitySource: EntitySource
get() = dataSource.entitySource
override fun connectionIdList(): List<${ConnectionId::class.fqn}> {
return connections
}
${implWsEntityBuilderCode().indentRestOnly(" ")}
}
""".trimIndent()
}
private fun getLinksOfConnectionIds(type: ObjClass<*>): String {
return lines(2) {
line("val connections = listOf<${ConnectionId::class.fqn}>(")
type.allRefsFields.forEach {
line(" " + it.refsConnectionId + ",")
}
line(")")
}
}
@@ -1,63 +0,0 @@
package com.intellij.workspaceModel.codegen.writer.classes
import com.intellij.workspaceModel.codegen.writer.LinesBuilder
internal fun LinesBuilder.lineWrapped(str: String) {
line()
line(str)
line()
}
internal fun LinesBuilder.sectionNl(head: String, s: LinesBuilder.() -> Unit) {
section(head, s)
result.append("\n")
}
internal fun LinesBuilder.conditionalLine(predicate: () -> Boolean, head: String, s: LinesBuilder.() -> Unit) {
if (predicate.invoke()) {
section(head, s)
result.append("\n")
}
}
internal fun <T> LinesBuilder.listNl(c: Collection<T>, f: T.() -> String = { "$this" }) {
list(c, f)
result.append("\n")
}
internal fun <T> LinesBuilder.list(c: Collection<T>, func: (LinesBuilder, T) -> Unit) {
c.forEach {
func(this, it)
}
}
internal fun LinesBuilder.`if`(condition: String, s: LinesBuilder.() -> Unit) {
section("if ($condition)", s)
}
internal fun LinesBuilder.lineComment(text: String) {
line("// $text")
}
internal fun LinesBuilder.`for`(condition: String, s: LinesBuilder.() -> Unit) {
section("for ($condition)", s)
}
internal fun LinesBuilder.`else`(s: LinesBuilder.() -> Unit) {
section("else", s)
}
internal fun LinesBuilder.ifElse(condition: String, s: LinesBuilder.() -> Unit, `else`: (LinesBuilder.() -> Unit)) {
section("if ($condition)", s)
section("else", `else`)
}
internal fun <T> LinesBuilder.listBuilder(c: Collection<T>, f: LinesBuilder.(item: T) -> Unit) {
c.forEach {
this.f(it)
}
}
internal fun LinesBuilder.wrapper(): LinesBuilder {
return LinesBuilder(result, indentLevel+1, indentSize)
}
@@ -1,32 +0,0 @@
package com.intellij.workspaceModel.codegen.writer.fields
import com.intellij.workspaceModel.codegen.writer.javaFullName
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
import com.intellij.workspaceModel.codegen.writer.QualifiedName
import com.intellij.workspaceModel.codegen.writer.toQualifiedName
val ValueType<*>.javaType: QualifiedName
get() = when (this) {
ValueType.Boolean -> "Boolean".toQualifiedName()
ValueType.Int -> "Int".toQualifiedName()
ValueType.String -> "String".toQualifiedName()
is ValueType.List<*> -> "List".toQualifiedName().appendSuffix("<${elementType.javaType}>")
is ValueType.Set<*> -> "Set".toQualifiedName().appendSuffix("<${elementType.javaType}>")
is ValueType.Map<*, *> -> "Map".toQualifiedName().appendSuffix("<${keyType.javaType}, ${valueType.javaType}>")
is ValueType.ObjRef -> target.javaFullName
is ValueType.Optional<*> -> type.javaType.appendSuffix("?")
is ValueType.JvmClass -> javaClassName.toQualifiedName()
else -> throw UnsupportedOperationException("$this type isn't supported")
}
val ValueType<*>.javaMutableType: QualifiedName
get() = when (this) {
is ValueType.List<*> -> "MutableList".toQualifiedName().appendSuffix("<${elementType.javaType}>")
is ValueType.Set<*> -> "MutableSet".toQualifiedName().appendSuffix("<${elementType.javaType}>")
is ValueType.Map<*, *> -> "MutableMap".toQualifiedName().appendSuffix("<${keyType.javaType}, ${valueType.javaType}>")
is ValueType.Optional<*> -> type.javaMutableType.appendSuffix("?")
else -> javaType
}
fun ValueType<*>.unsupportedTypeError(): Nothing = error("Unsupported field type: $this")
@@ -1,103 +0,0 @@
package com.intellij.workspaceModel.codegen.writer.fields
import com.intellij.workspaceModel.storage.EntityStorage
import com.intellij.workspaceModel.storage.impl.*
import com.intellij.workspaceModel.codegen.writer.getRefType
import com.intellij.workspaceModel.codegen.writer.refsFields
import com.intellij.workspaceModel.codegen.writer.*
import com.intellij.workspaceModel.codegen.deft.meta.ObjProperty
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
val ObjProperty<*, *>.refsConnectionId: String
get() = if (name == "parent") {
val originalField = receiver.refsFields.first { it.valueType.javaType == valueType.javaType }
"${originalField.name.uppercase()}_CONNECTION_ID"
}
else "${name.uppercase()}_CONNECTION_ID"
val ObjProperty<*, *>.refsConnectionIdCode: String
get() = buildString {
val ref = valueType.getRefType()
val isListType = valueType is ValueType.List<*> || ((valueType as? ValueType.Optional<*>)?.type is ValueType.List<*>)
append("internal val $refsConnectionId: ${ConnectionId::class.fqn} = ConnectionId.create(")
if (ref.child) {
append("${receiver.name}::class.java, ${ref.javaType}::class.java,")
}
else {
append("${ref.javaType}::class.java, ${receiver.name}::class.java,")
}
val isParentNullable = if (ref.child) {
if (isListType) {
if (ref.target.openness.extendable) {
append(" ConnectionId.ConnectionType.ONE_TO_ABSTRACT_MANY,")
}
else {
append(" ConnectionId.ConnectionType.ONE_TO_MANY,")
}
}
else {
if (ref.target.openness.extendable) {
append(" ConnectionId.ConnectionType.ABSTRACT_ONE_TO_ONE,")
}
else {
append(" ConnectionId.ConnectionType.ONE_TO_ONE,")
}
}
referencedField.valueType is ValueType.Optional<*>
}
else {
val declaredReferenceFromParent = referencedField
var valueType = declaredReferenceFromParent.valueType
if (valueType is ValueType.Optional<*>) {
valueType = valueType.type
}
if (valueType is ValueType.List<*>) {
if (receiver.openness.extendable) {
append(" ConnectionId.ConnectionType.ONE_TO_ABSTRACT_MANY,")
}
else {
append(" ConnectionId.ConnectionType.ONE_TO_MANY,")
}
}
else if (valueType is ValueType.ObjRef<*>) {
if (receiver.openness.extendable) {
append(" ConnectionId.ConnectionType.ABSTRACT_ONE_TO_ONE,")
}
else {
append(" ConnectionId.ConnectionType.ONE_TO_ONE,")
}
}
this@refsConnectionIdCode.valueType is ValueType.Optional<*>
}
append(" $isParentNullable)")
}
fun ObjProperty<*, *>.refsConnectionMethodCode(genericType: String = ""): String {
val ref = valueType.getRefType()
val connectionName = name.uppercase() + "_CONNECTION_ID"
val getterName = if (ref.child) {
if (ref.target.openness.extendable)
"${fqn1(EntityStorage::extractOneToAbstractOneChild)}$genericType"
else
"${fqn1(EntityStorage::extractOneToOneChild)}$genericType"
}
else {
var valueType = referencedField.valueType
if (valueType is ValueType.Optional<*>) {
valueType = valueType.type
}
when (valueType) {
is ValueType.List<*> -> if (receiver.openness.extendable)
"${fqn1(EntityStorage::extractOneToAbstractManyParent)}$genericType"
else
"${fqn1(EntityStorage::extractOneToManyParent)}$genericType"
is ValueType.ObjRef<*> -> if (receiver.openness.extendable)
"${fqn1(EntityStorage::extractOneToAbstractOneParent)}$genericType"
else
"${fqn1(EntityStorage::extractOneToOneParent)}$genericType"
else -> error("Unsupported reference type")
}
}
return "$getterName($connectionName, this)"
}
@@ -1,79 +0,0 @@
package com.intellij.workspaceModel.codegen.writer.fields
import com.intellij.workspaceModel.codegen.deft.meta.ObjProperty
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
import com.intellij.workspaceModel.codegen.writer.isRefType
import com.intellij.workspaceModel.codegen.writer.hasSetter
import com.intellij.workspaceModel.codegen.writer.isOverride
import com.intellij.workspaceModel.codegen.writer.javaName
val ObjProperty<*, *>.implWsDataFieldCode: String
get() = buildString {
if (hasSetter) {
if (isOverride && name !in listOf("name", "entitySource")) append(implWsBlockingCodeOverride)
else append(implWsDataBlockingCode)
}
else {
val expression = when (val kind = valueKind) {
is ObjProperty.ValueKind.Computable -> kind.expression
is ObjProperty.ValueKind.WithDefault -> kind.value
else -> error(kind)
}
if (expression.startsWith("=")) {
append("var $javaName: ${valueType.javaType} $expression")
} else {
append("var $javaName: ${valueType.javaType} = $expression")
}
}
}
private val ObjProperty<*, *>.implWsDataBlockingCode: String
get() = implWsDataBlockCode(valueType, name)
private fun ObjProperty<*, *>.implWsDataBlockCode(fieldType: ValueType<*>, name: String, isOptional: Boolean = false): String {
return when (fieldType) {
ValueType.Int -> "var $javaName: ${fieldType.javaType} = 0"
ValueType.Boolean -> "var $javaName: ${fieldType.javaType} = false"
ValueType.String -> "lateinit var $javaName: String"
is ValueType.ObjRef<*> -> error("Reference type at EntityData not supported")
is ValueType.Collection<*, *> -> {
if (fieldType.isRefType()) error("Reference type at EntityData not supported")
if (!isOptional) {
"lateinit var $javaName: ${fieldType.javaMutableType}"
}
else {
"var $javaName: ${fieldType.javaMutableType}? = null"
}
}
is ValueType.Map<*, *> -> {
if (!isOptional) {
"lateinit var $javaName: ${fieldType.javaType}"
}
else {
"var $javaName: ${fieldType.javaType}? = null"
}
}
is ValueType.Optional<*> -> when (fieldType.type) {
ValueType.Int, ValueType.Boolean, ValueType.String -> "var $javaName: ${fieldType.javaType} = null"
else -> implWsDataBlockCode(fieldType.type, name, true)
}
is ValueType.JvmClass -> {
if (!isOptional) {
"lateinit var $javaName: ${fieldType.javaType}"
}
else {
"var $javaName: ${fieldType.javaType}? = null"
}
}
else -> error("Unsupported field type: $this")
}
}
val ObjProperty<*, *>.implWsDataFieldInitializedCode: String
get() = when (valueType) {
is ValueType.Int, is ValueType.Boolean -> ""
is ValueType.String, is ValueType.JvmClass, is ValueType.Collection<*, *>, is ValueType.Map<*, *> -> {
val capitalizedFieldName = javaName.replaceFirstChar { it.titlecaseChar() }
"fun is${capitalizedFieldName}Initialized(): Boolean = ::${javaName}.isInitialized"
}
else -> error("Unsupported field type: $this")
}
@@ -1,354 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.writer.fields
import com.intellij.workspaceModel.codegen.writer.classes.*
import com.intellij.workspaceModel.codegen.deft.meta.ObjProperty
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
import com.intellij.workspaceModel.codegen.writer.getRefType
import com.intellij.workspaceModel.codegen.writer.isRefType
import com.intellij.workspaceModel.codegen.writer.*
import com.intellij.workspaceModel.codegen.writer.javaName
import com.intellij.workspaceModel.storage.EntityStorage
import com.intellij.workspaceModel.storage.bridgeEntities.LibraryRoot
import com.intellij.workspaceModel.storage.impl.*
import com.intellij.workspaceModel.storage.impl.containers.MutableWorkspaceList
import com.intellij.workspaceModel.storage.impl.containers.MutableWorkspaceSet
import com.intellij.workspaceModel.storage.url.VirtualFileUrl
val ObjProperty<*, *>.implWsBuilderFieldCode: String
get() = valueType.implWsBuilderBlockingCode(this)
private fun ValueType<*>.implWsBuilderBlockingCode(field: ObjProperty<*, *>, optionalSuffix: String = ""): String = when (this) {
ValueType.Boolean, ValueType.Int -> """
override var ${field.javaName}: ${field.valueType.javaMutableType}$optionalSuffix
get() = getEntityData().${field.javaName}
set(value) {
checkModificationAllowed()
getEntityData(true).${field.javaName} = value
changedProperty.add("${field.javaName}")
}
""".trimIndent()
ValueType.String -> """
override var ${field.javaName}: ${field.valueType.javaMutableType}
get() = getEntityData().${field.javaName}
set(value) {
checkModificationAllowed()
getEntityData(true).${field.javaName} = value
changedProperty.add("${field.javaName}")
}
""".trimIndent()
is ValueType.ObjRef -> {
val connectionName = field.refsConnectionId
val getterSetterNames = field.refNames()
// Opposite field may be either one-to-one or one-to-many
val notNullAssertion = if (optionalSuffix.isBlank()) "!!" else ""
lines {
sectionNoBrackets("override var ${field.javaName}: $javaType$optionalSuffix") {
section("get()") {
line("val _diff = diff")
line("return if (_diff != null) {")
line(" _diff.${getterSetterNames.getter}($connectionName, this) ?: this.entityLinks[${EntityLink::class.fqn}(${field.valueType.getRefType().child}, ${field.refsConnectionId})]$notNullAssertion as$optionalSuffix $javaType")
line("} else {")
line(" this.entityLinks[${EntityLink::class.fqn}(${field.valueType.getRefType().child}, ${field.refsConnectionId})]$notNullAssertion as$optionalSuffix $javaType")
line("}")
}
section("set(value)") {
line("checkModificationAllowed()")
line("val _diff = diff")
`if`("_diff != null && value is ${ModifiableWorkspaceEntityBase::class.fqn}<*, *> && value.diff == null") {
backrefSetup(field)
line("_diff.addEntity(value)")
}
section("if (_diff != null && (value !is ${ModifiableWorkspaceEntityBase::class.fqn}<*, *> || value.diff != null))") {
line("_diff.${getterSetterNames.setter}($connectionName, this, value)")
}
section("else") {
backrefSetup(field)
line()
line("this.entityLinks[${EntityLink::class.fqn}(${field.valueType.getRefType().child}, ${field.refsConnectionId})] = value")
}
line("changedProperty.add(\"${field.javaName}\")")
}
}
}
}
is ValueType.List<*> -> {
val elementType = this.elementType
if (this.isRefType()) {
val connectionName = field.refsConnectionId
val notNullAssertion = if (optionalSuffix.isBlank()) "!!" else error("It's prohibited to have nullable reference list")
if ((elementType as ValueType.ObjRef<*>).target.openness.extendable) {
lines(level = 1) {
sectionNoBrackets("override var ${field.javaName}: $javaType$optionalSuffix") {
section("get()") {
line("val _diff = diff")
line("return if (_diff != null) {")
line(" _diff.${fqn2(EntityStorage::extractOneToAbstractManyChildren)}<${elementType.javaType}>($connectionName, this)$notNullAssertion.toList() + (this.entityLinks[${EntityLink::class.fqn}(${field.valueType.getRefType().child}, ${field.refsConnectionId})] as? $javaType ?: emptyList())")
line("} else {")
line(" this.entityLinks[${EntityLink::class.fqn}(${field.valueType.getRefType().child}, ${field.refsConnectionId})] as $javaType ${if (notNullAssertion.isNotBlank()) "?: emptyList()" else ""}")
line("}")
}
section("set(value)") {
lineComment("Set list of ref types for abstract entities")
line("checkModificationAllowed()")
line("val _diff = diff")
`if`("_diff != null") {
`for`("item_value in value") {
`if`("item_value is ${ModifiableWorkspaceEntityBase::class.fqn}<*, *> && (item_value as? ${
ModifiableWorkspaceEntityBase::class.fqn
}<*, *>)?.diff == null") {
lineComment("Backref setup before adding to store an abstract entity")
backrefSetup(field, "item_value")
line("_diff.addEntity(item_value)")
}
}
line("_diff.${fqn5(EntityStorage::updateOneToAbstractManyChildrenOfParent)}($connectionName, this, value.asSequence())")
}
`else` {
backrefListSetup(field)
line()
line("this.entityLinks[${EntityLink::class.fqn}(${field.valueType.getRefType().child}, ${field.refsConnectionId})] = value")
}
line("changedProperty.add(\"${field.javaName}\")")
}
}
}
}
else {
lines {
lineComment("List of non-abstract referenced types")
line("var _${field.javaName}: $javaType? = emptyList()")
sectionNoBrackets("override var ${field.javaName}: $javaType$optionalSuffix") {
section("get()") {
lineComment("Getter of the list of non-abstract referenced types")
line("val _diff = diff")
line("return if (_diff != null) {")
line(" _diff.${fqn2(EntityStorage::extractOneToManyChildren)}<${elementType.javaType}>($connectionName, this)$notNullAssertion.toList() + (this.entityLinks[${EntityLink::class.fqn}(${field.valueType.getRefType().child}, ${field.refsConnectionId})] as? $javaType ?: emptyList())")
line("} else {")
line(
" this.entityLinks[${EntityLink::class.fqn}(${field.valueType.getRefType().child}, ${field.refsConnectionId})] as? $javaType ${if (notNullAssertion.isNotBlank()) "?: emptyList()" else ""}")
line("}")
}
section("set(value)") {
lineComment("Setter of the list of non-abstract referenced types")
line("checkModificationAllowed()")
line("val _diff = diff")
`if`("_diff != null") {
`for`("item_value in value") {
`if`("item_value is ${ModifiableWorkspaceEntityBase::class.fqn}<*, *> && (item_value as? ${ModifiableWorkspaceEntityBase::class.fqn}<*, *>)?.diff == null") {
lineComment("Backref setup before adding to store")
backrefSetup(field, "item_value")
line()
line("_diff.addEntity(item_value)")
}
}
line("_diff.${fqn4(EntityStorage::updateOneToManyChildrenOfParent)}($connectionName, this, value)")
}
`else` {
backrefListSetup(field)
line()
line("this.entityLinks[${EntityLink::class.fqn}(${field.valueType.getRefType().child}, ${field.refsConnectionId})] = value")
}
line("changedProperty.add(\"${field.javaName}\")")
}
}
}
}
}
else {
"""
private val ${field.javaName}Updater: (value: List<${elementType.javaType}>) -> Unit = { value ->
${elementType.addVirtualFileIndex(field)}
changedProperty.add("${field.javaName}")
}
override var ${field.javaName}: MutableList<${elementType.javaType}>
get() {
val collection_${field.javaName} = getEntityData().${field.javaName}
if (collection_${field.javaName} !is ${MutableWorkspaceList::class.fqn}) return collection_${field.javaName}
if (diff == null || modifiable.get()) {
collection_${field.javaName}.setModificationUpdateAction(${field.javaName}Updater)
} else {
collection_${field.javaName}.cleanModificationUpdateAction()
}
return collection_${field.javaName}
}
set(value) {
checkModificationAllowed()
getEntityData(true).${field.javaName} = value
${field.javaName}Updater.invoke(value)
}
""".trimIndent()
}
}
is ValueType.Set<*> -> {
val elementType = this.elementType
if (this.isRefType()) {
error("Set of references is not supported")
} else {
"""
private val ${field.javaName}Updater: (value: Set<${elementType.javaType}>) -> Unit = { value ->
${elementType.addVirtualFileIndex(field)}
changedProperty.add("${field.javaName}")
}
override var ${field.javaName}: MutableSet<${elementType.javaType}>
get() {
val collection_${field.javaName} = getEntityData().${field.javaName}
if (collection_${field.javaName} !is ${MutableWorkspaceSet::class.fqn}) return collection_${field.javaName}
if (diff == null || modifiable.get()) {
collection_${field.javaName}.setModificationUpdateAction(${field.javaName}Updater)
} else {
collection_${field.javaName}.cleanModificationUpdateAction()
}
return collection_${field.javaName}
}
set(value) {
checkModificationAllowed()
getEntityData(true).${field.javaName} = value
${field.javaName}Updater.invoke(value)
}
""".trimIndent()
}
}
is ValueType.Map<*, *> -> """
override var ${field.javaName}: $javaType
get() = getEntityData().${field.javaName}
set(value) {
checkModificationAllowed()
getEntityData(true).${field.javaName} = value
changedProperty.add("${field.javaName}")
}
""".trimIndent()
is ValueType.Optional<*> -> type.implWsBuilderBlockingCode(field, "?")
is ValueType.Structure<*> -> "//TODO: ${field.javaName}"
is ValueType.JvmClass -> """
override var ${field.javaName}: ${javaType.appendSuffix(optionalSuffix)}
get() = getEntityData().${field.javaName}
set(value) {
checkModificationAllowed()
getEntityData(true).${field.javaName} = value
changedProperty.add("${field.javaName}")
${
if (javaType.decoded == VirtualFileUrl::class.java.name)
"""val _diff = diff
| if (_diff != null) index(this, "${field.javaName}", value)
""".trimMargin()
else ""
}
}
""".trimIndent()
else -> unsupportedTypeError()
}
private fun LinesBuilder.backrefSetup(
field: ObjProperty<*, *>,
varName: String = "value",
) {
val referencedField = field.referencedField
val type = referencedField.valueType
val isChild = type.getRefType().child
when (type) {
is ValueType.List<*> -> {
lineComment("Setting backref of the list")
`if`("$varName is ${ModifiableWorkspaceEntityBase::class.fqn}<*, *>") {
line("val data = ($varName.entityLinks[${EntityLink::class.fqn}($isChild, ${field.refsConnectionId})] as? List<Any> ?: emptyList()) + this")
line("$varName.entityLinks[${EntityLink::class.fqn}($isChild, ${field.refsConnectionId})] = data")
}
line("// else you're attaching a new entity to an existing entity that is not modifiable")
}
is ValueType.Set<*> -> {
lineComment("Setting backref of the set")
`if`("$varName is ${ModifiableWorkspaceEntityBase::class.fqn}<*, *>") {
line("val data = ($varName.entityLinks[${EntityLink::class.fqn}($isChild, ${field.refsConnectionId})] as? Set<Any> ?: emptySet()) + this")
line("$varName.entityLinks[${EntityLink::class.fqn}($isChild, ${field.refsConnectionId})] = data")
}
line("// else you're attaching a new entity to an existing entity that is not modifiable")
}
is ValueType.Optional<*> -> {
`if`("$varName is ${ModifiableWorkspaceEntityBase::class.fqn}<*, *>") {
line("$varName.entityLinks[${EntityLink::class.fqn}($isChild, ${field.refsConnectionId})] = this")
}
line("// else you're attaching a new entity to an existing entity that is not modifiable")
}
is ValueType.ObjRef<*> -> {
`if`("$varName is ${ModifiableWorkspaceEntityBase::class.fqn}<*, *>") {
line("$varName.entityLinks[${EntityLink::class.fqn}($isChild, ${field.refsConnectionId})] = this")
}
line("// else you're attaching a new entity to an existing entity that is not modifiable")
}
else -> error("Unexpected")
}
}
private fun LinesBuilder.backrefListSetup(
field: ObjProperty<*, *>,
varName: String = "value",
) {
val itemName = "item_$varName"
`for`("$itemName in $varName") {
backrefSetup(field, itemName)
}
}
fun LinesBuilder.implWsBuilderIsInitializedCode(field: ObjProperty<*, *>) {
val javaName = field.javaName
when (field.valueType) {
is ValueType.List<*> -> if (field.valueType.isRefType()) {
lineComment("Check initialization for list with ref type")
ifElse("_diff != null", {
`if`("_diff.${fqn2(EntityStorage::extractOneToManyChildren)}<${WorkspaceEntityBase::class.fqn}>(${field.refsConnectionId}, this) == null") {
line("error(\"Field ${field.receiver.name}#$javaName should be initialized\")")
}
}) {
isInitializedBaseCode(field, "this.entityLinks[${EntityLink::class.fqn}(${field.valueType.getRefType().child}, ${field.refsConnectionId})] == null")
}
}
else {
val capitalizedFieldName = javaName.replaceFirstChar { it.titlecaseChar() }
isInitializedBaseCode(field, "!getEntityData().is${capitalizedFieldName}Initialized()")
}
is ValueType.ObjRef<*> -> {
ifElse("_diff != null", {
`if`("_diff.${field.refsConnectionMethodCode("<${WorkspaceEntityBase::class.fqn}>")} == null") {
line("error(\"Field ${field.receiver.name}#$javaName should be initialized\")")
}
}) {
isInitializedBaseCode(field, "this.entityLinks[${EntityLink::class.fqn}(${field.valueType.getRefType().child}, ${field.refsConnectionId})] == null")
}.toString()
}
is ValueType.Int, is ValueType.Boolean -> return
else -> {
val capitalizedFieldName = javaName.replaceFirstChar { it.titlecaseChar() }
isInitializedBaseCode(field, "!getEntityData().is${capitalizedFieldName}Initialized()")
}
}
}
private fun LinesBuilder.isInitializedBaseCode(field: ObjProperty<*, *>, expression: String) {
section("if ($expression)") {
line("error(\"Field ${field.receiver.name}#${field.javaName} should be initialized\")")
}
}
private fun ValueType<*>.addVirtualFileIndex(field: ObjProperty<*, *>): String {
return when {
this is ValueType.Blob && javaClassName == VirtualFileUrl::class.java.name ->
"""val _diff = diff
| if (_diff != null) index(this, "${field.javaName}", value)
""".trimMargin()
this is ValueType.JvmClass && javaClassName == LibraryRoot::class.java.name -> """
val _diff = diff
if (_diff != null) {
indexLibraryRoots(value)
}
"""
else -> ""
}
}
@@ -1,60 +0,0 @@
package com.intellij.workspaceModel.codegen.writer.fields
import com.intellij.workspaceModel.storage.EntityStorage
import com.intellij.workspaceModel.storage.impl.*
import com.intellij.workspaceModel.codegen.writer.isRefType
import com.intellij.workspaceModel.codegen.deft.meta.ObjProperty
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
import com.intellij.workspaceModel.codegen.writer.*
data class RefMethods(val getter: QualifiedName, val setter: QualifiedName)
infix fun QualifiedName.getterWithSetter(setter: QualifiedName): RefMethods = RefMethods(this, setter)
fun ObjProperty<*, *>.refNames(): RefMethods {
if (!valueType.isRefType()) error("Call this on ref field")
return when (valueType) {
is ValueType.ObjRef -> constructCode(valueType)
is ValueType.Optional -> constructCode((this.valueType as ValueType.Optional<*>).type)
is ValueType.List<*> -> fqn2(EntityStorage::extractOneToManyChildren) getterWithSetter fqn4(EntityStorage::updateOneToManyChildrenOfParent)
else -> error("Call this on ref field")
}
}
private fun ObjProperty<*, *>.constructCode(type: ValueType<*>): RefMethods {
type as ValueType.ObjRef<*>
return if (type.child) {
if (type.target.openness.extendable) {
fqn1(EntityStorage::extractOneToAbstractOneChild) getterWithSetter fqn3(EntityStorage::updateOneToAbstractOneChildOfParent)
}
else {
fqn1(EntityStorage::extractOneToOneChild) getterWithSetter fqn3(EntityStorage::updateOneToOneChildOfParent)
}
}
else {
var valueType = referencedField.valueType
if (valueType is ValueType.Optional<*>) {
valueType = valueType.type
}
when (valueType) {
is ValueType.List<*> -> {
if (receiver.openness.extendable) {
fqn1(EntityStorage::extractOneToAbstractManyParent) getterWithSetter fqn3(EntityStorage::updateOneToAbstractManyParentOfChild)
}
else {
fqn1(EntityStorage::extractOneToManyParent) getterWithSetter fqn3(EntityStorage::updateOneToManyParentOfChild)
}
}
is ValueType.ObjRef<*> -> {
if (receiver.openness.extendable) {
fqn1(EntityStorage::extractOneToAbstractOneParent) getterWithSetter fqn3(EntityStorage::updateOneToAbstractOneParentOfChild)
}
else {
fqn1(EntityStorage::extractOneToOneParent) getterWithSetter fqn3(EntityStorage::updateOneToOneParentOfChild)
}
}
else -> error("Unsupported reference type")
}
}
}
@@ -1,159 +0,0 @@
package com.intellij.workspaceModel.codegen.writer.fields
import com.intellij.workspaceModel.codegen.deft.meta.ObjProperty
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
import com.intellij.workspaceModel.codegen.writer.getRefType
import com.intellij.workspaceModel.codegen.writer.isRefType
import com.intellij.workspaceModel.codegen.writer.refsFields
import com.intellij.workspaceModel.codegen.writer.fqn1
import com.intellij.workspaceModel.codegen.writer.fqn2
import com.intellij.workspaceModel.codegen.writer.toQualifiedName
import com.intellij.workspaceModel.codegen.writer.hasSetter
import com.intellij.workspaceModel.codegen.writer.isOverride
import com.intellij.workspaceModel.codegen.writer.javaName
import com.intellij.workspaceModel.storage.EntityStorage
import com.intellij.workspaceModel.storage.impl.*
val ObjProperty<*, *>.implWsEntityFieldCode: String
get() = buildString {
if (hasSetter) {
if (isOverride && name !in listOf("name", "entitySource")) {
append(implWsBlockingCodeOverride)
}
else append(implWsBlockingCode)
} else {
append("override var $javaName: ${valueType.javaType} = dataSource.$javaName\n")
}
}
private val ObjProperty<*, *>.implWsBlockingCode: String
get() = implWsBlockCode(valueType, name, "")
internal fun ObjProperty<*, *>.implWsBlockCode(fieldType: ValueType<*>, name: String, optionalSuffix: String = ""): String {
return when (fieldType) {
ValueType.Int -> "override val $name: ${fieldType.javaType} get() = dataSource.$name"
ValueType.Boolean -> "override val $name: ${fieldType.javaType} get() = dataSource.$name"
ValueType.String -> """
override val $name: ${fieldType.javaType}${optionalSuffix}
get() = dataSource.$name
""".trimIndent()
is ValueType.ObjRef -> {
val notNullAssertion = if (optionalSuffix.isBlank()) "!!" else ""
"""
override val $name: ${fieldType.javaType}$optionalSuffix
get() = snapshot.${refsConnectionMethodCode()}$notNullAssertion
""".trimIndent()
}
is ValueType.List<*> -> {
if (fieldType.isRefType()) {
val connectionName = name.uppercase() + "_CONNECTION_ID"
val notNullAssertion = if (optionalSuffix.isBlank()) "!!" else ""
if ((fieldType.elementType as ValueType.ObjRef<*>).target.openness.extendable) {
"""
override val $name: ${fieldType.javaType}$optionalSuffix
get() = snapshot.${fqn2(EntityStorage::extractOneToAbstractManyChildren)}<${fieldType.elementType.javaType}>($connectionName, this)$notNullAssertion.toList()
""".trimIndent()
}
else {
"""
override val $name: ${fieldType.javaType}$optionalSuffix
get() = snapshot.${fqn2(EntityStorage::extractOneToManyChildren)}<${fieldType.elementType.javaType}>($connectionName, this)$notNullAssertion.toList()
""".trimIndent()
}
}
else {
"""
override val $name: ${fieldType.javaType}$optionalSuffix
get() = dataSource.$name
""".trimIndent()
}
}
is ValueType.Set<*> -> {
if (fieldType.isRefType()) {
error("Set of references is not supported")
}
else {
"""
override val $javaName: ${fieldType.javaType}$optionalSuffix
get() = dataSource.$name
""".trimIndent()
}
}
is ValueType.Map<*, *> -> """
override val $name: ${fieldType.javaType}$optionalSuffix
get() = dataSource.$name
""".trimIndent()
is ValueType.Optional<*> -> when (fieldType.type) {
ValueType.Int, ValueType.Boolean -> "override val $name: ${fieldType.javaType} get() = dataSource.$name"
else -> implWsBlockCode(fieldType.type, name, "?")
}
is ValueType.JvmClass -> """
override val $name: ${fieldType.javaClassName.toQualifiedName()}$optionalSuffix
get() = dataSource.$name
""".trimIndent()
else -> error("Unsupported field type: $this")
}
}
internal val ObjProperty<*, *>.implWsBlockingCodeOverride: String
get() {
val originalField = receiver.refsFields.first { it.valueType.javaType == valueType.javaType }
val connectionName = originalField.name.uppercase() + "_CONNECTION_ID"
var valueType = referencedField.valueType
val notNullAssertion = if (valueType is ValueType.Optional<*>) "" else "!!"
if (valueType is ValueType.Optional<*>) {
valueType = valueType.type
}
val getterName = when (valueType) {
is ValueType.List<*> -> if (receiver.openness.extendable)
fqn1(EntityStorage::extractOneToAbstractManyParent)
else
fqn1(EntityStorage::extractOneToManyParent)
is ValueType.ObjRef<*> -> if (receiver.openness.extendable)
fqn1(EntityStorage::extractOneToAbstractOneParent)
else
fqn1(EntityStorage::extractOneToOneParent)
else -> error("Unsupported reference type")
}
return """
override val $name: ${this.valueType.javaType}
get() = snapshot.$getterName($connectionName, this)$notNullAssertion
""".trimIndent()
}
internal val ObjProperty<*, *>.referencedField: ObjProperty<*, *>
get() {
val ref = valueType.getRefType()
val declaredReferenceFromChild =
ref.target.refsFields.filter { it.valueType.getRefType().target == receiver && it != this } +
setOf(ref.target.module,
receiver.module).flatMap { it.extensions }.filter { it.valueType.getRefType().target == receiver && it.receiver == ref.target && it != this }
if (declaredReferenceFromChild.isEmpty()) {
error("Reference should be declared at both entities. It exist at ${receiver.name}#$name but absent at ${ref.target.name}")
}
if (declaredReferenceFromChild.size > 1) {
error("""
|More then one reference to ${receiver.name} declared at ${declaredReferenceFromChild[0].receiver.name}#${declaredReferenceFromChild[0].name},
|${declaredReferenceFromChild[1].receiver.name}#${declaredReferenceFromChild[1].name}
|""".trimMargin())
}
val referencedField = declaredReferenceFromChild[0]
if (this.valueType.getRefType().child == referencedField.valueType.getRefType().child) {
val (childStr, fix) = if (this.valueType.getRefType().child) {
"child" to "Have you @Child annotation on both sides?"
}
else {
"parent" to "Did you forget to add @Child annotation?"
}
error("Both fields ${receiver.name}#$name and ${ref.target.name}#${referencedField.name} are marked as $childStr. $fix")
}
return referencedField
}
@@ -1,17 +0,0 @@
package com.intellij.workspaceModel.codegen.writer.fields
import com.intellij.workspaceModel.codegen.deft.meta.ExtProperty
import com.intellij.workspaceModel.codegen.writer.getRefType
import com.intellij.workspaceModel.codegen.writer.javaBuilderName
import com.intellij.workspaceModel.codegen.writer.fqn
import com.intellij.workspaceModel.codegen.writer.lines
import org.jetbrains.deft.annotations.Child
val ExtProperty<*, *>.wsCode: String
get() = lines {
val isChild = valueType.getRefType().child
val annotation = if (isChild) "@${Child::class.fqn} " else ""
sectionNoBrackets("var ${receiver.javaBuilderName}.$name: $annotation${valueType.javaType}") {
line("by WorkspaceEntity.extension()")
}
}
@@ -1,44 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.writer
import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
import com.intellij.workspaceModel.codegen.deft.meta.ObjProperty
import com.intellij.workspaceModel.codegen.deft.meta.OwnProperty
import com.intellij.workspaceModel.storage.WorkspaceEntity
import com.intellij.workspaceModel.storage.WorkspaceEntityWithSymbolicId
val ObjClass<*>.isStandardInterface: Boolean
get() = name in setOf(WorkspaceEntity::class.java.simpleName, WorkspaceEntityWithSymbolicId::class.java.simpleName)
val ObjClass<*>.allSuperClasses: List<ObjClass<*>>
get() = superTypes.filterIsInstance<ObjClass<*>>().flatMapTo(LinkedHashSet()) { it.allSuperClasses + listOf(it) }.toList()
val ObjClass<*>.allFields: List<OwnProperty<*, *>>
get() {
val fieldsByName = LinkedHashMap<String, OwnProperty<*, *>>()
collectFields(this, fieldsByName)
return fieldsByName.values.toList()
}
private fun collectFields(objClass: ObjClass<*>, fieldsByName: MutableMap<String, OwnProperty<*, *>>) {
for (superType in objClass.superTypes) {
if (superType is ObjClass<*>) {
collectFields(superType, fieldsByName)
}
}
for (field in objClass.fields) {
if (field.valueKind !is ObjProperty.ValueKind.Computable) {
fieldsByName.remove(field.name)
fieldsByName[field.name] = field
}
}
}
val ObjProperty<*, *>.hasSetter: Boolean
get() = open || valueKind == ObjProperty.ValueKind.Plain
val ObjProperty<*, *>.javaName: String
get() = name
val ObjProperty<*, *>.isOverride: Boolean
get() = receiver.allSuperClasses.any { name in it.fieldsByName }
@@ -1,38 +0,0 @@
package com.intellij.workspaceModel.codegen.writer
import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
import com.intellij.workspaceModel.codegen.deft.meta.OwnProperty
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
import com.intellij.workspaceModel.storage.url.VirtualFileUrl
val ObjClass<*>.refsFields: List<OwnProperty<*, *>>
get() = fields.filter { !it.isOverride && it.valueType.isRefType() }
val ObjClass<*>.allRefsFields: List<OwnProperty<*, *>>
get() = allFields.filter { it.valueType.isRefType() }
val ObjClass<*>.vfuFields: List<OwnProperty<*, *>>
get() = fields.filter { !it.isOverride && it.valueType.isVfuType() }
fun ValueType<*>.getRefType(): ValueType.ObjRef<*> = when (this) {
is ValueType.ObjRef<*> -> this
is ValueType.Optional<*> -> type.getRefType()
is ValueType.Collection<*, *> -> elementType.getRefType()
else -> error("Unsupported type of requester, should be called only if `isRefType` is true")
}
fun ValueType<*>.isRefType(): Boolean = when (this) {
is ValueType.ObjRef<*> -> true
is ValueType.Optional<*> -> type.isRefType()
is ValueType.Collection<*, *> -> elementType.isRefType()
else -> false
}
fun ValueType<*>.isVfuType(): Boolean = when (this) {
is ValueType.Blob -> javaClassName == VirtualFileUrl::class.java.name
is ValueType.Optional<*> -> type.isVfuType()
is ValueType.Collection<*, *> -> elementType.isVfuType()
else -> false
}
fun sups(vararg extensions: String?): String = extensions.filterNotNull().joinToString(separator = ", ")
@@ -1,28 +0,0 @@
package com.intellij.workspaceModel.codegen.writer
fun <T> Collection<T>.lines(f: T.() -> String = { "$this" }): String =
mapNotNull { f(it).takeIf { item -> item.isNotBlank() } }.joinToString("\n")
fun <T> Collection<T>.lines(indent: String, f: T.() -> String = { "$this" }): String =
mapNotNull { f(it).takeIf { item -> item.isNotBlank() } }.indent(indent)
fun Collection<String>.indent(indent: String): String = when {
size > 1 -> first().indentRestOnly(indent) + "\n" +
drop(1).joinToString("\n") { it.indentAll(indent) }
size == 1 -> single().indentRestOnly(indent)
else -> joinToString("\n") { it.indentAll(indent) }
}
fun String.indentRestOnly(indent: String): String {
val lines = lines()
return when {
lines.size > 1 -> lines.first() + "\n" + lines.drop(1).joinToString("\n") { "$indent$it" }
lines.size == 1 -> lines.first()
else -> ""
}
}
private fun String.indentAll(indent: String): String {
return lines().joinToString("\n") { "$indent$it" }
}
@@ -1,39 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.codegen.writer
import com.intellij.workspaceModel.codegen.writer.classes.implWsDataClassCode
import com.intellij.workspaceModel.codegen.writer.classes.implWsEntityCode
import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
/**
* TODO:
* - Abstract Class do
* - This about mutable lists (custom implementation?)
* - This about mutable lists for properties
* - This about mutable lists for references
* - Facet: 2 parents, how to implement?
* Поправить генерилку, чтоб все было чисто без лишних строк (почистил в applyToBuilder)
* factory: ObjType<ChildSubSubEntity, *>
* hasNewValue -- Будем обсуждать с Сережей после НГ
* setValue -- Будем обсуждать с Сережей после НГ
* builder(): ObjBuilder<*>
* Привести билдер в порядок: поля идут первыми, потом applyBuilder, потом все утильные методы..
*
* Done:
* createReference проверить нужны ли они в ентити (не нужны, грохнул)
* hasEqualProperties (забахали на всяк случай) // Там всего одно использование, посовещавшись мы решили хрохнуть его
* Поправить импорты
* Метод проверки, что все поля заиничены
*
* ---------------------------
* Перенести тесты идеи к нам или наоборрот <--
*/
fun ObjClass<*>.implWsCode(): String? {
if (!openness.instantiatable) return null
return """
${implWsEntityCode()}
${implWsDataClassCode()}
""".trimIndent()
}
@@ -1 +0,0 @@
com.intellij.workspaceModel.codegen.engine.impl.CodeGeneratorImpl