diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..073fb6a0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{kt,kts}] +ij_kotlin_allow_trailing_comma = true +ij_kotlin_allow_trailing_comma_on_call_site = true +ij_kotlin_imports_layout = * diff --git a/build.gradle b/build.gradle index 51a74fe8..bbf814e1 100644 --- a/build.gradle +++ b/build.gradle @@ -16,12 +16,7 @@ spotless { kotlin { target "**/*.kt" targetExclude "**/gen/**/*.*" - ktlint('0.49.1').editorConfigOverride([ - "indent_size": "2", - "disabled_rules": "package-name", - "ij_kotlin_allow_trailing_comma": "true", - "ij_kotlin_allow_trailing_comma_on_call_site": "true", - ]) + ktfmt(libs.ktfmt.get().version).googleStyle() trimTrailingWhitespace() endWithNewline() } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/ModifiableFileLazy.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/ModifiableFileLazy.kt index e9d6c861..1e89703c 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/ModifiableFileLazy.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/ModifiableFileLazy.kt @@ -3,9 +3,7 @@ package com.alecstrong.sql.psi.core import com.intellij.psi.PsiFile import java.util.concurrent.atomic.AtomicReference -class ModifiableFileLazy( - private val initializer: () -> T, -) { +class ModifiableFileLazy(private val initializer: () -> T) { private var modifiedStamp = -1L private var state = AtomicReference() diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/ModuleParserUtil.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/ModuleParserUtil.kt index 1eedcccf..157797aa 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/ModuleParserUtil.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/ModuleParserUtil.kt @@ -7,16 +7,19 @@ import com.intellij.lang.parser.GeneratedParserUtilBase abstract class ModuleParserUtil : GeneratedParserUtilBase() { companion object { - @JvmStatic fun custom_module_argument(builder: PsiBuilder, level: Int, columnName: Parser): Boolean { - if (!GeneratedParserUtilBase.recursion_guard_(builder, level, "module_argument_real")) return false + @JvmStatic + fun custom_module_argument(builder: PsiBuilder, level: Int, columnName: Parser): Boolean { + if (!GeneratedParserUtilBase.recursion_guard_(builder, level, "module_argument_real")) + return false var result: Boolean - val marker = GeneratedParserUtilBase.enter_section_( - builder, - level, - GeneratedParserUtilBase._COLLAPSE_, - MODULE_ARGUMENT, - "", - ) + val marker = + GeneratedParserUtilBase.enter_section_( + builder, + level, + GeneratedParserUtilBase._COLLAPSE_, + MODULE_ARGUMENT, + "", + ) columnName.parse(builder, level + 1) var parens = 0 while (builder.tokenType != SqlTypes.COMMA) { diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlAnnotator.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlAnnotator.kt index 7438fef3..5fee9792 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlAnnotator.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlAnnotator.kt @@ -22,7 +22,8 @@ open class SqlAnnotator : Annotator { } } -class AnnotationException(val msg: String, val element: PsiElement? = null) : IllegalStateException(msg) +class AnnotationException(val msg: String, val element: PsiElement? = null) : + IllegalStateException(msg) fun interface SqlAnnotationHolder { fun createErrorAnnotation(element: PsiElement, message: String) diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlElementType.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlElementType.kt index c9cfe537..06f293a0 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlElementType.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlElementType.kt @@ -31,7 +31,8 @@ class SqlElementType(name: String) : IElementType(name, null) { abstract class SqlSchemaContributorElementType( private val name: String, /** - * This should be the same class used when interfacing with [com.alecstrong.sql.psi.core.psi.Schema] + * This should be the same class used when interfacing with + * [com.alecstrong.sql.psi.core.psi.Schema] */ private val schemaClass: Class, ) : ILightStubElementType(name, null) { diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlFileBase.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlFileBase.kt index ec9f3d35..e0bdcefc 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlFileBase.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlFileBase.kt @@ -17,10 +17,8 @@ import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.PsiTreeUtil import kotlin.reflect.KClass -abstract class SqlFileBase( - viewProvider: FileViewProvider, - language: Language, -) : PsiFileBase(viewProvider, language) { +abstract class SqlFileBase(viewProvider: FileViewProvider, language: Language) : + PsiFileBase(viewProvider, language) { abstract val order: Long? val sqlStmtList @@ -28,7 +26,8 @@ abstract class SqlFileBase( fun tablesAvailable(child: PsiElement) = schema(child).map { it.tableExposed() } - fun triggers(sqlStmtElement: PsiElement?): Collection = schema(sqlStmtElement) + fun triggers(sqlStmtElement: PsiElement?): Collection = + schema(sqlStmtElement) internal inline fun schema( sqlStmtElement: PsiElement? = null, @@ -62,9 +61,8 @@ abstract class SqlFileBase( } /** - * @return Tables this file exposes as LazyQuery. - * * @param includeAll If true, also return tables that other files expose. + * @return Tables this file exposes as LazyQuery. */ fun tables(includeAll: Boolean): Collection { val tables = schema().map { it.tableExposed() } @@ -72,19 +70,22 @@ abstract class SqlFileBase( } internal fun viewForName(name: String): SqlCreateViewStmt? { - return schema().filterIsInstance().singleOrNull { it.name() == name } + return schema().filterIsInstance().singleOrNull { + it.name() == name + } } private fun views(): List { - return sqlStmtList?.stmtList?.mapNotNull { - it.createViewStmt - }.orEmpty() + return sqlStmtList?.stmtList?.mapNotNull { it.createViewStmt }.orEmpty() } private fun tables(): List { - return sqlStmtList?.stmtList?.mapNotNull { - (it.createViewStmt as TableElement?) ?: it.createTableStmt ?: it.createVirtualTableStmt - }.orEmpty() + return sqlStmtList + ?.stmtList + ?.mapNotNull { + (it.createViewStmt as TableElement?) ?: it.createTableStmt ?: it.createVirtualTableStmt + } + .orEmpty() } private inline fun iteratePreviousStatements( @@ -127,17 +128,17 @@ abstract class SqlFileBase( topContributors.forEach(block) } - contributors()?.takeWhile { order == null || until == null || it.textOffset <= until.textOffset } - ?.forEach { - block(it) - } + contributors() + ?.takeWhile { order == null || until == null || it.textOffset <= until.textOffset } + ?.forEach { block(it) } } - private fun contributors() = sqlStmtList?.stmtList?.mapNotNull { it.firstChild as? SchemaContributor } + private fun contributors() = + sqlStmtList?.stmtList?.mapNotNull { it.firstChild as? SchemaContributor } /** - * Optional files which can be used for extra Schema Contributors that are unindexed. - * The files are added to the schema in the provided order. + * Optional files which can be used for extra Schema Contributors that are unindexed. The files + * are added to the schema in the provided order. */ protected open fun baseContributorFiles(): List = emptyList() diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlParserDefinition.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlParserDefinition.kt index 8c49340b..2606076b 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlParserDefinition.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/SqlParserDefinition.kt @@ -21,14 +21,20 @@ abstract class SqlParserDefinition : ParserDefinition { } override fun createLexer(project: Project): Lexer = SqlLexerAdapter() + override fun getWhitespaceTokens() = WHITE_SPACES + override fun getCommentTokens() = COMMENTS + override fun getStringLiteralElements(): TokenSet = TokenSet.EMPTY + override fun spaceExistenceTypeBetweenTokens(p0: ASTNode, p1: ASTNode) = MAY + override fun createElement(node: ASTNode): PsiElement = SqlParserUtil.createElement(node) override fun createParser(project: Project) = SqlParser() abstract override fun createFile(viewProvider: FileViewProvider): SqlFileBase + abstract fun getLanguage(): Language } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/AlterTableApplier.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/AlterTableApplier.kt index 2d1284e2..004006e7 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/AlterTableApplier.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/AlterTableApplier.kt @@ -8,33 +8,30 @@ interface AlterTableApplier : PsiElement { } val AlterTableApplier.alterStmt - get() = PsiTreeUtil.getParentOfType( - this, - SqlAlterTableStmt::class.java, - )!! + get() = PsiTreeUtil.getParentOfType(this, SqlAlterTableStmt::class.java)!! internal fun LazyQuery.withAlterStatement( alter: SqlAlterTableStmt, until: SqlAlterTableRules? = null, ): LazyQuery { - return alter.alterTableRulesList.takeWhile { it != until }.fold( - this, - { lazyQuery, alterTableRules -> - // Rename table. - alterTableRules.alterTableRenameTable?.let { renameTable -> - return@fold LazyQuery( - tableName = renameTable.newTableName, - query = { - lazyQuery.query.copy(table = renameTable.newTableName) - }, - ) - } + return alter.alterTableRulesList + .takeWhile { it != until } + .fold( + this, + { lazyQuery, alterTableRules -> + // Rename table. + alterTableRules.alterTableRenameTable?.let { renameTable -> + return@fold LazyQuery( + tableName = renameTable.newTableName, + query = { lazyQuery.query.copy(table = renameTable.newTableName) }, + ) + } - (alterTableRules.firstChild as? AlterTableApplier)?.let { - return@fold it.applyTo(lazyQuery) - } + (alterTableRules.firstChild as? AlterTableApplier)?.let { + return@fold it.applyTo(lazyQuery) + } - return@fold lazyQuery - }, - ) + return@fold lazyQuery + }, + ) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/QueryElement.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/QueryElement.kt index 9351034f..6a6ca411 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/QueryElement.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/QueryElement.kt @@ -8,16 +8,21 @@ interface QueryElement : PsiElement { /** * Return all of the results that this query exposes. The select_stmt rule * - * SELECT * - * FROM a_table; + * ``` + * SELECT * + * FROM a_table; + * ``` * - * Would expose [QueryResults(a_table, [all of a_tables columns])] + * Would expose `[QueryResults(a_table, [all of a_tables columns])]` * * The join_clause rule * - * a_table JOIN a_second_table + * ``` + * a_table JOIN a_second_table + * ``` * - * Would expose [QueryResult(a_table, [all of a_tables columns]), QueryResult(a_second_table, [all of a_second_tables columns])] + * Would expose `[QueryResult(a_table, [all of a_tables columns]), QueryResult(a_second_table, + * [all of a_second_tables columns])]` */ fun queryExposed(): Collection @@ -51,8 +56,8 @@ interface QueryElement : PsiElement { ) /** - * These aren't considered part of the exposed query (ie performing a SELECT * does not return - * the column in the result set) but they can be explicitly referenced. + * These aren't considered part of the exposed query (ie performing a SELECT * does not return the + * column in the result set) but they can be explicitly referenced. */ data class SynthesizedColumn( val table: PsiElement, diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SchemaContributor.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SchemaContributor.kt index 34f634cf..0b4468d4 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SchemaContributor.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SchemaContributor.kt @@ -7,11 +7,13 @@ import kotlin.reflect.KClass interface SchemaContributor : SqlCompositeElement { fun modifySchema(schema: Schema) + fun name(): String } interface SchemaContributorStub : StubElement { fun name(): String + fun getTextOffset(): Int } @@ -20,14 +22,15 @@ internal open class SchemaContributorStubImpl( type: SqlSchemaContributorElementType, private val name: String, private val textOffset: Int, -) : StubBase(parent, type), - SchemaContributorStub { +) : StubBase(parent, type), SchemaContributorStub { override fun name() = name + override fun getTextOffset() = textOffset } class Schema { - private val map = mutableMapOf, MutableMap>() + private val map = + mutableMapOf, MutableMap>() @Suppress("UNCHECKED_CAST") internal inline fun forType(): MutableMap = @@ -35,7 +38,9 @@ class Schema { @Suppress("UNCHECKED_CAST") internal inline fun put(value: SchemaContributor) { - val map = map.getOrPut(Value::class, { linkedMapOf() }) as MutableMap + val map = + map.getOrPut(Value::class, { linkedMapOf() }) + as MutableMap map.putIfAbsent(value.name(), value) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SchemaContributorIndex.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SchemaContributorIndex.kt index 1b7ee91b..e3d3ab28 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SchemaContributorIndex.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SchemaContributorIndex.kt @@ -10,12 +10,11 @@ import com.intellij.psi.stubs.StubIndexKey interface SchemaContributorIndex { fun getKey(): StubIndexKey + fun get(key: String, project: Project, scope: GlobalSearchScope): Collection companion object { - val KEY by lazy { - StubIndexKey.createIndexKey("sqldelight.schema") - } + val KEY by lazy { StubIndexKey.createIndexKey("sqldelight.schema") } fun getInstance(project: Project): SchemaContributorIndex { return project.serviceOrNull() ?: SchemaContributorIndexImpl.instance @@ -23,7 +22,8 @@ interface SchemaContributorIndex { } } -internal class SchemaContributorIndexImpl : SchemaContributorIndex, StringStubIndexExtension() { +internal class SchemaContributorIndexImpl : + SchemaContributorIndex, StringStubIndexExtension() { override fun getVersion() = 4 override fun getKey(): StubIndexKey { diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlAnnotatedElement.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlAnnotatedElement.kt index ab413a89..22ad3db8 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlAnnotatedElement.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlAnnotatedElement.kt @@ -4,8 +4,6 @@ import com.alecstrong.sql.psi.core.SqlAnnotationHolder import com.intellij.psi.PsiElement interface SqlAnnotatedElement : PsiElement { - /** - * Called by the annotator to annotate this element with any errors or warnings. - */ + /** Called by the annotator to annotate this element with any errors or warnings. */ fun annotate(annotationHolder: SqlAnnotationHolder) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlColumnReference.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlColumnReference.kt index 4028b241..6e41d711 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlColumnReference.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlColumnReference.kt @@ -12,9 +12,8 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiNamedElement import com.intellij.psi.PsiReferenceBase -internal class SqlColumnReference( - element: T, -) : PsiReferenceBase(element, TextRange.from(0, element.textLength)) { +internal class SqlColumnReference(element: T) : + PsiReferenceBase(element, TextRange.from(0, element.textLength)) { override fun handleElementRename(newElementName: String) = element.setName(newElementName) private val resolved = ModifiableFileLazy { @@ -25,12 +24,15 @@ internal class SqlColumnReference( } } - override fun resolve() = if (!element.isValid) null else resolved.forFile(element.containingFile)?.element + override fun resolve() = + if (!element.isValid) null else resolved.forFile(element.containingFile)?.element - internal fun resolveToQuery(): QueryColumn? = if (!element.isValid) null else resolved.forFile(element.containingFile) + internal fun resolveToQuery(): QueryColumn? = + if (!element.isValid) null else resolved.forFile(element.containingFile) internal fun unsafeResolve(): QueryColumn? { - if (element.parent is SqlColumnDef || element.parent is CreateVirtualTableMixin) return QueryColumn(element) + if (element.parent is SqlColumnDef || element.parent is CreateVirtualTableMixin) + return QueryColumn(element) val tableName = tableName() val tables: List @@ -45,11 +47,13 @@ internal class SqlColumnReference( } fun List.matchingColumns(): List { - val columns = flatMap { it.columns } - .filter { it.element is PsiNamedElement && it.element.name == element.name } - val synthesizedColumns = flatMap { it.synthesizedColumns } - .filter { element.name in it.acceptableValues } - .map { QueryColumn(it.table, it.nullable) } + val columns = + flatMap { it.columns } + .filter { it.element is PsiNamedElement && it.element.name == element.name } + val synthesizedColumns = + flatMap { it.synthesizedColumns } + .filter { element.name in it.acceptableValues } + .map { QueryColumn(it.table, it.nullable) } return columns + synthesizedColumns } @@ -68,7 +72,8 @@ internal class SqlColumnReference( override fun getVariants(): Array { tableName()?.let { tableName -> // Only include columns for the already specified table. - return availableQuery().filter { it.table?.name == tableName.name } + return availableQuery() + .filter { it.table?.name == tableName.name } .flatMap { it.columns } .map { it.element } .toLookupArray() @@ -81,23 +86,23 @@ internal class SqlColumnReference( return availableQuery().flatMap { it.columns.map { it.element } }.toLookupArray() } - private fun List.toLookupArray(): Array = filterIsInstance() - .distinctBy { it.name } - .filter { it.isValid } - .map { - if (it is SqlColumnName) { - val sqlColumnDef = it.reference?.resolve()?.parent as? SqlColumnDef - LookupElementBuilder.createWithIcon(it) - .withTypeText(sqlColumnDef?.columnType?.text) - } else { - LookupElementBuilder.createWithIcon(it) + private fun List.toLookupArray(): Array = + filterIsInstance() + .distinctBy { it.name } + .filter { it.isValid } + .map { + if (it is SqlColumnName) { + val sqlColumnDef = it.reference?.resolve()?.parent as? SqlColumnDef + LookupElementBuilder.createWithIcon(it).withTypeText(sqlColumnDef?.columnType?.text) + } else { + LookupElementBuilder.createWithIcon(it) + } } - } - .toTypedArray() + .toTypedArray() /** - * Return the table that the column element this reference wraps belongs to, or null if no - * table was specified. + * Return the table that the column element this reference wraps belongs to, or null if no table + * was specified. */ private fun tableName(): PsiNamedElement? { val parent = element.parent diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlCompositeElement.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlCompositeElement.kt index 39b81159..43731a5e 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlCompositeElement.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlCompositeElement.kt @@ -10,25 +10,27 @@ interface SqlCompositeElement : SqlAnnotatedElement { * * The result set are any rows that have already been selected and the operation is running on. * For example: + * ``` + * CREATE TRIGGER some_trigger + * BEFORE INSERT OF some_table + * BEGIN; + * SELECT * + * FROM some_table + * WHERE new._id = some_table._id; + * END; + * ``` * - * CREATE TRIGGER some_trigger - * BEFORE INSERT OF some_table - * BEGIN; - * SELECT * - * FROM some_table - * WHERE new._id = some_table._id; - * END; - * - * In this situation, everything between BEGIN and END has access to the "new" row, which is - * its own result set with columns. However, "new" is not a table that can be selected from: - * - * CREATE TRIGGER some_trigger - * BEFORE INSERT OF some_table - * BEGIN; - * SELECT * - * FROM new -- invalid - * WHERE new._id = some_table._id; - * END; + * In this situation, everything between BEGIN and END has access to the "new" row, which is its + * own result set with columns. However, "new" is not a table that can be selected from: + * ``` + * CREATE TRIGGER some_trigger + * BEFORE INSERT OF some_table + * BEGIN; + * SELECT * + * FROM new -- invalid + * WHERE new._id = some_table._id; + * END; + * ``` */ fun queryAvailable(child: PsiElement): Collection @@ -36,20 +38,17 @@ interface SqlCompositeElement : SqlAnnotatedElement { * Returns a list of the selectable tables for the given child. * * The available tables are contextual because of common table expressions: - * + * ``` * WITH some_table AS (...) * SELECT * * FROM some_table - * + * ``` */ fun tablesAvailable(child: PsiElement): Collection override fun getContainingFile(): SqlFileBase } -class LazyQuery( - val tableName: NamedElement, - query: () -> QueryResult, -) { +class LazyQuery(val tableName: NamedElement, query: () -> QueryResult) { val query by lazy(query) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlCompositeElementImpl.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlCompositeElementImpl.kt index 2dd3b847..651307c6 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlCompositeElementImpl.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlCompositeElementImpl.kt @@ -10,10 +10,8 @@ import com.intellij.lang.ASTNode import com.intellij.psi.PsiElement import com.intellij.psi.tree.IElementType -open class SqlCompositeElementImpl( - node: ASTNode, -) : ASTWrapperPsiElement(node), - SqlCompositeElement { +open class SqlCompositeElementImpl(node: ASTNode) : + ASTWrapperPsiElement(node), SqlCompositeElement { override fun queryAvailable(child: PsiElement): Collection { return (parent as SqlCompositeElement).queryAvailable(this) } @@ -41,12 +39,11 @@ open class SqlCompositeElementImpl( } } -internal abstract class SqlSchemaContributorImpl>( - stub: SchemaContributorStub?, - nodeType: IElementType?, - node: ASTNode?, -) : StubBasedPsiElementBase(stub, nodeType, node), - SchemaContributor { +internal abstract class SqlSchemaContributorImpl< + SchemaType : SchemaContributor, + ElementType : SqlSchemaContributorElementType, +>(stub: SchemaContributorStub?, nodeType: IElementType?, node: ASTNode?) : + StubBasedPsiElementBase(stub, nodeType, node), SchemaContributor { override fun queryAvailable(child: PsiElement): Collection { return (parent as SqlCompositeElement).queryAvailable(this) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlNamedElementImpl.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlNamedElementImpl.kt index d808b2ce..1cc15bf2 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlNamedElementImpl.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlNamedElementImpl.kt @@ -12,17 +12,13 @@ import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.psi.impl.GeneratedMarkerVisitor import com.intellij.psi.impl.source.tree.TreeElement -abstract class SqlNamedElementImpl( - node: ASTNode, -) : SqlCompositeElementImpl(node), - PsiNameIdentifierOwner { +abstract class SqlNamedElementImpl(node: ASTNode) : + SqlCompositeElementImpl(node), PsiNameIdentifierOwner { abstract val parseRule: (builder: PsiBuilder, level: Int) -> Boolean override fun getText(): String { - return ( - node.findChildByType(SqlTypes.ID)?.text - ?: node.findChildByType(SqlTypes.STRING)!!.text - ).trim('\'', '"', '`', '[', ']') + return (node.findChildByType(SqlTypes.ID)?.text ?: node.findChildByType(SqlTypes.STRING)!!.text) + .trim('\'', '"', '`', '[', ']') } override fun getName() = text @@ -34,20 +30,18 @@ abstract class SqlNamedElementImpl( // is implemented since it's inspired by that, which is documented online in IntelliJ's // official documentation for writing a language plugin. Good luck! - val parserDefinition: ParserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(language) - var builder = PsiBuilderFactory.getInstance().createBuilder( - project, - parent.node, - parserDefinition.createLexer(project), - language, - name, - ) - builder = GeneratedParserUtilBase.adapt_builder_( - node.elementType, - builder, - SqlParser(), - SqlParser.EXTENDS_SETS_, - ) + val parserDefinition: ParserDefinition = + LanguageParserDefinitions.INSTANCE.forLanguage(language) + var builder = + PsiBuilderFactory.getInstance() + .createBuilder(project, parent.node, parserDefinition.createLexer(project), language, name) + builder = + GeneratedParserUtilBase.adapt_builder_( + node.elementType, + builder, + SqlParser(), + SqlParser.EXTENDS_SETS_, + ) GeneratedParserUtilBase.ErrorState.get(builder).currentFrame = GeneratedParserUtilBase.Frame() parseRule(builder, 0) diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlTableReference.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlTableReference.kt index 4ef616eb..9cc3ca97 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlTableReference.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/SqlTableReference.kt @@ -8,15 +8,15 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiNamedElement import com.intellij.psi.PsiReferenceBase -internal class SqlTableReference( - element: T, -) : PsiReferenceBase(element, TextRange.from(0, element.textLength)) { +internal class SqlTableReference(element: T) : + PsiReferenceBase(element, TextRange.from(0, element.textLength)) { override fun handleElementRename(newElementName: String) = element.setName(newElementName) private val resolved = ModifiableFileLazy lazy@{ if (element is SqlNewTableName) return@lazy element if (element.parent.isDefinition()) return@lazy element - return@lazy variants.mapNotNull { it.psiElement } + return@lazy variants + .mapNotNull { it.psiElement } .filterIsInstance() .firstOrNull { it.name == element.name } } @@ -27,25 +27,28 @@ internal class SqlTableReference( if (element is SqlNewTableName) return emptyArray() if (element.parent.isDefinition()) return emptyArray() if (selectFromCurrentQuery()) { - return (element.parent as SqlCompositeElement).queryAvailable(element) + return (element.parent as SqlCompositeElement) + .queryAvailable(element) .mapNotNull { it.table } .filter { it.isValid } .map(LookupElementBuilder::createWithIcon) .toTypedArray() } - return (element.parent as SqlCompositeElement).tablesAvailable(element) + return (element.parent as SqlCompositeElement) + .tablesAvailable(element) .filter { it.tableName.isValid } .map { LookupElementBuilder.createWithIcon(it.tableName) } .toTypedArray() } - private fun PsiElement.isDefinition() = when (this) { - is SqlCreateTableStmt -> true - is SqlCteTableName -> true - is SqlCreateVirtualTableStmt -> true - is SqlCreateViewStmt -> true - else -> false - } + private fun PsiElement.isDefinition() = + when (this) { + is SqlCreateTableStmt -> true + is SqlCteTableName -> true + is SqlCreateVirtualTableStmt -> true + is SqlCreateViewStmt -> true + else -> false + } private fun selectFromCurrentQuery(): Boolean { return element.parent is SqlColumnExpr || element.parent is SqlResultColumn diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/AlterTableAddColumnMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/AlterTableAddColumnMixin.kt index 77e0cc34..c93d55b4 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/AlterTableAddColumnMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/AlterTableAddColumnMixin.kt @@ -7,17 +7,14 @@ import com.alecstrong.sql.psi.core.psi.SqlAlterTableAddColumn import com.alecstrong.sql.psi.core.psi.SqlCompositeElementImpl import com.intellij.lang.ASTNode -internal abstract class AlterTableAddColumnMixin( - node: ASTNode, -) : SqlCompositeElementImpl(node), - SqlAlterTableAddColumn, - AlterTableApplier { +internal abstract class AlterTableAddColumnMixin(node: ASTNode) : + SqlCompositeElementImpl(node), SqlAlterTableAddColumn, AlterTableApplier { override fun applyTo(lazyQuery: LazyQuery): LazyQuery { return LazyQuery( tableName = lazyQuery.tableName, query = { lazyQuery.query.copy( - columns = lazyQuery.query.columns + QueryElement.QueryColumn(columnDef.columnName), + columns = lazyQuery.query.columns + QueryElement.QueryColumn(columnDef.columnName) ) }, ) diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/AlterTableMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/AlterTableMixin.kt index 16de052d..8f17596f 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/AlterTableMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/AlterTableMixin.kt @@ -42,29 +42,28 @@ internal class AlterTableStmtStubImpl( override fun newTableName() = newTableName } -internal abstract class AlterTableMixin private constructor( - stub: AlterTableStmtStub?, - nodeType: IElementType?, - node: ASTNode?, -) : SqlSchemaContributorImpl(stub, nodeType, node), +internal abstract class AlterTableMixin +private constructor(stub: AlterTableStmtStub?, nodeType: IElementType?, node: ASTNode?) : + SqlSchemaContributorImpl(stub, nodeType, node), SqlAlterTableStmt, TableElement { constructor(node: ASTNode) : this(null, null, node) - constructor( - stub: AlterTableStmtStub, - nodeType: IElementType, - ) : this(stub, nodeType, null) + constructor(stub: AlterTableStmtStub, nodeType: IElementType) : this(stub, nodeType, null) override fun getStub() = super.getStub() as AlterTableStmtStub? fun newTableName(): String? { - stub?.let { return it.newTableName() } + stub?.let { + return it.newTableName() + } return newTableName?.name } override fun name(): String { - stub?.let { return it.name() } + stub?.let { + return it.name() + } return tableName.name } @@ -87,15 +86,17 @@ internal abstract class AlterTableMixin private constructor( return LazyQuery( tableName = newTableName ?: tableName, query = result@{ - val tableName = getParentOfType(tableName.reference?.resolve(), TableElement::class.java) - ?: return@result QueryElement.QueryResult(columns = emptyList()) - val lazyQuery = tableName.tableExposed() - try { - lazyQuery.withAlterStatement(this) - } catch (e: AnnotationException) { - lazyQuery - }.query - }, + val tableName = + getParentOfType(tableName.reference?.resolve(), TableElement::class.java) + ?: return@result QueryElement.QueryResult(columns = emptyList()) + val lazyQuery = tableName.tableExposed() + try { + lazyQuery.withAlterStatement(this) + } catch (e: AnnotationException) { + lazyQuery + } + .query + }, ) } @@ -109,8 +110,8 @@ internal abstract class AlterTableMixin private constructor( } val parent = getParentOfType(tableName.reference?.resolve(), TableElement::class.java) when (parent) { - is SqlAlterTableStmt, is SqlCreateTableStmt -> { - } + is SqlAlterTableStmt, + is SqlCreateTableStmt -> {} else -> { annotationHolder.createErrorAnnotation( tableName, @@ -128,14 +129,12 @@ internal abstract class AlterTableMixin private constructor( } } -open class AlterTableElementType( - name: String, -) : SqlSchemaContributorElementType(name, TableElement::class.java) { +open class AlterTableElementType(name: String) : + SqlSchemaContributorElementType(name, TableElement::class.java) { override fun nameType() = SqlTypes.TABLE_NAME - override fun createPsi(stub: SchemaContributorStub) = SqlAlterTableStmtImpl( - stub as AlterTableStmtStub, - this, - ) + + override fun createPsi(stub: SchemaContributorStub) = + SqlAlterTableStmtImpl(stub as AlterTableStmtStub, this) override fun serialize(stub: SchemaContributorStub, stubOutputStream: StubOutputStream) { super.serialize(stub, stubOutputStream) @@ -180,6 +179,4 @@ open class AlterTableElementType( } private val SqlAlterTableStmt.newTableName - get() = alterTableRulesList - .mapNotNull { it.alterTableRenameTable?.newTableName } - .lastOrNull() + get() = alterTableRulesList.mapNotNull { it.alterTableRenameTable?.newTableName }.lastOrNull() diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/BinaryComparisonExprMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/BinaryComparisonExprMixin.kt index 951d00e4..e01609b8 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/BinaryComparisonExprMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/BinaryComparisonExprMixin.kt @@ -6,15 +6,16 @@ import com.alecstrong.sql.psi.core.psi.SqlBindExpr import com.alecstrong.sql.psi.core.psi.SqlCompositeElementImpl import com.intellij.lang.ASTNode -internal abstract class BinaryComparisonExprMixin( - node: ASTNode, -) : SqlCompositeElementImpl(node), - SqlBinaryExpr { +internal abstract class BinaryComparisonExprMixin(node: ASTNode) : + SqlCompositeElementImpl(node), SqlBinaryExpr { override fun annotate(annotationHolder: SqlAnnotationHolder) { super.annotate(annotationHolder) if (firstChild is SqlBindExpr && lastChild is SqlBindExpr) { - annotationHolder.createErrorAnnotation(this, "Cannot bind both sides of a binary comparison expression") + annotationHolder.createErrorAnnotation( + this, + "Cannot bind both sides of a binary comparison expression", + ) } } } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/BinaryLikeExprMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/BinaryLikeExprMixin.kt index 1f282c2e..afaf2721 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/BinaryLikeExprMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/BinaryLikeExprMixin.kt @@ -11,19 +11,18 @@ import com.alecstrong.sql.psi.core.psi.SqlTypes import com.intellij.lang.ASTNode import com.intellij.psi.util.PsiTreeUtil -internal abstract class BinaryLikeExprMixin( - node: ASTNode, -) : SqlCompositeElementImpl(node), - SqlBinaryLikeExpr { +internal abstract class BinaryLikeExprMixin(node: ASTNode) : + SqlCompositeElementImpl(node), SqlBinaryLikeExpr { private val hasMatchOperator: Boolean - get() = binaryLikeOperator.node.findChildByType( - SqlTypes.MATCH, - ) != null + get() = binaryLikeOperator.node.findChildByType(SqlTypes.MATCH) != null override fun annotate(annotationHolder: SqlAnnotationHolder) { if (firstChild is SqlBindExpr && lastChild is SqlBindExpr) { - annotationHolder.createErrorAnnotation(this, "Cannot bind both sides of a ${operatorName()} expression") + annotationHolder.createErrorAnnotation( + this, + "Cannot bind both sides of a ${operatorName()} expression", + ) } else { if (hasMatchOperator) { checkForMatchUsageError(annotationHolder) @@ -32,22 +31,26 @@ internal abstract class BinaryLikeExprMixin( } /** - * Check for common cases where the MATCH operator would fail. For example, the left hand side of the MATCH operator - * must be a column in an FTS table and that table must not be on the right hand side of a LEFT JOIN. + * Check for common cases where the MATCH operator would fail. For example, the left hand side of + * the MATCH operator must be a column in an FTS table and that table must not be on the right + * hand side of a LEFT JOIN. */ private fun checkForMatchUsageError(annotationHolder: SqlAnnotationHolder) { - val isMatchUsageError = when (val firstExpression = exprList.first()) { - is SqlColumnExpr -> { - when (val resolvedReference = firstExpression.columnName.reference?.resolve()) { - is SqlCreateVirtualTableStmt -> - isMatchUsageErrorOnSynthesizedColumn(firstExpression, resolvedReference) - is SqlColumnName -> isMatchUsageErrorOnRegularColumn(firstExpression, resolvedReference) - null -> false // Column is invalid, which is a different error that's handled by the column name element - else -> true + val isMatchUsageError = + when (val firstExpression = exprList.first()) { + is SqlColumnExpr -> { + when (val resolvedReference = firstExpression.columnName.reference?.resolve()) { + is SqlCreateVirtualTableStmt -> + isMatchUsageErrorOnSynthesizedColumn(firstExpression, resolvedReference) + is SqlColumnName -> isMatchUsageErrorOnRegularColumn(firstExpression, resolvedReference) + null -> + false // Column is invalid, which is a different error that's handled by the column + // name element + else -> true + } } + else -> true } - else -> true - } if (isMatchUsageError) { annotationHolder.createErrorAnnotation( @@ -74,24 +77,28 @@ internal abstract class BinaryLikeExprMixin( expression: SqlColumnExpr, columnName: SqlColumnName, ): Boolean { - val table = PsiTreeUtil.findFirstParent(columnName) { it is SqlCreateVirtualTableStmt } - as? SqlCreateVirtualTableStmt + val table = + PsiTreeUtil.findFirstParent(columnName) { it is SqlCreateVirtualTableStmt } + as? SqlCreateVirtualTableStmt return if (table?.usesFtsModule == true) { queryAvailable(expression) .filter { it.table?.name == table.tableName.name } .any { query -> - query.columns.filter { it.element.textMatches(expression.columnName.name) }.any { it.nullable == true } + query.columns + .filter { it.element.textMatches(expression.columnName.name) } + .any { it.nullable == true } } } else { true } } - private fun operatorName() = when { - binaryLikeOperator.node.findChildByType(SqlTypes.MATCH) != null -> "MATCH" - binaryLikeOperator.node.findChildByType(SqlTypes.REGEXP) != null -> "REGEXP" - binaryLikeOperator.node.findChildByType(SqlTypes.GLOB) != null -> "GLOB" - else -> "LIKE" - } + private fun operatorName() = + when { + binaryLikeOperator.node.findChildByType(SqlTypes.MATCH) != null -> "MATCH" + binaryLikeOperator.node.findChildByType(SqlTypes.REGEXP) != null -> "REGEXP" + binaryLikeOperator.node.findChildByType(SqlTypes.GLOB) != null -> "GLOB" + else -> "LIKE" + } } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ColumnAliasMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ColumnAliasMixin.kt index d97a34f1..fe3d1f55 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ColumnAliasMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ColumnAliasMixin.kt @@ -10,10 +10,8 @@ import com.intellij.lang.ASTNode import com.intellij.lang.PsiBuilder import com.intellij.psi.PsiElement -internal abstract class ColumnAliasMixin( - node: ASTNode, -) : SqlNamedElementImpl(node), - SqlColumnAlias { +internal abstract class ColumnAliasMixin(node: ASTNode) : + SqlNamedElementImpl(node), SqlColumnAlias { override val parseRule: (PsiBuilder, Int) -> Boolean = SqlParser::column_alias_real override fun source(): PsiElement { @@ -33,6 +31,7 @@ internal abstract class ColumnAliasMixin( private fun SqlCteTableName.selectStatement(): SqlCompoundSelectStmt { val withClause = parent as SqlWithClause - return withClause.withClauseAuxiliaryStmtList[withClause.cteTableNameList.indexOf(this)].compoundSelectStmt + return withClause.withClauseAuxiliaryStmtList[withClause.cteTableNameList.indexOf(this)] + .compoundSelectStmt } } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ColumnNameMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ColumnNameMixin.kt index d771da96..4843b94f 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ColumnNameMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ColumnNameMixin.kt @@ -10,9 +10,7 @@ import com.intellij.lang.ASTNode import com.intellij.lang.PsiBuilder import javax.swing.Icon -internal abstract class ColumnNameMixin( - node: ASTNode, -) : SqlNamedElementImpl(node) { +internal abstract class ColumnNameMixin(node: ASTNode) : SqlNamedElementImpl(node) { override val parseRule: (PsiBuilder, Int) -> Boolean = SqlParser::column_name_real override fun getReference() = SqlColumnReference(this) diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CompoundSelectStmtMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CompoundSelectStmtMixin.kt index bff8eb89..3248e8e4 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CompoundSelectStmtMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CompoundSelectStmtMixin.kt @@ -16,10 +16,8 @@ import com.intellij.lang.ASTNode import com.intellij.psi.PsiElement import com.intellij.psi.util.PsiTreeUtil -internal abstract class CompoundSelectStmtMixin( - node: ASTNode, -) : WithClauseContainer(node), - SqlCompoundSelectStmt { +internal abstract class CompoundSelectStmtMixin(node: ASTNode) : + WithClauseContainer(node), SqlCompoundSelectStmt { private val queryExposed = ModifiableFileLazy { if (detectRecursion() != null) { return@ModifiableFileLazy emptyList() @@ -28,15 +26,20 @@ internal abstract class CompoundSelectStmtMixin( // Compound information not needed. return@ModifiableFileLazy selectStmtList.first().queryExposed() } - return@ModifiableFileLazy selectStmtList.drop(1).fold(selectStmtList.first().queryExposed()) { query, compounded -> + return@ModifiableFileLazy selectStmtList.drop(1).fold(selectStmtList.first().queryExposed()) { + query, + compounded -> val columns = query.flatMap { it.columns } val compoundedColumns = compounded.queryExposed().flatMap { it.columns } return@fold listOf( - query.first().copy( - columns = columns.zip(compoundedColumns) { column, compounded -> - column.copy(compounded = column.compounded + compounded) - }, - ), + query + .first() + .copy( + columns = + columns.zip(compoundedColumns) { column, compounded -> + column.copy(compounded = column.compounded + compounded) + } + ) ) } } @@ -47,25 +50,32 @@ internal abstract class CompoundSelectStmtMixin( val tablesAvailable = super.tablesAvailable(child) val withClauseAuxiliaryStmts = parent as? SqlWithClauseAuxiliaryStmt ?: return tablesAvailable val withClause = withClauseAuxiliaryStmts.parent as SqlWithClause - if (withClause.node.findChildByType(SqlTypes.RECURSIVE) != null && child != selectStmtList.first()) { + if ( + withClause.node.findChildByType(SqlTypes.RECURSIVE) != null && child != selectStmtList.first() + ) { return tablesAvailable + withClause.tablesExposed() } - val myIndex = withClause.withClauseAuxiliaryStmtList - .mapNotNull { withClauseAuxiliaryStmt -> - PsiTreeUtil.findChildOfAnyType(withClauseAuxiliaryStmt, QueryElement::class.java) - } - .indexOf(this) - return tablesAvailable + withClause.tablesExposed().filterIndexed { index, _ -> index != myIndex } + val myIndex = + withClause.withClauseAuxiliaryStmtList + .mapNotNull { withClauseAuxiliaryStmt -> + PsiTreeUtil.findChildOfAnyType(withClauseAuxiliaryStmt, QueryElement::class.java) + } + .indexOf(this) + return tablesAvailable + + withClause.tablesExposed().filterIndexed { index, _ -> index != myIndex } } override fun queryAvailable(child: PsiElement): Collection { if (child is SqlOrderingTerm && selectStmtList.size == 1) { - val exposed = (selectStmtList.first() as SelectStmtMixin).fromQuery() - .map { it.copy(columns = it.columns.filter { !it.hiddenByUsing }) } + val exposed = + (selectStmtList.first() as SelectStmtMixin).fromQuery().map { + it.copy(columns = it.columns.filter { !it.hiddenByUsing }) + } val exposedColumns = exposed.flatMap { it.columns } // Ordering terms are also applicable in the select statement's from clause. - return queryExposed().filter { it !in exposed } + return queryExposed() + .filter { it !in exposed } .map { QueryResult(it.table, it.columns.filter { it !in exposedColumns }, adjacent = true) } .plus(exposed) } else if (child is SqlExpr || child is SqlOrderingTerm) { @@ -81,17 +91,16 @@ internal abstract class CompoundSelectStmtMixin( annotationHolder.createErrorAnnotation(this, "Recursive subquery found: $recursion") } - selectStmtList.drop(1) - .forEach { - val count = it.queryExposed().flatMap { it.columns }.count() - if (count != numColumns) { - annotationHolder.createErrorAnnotation( - it, - "Unexpected number of columns in compound" + - " statement found: $count expected: $numColumns", - ) - } + selectStmtList.drop(1).forEach { + val count = it.queryExposed().flatMap { it.columns }.count() + if (count != numColumns) { + annotationHolder.createErrorAnnotation( + it, + "Unexpected number of columns in compound" + + " statement found: $count expected: $numColumns", + ) } + } } private fun detectRecursion(): String? { @@ -105,7 +114,9 @@ internal abstract class CompoundSelectStmtMixin( if (!viewTree.add(name)) { return viewTree.joinToString(" -> ") + " -> $name" } - containingFile.viewForName(name)?.recursion()?.let { return it } + containingFile.viewForName(name)?.recursion()?.let { + return it + } viewTree.remove(name) } return null diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateIndexMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateIndexMixin.kt index 6a94e4ad..ffea3c3d 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateIndexMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateIndexMixin.kt @@ -17,17 +17,17 @@ internal abstract class CreateIndexMixin( stub: SchemaContributorStub?, nodeType: IElementType?, node: ASTNode?, -) : SqlSchemaContributorImpl(stub, nodeType, node), +) : + SqlSchemaContributorImpl(stub, nodeType, node), SqlCreateIndexStmt { constructor(node: ASTNode) : this(null, null, node) - constructor( - stub: SchemaContributorStub, - nodeType: IElementType, - ) : this(stub, nodeType, null) + constructor(stub: SchemaContributorStub, nodeType: IElementType) : this(stub, nodeType, null) override fun name(): String { - stub?.let { return it.name() } + stub?.let { + return it.name() + } return indexName.text } @@ -38,16 +38,18 @@ internal abstract class CreateIndexMixin( override fun queryAvailable(child: PsiElement): Collection { if (child in indexedColumnList || child == expr) { return listOfNotNull( - tablesAvailable(child).firstOrNull { it.tableName.name == tableName?.name }?.query, + tablesAvailable(child).firstOrNull { it.tableName.name == tableName?.name }?.query ) } return super.queryAvailable(child) } override fun annotate(annotationHolder: SqlAnnotationHolder) { - if (node.findChildByType(SqlTypes.EXISTS) == null && - containingFile.schema(this) - .any { it != this && it.indexName.textMatches(indexName) } + if ( + node.findChildByType(SqlTypes.EXISTS) == null && + containingFile.schema(this).any { + it != this && it.indexName.textMatches(indexName) + } ) { annotationHolder.createErrorAnnotation(indexName, "Duplicate index name ${indexName.text}") } @@ -55,9 +57,9 @@ internal abstract class CreateIndexMixin( } } -open class CreateIndexElementType( - name: String, -) : SqlSchemaContributorElementType(name, SqlCreateIndexStmt::class.java) { +open class CreateIndexElementType(name: String) : + SqlSchemaContributorElementType(name, SqlCreateIndexStmt::class.java) { override fun nameType() = SqlTypes.INDEX_NAME + override fun createPsi(stub: SchemaContributorStub) = SqlCreateIndexStmtImpl(stub, this) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateTableMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateTableMixin.kt index 221f2576..00d0ccae 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateTableMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateTableMixin.kt @@ -24,22 +24,19 @@ import com.intellij.psi.PsiElement import com.intellij.psi.tree.IElementType import com.intellij.psi.util.PsiTreeUtil -internal abstract class CreateTableMixin private constructor( - stub: SchemaContributorStub?, - nodeType: IElementType?, - node: ASTNode?, -) : SqlSchemaContributorImpl(stub, nodeType, node), +internal abstract class CreateTableMixin +private constructor(stub: SchemaContributorStub?, nodeType: IElementType?, node: ASTNode?) : + SqlSchemaContributorImpl(stub, nodeType, node), SqlCreateTableStmt, TableElement { constructor(node: ASTNode) : this(null, null, node) - constructor( - stub: SchemaContributorStub, - nodeType: IElementType, - ) : this(stub, nodeType, null) + constructor(stub: SchemaContributorStub, nodeType: IElementType) : this(stub, nodeType, null) override fun name(): String { - stub?.let { return it.name() } + stub?.let { + return it.name() + } return tableName.name } @@ -47,35 +44,34 @@ internal abstract class CreateTableMixin private constructor( schema.put(this) } - override fun tableExposed() = LazyQuery(tableName) { - compoundSelectStmt?.let { - QueryResult(tableName, it.queryExposed().flatMap { it.columns }) - } ?: queryAvailable(this).single() - } + override fun tableExposed() = + LazyQuery(tableName) { + compoundSelectStmt?.let { QueryResult(tableName, it.queryExposed().flatMap { it.columns }) } + ?: queryAvailable(this).single() + } override fun queryAvailable(child: PsiElement): List { - val containsWithoutId = tableOptions - ?.tableOptionList - ?.any { - (it.node.findChildByType(SqlTypes.WITHOUT) != null) - } ?: false - val synthesizedColumns = if (!containsWithoutId) { - val columnNames = columnDefList.mapNotNull { it.columnName.name } - listOf( - SynthesizedColumn( - table = this, - acceptableValues = listOf("rowid", "oid", "_rowid_").filter { it !in columnNames }, - ), - ) - } else { - emptyList() - } + val containsWithoutId = + tableOptions?.tableOptionList?.any { (it.node.findChildByType(SqlTypes.WITHOUT) != null) } + ?: false + val synthesizedColumns = + if (!containsWithoutId) { + val columnNames = columnDefList.mapNotNull { it.columnName.name } + listOf( + SynthesizedColumn( + table = this, + acceptableValues = listOf("rowid", "oid", "_rowid_").filter { it !in columnNames }, + ) + ) + } else { + emptyList() + } return listOf( QueryResult( table = tableName, columns = columnDefList.map { it.columnName }.asColumns(), synthesizedColumns = synthesizedColumns, - ), + ) ) } @@ -98,13 +94,15 @@ internal abstract class CreateTableMixin private constructor( } } - return columnDefList.filter { it.columnConstraintList.any { it.hasPrimaryKey() } } + return columnDefList + .filter { it.columnConstraintList.any { it.hasPrimaryKey() } } .take(1) .map { it.columnName.name } } private fun isCollectivelyUnique(columns: List): Boolean { - tableConstraintList.filter { it.hasPrimaryKey() || it.isUnique() } + tableConstraintList + .filter { it.hasPrimaryKey() || it.isUnique() } .map { it.indexedColumnList.mapNotNull { val expr = it.expr @@ -113,25 +111,25 @@ internal abstract class CreateTableMixin private constructor( } .plus( listOf( - columnDefList.filter { - it.columnConstraintList.any { it.hasPrimaryKey() || it.isUnique() } - }.mapNotNull { it.columnName.name }, - ), + columnDefList + .filter { it.columnConstraintList.any { it.hasPrimaryKey() || it.isUnique() } } + .mapNotNull { it.columnName.name } + ) ) - .forEach { uniqueKeys -> - if (columns.map { it.name }.all { it in uniqueKeys }) return true - } + .forEach { uniqueKeys -> if (columns.map { it.name }.all { it in uniqueKeys }) return true } // Check if there is an externally created unique index that matches the given columns. - containingFile.schema(this) + containingFile + .schema(this) .filter { it.isUnique() && it.indexedColumnList.all { it.collationName == null } } .forEach { - val indexedColumns = it.indexedColumnList.mapNotNull { - val expr = it.expr - if (expr is SqlColumnExpr) expr.columnName.name else null - } - if (columns.map { it.name }.containsAll(indexedColumns) && - columns.size == indexedColumns.size + val indexedColumns = + it.indexedColumnList.mapNotNull { + val expr = it.expr + if (expr is SqlColumnExpr) expr.columnName.name else null + } + if ( + columns.map { it.name }.containsAll(indexedColumns) && columns.size == indexedColumns.size ) { return true } @@ -141,14 +139,13 @@ internal abstract class CreateTableMixin private constructor( } private fun checkForDuplicateColumns(annotationHolder: SqlAnnotationHolder) { - columnDefList.map { it.columnName } + columnDefList + .map { it.columnName } .groupBy { it.name } .map { it.value } .filter { it.size > 1 } .flatMap { it } - .forEach { - annotationHolder.createErrorAnnotation(it, "Duplicate column name") - } + .forEach { annotationHolder.createErrorAnnotation(it, "Duplicate column name") } } private fun checkForeignKeys(annotationHolder: SqlAnnotationHolder) { @@ -207,19 +204,20 @@ internal abstract class CreateTableMixin private constructor( } } - tableConstraintList.filter { it.foreignKeyClause != null } + tableConstraintList + .filter { it.foreignKeyClause != null } .forEach { constraint -> - constraint.foreignKeyClause!!.checkCompositeForeignKey( - constraint.columnNameList, - ) + constraint.foreignKeyClause!!.checkCompositeForeignKey(constraint.columnNameList) } } private fun checkPrimaryKey(annotationHolder: SqlAnnotationHolder) { // Verify there is only a single primary key - val constraints = columnDefList.flatMap { it.columnConstraintList } - .filter { it.hasPrimaryKey() } - .plus(tableConstraintList.filter { it.hasPrimaryKey() }) + val constraints = + columnDefList + .flatMap { it.columnConstraintList } + .filter { it.hasPrimaryKey() } + .plus(tableConstraintList.filter { it.hasPrimaryKey() }) if (constraints.size > 1) { constraints.forEach { annotationHolder.createErrorAnnotation( @@ -241,9 +239,7 @@ internal abstract class CreateTableMixin private constructor( } } - /** - * @return true if the column constraint lists are all well formed. - */ + /** @return true if the column constraint lists are all well formed. */ private fun checkForDuplicateColumnConstraints(annotationHolder: SqlAnnotationHolder): Boolean { columnDefList.forEach { if (it.columnConstraintList.count { it.hasPrimaryKey() } > 1) { @@ -260,13 +256,14 @@ internal abstract class CreateTableMixin private constructor( companion object { private fun SqlCompositeElement.hasPrimaryKey() = node.findChildByType(SqlTypes.PRIMARY) != null + private fun SqlCompositeElement.isUnique() = node.findChildByType(SqlTypes.UNIQUE) != null } } -open class CreateTableElementType( - name: String, -) : SqlSchemaContributorElementType(name, TableElement::class.java) { +open class CreateTableElementType(name: String) : + SqlSchemaContributorElementType(name, TableElement::class.java) { override fun nameType() = SqlTypes.TABLE_NAME + override fun createPsi(stub: SchemaContributorStub) = SqlCreateTableStmtImpl(stub, this) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateTriggerMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateTriggerMixin.kt index be63336d..bda4a99f 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateTriggerMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateTriggerMixin.kt @@ -19,17 +19,17 @@ internal abstract class CreateTriggerMixin( stub: SchemaContributorStub?, nodeType: IElementType?, node: ASTNode?, -) : SqlSchemaContributorImpl(stub, nodeType, node), +) : + SqlSchemaContributorImpl(stub, nodeType, node), SqlCreateTriggerStmt { constructor(node: ASTNode) : this(null, null, node) - constructor( - stub: SchemaContributorStub, - nodeType: IElementType, - ) : this(stub, nodeType, null) + constructor(stub: SchemaContributorStub, nodeType: IElementType) : this(stub, nodeType, null) override fun name(): String { - stub?.let { return it.name() } + stub?.let { + return it.name() + } return triggerName.text } @@ -39,9 +39,9 @@ internal abstract class CreateTriggerMixin( override fun queryAvailable(child: PsiElement): Collection { if (child is MutatorMixin || child is SqlExpr || child is CompoundSelectStmtMixin) { - val table = tablesAvailable(this).firstOrNull { - it.tableName.name == tableName?.name - }?.query ?: return super.queryAvailable(child) + val table = + tablesAvailable(this).firstOrNull { it.tableName.name == tableName?.name }?.query + ?: return super.queryAvailable(child) if (hasElement(SqlTypes.INSERT)) { return listOf( @@ -49,7 +49,7 @@ internal abstract class CreateTriggerMixin( SingleRow(tableName!!, "new"), table.columns, synthesizedColumns = table.synthesizedColumns, - ), + ) ) } if (hasElement(SqlTypes.UPDATE)) { @@ -72,22 +72,24 @@ internal abstract class CreateTriggerMixin( SingleRow(tableName!!, "old"), table.columns, synthesizedColumns = table.synthesizedColumns, - ), + ) ) } } if (child is SqlColumnName) { return listOfNotNull( - tablesAvailable(this).firstOrNull { it.tableName.name == tableName?.name }?.query, + tablesAvailable(this).firstOrNull { it.tableName.name == tableName?.name }?.query ) } return super.queryAvailable(child) } override fun annotate(annotationHolder: SqlAnnotationHolder) { - if (node.findChildByType(SqlTypes.EXISTS) == null && - containingFile.schema(this) - .any { it != this && it.triggerName.textMatches(triggerName) } + if ( + node.findChildByType(SqlTypes.EXISTS) == null && + containingFile.schema(this).any { + it != this && it.triggerName.textMatches(triggerName) + } ) { annotationHolder.createErrorAnnotation( triggerName, @@ -105,5 +107,6 @@ internal abstract class CreateTriggerMixin( internal class CreateTriggerElementType(name: String) : SqlSchemaContributorElementType(name, SqlCreateTriggerStmt::class.java) { override fun nameType() = SqlTypes.TRIGGER_NAME + override fun createPsi(stub: SchemaContributorStub) = SqlCreateTriggerStmtImpl(stub, this) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateViewMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateViewMixin.kt index b95852cf..3ea2e43e 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateViewMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateViewMixin.kt @@ -19,18 +19,18 @@ internal abstract class CreateViewMixin( stub: SchemaContributorStub?, nodeType: IElementType?, node: ASTNode?, -) : SqlSchemaContributorImpl(stub, nodeType, node), +) : + SqlSchemaContributorImpl(stub, nodeType, node), SqlCreateViewStmt, TableElement { constructor(node: ASTNode) : this(null, null, node) - constructor( - stub: SchemaContributorStub, - nodeType: IElementType, - ) : this(stub, nodeType, null) + constructor(stub: SchemaContributorStub, nodeType: IElementType) : this(stub, nodeType, null) override fun name(): String { - stub?.let { return it.name() } + stub?.let { + return it.name() + } return viewName.name } @@ -41,16 +41,17 @@ internal abstract class CreateViewMixin( schema.put(this) } - override fun tableExposed() = LazyQuery(viewName) { - val columns = - if (columnAliasList.isEmpty()) { - compoundSelectStmt?.queryExposed()?.flatMap { it.columns } - } else { - columnAliasList.asColumns() - } + override fun tableExposed() = + LazyQuery(viewName) { + val columns = + if (columnAliasList.isEmpty()) { + compoundSelectStmt?.queryExposed()?.flatMap { it.columns } + } else { + columnAliasList.asColumns() + } - QueryResult(viewName, columns ?: emptyList()) - } + QueryResult(viewName, columns ?: emptyList()) + } override fun annotate(annotationHolder: SqlAnnotationHolder) { super.annotate(annotationHolder) @@ -68,5 +69,6 @@ internal abstract class CreateViewMixin( open class CreateViewElementType(name: String) : SqlSchemaContributorElementType(name, TableElement::class.java) { override fun nameType() = SqlTypes.VIEW_NAME + override fun createPsi(stub: SchemaContributorStub) = SqlCreateViewStmtImpl(stub, this) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateVirtualTableMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateVirtualTableMixin.kt index 6777f784..2de88488 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateVirtualTableMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/CreateVirtualTableMixin.kt @@ -20,18 +20,18 @@ internal abstract class CreateVirtualTableMixin( stub: SchemaContributorStub?, nodeType: IElementType?, node: ASTNode?, -) : SqlSchemaContributorImpl(stub, nodeType, node), +) : + SqlSchemaContributorImpl(stub, nodeType, node), SqlCreateVirtualTableStmt, TableElement { constructor(node: ASTNode) : this(null, null, node) - constructor( - stub: SchemaContributorStub, - nodeType: IElementType, - ) : this(stub, nodeType, null) + constructor(stub: SchemaContributorStub, nodeType: IElementType) : this(stub, nodeType, null) override fun name(): String { - stub?.let { return it.name() } + stub?.let { + return it.name() + } return tableName.name } @@ -40,37 +40,41 @@ internal abstract class CreateVirtualTableMixin( } override fun tableExposed(): LazyQuery { - val columnNameElements = findChildrenByClass( - SqlModuleArgument::class.java, - ) - .mapNotNull { it.moduleArgumentDef?.moduleColumnDef?.columnName ?: it.moduleArgumentDef?.columnDef?.columnName } - - val synthesizedColumns = when { - usesFts3Module || usesFts4Module -> { - val columnNames = columnNameElements.map { it.name } - - listOf( - SynthesizedColumn( - table = this, - acceptableValues = listOf("docid", "rowid", "oid", "_rowid_", tableName.name) - .filter { it !in columnNames }, - ), - ) - } - usesFts5Module -> { - val columnNames = columnNameElements.map { it.name } - - listOf( - SynthesizedColumn( - table = this, - acceptableValues = listOf("rowid", "_row_id_", "rank", tableName.name) - .filter { it !in columnNames }, - ), - ) + val columnNameElements = + findChildrenByClass(SqlModuleArgument::class.java).mapNotNull { + it.moduleArgumentDef?.moduleColumnDef?.columnName + ?: it.moduleArgumentDef?.columnDef?.columnName } - else -> emptyList() - } + val synthesizedColumns = + when { + usesFts3Module || usesFts4Module -> { + val columnNames = columnNameElements.map { it.name } + + listOf( + SynthesizedColumn( + table = this, + acceptableValues = + listOf("docid", "rowid", "oid", "_rowid_", tableName.name).filter { + it !in columnNames + }, + ) + ) + } + usesFts5Module -> { + val columnNames = columnNameElements.map { it.name } + + listOf( + SynthesizedColumn( + table = this, + acceptableValues = + listOf("rowid", "_row_id_", "rank", tableName.name).filter { it !in columnNames }, + ) + ) + } + + else -> emptyList() + } return LazyQuery(tableName) { QueryResult( @@ -85,6 +89,7 @@ internal abstract class CreateVirtualTableMixin( internal class CreateVirtualTableElementType(name: String) : SqlSchemaContributorElementType(name, TableElement::class.java) { override fun nameType() = SqlTypes.TABLE_NAME + override fun createPsi(stub: SchemaContributorStub) = SqlCreateVirtualTableStmtImpl(stub, this) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropIndexMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropIndexMixin.kt index 9538cf65..183eb1ee 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropIndexMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropIndexMixin.kt @@ -12,21 +12,18 @@ import com.alecstrong.sql.psi.core.psi.impl.SqlDropIndexStmtImpl import com.intellij.lang.ASTNode import com.intellij.psi.tree.IElementType -internal abstract class DropIndexMixin private constructor( - stub: SchemaContributorStub?, - nodeType: IElementType?, - node: ASTNode?, -) : SqlSchemaContributorImpl(stub, nodeType, node), +internal abstract class DropIndexMixin +private constructor(stub: SchemaContributorStub?, nodeType: IElementType?, node: ASTNode?) : + SqlSchemaContributorImpl(stub, nodeType, node), SqlDropIndexStmt { constructor(node: ASTNode) : this(null, null, node) - constructor( - stub: SchemaContributorStub, - nodeType: IElementType, - ) : this(stub, nodeType, null) + constructor(stub: SchemaContributorStub, nodeType: IElementType) : this(stub, nodeType, null) override fun name(): String { - stub?.let { return it.name() } + stub?.let { + return it.name() + } return indexName?.text ?: "" } @@ -36,9 +33,11 @@ internal abstract class DropIndexMixin private constructor( override fun annotate(annotationHolder: SqlAnnotationHolder) { indexName?.let { indexName -> - if (node.findChildByType(SqlTypes.EXISTS) == null && - containingFile.schema(this) - .none { it != this && it.indexName.textMatches(indexName) } + if ( + node.findChildByType(SqlTypes.EXISTS) == null && + containingFile.schema(this).none { + it != this && it.indexName.textMatches(indexName) + } ) { annotationHolder.createErrorAnnotation( indexName, @@ -51,9 +50,9 @@ internal abstract class DropIndexMixin private constructor( } } -internal class DropIndexElementType( - name: String, -) : SqlSchemaContributorElementType(name, SqlCreateIndexStmt::class.java) { +internal class DropIndexElementType(name: String) : + SqlSchemaContributorElementType(name, SqlCreateIndexStmt::class.java) { override fun nameType() = SqlTypes.TABLE_NAME + override fun createPsi(stub: SchemaContributorStub) = SqlDropIndexStmtImpl(stub, this) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropTableMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropTableMixin.kt index ecfb205c..c2bf6e65 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropTableMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropTableMixin.kt @@ -11,21 +11,18 @@ import com.alecstrong.sql.psi.core.psi.impl.SqlDropTableStmtImpl import com.intellij.lang.ASTNode import com.intellij.psi.tree.IElementType -internal abstract class DropTableMixin private constructor( - stub: SchemaContributorStub?, - nodeType: IElementType?, - node: ASTNode?, -) : SqlSchemaContributorImpl(stub, nodeType, node), +internal abstract class DropTableMixin +private constructor(stub: SchemaContributorStub?, nodeType: IElementType?, node: ASTNode?) : + SqlSchemaContributorImpl(stub, nodeType, node), SqlDropTableStmt { constructor(node: ASTNode) : this(null, null, node) - constructor( - stub: SchemaContributorStub, - nodeType: IElementType, - ) : this(stub, nodeType, null) + constructor(stub: SchemaContributorStub, nodeType: IElementType) : this(stub, nodeType, null) override fun name(): String { - stub?.let { return it.name() } + stub?.let { + return it.name() + } return tableName?.name ?: "" } @@ -34,9 +31,9 @@ internal abstract class DropTableMixin private constructor( } } -internal class DropTableElementType( - name: String, -) : SqlSchemaContributorElementType(name, TableElement::class.java) { +internal class DropTableElementType(name: String) : + SqlSchemaContributorElementType(name, TableElement::class.java) { override fun nameType() = SqlTypes.TABLE_NAME + override fun createPsi(stub: SchemaContributorStub) = SqlDropTableStmtImpl(stub, this) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropTriggerMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropTriggerMixin.kt index a5d55f40..acfeceab 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropTriggerMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropTriggerMixin.kt @@ -16,14 +16,12 @@ internal abstract class DropTriggerMixin( stub: SchemaContributorStub?, nodeType: IElementType?, node: ASTNode?, -) : SqlSchemaContributorImpl(stub, nodeType, node), +) : + SqlSchemaContributorImpl(stub, nodeType, node), SqlDropTriggerStmt { constructor(node: ASTNode) : this(null, null, node) - constructor( - stub: SchemaContributorStub, - nodeType: IElementType, - ) : this(stub, nodeType, null) + constructor(stub: SchemaContributorStub, nodeType: IElementType) : this(stub, nodeType, null) override fun name() = triggerName?.text ?: "" @@ -35,9 +33,11 @@ internal abstract class DropTriggerMixin( override fun annotate(annotationHolder: SqlAnnotationHolder) { triggerName?.let { triggerName -> - if (node.findChildByType(SqlTypes.EXISTS) == null && - containingFile.schema(this) - .none { it != this && it.triggerName.textMatches(triggerName) } + if ( + node.findChildByType(SqlTypes.EXISTS) == null && + containingFile.schema(this).none { + it != this && it.triggerName.textMatches(triggerName) + } ) { annotationHolder.createErrorAnnotation( triggerName, @@ -53,5 +53,6 @@ internal abstract class DropTriggerMixin( internal class DropTriggerElementType(name: String) : SqlSchemaContributorElementType(name, SqlCreateTriggerStmt::class.java) { override fun nameType() = SqlTypes.TRIGGER_NAME + override fun createPsi(stub: SchemaContributorStub) = SqlDropTriggerStmtImpl(stub, this) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropViewMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropViewMixin.kt index 81a51af6..68336ba3 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropViewMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/DropViewMixin.kt @@ -16,17 +16,17 @@ internal abstract class DropViewMixin( stub: SchemaContributorStub?, nodeType: IElementType?, node: ASTNode?, -) : SqlSchemaContributorImpl(stub, nodeType, node), +) : + SqlSchemaContributorImpl(stub, nodeType, node), SqlDropViewStmt { constructor(node: ASTNode) : this(null, null, node) - constructor( - stub: SchemaContributorStub, - nodeType: IElementType, - ) : this(stub, nodeType, null) + constructor(stub: SchemaContributorStub, nodeType: IElementType) : this(stub, nodeType, null) override fun name(): String { - stub?.let { return it.name() } + stub?.let { + return it.name() + } return viewName?.text ?: "" } @@ -39,5 +39,6 @@ internal abstract class DropViewMixin( internal class DropViewElementType(name: String) : SqlSchemaContributorElementType(name, TableElement::class.java) { override fun nameType() = SqlTypes.VIEW_NAME + override fun createPsi(stub: SchemaContributorStub) = SqlDropViewStmtImpl(stub, this) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ForeignKeyClauseMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ForeignKeyClauseMixin.kt index 351a7998..b8e996eb 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ForeignKeyClauseMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ForeignKeyClauseMixin.kt @@ -6,13 +6,13 @@ import com.alecstrong.sql.psi.core.psi.SqlForeignKeyClause import com.intellij.lang.ASTNode import com.intellij.psi.PsiElement -internal abstract class ForeignKeyClauseMixin( - node: ASTNode, -) : SqlCompositeElementImpl(node), - SqlForeignKeyClause { +internal abstract class ForeignKeyClauseMixin(node: ASTNode) : + SqlCompositeElementImpl(node), SqlForeignKeyClause { override fun queryAvailable(child: PsiElement): Collection { if (child in columnNameList) { - val table = tablesAvailable(child).firstOrNull { it.tableName.name == foreignTable.name } ?: return emptyList() + val table = + tablesAvailable(child).firstOrNull { it.tableName.name == foreignTable.name } + ?: return emptyList() return listOf(table.query) } return super.queryAvailable(child) diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/GroupByMixing.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/GroupByMixing.kt index 0dca697e..e3e08aba 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/GroupByMixing.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/GroupByMixing.kt @@ -9,10 +9,7 @@ import com.alecstrong.sql.psi.core.psi.SqlSelectStmt import com.intellij.lang.ASTNode import com.intellij.psi.PsiElement -internal abstract class GroupByMixing( - node: ASTNode, -) : SqlCompositeElementImpl(node), - SqlGroupBy { +internal abstract class GroupByMixing(node: ASTNode) : SqlCompositeElementImpl(node), SqlGroupBy { override fun queryAvailable(child: PsiElement): Collection { return (parent as SqlSelectStmt).queryAvailable(child) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/InExprMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/InExprMixin.kt index feac959d..6d6b8dda 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/InExprMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/InExprMixin.kt @@ -6,18 +6,16 @@ import com.alecstrong.sql.psi.core.psi.SqlCompositeElementImpl import com.alecstrong.sql.psi.core.psi.SqlInExpr import com.intellij.lang.ASTNode -internal abstract class InExprMixin( - node: ASTNode, -) : SqlCompositeElementImpl(node), - SqlInExpr { +internal abstract class InExprMixin(node: ASTNode) : SqlCompositeElementImpl(node), SqlInExpr { override fun annotate(annotationHolder: SqlAnnotationHolder) { if (firstChild is SqlBindExpr && lastChild is SqlBindExpr) { annotationHolder.createErrorAnnotation(this, "Cannot bind both sides of an IN expression") } - val query = compoundSelectStmt?.queryExposed() - ?: tableName?.let { table -> tableAvailable(this, table.name) } - ?: emptyList() + val query = + compoundSelectStmt?.queryExposed() + ?: tableName?.let { table -> tableAvailable(this, table.name) } + ?: emptyList() if (query.flatMap { it.columns }.size > 1) { annotationHolder.createErrorAnnotation( this, diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/InsertStmtMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/InsertStmtMixin.kt index 51f8d8c6..78a05118 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/InsertStmtMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/InsertStmtMixin.kt @@ -5,13 +5,11 @@ import com.alecstrong.sql.psi.core.psi.SqlInsertStmt import com.intellij.lang.ASTNode import com.intellij.psi.PsiElement -internal abstract class InsertStmtMixin( - node: ASTNode, -) : MutatorMixin(node), - SqlInsertStmt { +internal abstract class InsertStmtMixin(node: ASTNode) : MutatorMixin(node), SqlInsertStmt { override fun queryAvailable(child: PsiElement): Collection { // Aliasing the table in an insert is useful when doing an UPSERT operation: - // INSERT INTO tbl AS tblAlias (..) VALUES (..) ON CONFLICT (..) DO UPDATE SET x = tblAlias.x + excluded.x + // INSERT INTO tbl AS tblAlias (..) VALUES (..) ON CONFLICT (..) DO UPDATE SET x = tblAlias.x + + // excluded.x // ^^^^^^^^ ^^^^^^^^ tableAlias?.let { alias -> val available = ArrayList(super.queryAvailable(child)) diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/InsertStmtValuesMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/InsertStmtValuesMixin.kt index 0b8934dc..0762e481 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/InsertStmtValuesMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/InsertStmtValuesMixin.kt @@ -8,10 +8,8 @@ import com.alecstrong.sql.psi.core.psi.SqlInsertStmtValues import com.alecstrong.sql.psi.core.psi.SqlTypes import com.intellij.lang.ASTNode -internal abstract class InsertStmtValuesMixin( - node: ASTNode, -) : SqlCompositeElementImpl(node), - SqlInsertStmtValues { +internal abstract class InsertStmtValuesMixin(node: ASTNode) : + SqlCompositeElementImpl(node), SqlInsertStmtValues { override fun getParent(): SqlInsertStmt? { return super.getParent() as SqlInsertStmt? } @@ -21,9 +19,7 @@ internal abstract class InsertStmtValuesMixin( val table = tableAvailable(this, parent.tableName.name).firstOrNull() ?: return val columns = table.columns.map { (it.element as SqlColumnName).name } // DEFAULT VALUES clause - val insertDefaultValues = node.findChildByType( - SqlTypes.DEFAULT, - ) != null + val insertDefaultValues = node.findChildByType(SqlTypes.DEFAULT) != null val setColumns = if (parent.columnNameList.isEmpty() && !insertDefaultValues) { columns @@ -52,10 +48,11 @@ internal abstract class InsertStmtValuesMixin( } } - val needsDefaultValue = table.columns - .filterNot { (element, _) -> element is SqlColumnName && element.name in setColumns } - .map { it.element as SqlColumnName } - .filterNot { (it.parent as ColumnDefMixin).hasDefaultValue() } + val needsDefaultValue = + table.columns + .filterNot { (element, _) -> element is SqlColumnName && element.name in setColumns } + .map { it.element as SqlColumnName } + .filterNot { (it.parent as ColumnDefMixin).hasDefaultValue() } if (needsDefaultValue.size == 1) { annotationHolder.createErrorAnnotation( parent, diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/JoinClauseMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/JoinClauseMixin.kt index e8960d1e..c4dd636d 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/JoinClauseMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/JoinClauseMixin.kt @@ -12,52 +12,52 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiNamedElement import com.intellij.psi.tree.TokenSet -internal abstract class JoinClauseMixin( - node: ASTNode, -) : SqlCompositeElementImpl(node), - SqlJoinClause { +internal abstract class JoinClauseMixin(node: ASTNode) : + SqlCompositeElementImpl(node), SqlJoinClause { override fun queryAvailable(child: PsiElement): Collection { if (child is SqlJoinConstraint) { - val queryAvailable = tableOrSubqueryList[0].queryExposed() - .map { it.copy(adjacent = true) } - .plus(super.queryAvailable(child).map { it.copy(adjacent = false) }) - .toMutableList() - tableOrSubqueryList.drop(1).zip(joinConstraintList) - .forEach { (subquery, constraint) -> - if (child == constraint) { - if (child.node.findChildByType( - SqlTypes.USING, - ) != null - ) { - return listOf( - QueryResult( - null, - queryAvailable.flatMap { it.columns } - .filter { (column, _) -> - column is PsiNamedElement && column.name!! in subquery.queryExposed() - .flatMap { it.columns } - .mapNotNull { (it.element as? PsiNamedElement)?.name } - } - .distinctBy { (it.element as? PsiNamedElement)?.name ?: it }, - ), + val queryAvailable = + tableOrSubqueryList[0] + .queryExposed() + .map { it.copy(adjacent = true) } + .plus(super.queryAvailable(child).map { it.copy(adjacent = false) }) + .toMutableList() + tableOrSubqueryList.drop(1).zip(joinConstraintList).forEach { (subquery, constraint) -> + if (child == constraint) { + if (child.node.findChildByType(SqlTypes.USING) != null) { + return listOf( + QueryResult( + null, + queryAvailable + .flatMap { it.columns } + .filter { (column, _) -> + column is PsiNamedElement && + column.name!! in + subquery + .queryExposed() + .flatMap { it.columns } + .mapNotNull { (it.element as? PsiNamedElement)?.name } + } + .distinctBy { (it.element as? PsiNamedElement)?.name ?: it }, ) - } - return queryAvailable + subquery.queryExposed() + ) } - queryAvailable += subquery.queryExposed() + return queryAvailable + subquery.queryExposed() } + queryAvailable += subquery.queryExposed() + } return queryExposed() } return super.queryAvailable(child) } private val queryExposed = ModifiableFileLazy { - var queryAvailable: Collection = tableOrSubqueryList.first().queryExposed() for ((index, subquery) in tableOrSubqueryList.zipWithNext().withIndex()) { - val constraint: SqlJoinConstraint? = if (index in joinConstraintList.indices) joinConstraintList[index] else null + val constraint: SqlJoinConstraint? = + if (index in joinConstraintList.indices) joinConstraintList[index] else null val operator: SqlJoinOperator = joinOperatorList[index] val query = subquery.second.queryExposed() @@ -76,12 +76,13 @@ internal abstract class JoinClauseMixin( rightSynthesizedColumns = rightSynthesizedColumns.map { it.copy(nullable = true) } queryAvailable -= rightQuery - queryAvailable += QueryResult( - table = rightQuery.first().table, - columns = rightColumns, - synthesizedColumns = rightSynthesizedColumns, - joinConstraint = joinConstraintList[index], - ) + queryAvailable += + QueryResult( + table = rightQuery.first().table, + columns = rightColumns, + synthesizedColumns = rightSynthesizedColumns, + joinConstraint = joinConstraintList[index], + ) } if (leftJoinOperator(operator)) { @@ -91,17 +92,19 @@ internal abstract class JoinClauseMixin( if (constraint != null && usingConstraint(constraint)) { val columnNames = constraint.columnNameList.map { it.name } - columns = columns.map { - it.copy(hiddenByUsing = it.element is PsiNamedElement && it.element.name in columnNames) - } + columns = + columns.map { + it.copy(hiddenByUsing = it.element is PsiNamedElement && it.element.name in columnNames) + } } - queryAvailable += QueryResult( - table = query.first().table, - columns = columns, - synthesizedColumns = synthesizedColumns, - joinConstraint = constraint, - ) + queryAvailable += + QueryResult( + table = query.first().table, + columns = columns, + synthesizedColumns = synthesizedColumns, + joinConstraint = constraint, + ) } return@ModifiableFileLazy queryAvailable @@ -109,26 +112,19 @@ internal abstract class JoinClauseMixin( private fun leftJoinOperator(operator: SqlJoinOperator): Boolean { return operator.node.findChildByType( - TokenSet.create( - SqlTypes.LEFT_JOIN_OPERATOR, - SqlTypes.FULL_JOIN_OPERATOR, - ), + TokenSet.create(SqlTypes.LEFT_JOIN_OPERATOR, SqlTypes.FULL_JOIN_OPERATOR) ) != null } private fun rightJoinOperator(operator: SqlJoinOperator): Boolean { return operator.node.findChildByType( - TokenSet.create( - SqlTypes.RIGHT_JOIN_OPERATOR, - SqlTypes.FULL_JOIN_OPERATOR, - ), + TokenSet.create(SqlTypes.RIGHT_JOIN_OPERATOR, SqlTypes.FULL_JOIN_OPERATOR) ) != null } private fun usingConstraint(constraint: SqlJoinConstraint): Boolean { - return constraint.node?.findChildByType( - SqlTypes.USING, - ) != null + return constraint.node?.findChildByType(SqlTypes.USING) != null } + override fun queryExposed() = queryExposed.forFile(containingFile) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/LiteralValueMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/LiteralValueMixin.kt index 24f07aa9..51a75d37 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/LiteralValueMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/LiteralValueMixin.kt @@ -4,7 +4,5 @@ import com.alecstrong.sql.psi.core.psi.SqlCompositeElementImpl import com.alecstrong.sql.psi.core.psi.SqlLiteralValue import com.intellij.lang.ASTNode -internal abstract class LiteralValueMixin( - node: ASTNode, -) : SqlCompositeElementImpl(node), - SqlLiteralValue +internal abstract class LiteralValueMixin(node: ASTNode) : + SqlCompositeElementImpl(node), SqlLiteralValue diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ModuleColumnDefMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ModuleColumnDefMixin.kt index 116301df..14f19d3f 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ModuleColumnDefMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ModuleColumnDefMixin.kt @@ -7,6 +7,5 @@ import com.intellij.lang.ASTNode // Throws if you access typeName and one doesn't // exist — typeName is optional for ModuleColumnDef -internal abstract class ModuleColumnDefMixin( - node: ASTNode, -) : SqlCompositeElementImpl(node), SqlModuleColumnDef, SqlColumnDef +internal abstract class ModuleColumnDefMixin(node: ASTNode) : + SqlCompositeElementImpl(node), SqlModuleColumnDef, SqlColumnDef diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/MutatorMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/MutatorMixin.kt index 8ab3d78d..685162af 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/MutatorMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/MutatorMixin.kt @@ -11,11 +11,10 @@ import com.alecstrong.sql.psi.core.psi.SqlWithClause import com.intellij.lang.ASTNode import com.intellij.psi.PsiElement -internal abstract class MutatorMixin( - node: ASTNode, -) : WithClauseContainer(node) { +internal abstract class MutatorMixin(node: ASTNode) : WithClauseContainer(node) { // One of these will get overridden with what we want. If not error! Kind of type safe? open fun getQualifiedTableName(): SqlQualifiedTableName = throw AssertionError() + open fun getTableName() = getQualifiedTableName().tableName override fun queryAvailable(child: PsiElement): Collection { @@ -30,7 +29,10 @@ internal abstract class MutatorMixin( override fun annotate(annotationHolder: SqlAnnotationHolder) { super.annotate(annotationHolder) - val tables = tableAvailable(this, getTableName().name).ifEmpty { return } + val tables = + tableAvailable(this, getTableName().name).ifEmpty { + return + } val tableUpdated = tables.singleOrNull()?.table if (tableUpdated == null) { annotationHolder.createErrorAnnotation( @@ -42,12 +44,16 @@ internal abstract class MutatorMixin( if ((this is SqlUpdateStmt || this is SqlUpdateStmtLimited) && tableUpdated is SqlViewName) { // Find the trigger that does INSTEAD OF UPDATE. - val trigger = containingFile.schema().find { - it.tableName?.name == tableUpdated.name && - it.node.getChildren(null).map { it.text }.containsAll(listOf("INSTEAD", "OF", "UPDATE")) - } + val trigger = + containingFile.schema().find { + it.tableName?.name == tableUpdated.name && + it.node.getChildren(null).map { it.text }.containsAll(listOf("INSTEAD", "OF", "UPDATE")) + } if (trigger == null) { - annotationHolder.createErrorAnnotation(getTableName(), "Cannot UPDATE the view ${tableUpdated.text} without a trigger on ${tableUpdated.text} that has INSTEAD OF UPDATE.") + annotationHolder.createErrorAnnotation( + getTableName(), + "Cannot UPDATE the view ${tableUpdated.text} without a trigger on ${tableUpdated.text} that has INSTEAD OF UPDATE.", + ) return } } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/OrderByMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/OrderByMixin.kt index dbd5433e..e540bd44 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/OrderByMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/OrderByMixin.kt @@ -6,15 +6,16 @@ import com.alecstrong.sql.psi.core.psi.SqlCompositeElementImpl import com.alecstrong.sql.psi.core.psi.SqlOrderingTerm import com.intellij.lang.ASTNode -internal abstract class OrderByMixin( - node: ASTNode, -) : SqlCompositeElementImpl(node), - SqlOrderingTerm { +internal abstract class OrderByMixin(node: ASTNode) : + SqlCompositeElementImpl(node), SqlOrderingTerm { override fun annotate(annotationHolder: SqlAnnotationHolder) { super.annotate(annotationHolder) if (expr is SqlBindExpr) { - annotationHolder.createErrorAnnotation(expr, "Cannot bind the name of a column in an ORDER BY clause") + annotationHolder.createErrorAnnotation( + expr, + "Cannot bind the name of a column in an ORDER BY clause", + ) } } } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ResultColumnMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ResultColumnMixin.kt index ccb2c5e2..ba5ac741 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ResultColumnMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/ResultColumnMixin.kt @@ -9,10 +9,8 @@ import com.alecstrong.sql.psi.core.psi.SqlCompositeElementImpl import com.alecstrong.sql.psi.core.psi.SqlResultColumn import com.intellij.lang.ASTNode -internal abstract class ResultColumnMixin( - node: ASTNode, -) : SqlCompositeElementImpl(node), - SqlResultColumn { +internal abstract class ResultColumnMixin(node: ASTNode) : + SqlCompositeElementImpl(node), SqlResultColumn { private val queryExposed = ModifiableFileLazy lazy@{ val fromQuery = (parent as? FromQuery)?.fromQuery() ?: return@lazy emptyList() tableName?.let { tableNameElement -> @@ -23,16 +21,15 @@ internal abstract class ResultColumnMixin( var column: QueryElement.QueryColumn if (it is SqlColumnExpr) { val reference = (it.columnName as ColumnNameMixin).reference - column = reference.resolveToQuery() - ?: QueryElement.QueryColumn(it.columnName.reference?.resolve() ?: it) + column = + reference.resolveToQuery() + ?: QueryElement.QueryColumn(it.columnName.reference?.resolve() ?: it) } else { column = QueryElement.QueryColumn(it) } // expr [ '.' column_alias ] - columnAlias?.let { alias -> - column = column.copy(element = alias) - } + columnAlias?.let { alias -> column = column.copy(element = alias) } return@lazy listOf(QueryResult(columns = listOf(column))) } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/SelectStmtMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/SelectStmtMixin.kt index 442dce36..e0a0d570 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/SelectStmtMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/SelectStmtMixin.kt @@ -22,11 +22,8 @@ import com.intellij.lang.ASTNode import com.intellij.psi.PsiElement import com.intellij.psi.PsiNamedElement -internal abstract class SelectStmtMixin( - node: ASTNode, -) : SqlCompositeElementImpl(node), - SqlSelectStmt, - FromQuery { +internal abstract class SelectStmtMixin(node: ASTNode) : + SqlCompositeElementImpl(node), SqlSelectStmt, FromQuery { /** * During some resolution steps we don't care about the parent's projection and can safely ignore * it to avoid recursing too far. @@ -35,44 +32,50 @@ internal abstract class SelectStmtMixin( private val queryExposed = ModifiableFileLazy { if (valuesExpressionList.isNotEmpty()) { - return@ModifiableFileLazy listOf(QueryResult(null, valuesExpressionList.first().exprList.asColumns())) + return@ModifiableFileLazy listOf( + QueryResult(null, valuesExpressionList.first().exprList.asColumns()) + ) } return@ModifiableFileLazy listOf( QueryResult( null, - columns = resultColumnList.flatMap { resultColumn -> - resultColumn.queryExposed().flatMap { queryResult -> - queryResult.columns.map { - if (exprList.size > 0 && it.element.nonNullIn(exprList[0])) { - it.copy(nullable = false) - } else { - it + columns = + resultColumnList.flatMap { resultColumn -> + resultColumn.queryExposed().flatMap { queryResult -> + queryResult.columns.map { + if (exprList.size > 0 && it.element.nonNullIn(exprList[0])) { + it.copy(nullable = false) + } else { + it + } } } - } - }, - ), + }, + ) ) } override fun queryAvailable(child: PsiElement): Collection { if (child in exprList || child in (groupBy?.exprList ?: emptyList())) { - val available = fromQuery().map { it.copy(adjacent = true) } + - super.queryAvailable(this).map { it.copy(adjacent = false) } + val available = + fromQuery().map { it.copy(adjacent = true) } + + super.queryAvailable(this).map { it.copy(adjacent = false) } if (ignoreParentProjection) return available - val projection = (parent as CompoundSelectStmtMixin).queryExposed().map { selectStmt -> - selectStmt.copy( - adjacent = false, - columns = selectStmt.columns.filter { projectionColumn -> - // Avoid including any projection columns that would create name collisions. - (projectionColumn.element as? PsiNamedElement)?.name !in - available.flatMap { - it.columns.mapNotNull { (it.element as? PsiNamedElement)?.name } - } - }, - ) - } + val projection = + (parent as CompoundSelectStmtMixin).queryExposed().map { selectStmt -> + selectStmt.copy( + adjacent = false, + columns = + selectStmt.columns.filter { projectionColumn -> + // Avoid including any projection columns that would create name collisions. + (projectionColumn.element as? PsiNamedElement)?.name !in + available.flatMap { + it.columns.mapNotNull { (it.element as? PsiNamedElement)?.name } + } + }, + ) + } return available + projection } @@ -107,10 +110,12 @@ internal abstract class SelectStmtMixin( (rhs is SqlLiteralExpr && rhs.literalValue.node.findChildByType(SqlTypes.NULL) != null) && whereExpr.node.findChildByType(SqlTypes.NOT) != null } - is SqlBinaryAndExpr -> nonNullIn(whereExpr.getExprList().getOrNull(0) ?: return false) || - nonNullIn(whereExpr.getExprList().getOrNull(1) ?: return false) - is SqlBinaryOrExpr -> nonNullIn(whereExpr.getExprList().getOrNull(0) ?: return false) && - nonNullIn(whereExpr.getExprList().getOrNull(1) ?: return false) + is SqlBinaryAndExpr -> + nonNullIn(whereExpr.getExprList().getOrNull(0) ?: return false) || + nonNullIn(whereExpr.getExprList().getOrNull(1) ?: return false) + is SqlBinaryOrExpr -> + nonNullIn(whereExpr.getExprList().getOrNull(0) ?: return false) && + nonNullIn(whereExpr.getExprList().getOrNull(1) ?: return false) else -> false } } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/SingleRow.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/SingleRow.kt index a03dea18..dcab1e83 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/SingleRow.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/SingleRow.kt @@ -3,10 +3,9 @@ package com.alecstrong.sql.psi.core.psi.mixins import com.intellij.extapi.psi.ASTWrapperPsiElement import com.intellij.psi.PsiNamedElement -class SingleRow( - val originalTable: PsiNamedElement, - var rowName: String = originalTable.name!!, -) : ASTWrapperPsiElement(originalTable.node), PsiNamedElement { +class SingleRow(val originalTable: PsiNamedElement, var rowName: String = originalTable.name!!) : + ASTWrapperPsiElement(originalTable.node), PsiNamedElement { override fun getName() = rowName + override fun setName(name: String) = apply { rowName = name } } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableAliasMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableAliasMixin.kt index 77c89745..3a6f89ca 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableAliasMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableAliasMixin.kt @@ -10,10 +10,7 @@ import com.intellij.lang.PsiBuilder import com.intellij.psi.PsiElement import javax.swing.Icon -internal abstract class TableAliasMixin( - node: ASTNode, -) : SqlNamedElementImpl(node), - SqlTableAlias { +internal abstract class TableAliasMixin(node: ASTNode) : SqlNamedElementImpl(node), SqlTableAlias { override val parseRule: (PsiBuilder, Int) -> Boolean = SqlParser::table_alias_real override fun source(): PsiElement { diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableNameMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableNameMixin.kt index aa5621ea..b1b1be94 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableNameMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableNameMixin.kt @@ -19,17 +19,16 @@ import com.intellij.psi.PsiReference import com.intellij.psi.tree.TokenSet import javax.swing.Icon -internal abstract class TableNameMixin( - node: ASTNode, -) : SqlNamedElementImpl(node) { +internal abstract class TableNameMixin(node: ASTNode) : SqlNamedElementImpl(node) { override val parseRule: (PsiBuilder, Int) -> Boolean - get() = when (this) { - is SqlTableName -> SqlParser::table_name_real - is SqlViewName -> SqlParser::view_name_real - is SqlForeignTable -> SqlParser::foreign_table_real - is SqlNewTableName -> SqlParser::new_table_name_real - else -> throw IllegalStateException("Unknown table type ${this::class}") - } + get() = + when (this) { + is SqlTableName -> SqlParser::table_name_real + is SqlViewName -> SqlParser::view_name_real + is SqlForeignTable -> SqlParser::foreign_table_real + is SqlNewTableName -> SqlParser::new_table_name_real + else -> throw IllegalStateException("Unknown table type ${this::class}") + } override fun getReference(): PsiReference { return SqlTableReference(this) @@ -46,7 +45,8 @@ internal abstract class TableNameMixin( annotationHolder.createErrorAnnotation(this, "Table already defined with name $name") } } else if (references == null) { - if ((parent is SqlDropTableStmt || parent is SqlDropViewStmt) && !createTableSchema(parent.node) + if ( + (parent is SqlDropTableStmt || parent is SqlDropViewStmt) && !createTableSchema(parent.node) ) { return } @@ -60,11 +60,6 @@ internal abstract class TableNameMixin( } private fun createTableSchema(node: ASTNode): Boolean { - return node.findChildByType( - TokenSet.create( - SqlTypes.EXISTS, - SqlTypes.REPLACE, - ), - ) == null + return node.findChildByType(TokenSet.create(SqlTypes.EXISTS, SqlTypes.REPLACE)) == null } } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableOrSubqueryMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableOrSubqueryMixin.kt index 15bddf2d..25cf6d13 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableOrSubqueryMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableOrSubqueryMixin.kt @@ -6,10 +6,8 @@ import com.alecstrong.sql.psi.core.psi.SqlCompositeElementImpl import com.alecstrong.sql.psi.core.psi.SqlTableOrSubquery import com.intellij.lang.ASTNode -internal abstract class TableOrSubqueryMixin( - node: ASTNode, -) : SqlCompositeElementImpl(node), - SqlTableOrSubquery { +internal abstract class TableOrSubqueryMixin(node: ASTNode) : + SqlCompositeElementImpl(node), SqlTableOrSubquery { private val queryExposed = ModifiableFileLazy lazy@{ tableName?.let { tableNameElement -> val result = tableAvailable(tableNameElement, tableNameElement.name) @@ -17,7 +15,13 @@ internal abstract class TableOrSubqueryMixin( return@lazy emptyList() } tableAlias?.let { alias -> - return@lazy listOf(QueryResult(alias, result.flatMap { it.columns }, result.flatMap { it.synthesizedColumns })) + return@lazy listOf( + QueryResult( + alias, + result.flatMap { it.columns }, + result.flatMap { it.synthesizedColumns }, + ) + ) } return@lazy result } @@ -28,7 +32,9 @@ internal abstract class TableOrSubqueryMixin( } return@lazy result } - joinClause?.let { return@lazy it.queryExposed() } + joinClause?.let { + return@lazy it.queryExposed() + } return@lazy tableOrSubqueryList.flatMap { it.queryExposed() } } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/WithClauseContainer.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/WithClauseContainer.kt index 8ac550f3..e15b7c9a 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/WithClauseContainer.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/WithClauseContainer.kt @@ -10,9 +10,7 @@ import com.intellij.lang.ASTNode import com.intellij.psi.PsiElement import com.intellij.psi.util.PsiTreeUtil -internal abstract class WithClauseContainer( - node: ASTNode, -) : SqlCompositeElementImpl(node) { +internal abstract class WithClauseContainer(node: ASTNode) : SqlCompositeElementImpl(node) { abstract fun getWithClause(): SqlWithClause? override fun tablesAvailable(child: PsiElement): Collection { @@ -23,15 +21,20 @@ internal abstract class WithClauseContainer( } protected fun SqlWithClause.tablesExposed(): List { - return cteTableNameList.zip(withClauseAuxiliaryStmtList) + return cteTableNameList + .zip(withClauseAuxiliaryStmtList) .mapNotNull { (name, withClauseAuxiliaryStmt) -> - PsiTreeUtil.findChildOfType(withClauseAuxiliaryStmt, QueryElement::class.java)?.let { name to it } + PsiTreeUtil.findChildOfType(withClauseAuxiliaryStmt, QueryElement::class.java)?.let { + name to it + } } .map { (name, queryElement) -> LazyQuery(name.tableName) { QueryResult( name.tableName, - name.columnAliasList.asColumns().ifEmpty { queryElement.queryExposed().flatMap(QueryResult::columns) }, + name.columnAliasList.asColumns().ifEmpty { + queryElement.queryExposed().flatMap(QueryResult::columns) + }, ) } } diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/WithClauseMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/WithClauseMixin.kt index ac8bef11..1f992da2 100644 --- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/WithClauseMixin.kt +++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/WithClauseMixin.kt @@ -8,14 +8,15 @@ import com.alecstrong.sql.psi.core.psi.SqlWithClause import com.intellij.lang.ASTNode import com.intellij.psi.util.PsiTreeUtil -internal abstract class WithClauseMixin( - node: ASTNode, -) : SqlCompositeElementImpl(node), - SqlWithClause { +internal abstract class WithClauseMixin(node: ASTNode) : + SqlCompositeElementImpl(node), SqlWithClause { override fun annotate(annotationHolder: SqlAnnotationHolder) { - cteTableNameList.zip(withClauseAuxiliaryStmtList) + cteTableNameList + .zip(withClauseAuxiliaryStmtList) .mapNotNull { (name, withClauseAuxiliaryStmt) -> - PsiTreeUtil.findChildOfAnyType(withClauseAuxiliaryStmt, QueryElement::class.java)?.let { name to it } + PsiTreeUtil.findChildOfAnyType(withClauseAuxiliaryStmt, QueryElement::class.java)?.let { + name to it + } } .forEach { (name, queryElement) -> val query = QueryResult(name.tableName, queryElement.queryExposed().flatMap { it.columns }) diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/AnsiSqlTests.kt b/core/src/test/kotlin/com/alecstrong/sql/psi/core/AnsiSqlTests.kt index 79b7ce90..e7e50e69 100644 --- a/core/src/test/kotlin/com/alecstrong/sql/psi/core/AnsiSqlTests.kt +++ b/core/src/test/kotlin/com/alecstrong/sql/psi/core/AnsiSqlTests.kt @@ -1,22 +1,23 @@ package com.alecstrong.sql.psi.core import com.alecstrong.sql.psi.test.fixtures.FixturesTest +import java.io.File import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.junit.runners.Parameterized.Parameters -import java.io.File @RunWith(Parameterized::class) class AnsiSqlTests(name: String, fixtureRoot: File) : FixturesTest(name, fixtureRoot) { - override val replaceRules = arrayOf( - "?1" to "?", - "?2" to "?", - ":searchText" to "?", - ":bind" to "?", - ":bufferId" to "?", - ":ignored" to "?", - "AUTOINCREMENT" to "DEFAULT 0", - ) + override val replaceRules = + arrayOf( + "?1" to "?", + "?2" to "?", + ":searchText" to "?", + ":bind" to "?", + ":bufferId" to "?", + ":ignored" to "?", + "AUTOINCREMENT" to "DEFAULT 0", + ) override fun setupDialect() { // No-op. diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/NullabilityTest.kt b/core/src/test/kotlin/com/alecstrong/sql/psi/core/NullabilityTest.kt index 0ce6d810..157650fb 100644 --- a/core/src/test/kotlin/com/alecstrong/sql/psi/core/NullabilityTest.kt +++ b/core/src/test/kotlin/com/alecstrong/sql/psi/core/NullabilityTest.kt @@ -30,9 +30,9 @@ class NullabilityTest { | FROM owner | LEFT OUTER JOIN car ON owner.carId = car.id) |WHERE carBrand = ?; - """.trimMargin(), + """ + .trimMargin() ) { file -> - val select = file.sqlStmtList!!.stmtList.mapNotNull { it.compoundSelectStmt }.single() val projection = select.queryExposed().flatMap { it.columns } @@ -73,9 +73,9 @@ class NullabilityTest { | GROUP BY 1 | ORDER BY target.name COLLATE NOCASE ASC |; - """.trimMargin(), + """ + .trimMargin() ) { file -> - val select = file.sqlStmtList!!.stmtList.mapNotNull { it.compoundSelectStmt }.single() val projection = select.queryExposed().flatMap { it.columns } @@ -97,9 +97,9 @@ class NullabilityTest { |SELECT name, name AS poop, thing AS poop2 |FROM target |WHERE name IS NOT NULL AND thing IS NOT NULL; - """.trimMargin(), + """ + .trimMargin() ) { file -> - val select = file.sqlStmtList!!.stmtList.mapNotNull { it.compoundSelectStmt }.single() val projection = select.queryExposed().flatMap { it.columns } diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/PassingPredefinedTablesTest.kt b/core/src/test/kotlin/com/alecstrong/sql/psi/core/PassingPredefinedTablesTest.kt index c1ff3105..f7b20e9c 100644 --- a/core/src/test/kotlin/com/alecstrong/sql/psi/core/PassingPredefinedTablesTest.kt +++ b/core/src/test/kotlin/com/alecstrong/sql/psi/core/PassingPredefinedTablesTest.kt @@ -1,11 +1,11 @@ package com.alecstrong.sql.psi.core import com.alecstrong.sql.psi.test.fixtures.TestHeadlessParser -import org.junit.Assert.fail -import org.junit.Test import java.nio.file.Files import kotlin.io.path.div import kotlin.io.path.writeText +import org.junit.Assert.fail +import org.junit.Test class PassingPredefinedTablesTest { @Test @@ -15,19 +15,21 @@ class PassingPredefinedTablesTest { """ SELECT * FROM dual; SELECT name FROM dual; - """.trimIndent(), - ) - val env = TestHeadlessParser.build( - sourceFolders = listOf(temp), - annotator = { _, message -> - fail(message) - }, - predefinedTables = listOf( - """ - CREATE TABLE dual ( name TEXT ); - """.trimIndent(), - ), + """ + .trimIndent() ) + val env = + TestHeadlessParser.build( + sourceFolders = listOf(temp), + annotator = { _, message -> fail(message) }, + predefinedTables = + listOf( + """ + CREATE TABLE dual ( name TEXT ); + """ + .trimIndent() + ), + ) env.close() } } diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/TablesExposedTest.kt b/core/src/test/kotlin/com/alecstrong/sql/psi/core/TablesExposedTest.kt index 3fce98f4..6203c797 100644 --- a/core/src/test/kotlin/com/alecstrong/sql/psi/core/TablesExposedTest.kt +++ b/core/src/test/kotlin/com/alecstrong/sql/psi/core/TablesExposedTest.kt @@ -6,7 +6,8 @@ import com.alecstrong.sql.psi.test.fixtures.compileFiles import org.junit.Test class TablesExposedTest { - @Test fun `tables works correctly for include all`() { + @Test + fun `tables works correctly for include all`() { compileFiles( """ |CREATE TABLE test1 ( @@ -20,7 +21,8 @@ class TablesExposedTest { |CREATE TABLE test3 ( | id TEXT NOT NULL |); - """.trimMargin(), + """ + .trimMargin(), """ |CREATE TABLE test4 ( | id TEXT NOT NULL @@ -29,28 +31,25 @@ class TablesExposedTest { |ALTER TABLE test2 ADD COLUMN id2 TEXT NOT NULL; | |ALTER TABLE test3 RENAME TO test5; - """.trimMargin(), - predefined = listOf( - """ - |CREATE TABLE predefined ( - | id TEXT NOT NULL - |); - """.trimMargin(), - ), + """ + .trimMargin(), + predefined = + listOf( + """ + |CREATE TABLE predefined ( + | id TEXT NOT NULL + |); + """ + .trimMargin() + ), ) { (_, file) -> - assertThat(file.tables(includeAll = true).map { it.tableName.text }) - .containsExactlyInAnyOrder( - "predefined", - "test1", - "test2", - "test4", - "test5", - ) + .containsExactlyInAnyOrder("predefined", "test1", "test2", "test4", "test5") } } - @Test fun `tables works correctly for include all=false`() { + @Test + fun `tables works correctly for include all=false`() { compileFiles( """ |CREATE TABLE test1 ( @@ -64,7 +63,8 @@ class TablesExposedTest { |CREATE TABLE test3 ( | id TEXT NOT NULL |); - """.trimMargin(), + """ + .trimMargin(), """ |CREATE TABLE test4 ( | id TEXT NOT NULL @@ -73,22 +73,20 @@ class TablesExposedTest { |ALTER TABLE test2 ADD COLUMN id2 TEXT NOT NULL; | |ALTER TABLE test3 RENAME TO test5; - """.trimMargin(), - predefined = listOf( - """ - |CREATE TABLE predefined ( - | id TEXT NOT NULL - |); - """.trimMargin(), - ), + """ + .trimMargin(), + predefined = + listOf( + """ + |CREATE TABLE predefined ( + | id TEXT NOT NULL + |); + """ + .trimMargin() + ), ) { (_, file) -> - assertThat(file.tables(includeAll = false).map { it.tableName.text }) - .containsExactlyInAnyOrder( - "test2", - "test4", - "test5", - ) + .containsExactlyInAnyOrder("test2", "test4", "test5") } } } diff --git a/core/src/testFixtures/kotlin/com/alecstrong/sql/psi/test/fixtures/CompileFile.kt b/core/src/testFixtures/kotlin/com/alecstrong/sql/psi/test/fixtures/CompileFile.kt index 07c4ad3d..93918896 100644 --- a/core/src/testFixtures/kotlin/com/alecstrong/sql/psi/test/fixtures/CompileFile.kt +++ b/core/src/testFixtures/kotlin/com/alecstrong/sql/psi/test/fixtures/CompileFile.kt @@ -9,18 +9,16 @@ import kotlin.io.path.writeText fun compileFile( // language=sql text: String, - customInit: CoreApplicationEnvironment.() -> Unit = { }, + customInit: CoreApplicationEnvironment.() -> Unit = {}, predefined: List = emptyList(), action: (SqlFileBase) -> Unit, ) { - compileFiles(text, predefined = predefined, customInit = customInit) { - action(it.single()) - } + compileFiles(text, predefined = predefined, customInit = customInit) { action(it.single()) } } fun compileFiles( vararg files: String, - customInit: CoreApplicationEnvironment.() -> Unit = { }, + customInit: CoreApplicationEnvironment.() -> Unit = {}, predefined: List = emptyList(), action: (List) -> Unit, ) { @@ -30,22 +28,23 @@ fun compileFiles( file.writeText(content) } - val environment = TestHeadlessParser.build( - sourceFolders = listOf(directory), - customInit = customInit, - annotator = { element, message -> - val tree = buildString { - appendLine(element.containingFile.name) - appendLine(element.containingFile.text) - element.containingFile.printTree { - append(" ") - append(it) + val environment = + TestHeadlessParser.build( + sourceFolders = listOf(directory), + customInit = customInit, + annotator = { element, message -> + val tree = buildString { + appendLine(element.containingFile.name) + appendLine(element.containingFile.text) + element.containingFile.printTree { + append(" ") + append(it) + } } - } - throw AssertionError("at ${element.textOffset} : $message\n$tree") - }, - predefinedTables = predefined, - ) + throw AssertionError("at ${element.textOffset} : $message\n$tree") + }, + predefinedTables = predefined, + ) val sqlFilesMap = buildMap { environment.forSourceFiles { sqlFile -> @@ -53,9 +52,7 @@ fun compileFiles( put(index, sqlFile) } } - val sqlFiles = List(sqlFilesMap.size) { - sqlFilesMap[it]!! - } + val sqlFiles = List(sqlFilesMap.size) { sqlFilesMap[it]!! } action(sqlFiles) environment.close() } diff --git a/core/src/testFixtures/kotlin/com/alecstrong/sql/psi/test/fixtures/FixturesTest.kt b/core/src/testFixtures/kotlin/com/alecstrong/sql/psi/test/fixtures/FixturesTest.kt index bc5b8d92..5159b941 100644 --- a/core/src/testFixtures/kotlin/com/alecstrong/sql/psi/test/fixtures/FixturesTest.kt +++ b/core/src/testFixtures/kotlin/com/alecstrong/sql/psi/test/fixtures/FixturesTest.kt @@ -3,7 +3,6 @@ package com.alecstrong.sql.psi.test.fixtures import com.alecstrong.sql.psi.core.SqlFileBase import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement -import org.junit.Test import java.io.File import java.nio.file.FileSystems import kotlin.io.path.ExperimentalPathApi @@ -12,6 +11,7 @@ import kotlin.io.path.div import kotlin.io.path.toPath import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty +import org.junit.Test abstract class FixturesTest( val name: String, @@ -32,21 +32,20 @@ abstract class FixturesTest( newRoot.replaceKeywords() } - val environment = TestHeadlessParser.build( - root = newRoot.toPath(), - customInit = { - setupDialect() - }, - annotator = { element, s -> - val documentManager = PsiDocumentManager.getInstance(element.project) - val name = element.containingFile.name - val document = documentManager.getDocument(element.containingFile)!! - val lineNum = document.getLineNumber(element.textOffset) - val offsetInLine = element.textOffset - document.getLineStartOffset(lineNum) - errors.add("$name line ${lineNum + 1}:$offsetInLine - $s") - }, - predefinedTables = predefinedTables, - ) + val environment = + TestHeadlessParser.build( + root = newRoot.toPath(), + customInit = { setupDialect() }, + annotator = { element, s -> + val documentManager = PsiDocumentManager.getInstance(element.project) + val name = element.containingFile.name + val document = documentManager.getDocument(element.containingFile)!! + val lineNum = document.getLineNumber(element.textOffset) + val offsetInLine = element.textOffset - document.getLineStartOffset(lineNum) + errors.add("$name line ${lineNum + 1}:$offsetInLine - $s") + }, + predefinedTables = predefinedTables, + ) val sourceFiles = StringBuilder() environment.forSourceFiles { @@ -70,7 +69,8 @@ abstract class FixturesTest( val document = PsiDocumentManager.getInstance(file.project).getDocument(file.containingFile)!! for (errorMatch in inlineErrors) { - // Add 1 to make it 1-based, and another 1 because the line where the error should happen is the next line + // Add 1 to make it 1-based, and another 1 because the line where the error should happen is + // the next line // after the error comment line val lineNum = document.getLineNumber(errorMatch.range.first) + 1 + 1 val (offsetInLine, errMsg) = errorMatch.destructured @@ -88,15 +88,21 @@ abstract class FixturesTest( val assertionMsgEnd = "\nOverall we expected to see $expectedFailuresStr but got $errorsStr" when { missingList.isNotEmpty() && extrasList.isNotEmpty() -> { - throw AssertionError("Test failed because the compile output is missing $missingStr and unexpectedly has $extrasStr. $assertionMsgEnd") + throw AssertionError( + "Test failed because the compile output is missing $missingStr and unexpectedly has $extrasStr. $assertionMsgEnd" + ) } missingList.isNotEmpty() -> { - throw AssertionError("Test failed because the compile output is missing $missingStr. $assertionMsgEnd") + throw AssertionError( + "Test failed because the compile output is missing $missingStr. $assertionMsgEnd" + ) } extrasList.isNotEmpty() -> { - throw AssertionError("Test failed because the compile output unexpectedly has $extrasStr. $assertionMsgEnd") + throw AssertionError( + "Test failed because the compile output unexpectedly has $extrasStr. $assertionMsgEnd" + ) } } @@ -109,36 +115,41 @@ abstract class FixturesTest( listFiles()?.forEach { it.replaceKeywords() } return } - replaceRules.forEach { (from, to) -> - writeText(readText().replace(from, to)) - } + replaceRules.forEach { (from, to) -> writeText(readText().replace(from, to)) } } companion object { @JvmStatic - protected val ansiFixtures = loadFolderFromResources("fixtures", target = File("build")).toParameter() + protected val ansiFixtures = + loadFolderFromResources("fixtures", target = File("build")).toParameter() } } fun File.toParameter(): List> = listFiles()?.filter { it.isDirectory }?.map { arrayOf(it.name, it) } ?: emptyList() -fun loadFolderFromResources(target: File) = object : ReadOnlyProperty>> { - override operator fun getValue(thisRef: Any?, property: KProperty<*>) = loadFolderFromResources(property.name, target).toParameter() -} +fun loadFolderFromResources(target: File) = + object : ReadOnlyProperty>> { + override operator fun getValue(thisRef: Any?, property: KProperty<*>) = + loadFolderFromResources(property.name, target).toParameter() + } @OptIn(ExperimentalPathApi::class) fun Any.loadFolderFromResources(path: String, target: File): File { val targetFile = File(target, path).apply { if (exists()) deleteRecursively() } val resourcesUri = javaClass.getResource("/$path")?.toURI() - requireNotNull(resourcesUri) { - "/$path not found in resources." - } + requireNotNull(resourcesUri) { "/$path not found in resources." } when (resourcesUri.scheme) { - "jar" -> FileSystems.newFileSystem(resourcesUri, emptyMap(), null).use { - it.getPath("/$path").copyToRecursively(target.toPath() / path, overwrite = true, followLinks = false) - } - "file" -> resourcesUri.toPath().copyToRecursively(target.toPath() / path, overwrite = true, followLinks = false) + "jar" -> + FileSystems.newFileSystem(resourcesUri, emptyMap(), null).use { + it + .getPath("/$path") + .copyToRecursively(target.toPath() / path, overwrite = true, followLinks = false) + } + "file" -> + resourcesUri + .toPath() + .copyToRecursively(target.toPath() / path, overwrite = true, followLinks = false) else -> error("Unsupported scheme ${resourcesUri.scheme} of $resourcesUri") } return targetFile @@ -157,7 +168,5 @@ private fun String.splitLines() = split("\\r?\\n".toRegex()) internal fun PsiElement.printTree(printer: (String) -> Unit) { printer("$this\n") - children.forEach { child -> - child.printTree { printer(" $it") } - } + children.forEach { child -> child.printTree { printer(" $it") } } } diff --git a/core/src/testFixtures/kotlin/com/alecstrong/sql/psi/test/fixtures/TestHeadlessParser.kt b/core/src/testFixtures/kotlin/com/alecstrong/sql/psi/test/fixtures/TestHeadlessParser.kt index 3c451e7a..4b57871f 100644 --- a/core/src/testFixtures/kotlin/com/alecstrong/sql/psi/test/fixtures/TestHeadlessParser.kt +++ b/core/src/testFixtures/kotlin/com/alecstrong/sql/psi/test/fixtures/TestHeadlessParser.kt @@ -18,7 +18,7 @@ object TestHeadlessParser { root: Path, annotator: SqlAnnotationHolder, predefinedTables: List = emptyList(), - customInit: CoreApplicationEnvironment.() -> Unit = { }, + customInit: CoreApplicationEnvironment.() -> Unit = {}, ): SqlCoreEnvironment { return build(listOf(root), annotator, predefinedTables, customInit) } @@ -27,45 +27,51 @@ object TestHeadlessParser { sourceFolders: List, annotator: SqlAnnotationHolder, predefinedTables: List = emptyList(), - customInit: CoreApplicationEnvironment.() -> Unit = { }, + customInit: CoreApplicationEnvironment.() -> Unit = {}, ): SqlCoreEnvironment { - val environment = object : SqlCoreEnvironment( - sourceFolders = sourceFolders, - dependencies = emptyList(), - ) { - init { - initializeApplication { - registerFileType(TestFileType, TestFileType.defaultExtension) - val parserDefinition = TestParserDefinition( - lazy { - val factory = PsiFileFactory.getInstance(projectEnvironment.project) - predefinedTables.map { - factory.createFileFromText(TestLanguage, it) as SqlFileBase - } - }, - ) - registerParserDefinition(parserDefinition) - - customInit() + val environment = + object : SqlCoreEnvironment(sourceFolders = sourceFolders, dependencies = emptyList()) { + init { + initializeApplication { + registerFileType(TestFileType, TestFileType.defaultExtension) + val parserDefinition = + TestParserDefinition( + lazy { + val factory = PsiFileFactory.getInstance(projectEnvironment.project) + predefinedTables.map { + factory.createFileFromText(TestLanguage, it) as SqlFileBase + } + } + ) + registerParserDefinition(parserDefinition) + + customInit() + } } } - } environment.annotate(annotationHolder = annotator) return environment } } private object TestLanguage : Language("Test") + private object TestFileType : LanguageFileType(TestLanguage) { override fun getIcon() = AllIcons.Icon + override fun getName() = "Test File" + override fun getDefaultExtension() = "s" + override fun getDescription() = "Test SQLite Language File" } -private class TestParserDefinition(private val predefinedTables: Lazy>) : SqlParserDefinition() { +private class TestParserDefinition(private val predefinedTables: Lazy>) : + SqlParserDefinition() { override fun createFile(viewProvider: FileViewProvider) = TestFile(viewProvider, predefinedTables) + override fun getFileNodeType() = FILE + override fun getLanguage() = TestLanguage companion object { @@ -73,15 +79,20 @@ private class TestParserDefinition(private val predefinedTables: Lazy>) : SqlFileBase(viewProvider, TestLanguage) { +private class TestFile( + viewProvider: FileViewProvider, + private val predefinedTables: Lazy>, +) : SqlFileBase(viewProvider, TestLanguage) { override fun getFileType() = TestFileType - override val order = name.substringBefore(".${fileType.defaultExtension}").let { name -> - if (name.all { it in '0'..'9' }) { - name.toLong() - } else { - null + + override val order = + name.substringBefore(".${fileType.defaultExtension}").let { name -> + if (name.all { it in '0'..'9' }) { + name.toLong() + } else { + null + } } - } override fun baseContributorFiles(): List { val base = super.baseContributorFiles() diff --git a/environment/src/main/kotlin/com/alecstrong/sql/psi/core/SqlCoreEnvironment.kt b/environment/src/main/kotlin/com/alecstrong/sql/psi/core/SqlCoreEnvironment.kt index 454acd12..6b0bb642 100644 --- a/environment/src/main/kotlin/com/alecstrong/sql/psi/core/SqlCoreEnvironment.kt +++ b/environment/src/main/kotlin/com/alecstrong/sql/psi/core/SqlCoreEnvironment.kt @@ -39,42 +39,37 @@ import kotlin.reflect.KClass private class ApplicationEnvironment { val disposable = Disposer.newDisposable() - val coreApplicationEnvironment: CoreApplicationEnvironment = CoreApplicationEnvironment(disposable).apply { - - System.setProperty("ide.hide.excluded.files", "false") - System.setProperty("psi.sleep.in.validity.check", "false") - System.setProperty("psi.incremental.reparse.depth.limit", "1000") - - CoreApplicationEnvironment.registerApplicationExtensionPoint( - MetaLanguage.EP_NAME, - MetaLanguage::class.java, - ) - CoreApplicationEnvironment.registerApplicationExtensionPoint( - SmartPointerAnchorProvider.EP_NAME, - SmartPointerAnchorProvider::class.java, - ) - CoreApplicationEnvironment.registerApplicationExtensionPoint( - WorkspaceFileIndexImpl.EP_NAME, - WorkspaceFileIndexContributor::class.java, - ) - CoreApplicationEnvironment.registerApplicationExtensionPoint( - CustomEntityProjectModelInfoProvider.EP, - CustomEntityProjectModelInfoProvider::class.java, - ) - } + val coreApplicationEnvironment: CoreApplicationEnvironment = + CoreApplicationEnvironment(disposable).apply { + System.setProperty("ide.hide.excluded.files", "false") + System.setProperty("psi.sleep.in.validity.check", "false") + System.setProperty("psi.incremental.reparse.depth.limit", "1000") + + CoreApplicationEnvironment.registerApplicationExtensionPoint( + MetaLanguage.EP_NAME, + MetaLanguage::class.java, + ) + CoreApplicationEnvironment.registerApplicationExtensionPoint( + SmartPointerAnchorProvider.EP_NAME, + SmartPointerAnchorProvider::class.java, + ) + CoreApplicationEnvironment.registerApplicationExtensionPoint( + WorkspaceFileIndexImpl.EP_NAME, + WorkspaceFileIndexContributor::class.java, + ) + CoreApplicationEnvironment.registerApplicationExtensionPoint( + CustomEntityProjectModelInfoProvider.EP, + CustomEntityProjectModelInfoProvider::class.java, + ) + } } -open class SqlCoreEnvironment( - sourceFolders: List, - dependencies: List, -) : AutoCloseable { +open class SqlCoreEnvironment(sourceFolders: List, dependencies: List) : AutoCloseable { private val fileIndex: CoreFileIndex private val env = ApplicationEnvironment() - protected val projectEnvironment = CoreProjectEnvironment( - env.disposable, - env.coreApplicationEnvironment, - ) + protected val projectEnvironment = + CoreProjectEnvironment(env.disposable, env.coreApplicationEnvironment) protected val localFileSystem: VirtualFileSystem = StandardFileSystems.local() protected val jarFileSystem: VirtualFileSystem = StandardFileSystems.jar() @@ -93,20 +88,22 @@ open class SqlCoreEnvironment( DirectoryIndexImpl(projectEnvironment.project), ) - fileIndex = CoreFileIndex( - sourceFolders, - localFileSystem, - jarFileSystem, - project = projectEnvironment.project, - ) + fileIndex = + CoreFileIndex( + sourceFolders, + localFileSystem, + jarFileSystem, + project = projectEnvironment.project, + ) projectEnvironment.project.registerService(ProjectFileIndex::class.java, fileIndex) - val contributorIndex = CoreFileIndex( - sourceFolders + dependencies, - localFileSystem, - jarFileSystem, - project = projectEnvironment.project, - ) + val contributorIndex = + CoreFileIndex( + sourceFolders + dependencies, + localFileSystem, + jarFileSystem, + project = projectEnvironment.project, + ) projectEnvironment.project.registerService( SchemaContributorIndex::class.java, object : SchemaContributorIndex { @@ -114,8 +111,10 @@ open class SqlCoreEnvironment( val manager = PsiManager.getInstance(projectEnvironment.project) val map = linkedMapOf>() contributorIndex.iterateContent { file -> - map[file] = (manager.findFile(file) as? SqlFileBase)?.sqlStmtList?.stmtList - ?.mapNotNull { it.firstChild as? SchemaContributor } ?: emptyList() + map[file] = + (manager.findFile(file) as? SqlFileBase)?.sqlStmtList?.stmtList?.mapNotNull { + it.firstChild as? SchemaContributor + } ?: emptyList() return@iterateContent true } map @@ -140,7 +139,8 @@ open class SqlCoreEnvironment( ) { val otherFailures = mutableListOf<() -> Unit>() val myHolder = SqlAnnotationHolder { element, s -> - if (PsiTreeUtil.getNonStrictParentOfType( + if ( + PsiTreeUtil.getNonStrictParentOfType( element, SqlCreateTableStmt::class.java, SqlCreateVirtualTableStmt::class.java, @@ -149,9 +149,7 @@ open class SqlCoreEnvironment( ) { annotationHolder.createErrorAnnotation(element, s) } else { - otherFailures.add { - annotationHolder.createErrorAnnotation(element, s) - } + otherFailures.add { annotationHolder.createErrorAnnotation(element, s) } } } forSourceFiles { @@ -195,7 +193,8 @@ open class SqlCoreEnvironment( |Failed to compile ${containingFile.virtualFile.path}:${node.startOffset}: | $text | - """.trimMargin(), + """ + .trimMargin(), e, ) } @@ -220,14 +219,16 @@ private class CoreFileIndex( ) : ProjectFileIndexImpl(project) { override fun iterateContent(iterator: ContentIterator): Boolean { for (file in sourceFolders) { - val vFile = when (val schema = file.fileSystem.provider().scheme) { - StandardFileSystems.JAR_PROTOCOL -> { - val jarFilePath = file.toUri().toString().removePrefix("jar:file://") - jarFileSystem.findFileByPath(jarFilePath) - } - StandardFileSystems.FILE_PROTOCOL -> localFileSystems.findFileByPath(file.toAbsolutePath().toString()) - else -> error("Not supported schema $schema") - } ?: throw NullPointerException("File ${file.pathString} not found") + val vFile = + when (val schema = file.fileSystem.provider().scheme) { + StandardFileSystems.JAR_PROTOCOL -> { + val jarFilePath = file.toUri().toString().removePrefix("jar:file://") + jarFileSystem.findFileByPath(jarFilePath) + } + StandardFileSystems.FILE_PROTOCOL -> + localFileSystems.findFileByPath(file.toAbsolutePath().toString()) + else -> error("Not supported schema $schema") + } ?: throw NullPointerException("File ${file.pathString} not found") if (!iterateContentUnderDirectory(vFile, iterator)) { return false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 90f83543..6a2dc592 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,6 +17,8 @@ coroutines-core = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2" junit = "junit:junit:4.13.2" assertk = "com.willowtreeapps.assertk:assertk:0.28.1" +ktfmt = "com.facebook:ktfmt:0.59" + [bundles] intelliJ = ["intellijCoreImpl", "intellijProjectModelImpl", "intellijAnalysisImpl", "intellijIndexing", "intellijUtilUi"] diff --git a/sample-core/src/main/kotlin/com/alecstrong/sql/psi/sample/core/SampleFile.kt b/sample-core/src/main/kotlin/com/alecstrong/sql/psi/sample/core/SampleFile.kt index 7e7ea621..c3a808fc 100644 --- a/sample-core/src/main/kotlin/com/alecstrong/sql/psi/sample/core/SampleFile.kt +++ b/sample-core/src/main/kotlin/com/alecstrong/sql/psi/sample/core/SampleFile.kt @@ -4,13 +4,16 @@ import com.alecstrong.sql.psi.core.SqlFileBase import com.intellij.psi.FileViewProvider class SampleFile(viewProvider: FileViewProvider) : SqlFileBase(viewProvider, SampleLanguage) { - override val order = name.substringBefore(".${fileType.defaultExtension}").let { name -> - if (name.all { it in '0'..'9' }) { - name.toLong() - } else { - null + override val order = + name.substringBefore(".${fileType.defaultExtension}").let { name -> + if (name.all { it in '0'..'9' }) { + name.toLong() + } else { + null + } } - } + override fun getFileType() = SampleFileType + override fun toString() = "Sample File" } diff --git a/sample-core/src/main/kotlin/com/alecstrong/sql/psi/sample/core/SampleFileType.kt b/sample-core/src/main/kotlin/com/alecstrong/sql/psi/sample/core/SampleFileType.kt index 2e6be609..d45a614a 100644 --- a/sample-core/src/main/kotlin/com/alecstrong/sql/psi/sample/core/SampleFileType.kt +++ b/sample-core/src/main/kotlin/com/alecstrong/sql/psi/sample/core/SampleFileType.kt @@ -5,7 +5,10 @@ import com.intellij.openapi.fileTypes.LanguageFileType object SampleFileType : LanguageFileType(SampleLanguage) { override fun getIcon() = AllIcons.Debugger.Db_db_object + override fun getName() = "Sample File" + override fun getDefaultExtension() = "samplesql" + override fun getDescription() = "Sample SQLite Language File" } diff --git a/sample-core/src/main/kotlin/com/alecstrong/sql/psi/sample/core/SampleParserDefinition.kt b/sample-core/src/main/kotlin/com/alecstrong/sql/psi/sample/core/SampleParserDefinition.kt index bcf1a650..15591d00 100644 --- a/sample-core/src/main/kotlin/com/alecstrong/sql/psi/sample/core/SampleParserDefinition.kt +++ b/sample-core/src/main/kotlin/com/alecstrong/sql/psi/sample/core/SampleParserDefinition.kt @@ -11,7 +11,9 @@ class SampleParserDefinition : SqlParserDefinition() { } override fun createFile(viewProvider: FileViewProvider) = SampleFile(viewProvider) + override fun getFileNodeType() = FILE + override fun getLanguage() = SampleLanguage companion object { diff --git a/sample-core/src/testFixtures/kotlin/SqliteTestFixtures.kt b/sample-core/src/testFixtures/kotlin/SqliteTestFixtures.kt index 3eba5e44..6e572fdb 100644 --- a/sample-core/src/testFixtures/kotlin/SqliteTestFixtures.kt +++ b/sample-core/src/testFixtures/kotlin/SqliteTestFixtures.kt @@ -9,11 +9,21 @@ import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty class SqliteTestFixtures : ReadOnlyProperty, AutoCloseable { - val jarFile: Path get() = SqliteTestFixtures::class.java.getResource("/SqliteTestFixtures.class")!!.toURI().toJarPath().parent + val jarFile: Path + get() = + SqliteTestFixtures::class + .java + .getResource("/SqliteTestFixtures.class")!! + .toURI() + .toJarPath() + .parent override operator fun getValue(thisRef: Nothing?, property: KProperty<*>): Path { val uri = - SqliteTestFixtures::class.java.getResource("/${property.name}.${SampleFileType.defaultExtension}")!!.toURI() + SqliteTestFixtures::class + .java + .getResource("/${property.name}.${SampleFileType.defaultExtension}")!! + .toURI() return uri.toJarPath() } @@ -26,12 +36,13 @@ class SqliteTestFixtures : ReadOnlyProperty, AutoCloseable { } private fun URI.toJarPath(): Path { - val fileSystem = try { - FileSystems.getFileSystem(this) - } catch (_: FileSystemNotFoundException) { - val env = mapOf("create" to "true") - FileSystems.newFileSystem(this, env) - } + val fileSystem = + try { + FileSystems.getFileSystem(this) + } catch (_: FileSystemNotFoundException) { + val env = mapOf("create" to "true") + FileSystems.newFileSystem(this, env) + } openFileSystems.add(fileSystem) return toPath() } diff --git a/sample-headless/src/main/kotlin/com/alecstrong/sql/psi/sample/headless/SampleHeadlessParser.kt b/sample-headless/src/main/kotlin/com/alecstrong/sql/psi/sample/headless/SampleHeadlessParser.kt index b975aacc..d0bc63e2 100644 --- a/sample-headless/src/main/kotlin/com/alecstrong/sql/psi/sample/headless/SampleHeadlessParser.kt +++ b/sample-headless/src/main/kotlin/com/alecstrong/sql/psi/sample/headless/SampleHeadlessParser.kt @@ -10,30 +10,26 @@ import java.nio.file.Path class SampleHeadlessParser { fun parseSqlite(sourceFolders: List, onError: (String) -> Unit): List { val parserDefinition = SampleParserDefinition() - val environment = object : SqlCoreEnvironment( - sourceFolders = sourceFolders, - dependencies = emptyList(), - ) { - init { - initializeApplication { - registerFileType(SampleFileType, SampleFileType.defaultExtension) - registerParserDefinition(parserDefinition) + val environment = + object : SqlCoreEnvironment(sourceFolders = sourceFolders, dependencies = emptyList()) { + init { + initializeApplication { + registerFileType(SampleFileType, SampleFileType.defaultExtension) + registerParserDefinition(parserDefinition) + } } - } - val project = projectEnvironment.project - } + val project = projectEnvironment.project + } environment.annotate { element, message -> - val file = PsiDocumentManager.getInstance(environment.project).getDocument(element.containingFile)!! - val error = "${element.containingFile.virtualFile.path}: (${file.getLineNumber(element.textOffset) + 1}, ${ + val file = + PsiDocumentManager.getInstance(environment.project).getDocument(element.containingFile)!! + val error = + "${element.containingFile.virtualFile.path}: (${file.getLineNumber(element.textOffset) + 1}, ${ element.textOffset - file.getLineStartOffset(file.getLineNumber(element.textOffset)) }): $message" onError(error) } - return buildList { - environment.forSourceFiles { - add(it) - } - } + return buildList { environment.forSourceFiles { add(it) } } } } diff --git a/sample-headless/src/test/kotlin/com/alecstrong/sql/psi/sample/headless/SampleHeadlessParserTest.kt b/sample-headless/src/test/kotlin/com/alecstrong/sql/psi/sample/headless/SampleHeadlessParserTest.kt index 16977987..712411bc 100644 --- a/sample-headless/src/test/kotlin/com/alecstrong/sql/psi/sample/headless/SampleHeadlessParserTest.kt +++ b/sample-headless/src/test/kotlin/com/alecstrong/sql/psi/sample/headless/SampleHeadlessParserTest.kt @@ -15,9 +15,7 @@ import kotlin.test.fail class SampleHeadlessParserTest { @Test fun parserIsSuccessfulWithSourceFolder() { - val files = SampleHeadlessParser().parseSqlite(listOf(Path("../sample-headless"))) { - fail(it) - } + val files = SampleHeadlessParser().parseSqlite(listOf(Path("../sample-headless"))) { fail(it) } files.test() } @@ -26,9 +24,7 @@ class SampleHeadlessParserTest { val sqliteTestFixtures = SqliteTestFixtures() try { val test by SqliteTestFixtures() - val files = SampleHeadlessParser().parseSqlite(listOf(test)) { - fail(it) - } + val files = SampleHeadlessParser().parseSqlite(listOf(test)) { fail(it) } files.test() } finally { sqliteTestFixtures.close() @@ -40,9 +36,8 @@ class SampleHeadlessParserTest { val sqliteTestFixtures = SqliteTestFixtures() val test2 by sqliteTestFixtures try { - val files = SampleHeadlessParser().parseSqlite(listOf(Path("../sample-headless"), test2)) { - fail(it) - } + val files = + SampleHeadlessParser().parseSqlite(listOf(Path("../sample-headless"), test2)) { fail(it) } files.test() } finally { sqliteTestFixtures.close() @@ -53,9 +48,8 @@ class SampleHeadlessParserTest { fun parserIsSuccessfulWithJarSource() { val sqliteTestFixtures = SqliteTestFixtures() try { - val files = SampleHeadlessParser().parseSqlite(listOf(sqliteTestFixtures.jarFile)) { - fail(it) - } + val files = + SampleHeadlessParser().parseSqlite(listOf(sqliteTestFixtures.jarFile)) { fail(it) } assertEquals(2, files.size) files.test() } finally { @@ -82,7 +76,12 @@ class SampleHeadlessParserTest { for (expr in exprs) { if (expr is CustomExpr) { val fooRule = expr.fooRule - val literalExpr = fooRule.childrenOfType(SqlLiteralExpr::class).single().childrenOfType(SqlLiteralExpr::class).single() + val literalExpr = + fooRule + .childrenOfType(SqlLiteralExpr::class) + .single() + .childrenOfType(SqlLiteralExpr::class) + .single() assertEquals(13, literalExpr.literalValue.numericLiteral!!.text.toInt()) } } @@ -93,4 +92,5 @@ class SampleHeadlessParserTest { } } -fun PsiElement.childrenOfType(kClass: KClass): List = PsiTreeUtil.getChildrenOfTypeAsList(this, kClass.java) +fun PsiElement.childrenOfType(kClass: KClass): List = + PsiTreeUtil.getChildrenOfTypeAsList(this, kClass.java)