From 7e7ccd372daf8f6537ba5ba34bc10fe113fbfbd7 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Fri, 24 Mar 2023 15:51:00 +0100 Subject: [PATCH] IDEA-301191: [DevKit] Inspection to discourage declaration of TokenSets in ParserDefinition GitOrigin-RevId: cab7298c1babe62754272d529bd4e471cf3b17c6 --- .../TokenSetInParserDefinition.html | 85 +++++++++++++ .../resources/intellij.devkit.core.xml | 5 + .../messages/DevKitBundle.properties | 3 + .../TokenSetInParserDefinitionInspection.kt | 119 ++++++++++++++++++ .../MyLangTokenTypes.java | 7 ++ ...nDirectImplementorWithIllegalTokenSet.java | 16 +++ .../ParserDefinitionWithIllegalTokenSet.java | 12 ++ ...legalTokenSetInitializedInConstructor.java | 16 +++ ...legalTokenSetInitializedInStaticBlock.java | 16 +++ ...ithIllegalTokenSetWhenComplexCreation.java | 12 ++ ...hIllegalTokenSetWhenStaticImportsUsed.java | 14 +++ ...ParserDefinitionWithLegalCoreTokenSet.java | 10 ++ ...lCoreTokenSetInitializedInConstructor.java | 15 +++ ...lCoreTokenSetInitializedInStaticBlock.java | 15 +++ ...arserDefinitionWithLegalCoreTokenType.java | 11 ++ ...CoreTokenTypeInitializedInConstructor.java | 16 +++ ...CoreTokenTypeInitializedInStaticBlock.java | 16 +++ ...egalTokenSetInitializedLazilyInMethod.java | 14 +++ ...okenSetInParserDefinitionInspectionTest.kt | 69 ++++++++++ .../MyLangTokenTypes.kt | 7 ++ ...NonDirectImplementorWithIllegalTokenSet.kt | 12 ++ .../ParserDefinitionWithIllegalTokenSet.kt | 10 ++ ...ionWithIllegalTokenSetInCompanionObject.kt | 12 ++ ...etInitializedInCompanionObjectInitBlock.kt | 17 +++ ...IllegalTokenSetInitializedInConstructor.kt | 14 +++ ...thIllegalTokenSetInitializedInInitBlock.kt | 15 +++ ...nWithIllegalTokenSetWhenComplexCreation.kt | 10 ++ ...nWithIllegalTokenSetWhenMembersImported.kt | 11 ++ .../ParserDefinitionWithLegalCoreTokenSet.kt | 9 ++ ...nWithLegalCoreTokenSetInCompanionObject.kt | 11 ++ ...etInitializedInCompanionObjectInitBlock.kt | 16 +++ ...galCoreTokenSetInitializedInConstructor.kt | 14 +++ .../ParserDefinitionWithLegalCoreTokenType.kt | 13 ++ ...alCoreTokenTypeInitializedInConstructor.kt | 15 +++ ...alCoreTokenTypeInitializedInStaticBlock.kt | 17 +++ ...tionWithLegalTokenSetDeclaredOnTopLevel.kt | 11 ++ ...hLegalTokenSetInitializedLazilyInMethod.kt | 13 ++ ...okenSetInParserDefinitionInspectionTest.kt | 86 +++++++++++++ ...SetInParserDefinitionInspectionTestBase.kt | 71 +++++++++++ 39 files changed, 855 insertions(+) create mode 100644 plugins/devkit/devkit-core/resources/inspectionDescriptions/TokenSetInParserDefinition.html create mode 100644 plugins/devkit/devkit-core/src/inspections/TokenSetInParserDefinitionInspection.kt create mode 100644 plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/MyLangTokenTypes.java create mode 100644 plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionNonDirectImplementorWithIllegalTokenSet.java create mode 100644 plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSet.java create mode 100644 plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInConstructor.java create mode 100644 plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInStaticBlock.java create mode 100644 plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenComplexCreation.java create mode 100644 plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenStaticImportsUsed.java create mode 100644 plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSet.java create mode 100644 plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInConstructor.java create mode 100644 plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInStaticBlock.java create mode 100644 plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenType.java create mode 100644 plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInConstructor.java create mode 100644 plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInStaticBlock.java create mode 100644 plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalTokenSetInitializedLazilyInMethod.java create mode 100644 plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/TokenSetInParserDefinitionInspectionTest.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/MyLangTokenTypes.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionNonDirectImplementorWithIllegalTokenSet.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSet.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInCompanionObject.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInCompanionObjectInitBlock.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInConstructor.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInInitBlock.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenComplexCreation.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenMembersImported.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSet.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInCompanionObject.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInCompanionObjectInitBlock.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInConstructor.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenType.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInConstructor.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInStaticBlock.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalTokenSetDeclaredOnTopLevel.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalTokenSetInitializedLazilyInMethod.kt create mode 100644 plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtTokenSetInParserDefinitionInspectionTest.kt create mode 100644 plugins/devkit/devkit-tests/testSrc/org/jetbrains/idea/devkit/inspections/TokenSetInParserDefinitionInspectionTestBase.kt diff --git a/plugins/devkit/devkit-core/resources/inspectionDescriptions/TokenSetInParserDefinition.html b/plugins/devkit/devkit-core/resources/inspectionDescriptions/TokenSetInParserDefinition.html new file mode 100644 index 000000000000..21f3644804aa --- /dev/null +++ b/plugins/devkit/devkit-core/resources/inspectionDescriptions/TokenSetInParserDefinition.html @@ -0,0 +1,85 @@ + + +Reports TokenSet field declarations referencing non-core element types in ParserDefinition classes. +

