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.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.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
|
||||
|
||||
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.util.JvmInheritanceUtil.isInheritor
|
||||
import com.intellij.lang.jvm.util.JvmUtil
|
||||
import com.intellij.openapi.components.ProjectComponent
|
||||
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.PsiUtil
|
||||
import com.intellij.psi.xml.XmlTag
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.annotations.Nls
|
||||
import org.jetbrains.idea.devkit.DevKitBundle
|
||||
import org.jetbrains.idea.devkit.util.processExtensionsByClassName
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.visitor.AbstractUastVisitor
|
||||
import java.util.*
|
||||
|
||||
class StatefulEpInspection : DevKitJvmInspection() {
|
||||
@@ -62,8 +65,9 @@ class StatefulEpInspection : DevKitJvmInspection() {
|
||||
override fun visitClass(clazz: JvmClass): Boolean? {
|
||||
if (canCapture(clazz) && isInheritor(clazz, localQuickFixFqn)) {
|
||||
for (capturedElement in getCapturedPoints(clazz)) {
|
||||
if (capturedElement.resolved is PsiVariable && isHoldingElement(capturedElement.resolved.type, PsiElement::class.java.canonicalName)) {
|
||||
(sink as HighlightSinkImpl).holder.registerProblem(capturedElement.reference, getMessage(true))
|
||||
if (capturedElement.resolved is UVariable && isHoldingElement(capturedElement.resolved.type, PsiElement::class.java.canonicalName)) {
|
||||
val capturedElementPsi = capturedElement.reference.sourcePsi ?: continue
|
||||
(sink as HighlightSinkImpl).holder.registerProblem(capturedElementPsi, getMessage(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,7 +85,12 @@ class StatefulEpInspection : DevKitJvmInspection() {
|
||||
return true
|
||||
}
|
||||
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
|
||||
}
|
||||
@@ -89,39 +98,63 @@ class StatefulEpInspection : DevKitJvmInspection() {
|
||||
private fun getMessage(isQuickFix: Boolean): @Nls String {
|
||||
var message = DevKitBundle.message("inspections.stateful.extension.point.leak.psi.element")
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
val res = mutableListOf<CapturedDescriptor>()
|
||||
if (clazz is PsiClass && canCapture(clazz)) {
|
||||
val argumentList = if (clazz is PsiAnonymousClass) clazz.argumentList else null
|
||||
clazz.accept(object : JavaRecursiveElementWalkingVisitor() {
|
||||
override fun visitReferenceExpression(expression: PsiReferenceExpression) {
|
||||
if (expression.qualifierExpression == null && (argumentList == null || !PsiTreeUtil.isAncestor(argumentList, expression, true))) {
|
||||
val refElement = expression.resolve()
|
||||
if (refElement is PsiVariable) {
|
||||
val containingClass = PsiTreeUtil.getParentOfType(refElement, PsiClass::class.java)
|
||||
if (PsiTreeUtil.isAncestor(containingClass, clazz, true)) {
|
||||
res.add(CapturedDescriptor(expression, refElement))
|
||||
}
|
||||
private fun getCapturedPoints(clazz: JvmClass): Collection<CapturedDescriptor> {
|
||||
val capturedPoints = mutableListOf<CapturedDescriptor>()
|
||||
if (canCapture(clazz)) {
|
||||
val uClass = (clazz as? PsiElement)?.toUElement() as? UClass ?: return emptyList()
|
||||
val argumentList = if (uClass is UAnonymousClass) (uClass.javaPsi as? PsiAnonymousClass)?.argumentList else null
|
||||
uClass.accept(object : AbstractUastVisitor() {
|
||||
override fun visitSimpleNameReferenceExpression(node: USimpleNameReferenceExpression): Boolean {
|
||||
val expressionPsi = node.sourcePsi ?: return super.visitSimpleNameReferenceExpression(node)
|
||||
if (argumentList == null || !PsiTreeUtil.isAncestor(argumentList, expressionPsi, true)) {
|
||||
val refElement = node.resolveToUElement() as? UVariable ?: return super.visitSimpleNameReferenceExpression(node)
|
||||
val containingClass = refElement.getUastParentOfType<UClass>() ?: return super.visitSimpleNameReferenceExpression(node)
|
||||
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 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> {
|
||||
val result = Collections.synchronizedList(SmartList<XmlTag>())
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
public class CapturedFromOuterClass extends 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>;
|
||||
final com.intellij.psi.PsiReference <warning descr="Do not use PsiReference as a field in quick-fix">r</warning>;
|
||||
com.intellij.openapi.project.Project <warning descr="Do not use Project as a field in quick-fix">p</warning>;
|
||||
final com.intellij.openapi.project.Project pf;
|
||||
public CapturedFromOuterClass(com.intellij.psi.PsiElement a, String b) {
|
||||
super();
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.openapi.project.Project;
|
||||
|
||||
public class CapturedFromOuterClass 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 CapturedFromOuterClass(PsiElement a, String b) {
|
||||
pe = null;
|
||||
r = null;
|
||||
p = pf = null;
|
||||
|
||||
com.intellij.codeInspection.LocalQuickFix fix = new com.intellij.codeInspection.LocalQuickFix() {
|
||||
private void a(com.intellij.psi.PsiElement a1, String b1) {
|
||||
System.out.println(<warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">a</warning>);
|
||||
LocalQuickFix fix = new LocalQuickFix() {
|
||||
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(b);
|
||||
System.out.println(a1);
|
||||
System.out.println(b1);
|
||||
}
|
||||
};
|
||||
com.intellij.psi.PsiElement notFix = new com.intellij.psi.PsiElement() {
|
||||
private void a(com.intellij.psi.PsiElement a1, String b1) {
|
||||
PsiElement notFix = new PsiElement() {
|
||||
private void a(PsiElement a1, String b1) {
|
||||
System.out.println(a);
|
||||
System.out.println(b);
|
||||
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) {
|
||||
class B extends com.intellij.codeInspection.LocalQuickFix {
|
||||
B(com.intellij.psi.PsiElement aa) {
|
||||
public void test(PsiElement a, String b) {
|
||||
class B implements LocalQuickFix {
|
||||
B(PsiElement aa) {
|
||||
}
|
||||
|
||||
private void a(com.intellij.psi.PsiElement a1, String b1) {
|
||||
System.out.println(<warning descr="Potential memory leak: don't hold PsiElement, use SmartPsiElementPointer instead See also LocalQuickFixOnPsiElement">a</warning>);
|
||||
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(b);
|
||||
System.out.println(a1);
|
||||
System.out.println(b1);
|
||||
|
||||
@@ -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,8 +1,12 @@
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.openapi.project.Project;
|
||||
|
||||
public class Ext {
|
||||
final com.intellij.psi.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>;
|
||||
com.intellij.openapi.project.Project <warning descr="Do not use Project as a field in extension">p</warning>;
|
||||
final com.intellij.openapi.project.Project pf;
|
||||
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 <warning descr="Do not use Project as a field in extension">p</warning>;
|
||||
final Project pf;
|
||||
public Ext() {
|
||||
super();
|
||||
pe = null;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
|
||||
public class FakeFile {
|
||||
final com.intellij.psi.PsiElement pe;
|
||||
final com.intellij.psi.PsiReference r;
|
||||
final PsiElement pe;
|
||||
final PsiReference r;
|
||||
Project p;
|
||||
final Project pf;
|
||||
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
public class Fix extends 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>;
|
||||
final com.intellij.psi.PsiReference <warning descr="Do not use PsiReference as a field in quick-fix">r</warning>;
|
||||
com.intellij.openapi.project.Project <warning descr="Do not use Project as a field in quick-fix">p</warning>;
|
||||
final com.intellij.openapi.project.Project pf;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.openapi.project.Project;
|
||||
|
||||
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() {
|
||||
super();
|
||||
pe = 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,8 +1,12 @@
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.openapi.project.Project;
|
||||
|
||||
public class NonFix {
|
||||
final com.intellij.psi.PsiElement pe;
|
||||
final com.intellij.psi.PsiReference r;
|
||||
com.intellij.openapi.project.Project p;
|
||||
final com.intellij.openapi.project.Project pf;
|
||||
final PsiElement pe;
|
||||
final PsiReference r;
|
||||
Project p;
|
||||
final Project pf;
|
||||
public NonFix() {
|
||||
super();
|
||||
pe = null;
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
public class ProjectComp implements com.intellij.openapi.components.ProjectComponent {
|
||||
final com.intellij.psi.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>;
|
||||
com.intellij.openapi.project.Project p;
|
||||
final com.intellij.openapi.project.Project pf;
|
||||
import com.intellij.openapi.components.ProjectComponent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
|
||||
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() {
|
||||
super();
|
||||
pe = null;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
|
||||
public class ProjectConfigurable {
|
||||
final com.intellij.psi.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 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 ProjectConfigurable(Project project) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
|
||||
public class ProjectService {
|
||||
final com.intellij.psi.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 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 ProjectService(Project 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;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.idea.devkit.DevkitJavaTestsUtil;
|
||||
|
||||
@TestDataPath("$CONTENT_ROOT/testData/inspections/statefulEp")
|
||||
public class StatefulEpInspectionTest extends PluginModuleTestCase {
|
||||
public class StatefulEpInspectionTest extends StatefulEpInspectionTestBase {
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return DevkitJavaTestsUtil.TESTDATA_PATH + "inspections/statefulEp";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
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());
|
||||
protected String getFileExtension() {
|
||||
return "java";
|
||||
}
|
||||
|
||||
public void testLocalQuickFix() {
|
||||
myFixture.testHighlighting("Fix.java");
|
||||
public void testFix() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNonFix() {
|
||||
setPluginXml("plugin.xml");
|
||||
myFixture.testHighlighting("NonFix.java");
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testExt() {
|
||||
setPluginXml("plugin.xml");
|
||||
myFixture.testHighlighting("Ext.java");
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testProjectComp() {
|
||||
setPluginXml("plugin.xml");
|
||||
myFixture.testHighlighting("ProjectComp.java");
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testProjectService() {
|
||||
setPluginXml("plugin.xml");
|
||||
myFixture.testHighlighting("ProjectService.java");
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testProjectConfigurable() {
|
||||
setPluginXml("plugin.xml");
|
||||
myFixture.testHighlighting("ProjectConfigurable.java");
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testFakeFile() {
|
||||
setPluginXml("plugin.xml");
|
||||
myFixture.testHighlighting("FakeFile.java");
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testCapturedFromOuterClass() {
|
||||
myFixture.testHighlighting("CapturedFromOuterClass.java");
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testCollection() {
|
||||
myFixture.testHighlighting("Collection.java");
|
||||
public void testCollectionTests() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testMap() {
|
||||
myFixture.testHighlighting("Map.java");
|
||||
public void testMapTests() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testRef() {
|
||||
myFixture.testHighlighting("Ref.java");
|
||||
public void testRefTests() {
|
||||
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