mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 02:59:33 +07:00
IDEA-316821: Support anonymous/inner class fields captured from context in StatefulEpInspection for Kotlin code
GitOrigin-RevId: 7f211c1b5bca9bdcb1f5281cd6717ad58f3751c3
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5252afcb0e
commit
73412b84ed
@@ -297,7 +297,7 @@ inspections.plugin.xml.dynamic.plugin.usage.of.non.dynamic.extension.point=Usage
|
|||||||
inspections.plugin.xml.dynamic.plugin.analyze.extension.point={0} for ''{1}''
|
inspections.plugin.xml.dynamic.plugin.analyze.extension.point={0} for ''{1}''
|
||||||
|
|
||||||
inspections.stateful.extension.point.leak.psi.element=Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead
|
inspections.stateful.extension.point.leak.psi.element=Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead
|
||||||
inspections.stateful.extension.point.leak.psi.element.quick.fix=See also LocalQuickFixOnPsiElement
|
inspections.stateful.extension.point.leak.psi.element.quick.fix=See also LocalQuickFixOnPsiElement.
|
||||||
inspections.stateful.extension.point.do.not.use.in.quick.fix=Do not use {0} as a field in quick-fix
|
inspections.stateful.extension.point.do.not.use.in.quick.fix=Do not use {0} as a field in quick-fix
|
||||||
inspections.stateful.extension.point.do.not.use.in.extension=Do not use {0} as a field in extension
|
inspections.stateful.extension.point.do.not.use.in.extension=Do not use {0} as a field in extension
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
// 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
|
package org.jetbrains.idea.devkit.inspections
|
||||||
|
|
||||||
import com.intellij.codeInspection.LocalQuickFix
|
import com.intellij.codeInspection.LocalQuickFix
|
||||||
@@ -10,16 +10,19 @@ import com.intellij.lang.jvm.types.JvmReferenceType
|
|||||||
import com.intellij.lang.jvm.types.JvmType
|
import com.intellij.lang.jvm.types.JvmType
|
||||||
import com.intellij.lang.jvm.util.JvmInheritanceUtil.isInheritor
|
import com.intellij.lang.jvm.util.JvmInheritanceUtil.isInheritor
|
||||||
import com.intellij.lang.jvm.util.JvmUtil
|
import com.intellij.lang.jvm.util.JvmUtil
|
||||||
import com.intellij.openapi.components.ProjectComponent
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.PsiAnonymousClass
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
import com.intellij.psi.PsiWildcardType
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import com.intellij.psi.util.PsiUtil
|
|
||||||
import com.intellij.psi.xml.XmlTag
|
import com.intellij.psi.xml.XmlTag
|
||||||
import com.intellij.util.SmartList
|
import com.intellij.util.SmartList
|
||||||
import org.jetbrains.annotations.Nls
|
import org.jetbrains.annotations.Nls
|
||||||
import org.jetbrains.idea.devkit.DevKitBundle
|
import org.jetbrains.idea.devkit.DevKitBundle
|
||||||
import org.jetbrains.idea.devkit.util.processExtensionsByClassName
|
import org.jetbrains.idea.devkit.util.processExtensionsByClassName
|
||||||
|
import org.jetbrains.uast.*
|
||||||
|
import org.jetbrains.uast.visitor.AbstractUastVisitor
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class StatefulEpInspection : DevKitJvmInspection() {
|
class StatefulEpInspection : DevKitJvmInspection() {
|
||||||
@@ -60,10 +63,11 @@ class StatefulEpInspection : DevKitJvmInspection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitClass(clazz: JvmClass): Boolean? {
|
override fun visitClass(clazz: JvmClass): Boolean? {
|
||||||
if (canCapture(clazz) && isInheritor (clazz, localQuickFixFqn)) {
|
if (canCapture(clazz) && isInheritor(clazz, localQuickFixFqn)) {
|
||||||
for (capturedElement in getCapturedPoints(clazz)) {
|
for (capturedElement in getCapturedPoints(clazz)) {
|
||||||
if (capturedElement.resolved is PsiVariable && isHoldingElement(capturedElement.resolved.type, PsiElement::class.java.canonicalName)) {
|
if (capturedElement.resolved is UVariable && isHoldingElement(capturedElement.resolved.type, PsiElement::class.java.canonicalName)) {
|
||||||
(sink as HighlightSinkImpl).holder.registerProblem(capturedElement.reference, getMessage(true))
|
val capturedElementPsi = capturedElement.reference.sourcePsi ?: continue
|
||||||
|
(sink as HighlightSinkImpl).holder.registerProblem(capturedElementPsi, getMessage(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,7 +85,12 @@ class StatefulEpInspection : DevKitJvmInspection() {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (type is JvmReferenceType && type.typeArguments().iterator().hasNext() && holderClasses.any { isInheritor(typeClass, it) }) {
|
if (type is JvmReferenceType && type.typeArguments().iterator().hasNext() && holderClasses.any { isInheritor(typeClass, it) }) {
|
||||||
return type.typeArguments().any { isHoldingElement(it, elementClass) }
|
return type.typeArguments().any {
|
||||||
|
// Kotlin's List<PsiElement> is List <? extends Element>, so we need to use bound if exists:
|
||||||
|
val typeBound = (it as? PsiWildcardType)?.bound
|
||||||
|
val actualType = typeBound ?: it
|
||||||
|
isHoldingElement(actualType, elementClass)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -89,39 +98,63 @@ class StatefulEpInspection : DevKitJvmInspection() {
|
|||||||
private fun getMessage(isQuickFix: Boolean): @Nls String {
|
private fun getMessage(isQuickFix: Boolean): @Nls String {
|
||||||
var message = DevKitBundle.message("inspections.stateful.extension.point.leak.psi.element")
|
var message = DevKitBundle.message("inspections.stateful.extension.point.leak.psi.element")
|
||||||
if (isQuickFix) {
|
if (isQuickFix) {
|
||||||
message += " " + DevKitBundle.message("inspections.stateful.extension.point.leak.psi.element.quick.fix")
|
message += ". " + DevKitBundle.message("inspections.stateful.extension.point.leak.psi.element.quick.fix")
|
||||||
}
|
}
|
||||||
return message
|
return message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class CapturedDescriptor(val reference: PsiElement, val resolved: PsiElement)
|
private data class CapturedDescriptor(val reference: UElement, val resolved: UElement)
|
||||||
|
|
||||||
fun getCapturedPoints(clazz: JvmClass): Collection<CapturedDescriptor> {
|
private fun getCapturedPoints(clazz: JvmClass): Collection<CapturedDescriptor> {
|
||||||
val res = mutableListOf<CapturedDescriptor>()
|
val capturedPoints = mutableListOf<CapturedDescriptor>()
|
||||||
if (clazz is PsiClass && canCapture(clazz)) {
|
if (canCapture(clazz)) {
|
||||||
val argumentList = if (clazz is PsiAnonymousClass) clazz.argumentList else null
|
val uClass = (clazz as? PsiElement)?.toUElement() as? UClass ?: return emptyList()
|
||||||
clazz.accept(object : JavaRecursiveElementWalkingVisitor() {
|
val argumentList = if (uClass is UAnonymousClass) (uClass.javaPsi as? PsiAnonymousClass)?.argumentList else null
|
||||||
override fun visitReferenceExpression(expression: PsiReferenceExpression) {
|
uClass.accept(object : AbstractUastVisitor() {
|
||||||
if (expression.qualifierExpression == null && (argumentList == null || !PsiTreeUtil.isAncestor(argumentList, expression, true))) {
|
override fun visitSimpleNameReferenceExpression(node: USimpleNameReferenceExpression): Boolean {
|
||||||
val refElement = expression.resolve()
|
val expressionPsi = node.sourcePsi ?: return super.visitSimpleNameReferenceExpression(node)
|
||||||
if (refElement is PsiVariable) {
|
if (argumentList == null || !PsiTreeUtil.isAncestor(argumentList, expressionPsi, true)) {
|
||||||
val containingClass = PsiTreeUtil.getParentOfType(refElement, PsiClass::class.java)
|
val refElement = node.resolveToUElement() as? UVariable ?: return super.visitSimpleNameReferenceExpression(node)
|
||||||
if (PsiTreeUtil.isAncestor(containingClass, clazz, true)) {
|
val containingClass = refElement.getUastParentOfType<UClass>() ?: return super.visitSimpleNameReferenceExpression(node)
|
||||||
res.add(CapturedDescriptor(expression, refElement))
|
if (isAncestor(containingClass, uClass)) {
|
||||||
}
|
capturedPoints.add(CapturedDescriptor(node, refElement))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return super.visitSimpleNameReferenceExpression(node)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return res
|
return capturedPoints
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun canCapture(clazz: JvmClass) = clazz is PsiClass && PsiUtil.isLocalOrAnonymousClass(clazz)
|
private fun isAncestor(ancestor: UElement, child: UElement): Boolean {
|
||||||
|
val ancestorPsi = ancestor.sourcePsi ?: return false
|
||||||
|
val childPsi = child.sourcePsi ?: return false
|
||||||
|
return PsiTreeUtil.isAncestor(ancestorPsi, childPsi, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun canCapture(clazz: JvmClass): Boolean {
|
||||||
|
val uClass = (clazz as? PsiElement)?.toUElement() as? UClass ?: return false
|
||||||
|
return uClass.isLocalOrAnonymousClass()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun UClass.isLocalOrAnonymousClass(): Boolean {
|
||||||
|
return this is UAnonymousClass || this.isLocalClass()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun UClass.isLocalClass(): Boolean {
|
||||||
|
val parent = this.uastParent
|
||||||
|
if (parent is UDeclarationsExpression && parent.uastParent is UBlockExpression) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return (parent as? UClass)?.isLocalOrAnonymousClass() == true
|
||||||
|
}
|
||||||
|
|
||||||
private val localQuickFixFqn = LocalQuickFix::class.java.canonicalName
|
private val localQuickFixFqn = LocalQuickFix::class.java.canonicalName
|
||||||
private val projectComponentFqn = ProjectComponent::class.java.canonicalName
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
private val projectComponentFqn = com.intellij.openapi.components.ProjectComponent::class.java.canonicalName
|
||||||
|
|
||||||
private fun findEpCandidates(project: Project, className: String): Collection<XmlTag> {
|
private fun findEpCandidates(project: Project, className: String): Collection<XmlTag> {
|
||||||
val result = Collections.synchronizedList(SmartList<XmlTag>())
|
val result = Collections.synchronizedList(SmartList<XmlTag>())
|
||||||
|
|||||||
@@ -1,24 +1,28 @@
|
|||||||
public class CapturedFromOuterClass extends com.intellij.codeInspection.LocalQuickFix {
|
import com.intellij.psi.PsiElement;
|
||||||
final com.intellij.psi.PsiElement <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">pe</warning>;
|
import com.intellij.codeInspection.LocalQuickFix;
|
||||||
final com.intellij.psi.PsiReference <warning descr="Do not use PsiReference as a field in quick-fix">r</warning>;
|
import com.intellij.psi.PsiReference;
|
||||||
com.intellij.openapi.project.Project <warning descr="Do not use Project as a field in quick-fix">p</warning>;
|
import com.intellij.openapi.project.Project;
|
||||||
final com.intellij.openapi.project.Project pf;
|
|
||||||
public CapturedFromOuterClass(com.intellij.psi.PsiElement a, String b) {
|
public class CapturedFromOuterClass implements LocalQuickFix {
|
||||||
super();
|
final PsiElement <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">pe</warning>;
|
||||||
|
final PsiReference <warning descr="Do not use PsiReference as a field in quick-fix">r</warning>;
|
||||||
|
Project <warning descr="Do not use Project as a field in quick-fix">p</warning>;
|
||||||
|
final Project pf;
|
||||||
|
public CapturedFromOuterClass(PsiElement a, String b) {
|
||||||
pe = null;
|
pe = null;
|
||||||
r =null;
|
r = null;
|
||||||
p = pf = null;
|
p = pf = null;
|
||||||
|
|
||||||
com.intellij.codeInspection.LocalQuickFix fix = new com.intellij.codeInspection.LocalQuickFix() {
|
LocalQuickFix fix = new LocalQuickFix() {
|
||||||
private void a(com.intellij.psi.PsiElement a1, String b1) {
|
private void a(PsiElement a1, String b1) {
|
||||||
System.out.println(<warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">a</warning>);
|
System.out.println(<warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">a</warning>);
|
||||||
System.out.println(b);
|
System.out.println(b);
|
||||||
System.out.println(a1);
|
System.out.println(a1);
|
||||||
System.out.println(b1);
|
System.out.println(b1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
com.intellij.psi.PsiElement notFix = new com.intellij.psi.PsiElement() {
|
PsiElement notFix = new PsiElement() {
|
||||||
private void a(com.intellij.psi.PsiElement a1, String b1) {
|
private void a(PsiElement a1, String b1) {
|
||||||
System.out.println(a);
|
System.out.println(a);
|
||||||
System.out.println(b);
|
System.out.println(b);
|
||||||
System.out.println(a1);
|
System.out.println(a1);
|
||||||
@@ -27,13 +31,13 @@ public class CapturedFromOuterClass extends com.intellij.codeInspection.LocalQui
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void test(com.intellij.psi.PsiElement a, String b) {
|
public void test(PsiElement a, String b) {
|
||||||
class B extends com.intellij.codeInspection.LocalQuickFix {
|
class B implements LocalQuickFix {
|
||||||
B(com.intellij.psi.PsiElement aa) {
|
B(PsiElement aa) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void a(com.intellij.psi.PsiElement a1, String b1) {
|
private void a(PsiElement a1, String b1) {
|
||||||
System.out.println(<warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">a</warning>);
|
System.out.println(<warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">a</warning>);
|
||||||
System.out.println(b);
|
System.out.println(b);
|
||||||
System.out.println(a1);
|
System.out.println(a1);
|
||||||
System.out.println(b1);
|
System.out.println(b1);
|
||||||
@@ -41,4 +45,4 @@ public class CapturedFromOuterClass extends com.intellij.codeInspection.LocalQui
|
|||||||
};
|
};
|
||||||
B b1 = new B(a) {};
|
B b1 = new B(a) {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
public class Collection extends com.intellij.codeInspection.LocalQuickFix {
|
|
||||||
java.util.Collection<com.intellij.psi.PsiElement> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">pe</warning>;
|
|
||||||
java.util.Collection<com.intellij.psi.PsiReference> <warning descr="Do not use PsiReference as a field in quick-fix">r</warning>;
|
|
||||||
java.util.Collection<java.util.Collection<com.intellij.psi.PsiReference>> <warning descr="Do not use PsiReference as a field in quick-fix">r1</warning>;
|
|
||||||
java.util.Collection r2;
|
|
||||||
java.util.Collection<Integer> r3;
|
|
||||||
java.util.Collection<java.util.Collection<com.intellij.psi.PsiElement>> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">r4</warning>;
|
|
||||||
com.intellij.openapi.project.Project <warning descr="Do not use Project as a field in quick-fix">p</warning>;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import com.intellij.codeInspection.LocalQuickFix;
|
||||||
|
import java.util.Collection;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiReference;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
|
||||||
|
public class CollectionTests implements LocalQuickFix {
|
||||||
|
Collection<PsiElement> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">pe</warning>;
|
||||||
|
Collection<PsiReference> <warning descr="Do not use PsiReference as a field in quick-fix">r</warning>;
|
||||||
|
Collection<Collection<PsiReference>> <warning descr="Do not use PsiReference as a field in quick-fix">r1</warning>;
|
||||||
|
Collection r2;
|
||||||
|
Collection<Integer> r3;
|
||||||
|
Collection<Collection<PsiElement>> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">r4</warning>;
|
||||||
|
Project <warning descr="Do not use Project as a field in quick-fix">p</warning>;
|
||||||
|
}
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiReference;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
|
||||||
public class Ext {
|
public class Ext {
|
||||||
final com.intellij.psi.PsiElement <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead">pe</warning>;
|
final PsiElement <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead">pe</warning>;
|
||||||
final com.intellij.psi.PsiReference <warning descr="Do not use PsiReference as a field in extension">r</warning>;
|
final PsiReference <warning descr="Do not use PsiReference as a field in extension">r</warning>;
|
||||||
com.intellij.openapi.project.Project <warning descr="Do not use Project as a field in extension">p</warning>;
|
Project <warning descr="Do not use Project as a field in extension">p</warning>;
|
||||||
final com.intellij.openapi.project.Project pf;
|
final Project pf;
|
||||||
public Ext() {
|
public Ext() {
|
||||||
super();
|
super();
|
||||||
pe = null;
|
pe = null;
|
||||||
r =null;
|
r =null;
|
||||||
p = pf = null;
|
p = pf = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiReference;
|
||||||
|
|
||||||
public class FakeFile {
|
public class FakeFile {
|
||||||
final com.intellij.psi.PsiElement pe;
|
final PsiElement pe;
|
||||||
final com.intellij.psi.PsiReference r;
|
final PsiReference r;
|
||||||
Project p;
|
Project p;
|
||||||
final Project pf;
|
final Project pf;
|
||||||
|
|
||||||
@@ -12,4 +14,4 @@ public class FakeFile {
|
|||||||
r = null;
|
r = null;
|
||||||
p = pf = project;
|
p = pf = project;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
public class Fix extends com.intellij.codeInspection.LocalQuickFix {
|
import com.intellij.codeInspection.LocalQuickFix;
|
||||||
final com.intellij.psi.PsiElement <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">pe</warning>;
|
import com.intellij.psi.PsiElement;
|
||||||
final com.intellij.psi.PsiReference <warning descr="Do not use PsiReference as a field in quick-fix">r</warning>;
|
import com.intellij.psi.PsiReference;
|
||||||
com.intellij.openapi.project.Project <warning descr="Do not use Project as a field in quick-fix">p</warning>;
|
import com.intellij.openapi.project.Project;
|
||||||
final com.intellij.openapi.project.Project pf;
|
|
||||||
|
public class Fix implements LocalQuickFix {
|
||||||
|
final PsiElement <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">pe</warning>;
|
||||||
|
final PsiReference <warning descr="Do not use PsiReference as a field in quick-fix">r</warning>;
|
||||||
|
Project <warning descr="Do not use Project as a field in quick-fix">p</warning>;
|
||||||
|
final Project pf;
|
||||||
public Fix() {
|
public Fix() {
|
||||||
super();
|
super();
|
||||||
pe = null;
|
pe = null;
|
||||||
r =null;
|
r =null;
|
||||||
p = pf = null;
|
p = pf = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
public class Map extends com.intellij.codeInspection.LocalQuickFix {
|
|
||||||
java.util.Map<com.intellij.psi.PsiElement, com.intellij.psi.PsiElement> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">pe</warning>;
|
|
||||||
java.util.Map<com.intellij.psi.PsiReference, com.intellij.psi.PsiElement> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">r</warning>;
|
|
||||||
java.util.Map<java.util.Map<com.intellij.psi.PsiReference, com.intellij.psi.PsiReference>, com.intellij.psi.PsiReference> <warning descr="Do not use PsiReference as a field in quick-fix">r1</warning>;
|
|
||||||
java.util.Map r2;
|
|
||||||
java.util.Map<Integer, Long> r3;
|
|
||||||
java.util.Collection<java.util.Map<com.intellij.psi.PsiElement, com.intellij.psi.PsiElement>> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">r4</warning>;
|
|
||||||
java.util.Map<com.intellij.psi.PsiElement, Long> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">r7</warning>;
|
|
||||||
java.util.Map<Integer, com.intellij.psi.PsiElement> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">r8</warning>;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import com.intellij.codeInspection.LocalQuickFix;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiReference;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class MapTests implements LocalQuickFix {
|
||||||
|
Map<PsiElement, PsiElement> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">pe</warning>;
|
||||||
|
Map<PsiReference, PsiElement> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">r</warning>;
|
||||||
|
Map<Map<PsiReference, PsiReference>, PsiReference> <warning descr="Do not use PsiReference as a field in quick-fix">r1</warning>;
|
||||||
|
Map r2;
|
||||||
|
Map<Integer, Long> r3;
|
||||||
|
Collection<Map<PsiElement, PsiElement>> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">r4</warning>;
|
||||||
|
Map<PsiElement, Long> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">r7</warning>;
|
||||||
|
Map<Integer, PsiElement> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">r8</warning>;
|
||||||
|
}
|
||||||
@@ -1,16 +1,20 @@
|
|||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiReference;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
|
||||||
public class NonFix {
|
public class NonFix {
|
||||||
final com.intellij.psi.PsiElement pe;
|
final PsiElement pe;
|
||||||
final com.intellij.psi.PsiReference r;
|
final PsiReference r;
|
||||||
com.intellij.openapi.project.Project p;
|
Project p;
|
||||||
final com.intellij.openapi.project.Project pf;
|
final Project pf;
|
||||||
public NonFix() {
|
public NonFix() {
|
||||||
super();
|
super();
|
||||||
pe = null;
|
pe = null;
|
||||||
r =null;
|
r = null;
|
||||||
p = pf = null;
|
p = pf = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Ext2 {
|
public static class Ext2 {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
public class ProjectComp implements com.intellij.openapi.components.ProjectComponent {
|
import com.intellij.openapi.components.ProjectComponent;
|
||||||
final com.intellij.psi.PsiElement <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead">pe</warning>;
|
import com.intellij.openapi.project.Project;
|
||||||
final com.intellij.psi.PsiReference <warning descr="Do not use PsiReference as a field in extension">r</warning>;
|
import com.intellij.psi.PsiElement;
|
||||||
com.intellij.openapi.project.Project p;
|
import com.intellij.psi.PsiReference;
|
||||||
final com.intellij.openapi.project.Project pf;
|
|
||||||
|
public class ProjectComp implements ProjectComponent {
|
||||||
|
final PsiElement <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead">pe</warning>;
|
||||||
|
final PsiReference <warning descr="Do not use PsiReference as a field in extension">r</warning>;
|
||||||
|
Project p;
|
||||||
|
final Project pf;
|
||||||
public ProjectComp() {
|
public ProjectComp() {
|
||||||
super();
|
super();
|
||||||
pe = null;
|
pe = null;
|
||||||
r =null;
|
r = null;
|
||||||
p = pf = null;
|
p = pf = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiReference;
|
||||||
|
|
||||||
public class ProjectConfigurable {
|
public class ProjectConfigurable {
|
||||||
final com.intellij.psi.PsiElement <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead">pe</warning>;
|
final PsiElement <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead">pe</warning>;
|
||||||
final com.intellij.psi.PsiReference <warning descr="Do not use PsiReference as a field in extension">r</warning>;
|
final PsiReference <warning descr="Do not use PsiReference as a field in extension">r</warning>;
|
||||||
Project p;
|
Project p;
|
||||||
final Project pf;
|
final Project pf;
|
||||||
public ProjectConfigurable(Project project) {
|
public ProjectConfigurable(Project project) {
|
||||||
@@ -11,4 +13,4 @@ public class ProjectConfigurable {
|
|||||||
r = null;
|
r = null;
|
||||||
p = pf = project;
|
p = pf = project;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiReference;
|
||||||
|
|
||||||
public class ProjectService {
|
public class ProjectService {
|
||||||
final com.intellij.psi.PsiElement <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead">pe</warning>;
|
final PsiElement <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead">pe</warning>;
|
||||||
final com.intellij.psi.PsiReference <warning descr="Do not use PsiReference as a field in extension">r</warning>;
|
final PsiReference <warning descr="Do not use PsiReference as a field in extension">r</warning>;
|
||||||
Project p;
|
Project p;
|
||||||
final Project pf;
|
final Project pf;
|
||||||
public ProjectService(Project project) {
|
public ProjectService(Project project) {
|
||||||
@@ -11,4 +13,4 @@ public class ProjectService {
|
|||||||
r = null;
|
r = null;
|
||||||
p = pf = project;
|
p = pf = project;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
public class Ref extends com.intellij.codeInspection.LocalQuickFix {
|
|
||||||
com.intellij.openapi.util.Ref<com.intellij.psi.PsiElement> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">pe</warning>;
|
|
||||||
com.intellij.openapi.util.Ref<com.intellij.psi.PsiReference> <warning descr="Do not use PsiReference as a field in quick-fix">r</warning>;
|
|
||||||
com.intellij.openapi.util.Ref<com.intellij.openapi.util.Ref<com.intellij.psi.PsiReference>> <warning descr="Do not use PsiReference as a field in quick-fix">r1</warning>;
|
|
||||||
com.intellij.openapi.util.Ref r2;
|
|
||||||
com.intellij.openapi.util.Ref<Integer> r3;
|
|
||||||
com.intellij.openapi.util.Ref<com.intellij.openapi.util.Ref<com.intellij.psi.PsiElement>> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">r4</warning>;
|
|
||||||
com.intellij.openapi.project.Project <warning descr="Do not use Project as a field in quick-fix">p</warning>;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import com.intellij.openapi.util.Ref;
|
||||||
|
import com.intellij.codeInspection.LocalQuickFix;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiReference;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
|
||||||
|
public class RefTests implements LocalQuickFix {
|
||||||
|
Ref<PsiElement> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">pe</warning>;
|
||||||
|
Ref<PsiReference> <warning descr="Do not use PsiReference as a field in quick-fix">r</warning>;
|
||||||
|
Ref<Ref<PsiReference>> <warning descr="Do not use PsiReference as a field in quick-fix">r1</warning>;
|
||||||
|
Ref r2;
|
||||||
|
Ref<Integer> r3;
|
||||||
|
Ref<Ref<PsiElement>> <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">r4</warning>;
|
||||||
|
Project <warning descr="Do not use Project as a field in quick-fix">p</warning>;
|
||||||
|
}
|
||||||
@@ -1,75 +1,68 @@
|
|||||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
// 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;
|
package org.jetbrains.idea.devkit.inspections;
|
||||||
|
|
||||||
import com.intellij.testFramework.TestDataPath;
|
import com.intellij.testFramework.TestDataPath;
|
||||||
import org.jetbrains.idea.devkit.DevkitJavaTestsUtil;
|
import org.jetbrains.idea.devkit.DevkitJavaTestsUtil;
|
||||||
|
|
||||||
@TestDataPath("$CONTENT_ROOT/testData/inspections/statefulEp")
|
@TestDataPath("$CONTENT_ROOT/testData/inspections/statefulEp")
|
||||||
public class StatefulEpInspectionTest extends PluginModuleTestCase {
|
public class StatefulEpInspectionTest extends StatefulEpInspectionTestBase {
|
||||||
@Override
|
@Override
|
||||||
protected String getBasePath() {
|
protected String getBasePath() {
|
||||||
return DevkitJavaTestsUtil.TESTDATA_PATH + "inspections/statefulEp";
|
return DevkitJavaTestsUtil.TESTDATA_PATH + "inspections/statefulEp";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setUp() throws Exception {
|
protected String getFileExtension() {
|
||||||
super.setUp();
|
return "java";
|
||||||
myFixture.addClass("package com.intellij.openapi.project; public class Project {}");
|
|
||||||
myFixture.addClass("package com.intellij.psi; public class PsiElement {}");
|
|
||||||
myFixture.addClass("package com.intellij.psi; public class PsiReference {}");
|
|
||||||
myFixture.addClass("package com.intellij.codeInspection; public class LocalQuickFix {}");
|
|
||||||
myFixture.addClass("package com.intellij.openapi.components; public interface ProjectComponent {}");
|
|
||||||
myFixture.addClass("package com.intellij.openapi.util; public class Ref<T> {}");
|
|
||||||
myFixture.enableInspections(new StatefulEpInspection());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testLocalQuickFix() {
|
public void testFix() {
|
||||||
myFixture.testHighlighting("Fix.java");
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testNonFix() {
|
public void testNonFix() {
|
||||||
setPluginXml("plugin.xml");
|
setPluginXml("plugin.xml");
|
||||||
myFixture.testHighlighting("NonFix.java");
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testExt() {
|
public void testExt() {
|
||||||
setPluginXml("plugin.xml");
|
setPluginXml("plugin.xml");
|
||||||
myFixture.testHighlighting("Ext.java");
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testProjectComp() {
|
public void testProjectComp() {
|
||||||
setPluginXml("plugin.xml");
|
setPluginXml("plugin.xml");
|
||||||
myFixture.testHighlighting("ProjectComp.java");
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testProjectService() {
|
public void testProjectService() {
|
||||||
setPluginXml("plugin.xml");
|
setPluginXml("plugin.xml");
|
||||||
myFixture.testHighlighting("ProjectService.java");
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testProjectConfigurable() {
|
public void testProjectConfigurable() {
|
||||||
setPluginXml("plugin.xml");
|
setPluginXml("plugin.xml");
|
||||||
myFixture.testHighlighting("ProjectConfigurable.java");
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFakeFile() {
|
public void testFakeFile() {
|
||||||
setPluginXml("plugin.xml");
|
setPluginXml("plugin.xml");
|
||||||
myFixture.testHighlighting("FakeFile.java");
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCapturedFromOuterClass() {
|
public void testCapturedFromOuterClass() {
|
||||||
myFixture.testHighlighting("CapturedFromOuterClass.java");
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCollection() {
|
public void testCollectionTests() {
|
||||||
myFixture.testHighlighting("Collection.java");
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMap() {
|
public void testMapTests() {
|
||||||
myFixture.testHighlighting("Map.java");
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRef() {
|
public void testRefTests() {
|
||||||
myFixture.testHighlighting("Ref.java");
|
doTest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import com.intellij.codeInspection.LocalQuickFix
|
||||||
|
import com.intellij.codeInspection.ProblemDescriptor
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
|
||||||
|
class CapturedFromOuterClass(a: PsiElement?, b: String?) : LocalQuickFix {
|
||||||
|
val <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">pe</warning>: PsiElement?
|
||||||
|
val <warning descr="Do not use PsiReference as a field in quick-fix">r</warning>: PsiReference?
|
||||||
|
var <warning descr="Do not use Project as a field in quick-fix">p</warning>: Project?
|
||||||
|
val pf: Project?
|
||||||
|
|
||||||
|
init {
|
||||||
|
pe = null
|
||||||
|
r = null
|
||||||
|
pf = null
|
||||||
|
p = pf
|
||||||
|
|
||||||
|
@Suppress("UNUSED_VARIABLE")
|
||||||
|
val fix: LocalQuickFix = object : LocalQuickFix {
|
||||||
|
private fun a(a1: PsiElement, b1: String) {
|
||||||
|
any(<warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">a</warning>)
|
||||||
|
any(b)
|
||||||
|
any(a1)
|
||||||
|
any(b1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_VARIABLE")
|
||||||
|
val notFix: Any = object : Any() {
|
||||||
|
private fun a(a1: PsiElement, b1: String) {
|
||||||
|
any(a)
|
||||||
|
any(b)
|
||||||
|
any(a1)
|
||||||
|
any(b1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test(a: PsiElement?, b: String?) {
|
||||||
|
open class B(@Suppress("UNUSED_PARAMETER") aa: PsiElement?) : LocalQuickFix {
|
||||||
|
private fun a(a1: PsiElement, b1: String) {
|
||||||
|
any(<warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">a</warning>)
|
||||||
|
any(b)
|
||||||
|
any(a1)
|
||||||
|
any(b1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_VARIABLE")
|
||||||
|
val b1 = object : B(a) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun any(@Suppress("UNUSED_PARAMETER") any: Any?) {
|
||||||
|
// any
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.codeInspection.LocalQuickFix
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
|
||||||
|
class CollectionTests : LocalQuickFix {
|
||||||
|
var <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">pe</warning>: Collection<PsiElement>? = null
|
||||||
|
var <warning descr="Do not use PsiReference as a field in quick-fix">r</warning>: Collection<PsiReference>? = null
|
||||||
|
var <warning descr="Do not use PsiReference as a field in quick-fix">r1</warning>: Collection<Collection<PsiReference>>? = null
|
||||||
|
var r2: Collection<*>? = null
|
||||||
|
var r3: Collection<Int>? = null
|
||||||
|
var <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">r4</warning>: Collection<Collection<PsiElement>>? = null
|
||||||
|
var <warning descr="Do not use Project as a field in quick-fix">p</warning>: Project? = null
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
|
||||||
|
class Ext {
|
||||||
|
val <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead">pe</warning>: PsiElement?
|
||||||
|
val <warning descr="Do not use PsiReference as a field in extension">r</warning>: PsiReference?
|
||||||
|
var <warning descr="Do not use Project as a field in extension">p</warning>: Project?
|
||||||
|
val pf: Project?
|
||||||
|
|
||||||
|
init {
|
||||||
|
pe = null
|
||||||
|
r = null
|
||||||
|
pf = null
|
||||||
|
p = pf
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
|
||||||
|
class FakeFile(val pf: Project) {
|
||||||
|
val pe: PsiElement? = null
|
||||||
|
val r: PsiReference? = null
|
||||||
|
var p: Project
|
||||||
|
|
||||||
|
init {
|
||||||
|
p = pf
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import com.intellij.codeInspection.LocalQuickFix
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
|
||||||
|
class Fix : LocalQuickFix {
|
||||||
|
val <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">pe</warning>: PsiElement?
|
||||||
|
val <warning descr="Do not use PsiReference as a field in quick-fix">r</warning>: PsiReference?
|
||||||
|
var <warning descr="Do not use Project as a field in quick-fix">p</warning>: Project?
|
||||||
|
val pf: Project?
|
||||||
|
|
||||||
|
init {
|
||||||
|
pe = null
|
||||||
|
r = null
|
||||||
|
pf = null
|
||||||
|
p = pf
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import com.intellij.codeInspection.LocalQuickFix
|
||||||
|
import kotlin.collections.Map
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
|
||||||
|
class MapTests : LocalQuickFix {
|
||||||
|
val <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">pe</warning>: Map<PsiElement, PsiElement>? = null
|
||||||
|
val <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">r</warning>: Map<PsiReference, PsiElement>? = null
|
||||||
|
val <warning descr="Do not use PsiReference as a field in quick-fix">r1</warning>: Map<Map<PsiReference, PsiReference>, PsiReference>? = null
|
||||||
|
var r2: Map<*, *>? = null
|
||||||
|
var r3: Map<Int, Long>? = null
|
||||||
|
val <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">r4</warning>: Collection<Map<PsiElement, PsiElement>>? = null
|
||||||
|
val <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">r7</warning>: Map<PsiElement, Long>? = null
|
||||||
|
val <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">r8</warning>: Map<Int, PsiElement>? = null
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
|
||||||
|
class NonFix {
|
||||||
|
val pe: PsiElement? = null
|
||||||
|
val r: PsiReference? = null
|
||||||
|
var p: Project?
|
||||||
|
val pf: Project? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
p = pf
|
||||||
|
}
|
||||||
|
|
||||||
|
class Ext2
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import com.intellij.openapi.components.ProjectComponent
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
|
||||||
|
class ProjectComp : ProjectComponent {
|
||||||
|
val <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead">pe</warning>: PsiElement?
|
||||||
|
val <warning descr="Do not use PsiReference as a field in extension">r</warning>: PsiReference?
|
||||||
|
var p: Project?
|
||||||
|
val pf: Project?
|
||||||
|
|
||||||
|
init {
|
||||||
|
pe = null
|
||||||
|
r = null
|
||||||
|
pf = null
|
||||||
|
p = pf
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
|
||||||
|
class ProjectConfigurable(project: Project) {
|
||||||
|
val <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead">pe</warning>: PsiElement?
|
||||||
|
val <warning descr="Do not use PsiReference as a field in extension">r</warning>: PsiReference?
|
||||||
|
var p: Project
|
||||||
|
val pf: Project
|
||||||
|
|
||||||
|
init {
|
||||||
|
pe = null
|
||||||
|
r = null
|
||||||
|
pf = project
|
||||||
|
p = pf
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
|
||||||
|
class ProjectService(project: Project) {
|
||||||
|
val <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead">pe</warning>: PsiElement?
|
||||||
|
val <warning descr="Do not use PsiReference as a field in extension">r</warning>: PsiReference?
|
||||||
|
var p: Project?
|
||||||
|
val pf: Project?
|
||||||
|
|
||||||
|
init {
|
||||||
|
pe = null
|
||||||
|
r = null
|
||||||
|
pf = project
|
||||||
|
p = pf
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import com.intellij.codeInspection.LocalQuickFix
|
||||||
|
import com.intellij.openapi.util.Ref
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
|
||||||
|
class RefTests : LocalQuickFix {
|
||||||
|
var <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">pe</warning>: Ref<PsiElement>? = null
|
||||||
|
var <warning descr="Do not use PsiReference as a field in quick-fix">r</warning>: Ref<PsiReference>? = null
|
||||||
|
var <warning descr="Do not use PsiReference as a field in quick-fix">r1</warning>: Ref<Ref<PsiReference>>? = null
|
||||||
|
var r2: Ref<*>? = null
|
||||||
|
var r3: Ref<Int>? = null
|
||||||
|
var <warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead. See also LocalQuickFixOnPsiElement.">r4</warning>: Ref<Ref<PsiElement>>? = null
|
||||||
|
var <warning descr="Do not use Project as a field in quick-fix">p</warning>: Project? = null
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<idea-plugin>
|
||||||
|
<extensionPoints>
|
||||||
|
<extensionPoint name="ep" beanClass="EP"/>
|
||||||
|
<extensionPoint name="projectService" beanClass="SD"/>
|
||||||
|
<extensionPoint name="projectConfigurable" beanClass="SD"/>
|
||||||
|
</extensionPoints>
|
||||||
|
<extensions>
|
||||||
|
<ep implementation="Ext"/>
|
||||||
|
<ep implementation="NonFix$Ext2"/>
|
||||||
|
<ep implementation="ProjectComp"/>
|
||||||
|
<ep implementation="ProjectComp"/>
|
||||||
|
<ep forClass="FakeFile" instance="ProjectConfigurable"/>
|
||||||
|
<projectService serviceImplementation="ProjectService"/>
|
||||||
|
<projectConfigurable instance="ProjectConfigurable"/>
|
||||||
|
</extensions>
|
||||||
|
</idea-plugin>
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
// 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.StatefulEpInspectionTestBase;
|
||||||
|
import org.jetbrains.idea.devkit.kotlin.DevkitKtTestsUtil;
|
||||||
|
|
||||||
|
@TestDataPath("$CONTENT_ROOT/testData/inspections/statefulEp")
|
||||||
|
public class KtStatefulEpInspectionTest extends StatefulEpInspectionTestBase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getBasePath() {
|
||||||
|
return DevkitKtTestsUtil.TESTDATA_PATH + "inspections/statefulEp";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getFileExtension() {
|
||||||
|
return "kt";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFix() {
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNonFix() {
|
||||||
|
setPluginXml("plugin.xml");
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testExt() {
|
||||||
|
setPluginXml("plugin.xml");
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testProjectComp() {
|
||||||
|
setPluginXml("plugin.xml");
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testProjectService() {
|
||||||
|
setPluginXml("plugin.xml");
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testProjectConfigurable() {
|
||||||
|
setPluginXml("plugin.xml");
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFakeFile() {
|
||||||
|
setPluginXml("plugin.xml");
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCapturedFromOuterClass() {
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCollectionTests() {
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMapTests() {
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRefTests() {
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
public abstract class StatefulEpInspectionTestBase extends PluginModuleTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
myFixture.addClass("package com.intellij.openapi.project; public interface Project {}");
|
||||||
|
myFixture.addClass("package com.intellij.psi; public interface PsiElement {}");
|
||||||
|
myFixture.addClass("package com.intellij.psi; public interface PsiReference {}");
|
||||||
|
myFixture.addClass("package com.intellij.codeInspection; public interface LocalQuickFix {}");
|
||||||
|
myFixture.addClass("package com.intellij.codeInspection; public interface ProblemDescriptor {}");
|
||||||
|
myFixture.addClass("package com.intellij.openapi.components; public interface ProjectComponent {}");
|
||||||
|
myFixture.addClass("package com.intellij.openapi.util; public class Ref<T> {}");
|
||||||
|
myFixture.enableInspections(new StatefulEpInspection());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doTest() {
|
||||||
|
myFixture.testHighlighting(getTestName(false) + '.' + getFileExtension());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String getFileExtension();
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user