+ All languages ParserDefinition are created on the application startup. + Declaring a TokenSet referencing non-core language element types may cause creating and registering + all the language element types in the holder class of the referenced type, even if a project doesn't contain any files in this language. +

+ +

Example:

+
+// element types holder:
+public interface MyLangTokenTypes {
+  IElementType COMMENT = new MyLangTokenType("COMMENT");
+  IElementType TYPE1 = new MyLangTokenType("TYPE1");
+  IElementType TYPE2 = new MyLangTokenType("TYPE2");
+  // more types...
+}
+
+
+// bad:
+
+public class MyLangParserDefinition implements ParserDefinition {
+  // this field causes initalizing and registering all the types from MyLangTokenTypes:
+  private static final TokenSet COMMENTS = TokenSet.create(MyLangTokenTypes.COMMENT);
+
+  @NotNull
+  @Override
+  public TokenSet getCommentTokens() {
+    return COMMENTS;
+  }
+  ...
+}
+
+
+// good:
+
+public final class MyLangTokenSets {
+  public static final TokenSet COMMENTS = TokenSet.create(MyLangTokenTypes.COMMENT);
+}
+
+public class MyLangParserDefinition implements ParserDefinition {
+  @NotNull
+  @Override
+  public TokenSet getCommentTokens() {
+    // types are referenced and registered only when this method is called:
+    return MyLangTokenSets.COMMENTS;
+  }
+  ...
+}
+
+// good (Kotlin):
+
+// top-level declaration is not loaded until getCommentTokens() method is called:
+private val COMMENTS = TokenSet.create(MyLangTokenTypes.COMMENT);
+
+class MyLangParserDefinition : ParserDefinition {
+  override getCommentTokens(): TokenSet {
+    return COMMENTS;
+  }
+  ...
+}
+
+// good:
+
+public class MyLangParserDefinition implements ParserDefinition {
+  // allowed core TokenSet:
+  private static final TokenSet COMMENTS1 = TokenSet.EMPTY;
+  // allowed core TokenType:
+  private static final TokenSet COMMENTS2 = TokenSet.create(TokenType.WHITE_SPACE);
+
+  @NotNull
+  @Override
+  public TokenSet getCommentTokens() {
+    ...
+  }
+  ...
+}
+
+
+ + +

