mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-301191: [DevKit] Inspection to discourage declaration of TokenSets in ParserDefinition
GitOrigin-RevId: cab7298c1babe62754272d529bd4e471cf3b17c6
This commit is contained in:
committed by
intellij-monorepo-bot
parent
29192c80ed
commit
7e7ccd372d
+85
@@ -0,0 +1,85 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports <code>TokenSet</code> field declarations referencing non-core element types in <code>ParserDefinition</code> classes.
|
||||
<p>
|
||||
All languages <code>ParserDefinition</code> are created on the application startup.
|
||||
Declaring a <code>TokenSet</code> 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.
|
||||
</p>
|
||||
|
||||
<p>Example:</p>
|
||||
<pre>
|
||||
// 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() {
|
||||
...
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
</pre>
|
||||
|
||||
<!-- tooltip end -->
|
||||
<p><small>New in 2023.2</small>
|
||||
</body>
|
||||
</html>
|
||||
@@ -315,6 +315,11 @@
|
||||
groupPathKey="inspections.group.path" groupKey="inspections.group.code"
|
||||
implementationClass="org.jetbrains.idea.devkit.inspections.ThreadingConcurrencyInspection"/>
|
||||
|
||||
<localInspection language="UAST" enabledByDefault="false" level="WARNING"
|
||||
key="inspection.token.set.in.parser.definition.display.name"
|
||||
groupPathKey="inspections.group.path" groupKey="inspections.group.code"
|
||||
implementationClass="org.jetbrains.idea.devkit.inspections.TokenSetInParserDefinitionInspection"/>
|
||||
|
||||
<moduleConfigurationEditorProvider implementation="org.jetbrains.idea.devkit.module.PluginModuleEditorsProvider"/>
|
||||
<implicitUsageProvider implementation="org.jetbrains.idea.devkit.inspections.DevKitImplicitUsageProvider"/>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<ProblemDescriptor> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.example;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
|
||||
public final class MyLangTokenTypes {
|
||||
public static final IElementType COMMENT = null;
|
||||
}
|
||||
+16
@@ -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 <warning descr="TokenSet in ParserDefinition references non-core classes">COMMENTS</warning> = TokenSet.create(MyLangTokenTypes.COMMENT);
|
||||
|
||||
@Override
|
||||
public TokenSet getCommentTokens() {
|
||||
return COMMENTS;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class CustomParserDefinition implements ParserDefinition {
|
||||
|
||||
}
|
||||
+12
@@ -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 <warning descr="TokenSet in ParserDefinition references non-core classes">COMMENTS</warning> = TokenSet.create(MyLangTokenTypes.COMMENT);
|
||||
|
||||
@Override
|
||||
public TokenSet getCommentTokens() {
|
||||
return COMMENTS;
|
||||
}
|
||||
}
|
||||
+16
@@ -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 <warning descr="TokenSet in ParserDefinition references non-core classes">comments</warning>;
|
||||
|
||||
public ParserDefinitionWithIllegalTokenSetInitializedInConstructor() {
|
||||
comments = TokenSet.create(MyLangTokenTypes.COMMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenSet getCommentTokens() {
|
||||
return comments;
|
||||
}
|
||||
}
|
||||
+16
@@ -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 <warning descr="TokenSet in ParserDefinition references non-core classes">COMMENTS</warning>;
|
||||
|
||||
static {
|
||||
COMMENTS = TokenSet.create(MyLangTokenTypes.COMMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenSet getCommentTokens() {
|
||||
return COMMENTS;
|
||||
}
|
||||
}
|
||||
+12
@@ -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 <warning descr="TokenSet in ParserDefinition references non-core classes">COMMENTS</warning> = TokenSet.orSet(TokenSet.create(MyLangTokenTypes.COMMENT), TokenSet.create(MyLangTokenTypes.COMMENT));
|
||||
|
||||
@Override
|
||||
public TokenSet getCommentTokens() {
|
||||
return COMMENTS;
|
||||
}
|
||||
}
|
||||
+14
@@ -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 <warning descr="TokenSet in ParserDefinition references non-core classes">COMMENTS</warning> = create(COMMENT);
|
||||
|
||||
@Override
|
||||
public TokenSet getCommentTokens() {
|
||||
return COMMENTS;
|
||||
}
|
||||
}
|
||||
+10
@@ -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;
|
||||
}
|
||||
}
|
||||
+15
@@ -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;
|
||||
}
|
||||
}
|
||||
+15
@@ -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;
|
||||
}
|
||||
}
|
||||
+11
@@ -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;
|
||||
}
|
||||
}
|
||||
+16
@@ -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;
|
||||
}
|
||||
}
|
||||
+16
@@ -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;
|
||||
}
|
||||
}
|
||||
+14
@@ -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;
|
||||
}
|
||||
}
|
||||
+69
@@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.example
|
||||
|
||||
import com.intellij.psi.tree.IElementType
|
||||
|
||||
object MyLangTokenTypes {
|
||||
val COMMENT: IElementType? = null
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import com.intellij.lang.ParserDefinition
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import com.example.MyLangTokenTypes
|
||||
|
||||
class ParserDefinitionNonDirectImplementorWithIllegalTokenSet : CustomParserDefinition() {
|
||||
val <warning descr="TokenSet in ParserDefinition references non-core classes">COMMENTS</warning> = TokenSet.create(MyLangTokenTypes.COMMENT)
|
||||
override fun getCommentTokens(): TokenSet {
|
||||
return COMMENTS
|
||||
}
|
||||
}
|
||||
|
||||
abstract class CustomParserDefinition : ParserDefinition
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import com.intellij.lang.ParserDefinition
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import com.example.MyLangTokenTypes
|
||||
|
||||
class ParserDefinitionWithIllegalTokenSet : ParserDefinition {
|
||||
val <warning descr="TokenSet in ParserDefinition references non-core classes">COMMENTS</warning> = TokenSet.create(MyLangTokenTypes.COMMENT)
|
||||
override fun getCommentTokens(): TokenSet {
|
||||
return COMMENTS
|
||||
}
|
||||
}
|
||||
+12
@@ -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 <warning descr="TokenSet in ParserDefinition references non-core classes">COMMENTS</warning> = TokenSet.create(MyLangTokenTypes.COMMENT)
|
||||
}
|
||||
}
|
||||
+17
@@ -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 <warning descr="TokenSet in ParserDefinition references non-core classes">COMMENTS</warning>: TokenSet
|
||||
|
||||
init {
|
||||
COMMENTS = TokenSet.create(MyLangTokenTypes.COMMENT)
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import com.intellij.lang.ParserDefinition
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import com.example.MyLangTokenTypes
|
||||
|
||||
class ParserDefinitionWithIllegalTokenSetInitializedInConstructor : ParserDefinition {
|
||||
val <warning descr="TokenSet in ParserDefinition references non-core classes">comments</warning>: TokenSet
|
||||
constructor() {
|
||||
comments = TokenSet.create(MyLangTokenTypes.COMMENT)
|
||||
}
|
||||
|
||||
override fun getCommentTokens(): TokenSet {
|
||||
return comments
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import com.intellij.lang.ParserDefinition
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import com.example.MyLangTokenTypes
|
||||
|
||||
class ParserDefinitionWithIllegalTokenSetInitializedInInitBlock : ParserDefinition {
|
||||
val <warning descr="TokenSet in ParserDefinition references non-core classes">comments</warning>: TokenSet
|
||||
|
||||
init {
|
||||
comments = TokenSet.create(MyLangTokenTypes.COMMENT)
|
||||
}
|
||||
|
||||
override fun getCommentTokens(): TokenSet {
|
||||
return comments
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import com.intellij.lang.ParserDefinition
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import com.example.MyLangTokenTypes
|
||||
|
||||
class ParserDefinitionWithIllegalTokenSetWhenComplexCreation : ParserDefinition {
|
||||
val <warning descr="TokenSet in ParserDefinition references non-core classes">COMMENTS</warning> = TokenSet.orSet(TokenSet.create(MyLangTokenTypes.COMMENT), TokenSet.create(MyLangTokenTypes.COMMENT))
|
||||
override fun getCommentTokens(): TokenSet {
|
||||
return COMMENTS
|
||||
}
|
||||
}
|
||||
+11
@@ -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 <warning descr="TokenSet in ParserDefinition references non-core classes">COMMENTS</warning> = create(COMMENT)
|
||||
override fun getCommentTokens(): TokenSet {
|
||||
return COMMENTS
|
||||
}
|
||||
}
|
||||
+9
@@ -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
|
||||
}
|
||||
}
|
||||
+11
@@ -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
|
||||
}
|
||||
}
|
||||
+16
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -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
|
||||
}
|
||||
}
|
||||
+13
@@ -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)
|
||||
}
|
||||
}
|
||||
+15
@@ -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
|
||||
}
|
||||
}
|
||||
+17
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -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
|
||||
}
|
||||
}
|
||||
+13
@@ -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!!
|
||||
}
|
||||
}
|
||||
+86
@@ -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()
|
||||
}
|
||||
}
|
||||
+71
@@ -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())
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user