New in 2023.2 + + diff --git a/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml b/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml index 5215c5137193..769e0d5e97f2 100644 --- a/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml +++ b/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml @@ -315,6 +315,11 @@ groupPathKey="inspections.group.path" groupKey="inspections.group.code" implementationClass="org.jetbrains.idea.devkit.inspections.ThreadingConcurrencyInspection"/> + + diff --git a/plugins/devkit/devkit-core/resources/messages/DevKitBundle.properties b/plugins/devkit/devkit-core/resources/messages/DevKitBundle.properties index e1f32ca3c70a..cc8e72167125 100644 --- a/plugins/devkit/devkit-core/resources/messages/DevKitBundle.properties +++ b/plugins/devkit/devkit-core/resources/messages/DevKitBundle.properties @@ -651,3 +651,6 @@ inspection.threading.concurrency.option.group.inside.requires.edt=Check inside @ inspection.threading.concurrency.option.group.inside.requires.edt.check.requires.read.lock=@RequiresReadLock inspection.threading.concurrency.option.group.inside.requires.edt.check.requires.write.lock=@RequiresWriteLock inspection.threading.concurrency.option.check.missing.annotations.methods=Check missing annotations for public methods + +inspection.token.set.in.parser.definition.display.name=Non-core TokenSet declared in ParserDefinition +inspection.token.set.in.parser.definition=TokenSet in ParserDefinition references non-core classes diff --git a/plugins/devkit/devkit-core/src/inspections/TokenSetInParserDefinitionInspection.kt b/plugins/devkit/devkit-core/src/inspections/TokenSetInParserDefinitionInspection.kt new file mode 100644 index 000000000000..307a91d6e972 --- /dev/null +++ b/plugins/devkit/devkit-core/src/inspections/TokenSetInParserDefinitionInspection.kt @@ -0,0 +1,119 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.idea.devkit.inspections + +import com.intellij.codeInspection.InspectionManager +import com.intellij.codeInspection.ProblemDescriptor +import com.intellij.codeInspection.ProblemsHolder +import com.intellij.lang.ParserDefinition +import com.intellij.psi.PsiClassType +import com.intellij.psi.TokenType +import com.intellij.psi.tree.TokenSet +import com.intellij.psi.util.InheritanceUtil +import org.jetbrains.idea.devkit.DevKitBundle +import org.jetbrains.uast.* +import org.jetbrains.uast.visitor.AbstractUastVisitor + +internal class TokenSetInParserDefinitionInspection : DevKitUastInspectionBase(UClass::class.java) { + + override fun checkClass(aClass: UClass, manager: InspectionManager, isOnTheFly: Boolean): Array { + if (!InheritanceUtil.isInheritor(aClass.javaPsi, ParserDefinition::class.java.name)) return ProblemDescriptor.EMPTY_ARRAY + + val problemsHolder = createProblemsHolder(aClass, manager, isOnTheFly) + aClass.fields + .filter { it.isTokenSetField() && it.isIllegal(aClass) } + .forEach { reportField(it, problemsHolder) } + + return problemsHolder.resultsArray + } + + private fun UField.isTokenSetField(): Boolean { + val fieldType = (this.type as? PsiClassType)?.resolve() ?: return false + return fieldType.qualifiedName == TokenSet::class.java.name + } + + private fun UField.isIllegal(aClass: UClass): Boolean { + val initializer = this.uastInitializer + if (initializer != null) { + return initializer.containsIllegalReferences() + } + else { + val constructors = aClass.methods.filter { it.isConstructor } + return constructors.any { it.containsFieldAssignmentWithIllegalReferences(this) } || + aClass.initializers.any { it.containsFieldAssignmentWithIllegalReferences(this) } || + companionObjectInitBlockContainsIllegalUsage(aClass) + } + } + + private fun UExpression.containsIllegalReferences(): Boolean { + if (this is UResolvable) { + val resolved = this.resolveToUElement() ?: return false + when (resolved) { + is UField -> { + // TokenSet.EMPTY, TokenSet.ANY, etc. are allowed to use + return resolved.getContainingUClass()?.qualifiedName != TokenSet::class.java.name + } + is UMethod -> { + // check if assignment contains any non-core class usage + val nonCoreApiFinder = NonCoreApiFinder() + this.accept(nonCoreApiFinder) + return nonCoreApiFinder.nonCoreApiUsed + } + } + } + return false + } + + private fun reportField(field: UField, problemsHolder: ProblemsHolder) { + val anchorPsi = field.getAnchorPsi() ?: return + problemsHolder.registerProblem(anchorPsi, DevKitBundle.message("inspection.token.set.in.parser.definition")) + } + + private fun UDeclaration.containsFieldAssignmentWithIllegalReferences(field: UField): Boolean { + var containsIllegalAssignment = false + this.accept(object : AbstractUastVisitor() { + private val checkChildrenFlag = false + private val skipChildrenFlag = true + override fun visitBinaryExpression(node: UBinaryExpression): Boolean { + if (containsIllegalAssignment) return skipChildrenFlag + val resolvedElement = (node.leftOperand as? UReferenceExpression)?.resolveToUElement() ?: return checkChildrenFlag + if (resolvedElement.sourcePsi?.isEquivalentTo(field.sourcePsi) == true && node.rightOperand.containsIllegalReferences()) { + containsIllegalAssignment = true + return skipChildrenFlag + } + return checkChildrenFlag + } + }) + return containsIllegalAssignment + } + + private fun UField.companionObjectInitBlockContainsIllegalUsage(aClass: UClass): Boolean { + val companionInitBlock = aClass.innerClasses.firstOrNull { it.javaPsi.name == "Companion" } + ?.methods?.firstOrNull { it.javaPsi.name == "Companion" } + return companionInitBlock?.containsFieldAssignmentWithIllegalReferences(this) == true + } + + private class NonCoreApiFinder : AbstractUastVisitor() { + private val checkChildrenFlag = false + private val skipChildrenFlag = true + var nonCoreApiUsed = false + + override fun visitQualifiedReferenceExpression(node: UQualifiedReferenceExpression): Boolean { + return node.checkNonCoreApiUsage() + } + + override fun visitSimpleNameReferenceExpression(node: USimpleNameReferenceExpression): Boolean { + return node.checkNonCoreApiUsage() + } + + private fun UReferenceExpression.checkNonCoreApiUsage(): Boolean { + if (nonCoreApiUsed) return skipChildrenFlag + val resolvedElementContainingClass = this.resolveToUElement()?.getContainingUClass()?.qualifiedName ?: return checkChildrenFlag + if (resolvedElementContainingClass != TokenSet::class.java.name && + resolvedElementContainingClass != TokenType::class.java.name) { + nonCoreApiUsed = true + return skipChildrenFlag + } + return checkChildrenFlag + } + } +} diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/MyLangTokenTypes.java b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/MyLangTokenTypes.java new file mode 100644 index 000000000000..417d12e65906 --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/MyLangTokenTypes.java @@ -0,0 +1,7 @@ +package com.example; + +import com.intellij.psi.tree.IElementType; + +public final class MyLangTokenTypes { + public static final IElementType COMMENT = null; +} diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionNonDirectImplementorWithIllegalTokenSet.java b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionNonDirectImplementorWithIllegalTokenSet.java new file mode 100644 index 000000000000..9e85a2f63a0e --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionNonDirectImplementorWithIllegalTokenSet.java @@ -0,0 +1,16 @@ +import com.intellij.lang.ParserDefinition; +import com.intellij.psi.tree.TokenSet; +import com.example.MyLangTokenTypes; + +public class ParserDefinitionNonDirectImplementorWithIllegalTokenSet extends CustomParserDefinition { + public static final TokenSet COMMENTS = TokenSet.create(MyLangTokenTypes.COMMENT); + + @Override + public TokenSet getCommentTokens() { + return COMMENTS; + } +} + +abstract class CustomParserDefinition implements ParserDefinition { + +} diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSet.java b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSet.java new file mode 100644 index 000000000000..8f2a490dd295 --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSet.java @@ -0,0 +1,12 @@ +import com.intellij.lang.ParserDefinition; +import com.intellij.psi.tree.TokenSet; +import com.example.MyLangTokenTypes; + +public class ParserDefinitionWithIllegalTokenSet implements ParserDefinition { + public static final TokenSet COMMENTS = TokenSet.create(MyLangTokenTypes.COMMENT); + + @Override + public TokenSet getCommentTokens() { + return COMMENTS; + } +} diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInConstructor.java b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInConstructor.java new file mode 100644 index 000000000000..b58e0bfd023c --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInConstructor.java @@ -0,0 +1,16 @@ +import com.intellij.lang.ParserDefinition; +import com.intellij.psi.tree.TokenSet; +import com.example.MyLangTokenTypes; + +public class ParserDefinitionWithIllegalTokenSetInitializedInConstructor implements ParserDefinition { + public final TokenSet comments; + + public ParserDefinitionWithIllegalTokenSetInitializedInConstructor() { + comments = TokenSet.create(MyLangTokenTypes.COMMENT); + } + + @Override + public TokenSet getCommentTokens() { + return comments; + } +} diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInStaticBlock.java b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInStaticBlock.java new file mode 100644 index 000000000000..2a40d86b29ee --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInStaticBlock.java @@ -0,0 +1,16 @@ +import com.intellij.lang.ParserDefinition; +import com.intellij.psi.tree.TokenSet; +import com.example.MyLangTokenTypes; + +public class ParserDefinitionWithIllegalTokenSetInitializedInStaticBlock implements ParserDefinition { + public static final TokenSet COMMENTS; + + static { + COMMENTS = TokenSet.create(MyLangTokenTypes.COMMENT); + } + + @Override + public TokenSet getCommentTokens() { + return COMMENTS; + } +} diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenComplexCreation.java b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenComplexCreation.java new file mode 100644 index 000000000000..f7a5eb8ace9a --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenComplexCreation.java @@ -0,0 +1,12 @@ +import com.intellij.lang.ParserDefinition; +import com.intellij.psi.tree.TokenSet; +import com.example.MyLangTokenTypes; + +public class ParserDefinitionWithIllegalTokenSetWhenComplexCreation implements ParserDefinition { + public static final TokenSet COMMENTS = TokenSet.orSet(TokenSet.create(MyLangTokenTypes.COMMENT), TokenSet.create(MyLangTokenTypes.COMMENT)); + + @Override + public TokenSet getCommentTokens() { + return COMMENTS; + } +} diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenStaticImportsUsed.java b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenStaticImportsUsed.java new file mode 100644 index 000000000000..a4e90780ed9b --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenStaticImportsUsed.java @@ -0,0 +1,14 @@ +import com.intellij.lang.ParserDefinition; +import com.intellij.psi.tree.TokenSet; + +import static com.example.MyLangTokenTypes.COMMENT; +import static com.intellij.psi.tree.TokenSet.create; + +public class ParserDefinitionWithIllegalTokenSetWhenStaticImportsUsed implements ParserDefinition { + public static final TokenSet COMMENTS = create(COMMENT); + + @Override + public TokenSet getCommentTokens() { + return COMMENTS; + } +} diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSet.java b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSet.java new file mode 100644 index 000000000000..c9465e80945e --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSet.java @@ -0,0 +1,10 @@ +import com.intellij.lang.ParserDefinition; +import com.intellij.psi.tree.TokenSet; + +public class ParserDefinitionWithLegalCoreTokenSet implements ParserDefinition { + public static final TokenSet COMMENTS = TokenSet.EMPTY; + @Override + public TokenSet getCommentTokens() { + return COMMENTS; + } +} diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInConstructor.java b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInConstructor.java new file mode 100644 index 000000000000..7b1ea82cb99c --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInConstructor.java @@ -0,0 +1,15 @@ +import com.intellij.lang.ParserDefinition; +import com.intellij.psi.tree.TokenSet; + +public class ParserDefinitionWithLegalCoreTokenSetInitializedInConstructor implements ParserDefinition { + public final TokenSet comments; + + public ParserDefinitionWithLegalCoreTokenSetInitializedInConstructor() { + comments = TokenSet.EMPTY; + } + + @Override + public TokenSet getCommentTokens() { + return comments; + } +} diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInStaticBlock.java b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInStaticBlock.java new file mode 100644 index 000000000000..ed9b27ae0e98 --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInStaticBlock.java @@ -0,0 +1,15 @@ +import com.intellij.lang.ParserDefinition; +import com.intellij.psi.tree.TokenSet; + +public class ParserDefinitionWithLegalCoreTokenSetInitializedInStaticBlock implements ParserDefinition { + public static final TokenSet COMMENTS; + + static { + COMMENTS = TokenSet.EMPTY; + } + + @Override + public TokenSet getCommentTokens() { + return COMMENTS; + } +} diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenType.java b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenType.java new file mode 100644 index 000000000000..f31332b112d1 --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenType.java @@ -0,0 +1,11 @@ +import com.intellij.lang.ParserDefinition; +import com.intellij.psi.TokenType; +import com.intellij.psi.tree.TokenSet; + +public class ParserDefinitionWithLegalCoreTokenType implements ParserDefinition { + public static final TokenSet COMMENTS = TokenSet.create(TokenType.WHITE_SPACE); + @Override + public TokenSet getCommentTokens() { + return COMMENTS; + } +} diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInConstructor.java b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInConstructor.java new file mode 100644 index 000000000000..efbad465318b --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInConstructor.java @@ -0,0 +1,16 @@ +import com.intellij.lang.ParserDefinition; +import com.intellij.psi.TokenType; +import com.intellij.psi.tree.TokenSet; + +public class ParserDefinitionWithLegalCoreTokenTypeInitializedInConstructor implements ParserDefinition { + public final TokenSet comments; + + public ParserDefinitionWithLegalCoreTokenTypeInitializedInConstructor() { + comments = TokenSet.create(TokenType.WHITE_SPACE); + } + + @Override + public TokenSet getCommentTokens() { + return comments; + } +} diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInStaticBlock.java b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInStaticBlock.java new file mode 100644 index 000000000000..35c3ca7eb845 --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInStaticBlock.java @@ -0,0 +1,16 @@ +import com.intellij.lang.ParserDefinition; +import com.intellij.psi.TokenType; +import com.intellij.psi.tree.TokenSet; + +public class ParserDefinitionWithLegalCoreTokenTypeInitializedInStaticBlock implements ParserDefinition { + public static final TokenSet COMMENTS; + + static { + COMMENTS = TokenSet.create(TokenType.WHITE_SPACE); + } + + @Override + public TokenSet getCommentTokens() { + return COMMENTS; + } +} diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalTokenSetInitializedLazilyInMethod.java b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalTokenSetInitializedLazilyInMethod.java new file mode 100644 index 000000000000..185cbedbda8f --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalTokenSetInitializedLazilyInMethod.java @@ -0,0 +1,14 @@ +import com.intellij.lang.ParserDefinition; +import com.intellij.psi.tree.TokenSet; +import com.example.MyLangTokenTypes; + +public class ParserDefinitionWithLegalTokenSetInitializedLazilyInMethod implements ParserDefinition { + private TokenSet comments; + @Override + public TokenSet getCommentTokens() { + if (comments == null) { + comments = TokenSet.create(MyLangTokenTypes.COMMENT); + } + return comments; + } +} diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/TokenSetInParserDefinitionInspectionTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/TokenSetInParserDefinitionInspectionTest.kt new file mode 100644 index 000000000000..40d7e5eb8743 --- /dev/null +++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/TokenSetInParserDefinitionInspectionTest.kt @@ -0,0 +1,69 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.idea.devkit.inspections + +import com.intellij.testFramework.TestDataPath +import org.jetbrains.idea.devkit.DevkitJavaTestsUtil + +@TestDataPath("\$CONTENT_ROOT/testData/inspections/tokenSetInParserDefinition") +class TokenSetInParserDefinitionInspectionTest : TokenSetInParserDefinitionInspectionTestBase() { + override fun getBasePath() = DevkitJavaTestsUtil.TESTDATA_PATH + "inspections/tokenSetInParserDefinition" + override fun getFileExtension() = "java" + + fun testParserDefinitionWithIllegalTokenSet() { + doInspectionTest() + } + + fun testParserDefinitionWithIllegalTokenSetWhenComplexCreation() { + doInspectionTest() + } + + fun testParserDefinitionWithIllegalTokenSetWhenStaticImportsUsed() { + doInspectionTest() + } + + fun testParserDefinitionNonDirectImplementorWithIllegalTokenSet() { + doInspectionTest() + } + + fun testParserDefinitionWithIllegalTokenSetInitializedInConstructor() { + doInspectionTest() + } + + fun testParserDefinitionWithIllegalTokenSetInitializedInStaticBlock() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalCoreTokenSet() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalCoreTokenSetInitializedInConstructor() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalCoreTokenSetInitializedInStaticBlock() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalCoreTokenType() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalCoreTokenTypeInitializedInConstructor() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalCoreTokenTypeInitializedInStaticBlock() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalTokenSetInitializedLazilyInMethod() { + doInspectionTest() + } + + private fun doInspectionTest() { + myFixture.copyFileToProject("MyLangTokenTypes.java") + doTest() + } + +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/MyLangTokenTypes.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/MyLangTokenTypes.kt new file mode 100644 index 000000000000..1b2859da0f89 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/MyLangTokenTypes.kt @@ -0,0 +1,7 @@ +package com.example + +import com.intellij.psi.tree.IElementType + +object MyLangTokenTypes { + val COMMENT: IElementType? = null +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionNonDirectImplementorWithIllegalTokenSet.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionNonDirectImplementorWithIllegalTokenSet.kt new file mode 100644 index 000000000000..ca24f4a81717 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionNonDirectImplementorWithIllegalTokenSet.kt @@ -0,0 +1,12 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.tree.TokenSet +import com.example.MyLangTokenTypes + +class ParserDefinitionNonDirectImplementorWithIllegalTokenSet : CustomParserDefinition() { + val COMMENTS = TokenSet.create(MyLangTokenTypes.COMMENT) + override fun getCommentTokens(): TokenSet { + return COMMENTS + } +} + +abstract class CustomParserDefinition : ParserDefinition diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSet.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSet.kt new file mode 100644 index 000000000000..3dd463728a1b --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSet.kt @@ -0,0 +1,10 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.tree.TokenSet +import com.example.MyLangTokenTypes + +class ParserDefinitionWithIllegalTokenSet : ParserDefinition { + val COMMENTS = TokenSet.create(MyLangTokenTypes.COMMENT) + override fun getCommentTokens(): TokenSet { + return COMMENTS + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInCompanionObject.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInCompanionObject.kt new file mode 100644 index 000000000000..3f8ef3842655 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInCompanionObject.kt @@ -0,0 +1,12 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.tree.TokenSet +import com.example.MyLangTokenTypes + +class ParserDefinitionWithIllegalTokenSetInCompanionObject : ParserDefinition { + override fun getCommentTokens(): TokenSet { + return COMMENTS + } + companion object { + val COMMENTS = TokenSet.create(MyLangTokenTypes.COMMENT) + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInCompanionObjectInitBlock.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInCompanionObjectInitBlock.kt new file mode 100644 index 000000000000..4a5eeb8a388b --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInCompanionObjectInitBlock.kt @@ -0,0 +1,17 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.tree.TokenSet +import com.example.MyLangTokenTypes + +class ParserDefinitionWithIllegalTokenSetInitializedInCompanionObjectInitBlock : ParserDefinition { + override fun getCommentTokens(): TokenSet { + return COMMENTS + } + + companion object { + val COMMENTS: TokenSet + + init { + COMMENTS = TokenSet.create(MyLangTokenTypes.COMMENT) + } + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInConstructor.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInConstructor.kt new file mode 100644 index 000000000000..5dc86c89c17f --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInConstructor.kt @@ -0,0 +1,14 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.tree.TokenSet +import com.example.MyLangTokenTypes + +class ParserDefinitionWithIllegalTokenSetInitializedInConstructor : ParserDefinition { + val comments: TokenSet + constructor() { + comments = TokenSet.create(MyLangTokenTypes.COMMENT) + } + + override fun getCommentTokens(): TokenSet { + return comments + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInInitBlock.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInInitBlock.kt new file mode 100644 index 000000000000..0de80a994416 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetInitializedInInitBlock.kt @@ -0,0 +1,15 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.tree.TokenSet +import com.example.MyLangTokenTypes + +class ParserDefinitionWithIllegalTokenSetInitializedInInitBlock : ParserDefinition { + val comments: TokenSet + + init { + comments = TokenSet.create(MyLangTokenTypes.COMMENT) + } + + override fun getCommentTokens(): TokenSet { + return comments + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenComplexCreation.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenComplexCreation.kt new file mode 100644 index 000000000000..ed12572adb8a --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenComplexCreation.kt @@ -0,0 +1,10 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.tree.TokenSet +import com.example.MyLangTokenTypes + +class ParserDefinitionWithIllegalTokenSetWhenComplexCreation : ParserDefinition { + val COMMENTS = TokenSet.orSet(TokenSet.create(MyLangTokenTypes.COMMENT), TokenSet.create(MyLangTokenTypes.COMMENT)) + override fun getCommentTokens(): TokenSet { + return COMMENTS + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenMembersImported.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenMembersImported.kt new file mode 100644 index 000000000000..e2c97f29a5cf --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithIllegalTokenSetWhenMembersImported.kt @@ -0,0 +1,11 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.tree.TokenSet +import com.intellij.psi.tree.TokenSet.create +import com.example.MyLangTokenTypes.COMMENT + +class ParserDefinitionWithIllegalTokenSetWhenMembersImported : ParserDefinition { + val COMMENTS = create(COMMENT) + override fun getCommentTokens(): TokenSet { + return COMMENTS + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSet.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSet.kt new file mode 100644 index 000000000000..59fd312bca0d --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSet.kt @@ -0,0 +1,9 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.tree.TokenSet + +class ParserDefinitionWithLegalCoreTokenSet : ParserDefinition { + val comments = TokenSet.EMPTY + override fun getCommentTokens(): TokenSet { + return comments + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInCompanionObject.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInCompanionObject.kt new file mode 100644 index 000000000000..d75f9b02221c --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInCompanionObject.kt @@ -0,0 +1,11 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.tree.TokenSet + +class ParserDefinitionWithLegalCoreTokenSetInCompanionObject : ParserDefinition { + override fun getCommentTokens(): TokenSet { + return COMMENTS + } + companion object { + val COMMENTS = TokenSet.EMPTY + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInCompanionObjectInitBlock.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInCompanionObjectInitBlock.kt new file mode 100644 index 000000000000..ef507d547bf9 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInCompanionObjectInitBlock.kt @@ -0,0 +1,16 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.tree.TokenSet + +class ParserDefinitionWithLegalCoreTokenSetInitializedInCompanionObjectInitBlock : ParserDefinition { + override fun getCommentTokens(): TokenSet { + return COMMENTS + } + + companion object { + val COMMENTS: TokenSet + + init { + COMMENTS = TokenSet.EMPTY + } + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInConstructor.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInConstructor.kt new file mode 100644 index 000000000000..af32fe4f1eb8 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenSetInitializedInConstructor.kt @@ -0,0 +1,14 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.tree.TokenSet + +class ParserDefinitionWithLegalCoreTokenSetInitializedInConstructor : ParserDefinition { + val comments: TokenSet + + init { + comments = TokenSet.EMPTY + } + + override fun getCommentTokens(): TokenSet { + return comments + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenType.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenType.kt new file mode 100644 index 000000000000..d267d8a36113 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenType.kt @@ -0,0 +1,13 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.TokenType +import com.intellij.psi.tree.TokenSet + +class ParserDefinitionWithLegalCoreTokenType : ParserDefinition { + override fun getCommentTokens(): TokenSet { + return COMMENTS + } + + companion object { + val COMMENTS = TokenSet.create(TokenType.WHITE_SPACE) + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInConstructor.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInConstructor.kt new file mode 100644 index 000000000000..ef7b9a7ff115 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInConstructor.kt @@ -0,0 +1,15 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.TokenType +import com.intellij.psi.tree.TokenSet + +class ParserDefinitionWithLegalCoreTokenTypeInitializedInConstructor : ParserDefinition { + val comments: TokenSet + + init { + comments = TokenSet.create(TokenType.WHITE_SPACE) + } + + override fun getCommentTokens(): TokenSet { + return comments + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInStaticBlock.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInStaticBlock.kt new file mode 100644 index 000000000000..498b57aa32a1 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalCoreTokenTypeInitializedInStaticBlock.kt @@ -0,0 +1,17 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.TokenType +import com.intellij.psi.tree.TokenSet + +class ParserDefinitionWithLegalCoreTokenTypeInitializedInStaticBlock : ParserDefinition { + override fun getCommentTokens(): TokenSet { + return COMMENTS + } + + companion object { + val COMMENTS: TokenSet + + init { + COMMENTS = TokenSet.create(TokenType.WHITE_SPACE) + } + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalTokenSetDeclaredOnTopLevel.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalTokenSetDeclaredOnTopLevel.kt new file mode 100644 index 000000000000..48c0550df6c5 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalTokenSetDeclaredOnTopLevel.kt @@ -0,0 +1,11 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.tree.TokenSet +import com.example.MyLangTokenTypes + +val comments: TokenSet = TokenSet.create(MyLangTokenTypes.COMMENT) + +class ParserDefinitionWithLegalTokenSetDeclaredOnTopLevel : ParserDefinition { + override fun getCommentTokens(): TokenSet { + return comments + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalTokenSetInitializedLazilyInMethod.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalTokenSetInitializedLazilyInMethod.kt new file mode 100644 index 000000000000..f161f0b53e44 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/tokenSetInParserDefinition/ParserDefinitionWithLegalTokenSetInitializedLazilyInMethod.kt @@ -0,0 +1,13 @@ +import com.intellij.lang.ParserDefinition +import com.intellij.psi.tree.TokenSet +import com.example.MyLangTokenTypes + +class ParserDefinitionWithLegalTokenSetInitializedLazilyInMethod : ParserDefinition { + private var comments: TokenSet? = null + override fun getCommentTokens(): TokenSet { + if (comments == null) { + comments = TokenSet.create(MyLangTokenTypes.COMMENT) + } + return comments!! + } +} diff --git a/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtTokenSetInParserDefinitionInspectionTest.kt b/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtTokenSetInParserDefinitionInspectionTest.kt new file mode 100644 index 000000000000..262cb2ebf3a7 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtTokenSetInParserDefinitionInspectionTest.kt @@ -0,0 +1,86 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.idea.devkit.kotlin.inspections + +import com.intellij.testFramework.TestDataPath +import org.jetbrains.idea.devkit.inspections.TokenSetInParserDefinitionInspectionTestBase +import org.jetbrains.idea.devkit.kotlin.DevkitKtTestsUtil + +@TestDataPath("/inspections/tokenSetInParserDefinition") +class KtTokenSetInParserDefinitionInspectionTest : TokenSetInParserDefinitionInspectionTestBase() { + override fun getBasePath() = DevkitKtTestsUtil.TESTDATA_PATH + "inspections/tokenSetInParserDefinition" + override fun getFileExtension() = "kt" + + fun testParserDefinitionWithIllegalTokenSet() { + doInspectionTest() + } + + fun testParserDefinitionWithIllegalTokenSetWhenComplexCreation() { + doInspectionTest() + } + + fun testParserDefinitionNonDirectImplementorWithIllegalTokenSet() { + doInspectionTest() + } + + fun testParserDefinitionWithIllegalTokenSetInCompanionObject() { + doInspectionTest() + } + + fun testParserDefinitionWithIllegalTokenSetInitializedInCompanionObjectInitBlock() { + doInspectionTest() + } + + fun testParserDefinitionWithIllegalTokenSetInitializedInConstructor() { + doInspectionTest() + } + + fun testParserDefinitionWithIllegalTokenSetInitializedInInitBlock() { + doInspectionTest() + } + + fun testParserDefinitionWithIllegalTokenSetWhenMembersImported() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalCoreTokenSet() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalCoreTokenSetInCompanionObject() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalCoreTokenSetInitializedInCompanionObjectInitBlock() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalCoreTokenSetInitializedInConstructor() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalCoreTokenType() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalCoreTokenTypeInitializedInConstructor() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalCoreTokenTypeInitializedInStaticBlock() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalTokenSetDeclaredOnTopLevel() { + doInspectionTest() + } + + fun testParserDefinitionWithLegalTokenSetInitializedLazilyInMethod() { + doInspectionTest() + } + + + private fun doInspectionTest() { + myFixture.copyFileToProject("MyLangTokenTypes.kt") + doTest() + } +} diff --git a/plugins/devkit/devkit-tests/testSrc/org/jetbrains/idea/devkit/inspections/TokenSetInParserDefinitionInspectionTestBase.kt b/plugins/devkit/devkit-tests/testSrc/org/jetbrains/idea/devkit/inspections/TokenSetInParserDefinitionInspectionTestBase.kt new file mode 100644 index 000000000000..3a46f9386346 --- /dev/null +++ b/plugins/devkit/devkit-tests/testSrc/org/jetbrains/idea/devkit/inspections/TokenSetInParserDefinitionInspectionTestBase.kt @@ -0,0 +1,71 @@ +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.idea.devkit.inspections + +import org.jetbrains.idea.devkit.inspections.quickfix.LightDevKitInspectionFixTestBase + +abstract class TokenSetInParserDefinitionInspectionTestBase : LightDevKitInspectionFixTestBase() { + + override fun setUp() { + super.setUp() + + myFixture.addClass(""" + package com.intellij.lang; + public abstract class Language {} + """.trimIndent()) + + myFixture.addClass(""" + package com.intellij.psi.tree; + + import com.intellij.lang.Language; + + public class IElementType { + public IElementType(String debugName, Language language) { + // any + } + } + """.trimIndent()) + + myFixture.addClass(""" + package com.intellij.psi; + + import com.intellij.psi.tree.IElementType; + + public interface TokenType { + IElementType WHITE_SPACE = null; + } + """.trimIndent()) + + myFixture.addClass(""" + package com.intellij.psi.tree; + + public final class TokenSet { + public static final TokenSet EMPTY = null; + public static final TokenSet ANY = null; + public static final TokenSet WHITE_SPACE = null; + + public static TokenSet create(IElementType... types) { + return null; + } + + public static TokenSet orSet(TokenSet... sets) { + return null; + } + + } + """.trimIndent()) + + myFixture.addClass(""" + package com.intellij.lang; + + import com.intellij.psi.tree.TokenSet; + + public interface ParserDefinition { + // only a single TokenSet-related method for simplicity + TokenSet getCommentTokens(); + } + """.trimIndent()) + + myFixture.enableInspections(TokenSetInParserDefinitionInspection()) + } + +}