Adapted keyword completion to changed parser + more precise completion for modifier keywords
This commit is contained in:
@@ -19,15 +19,20 @@ package org.jetbrains.kotlin.resolve
|
||||
import com.intellij.lang.ASTNode
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken
|
||||
import java.util.*
|
||||
import org.jetbrains.kotlin.lexer.JetTokens.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.*
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.lexer.JetTokens.*
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||
import org.jetbrains.kotlin.psi.JetDeclarationWithBody
|
||||
import org.jetbrains.kotlin.psi.JetModifierList
|
||||
import org.jetbrains.kotlin.psi.JetModifierListOwner
|
||||
import java.util.*
|
||||
|
||||
public object ModifierCheckerCore {
|
||||
private enum class Compatibility {
|
||||
@@ -51,7 +56,7 @@ public object ModifierCheckerCore {
|
||||
MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER,
|
||||
MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, CONSTRUCTOR)
|
||||
|
||||
private val possibleTargetMap = mapOf<JetModifierKeywordToken, Set<KotlinTarget>>(
|
||||
val possibleTargetMap = mapOf<JetModifierKeywordToken, Set<KotlinTarget>>(
|
||||
ENUM_KEYWORD to EnumSet.of(ENUM_CLASS),
|
||||
ABSTRACT_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INNER_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
OPEN_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INNER_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
|
||||
+24
-10
@@ -28,15 +28,18 @@ import com.intellij.psi.filters.position.LeftNeighbour
|
||||
import com.intellij.psi.filters.position.PositionElementFilter
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.*
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.KotlinKeywordInsertHandler
|
||||
import org.jetbrains.kotlin.lexer.JetKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.JetTokens.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.nextLeaf
|
||||
import org.jetbrains.kotlin.psi.psiUtil.prevLeaf
|
||||
import org.jetbrains.kotlin.psi.psiUtil.siblings
|
||||
import org.jetbrains.kotlin.resolve.ModifierCheckerCore
|
||||
|
||||
open class KeywordLookupObject
|
||||
|
||||
@@ -47,10 +50,8 @@ object KeywordCompletion {
|
||||
.filter { it !in NON_ACTUAL_KEYWORDS }
|
||||
.map { it as JetKeywordToken }
|
||||
|
||||
private val KEYWORD_TO_DUMMY_POSTFIX = mapOf(
|
||||
OUT_KEYWORD to " X",
|
||||
FILE_KEYWORD to ":"
|
||||
)
|
||||
private val DEFAULT_DUMMY_POSTFIX = " X"
|
||||
private val KEYWORD_TO_DUMMY_POSTFIX = mapOf(FILE_KEYWORD to ":")
|
||||
|
||||
private val KEYWORDS_TO_IGNORE_PREFIX = TokenSet.create(OVERRIDE_KEYWORD /* it's needed to complete overrides that should be work by member name too */)
|
||||
|
||||
@@ -176,19 +177,32 @@ object KeywordCompletion {
|
||||
|
||||
private fun buildFilterByText(prefixText: String, project: Project): (JetKeywordToken) -> Boolean {
|
||||
val psiFactory = JetPsiFactory(project)
|
||||
return { keywordTokenType ->
|
||||
val postfix = KEYWORD_TO_DUMMY_POSTFIX[keywordTokenType] ?: ""
|
||||
return fun (keywordTokenType): Boolean {
|
||||
val postfix = KEYWORD_TO_DUMMY_POSTFIX[keywordTokenType] ?: DEFAULT_DUMMY_POSTFIX
|
||||
val file = psiFactory.createFile(prefixText + keywordTokenType.getValue() + postfix)
|
||||
val elementAt = file.findElementAt(prefixText.length())!!
|
||||
|
||||
when {
|
||||
!elementAt.getNode()!!.getElementType().matchesKeyword(keywordTokenType) -> false
|
||||
!elementAt.getNode()!!.getElementType().matchesKeyword(keywordTokenType) -> return false
|
||||
|
||||
elementAt.getNonStrictParentOfType<PsiErrorElement>() != null -> false
|
||||
elementAt.getNonStrictParentOfType<PsiErrorElement>() != null -> return false
|
||||
|
||||
elementAt.prevLeaf { it !is PsiWhiteSpace && it !is PsiComment } is PsiErrorElement -> false
|
||||
elementAt.prevLeaf { it !is PsiWhiteSpace && it !is PsiComment } is PsiErrorElement -> return false
|
||||
|
||||
else -> true
|
||||
keywordTokenType !is JetModifierKeywordToken -> return true
|
||||
|
||||
else -> {
|
||||
if (elementAt.parent !is JetModifierList) return true
|
||||
val possibleTargets = when (elementAt.parent.parent) {
|
||||
is JetParameter -> listOf(VALUE_PARAMETER)
|
||||
is JetTypeParameter -> listOf(TYPE_PARAMETER)
|
||||
is JetClassBody -> listOf(CLASS_ONLY, INTERFACE, OBJECT, ENUM_CLASS, ANNOTATION_CLASS, INNER_CLASS, MEMBER_FUNCTION, MEMBER_PROPERTY, FUNCTION, PROPERTY)
|
||||
is JetFile -> listOf(CLASS_ONLY, INTERFACE, OBJECT, ENUM_CLASS, ANNOTATION_CLASS, TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, FUNCTION, PROPERTY)
|
||||
else -> return true
|
||||
}
|
||||
val modifierTargets = ModifierCheckerCore.possibleTargetMap[keywordTokenType] ?: return true
|
||||
return possibleTargets.any { it in modifierTargets }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,16 +11,10 @@ class MouseMovedEventArgs
|
||||
// EXIST: final
|
||||
// EXIST: fun
|
||||
// EXIST: get
|
||||
// EXIST: in
|
||||
/*why?*/
|
||||
// EXIST: inner
|
||||
// EXIST: internal
|
||||
// EXIST: object
|
||||
// EXIST: open
|
||||
// EXIST: out
|
||||
/*why?*/
|
||||
// EXIST: reified
|
||||
/*why?*/
|
||||
// EXIST: override
|
||||
// EXIST: private
|
||||
// EXIST: protected
|
||||
@@ -29,7 +23,6 @@ class MouseMovedEventArgs
|
||||
// EXIST: interface
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: vararg
|
||||
// EXIST: constructor
|
||||
// EXIST: init
|
||||
/*why?*/
|
||||
@@ -40,10 +33,8 @@ class MouseMovedEventArgs
|
||||
// EXIST: lateinit
|
||||
// EXIST: data
|
||||
// EXIST: inline
|
||||
// EXIST: noinline
|
||||
// EXIST: tailrec
|
||||
// EXIST: external
|
||||
// EXIST: annotation
|
||||
// EXIST: crossinline
|
||||
// EXIST: const
|
||||
// NOTHING_ELSE
|
||||
|
||||
+4
-15
@@ -17,37 +17,26 @@ class B {
|
||||
// EXIST: enum
|
||||
// EXIST: final
|
||||
// EXIST: fun
|
||||
// EXIST: in
|
||||
/*why?*/
|
||||
// EXIST: inner
|
||||
// EXIST: internal
|
||||
// EXIST: object
|
||||
// EXIST: open
|
||||
// EXIST: out
|
||||
/*why?*/
|
||||
// EXIST: reified
|
||||
/*why?*/
|
||||
// EXIST: override
|
||||
// EXIST: private
|
||||
// EXIST: protected
|
||||
// EXIST: public
|
||||
// EXIST: interface
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: vararg
|
||||
/*why?*/
|
||||
// EXIST: companion object
|
||||
// EXIST: operator
|
||||
// EXIST: infix
|
||||
// EXIST: sealed
|
||||
// EXIST: lateinit
|
||||
// EXIST: data
|
||||
// EXIST: inline
|
||||
// EXIST: noinline
|
||||
// EXIST: tailrec
|
||||
// EXIST: external
|
||||
// EXIST: annotation
|
||||
// EXIST: crossinline
|
||||
// EXIST: const
|
||||
/*TODO*/
|
||||
/*TODO:*/
|
||||
// EXIST: inner
|
||||
/*TODO:*/
|
||||
// EXIST: companion object
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -15,16 +15,10 @@ class A {
|
||||
// EXIST: enum
|
||||
// EXIST: final
|
||||
// EXIST: fun
|
||||
// EXIST: in
|
||||
/*why?*/
|
||||
// EXIST: inner
|
||||
// EXIST: internal
|
||||
// EXIST: object
|
||||
// EXIST: open
|
||||
// EXIST: out
|
||||
/*why?*/
|
||||
// EXIST: reified
|
||||
/*why?*/
|
||||
// EXIST: override
|
||||
// EXIST: private
|
||||
// EXIST: protected
|
||||
@@ -32,7 +26,6 @@ class A {
|
||||
// EXIST: interface
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: vararg
|
||||
// EXIST: constructor
|
||||
// EXIST: init
|
||||
/*why?*/
|
||||
@@ -43,10 +36,8 @@ class A {
|
||||
// EXIST: lateinit
|
||||
// EXIST: data
|
||||
// EXIST: inline
|
||||
// EXIST: noinline
|
||||
// EXIST: tailrec
|
||||
// EXIST: external
|
||||
// EXIST: annotation
|
||||
// EXIST: crossinline
|
||||
// EXIST: const
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
// EXIST: {"lookupString":"class","itemText":"class","attributes":"bold"}
|
||||
// EXIST: {"lookupString":"fun","itemText":"fun","attributes":"bold"}
|
||||
// EXIST: {"lookupString":"in","itemText":"in","attributes":"bold"}
|
||||
// EXIST: {"lookupString":"interface","itemText":"interface","attributes":"bold"}
|
||||
// EXIST: {"lookupString":"object","itemText":"object","attributes":"bold"}
|
||||
// EXIST: {"lookupString":"package","itemText":"package","attributes":"bold"}
|
||||
|
||||
@@ -16,17 +16,10 @@ var a : Int
|
||||
// EXIST: final
|
||||
// EXIST: fun
|
||||
// EXIST: get
|
||||
// EXIST: in
|
||||
/*why?*/
|
||||
// EXIST: inner
|
||||
// EXIST: internal
|
||||
// EXIST: object
|
||||
// EXIST: open
|
||||
// EXIST: out
|
||||
/*why?*/
|
||||
// EXIST: reified
|
||||
/*why?*/
|
||||
// EXIST: override
|
||||
// EXIST: private
|
||||
// EXIST: protected
|
||||
// EXIST: public
|
||||
@@ -34,20 +27,14 @@ var a : Int
|
||||
// EXIST: interface
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: vararg
|
||||
/*why?*/
|
||||
// EXIST: companion object
|
||||
// EXIST: operator
|
||||
// EXIST: infix
|
||||
// EXIST: sealed
|
||||
// EXIST: lateinit
|
||||
// EXIST: data
|
||||
// EXIST: inline
|
||||
// EXIST: noinline
|
||||
// EXIST: tailrec
|
||||
// EXIST: external
|
||||
// EXIST: annotation
|
||||
// EXIST: crossinline
|
||||
// EXIST: const
|
||||
/*TODO*/
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -13,16 +13,10 @@ public class Test {
|
||||
// EXIST: enum
|
||||
// EXIST: final
|
||||
// EXIST: fun
|
||||
// EXIST: in
|
||||
/*why?*/
|
||||
// EXIST: inner
|
||||
// EXIST: internal
|
||||
// EXIST: object
|
||||
// EXIST: open
|
||||
// EXIST: out
|
||||
/*why?*/
|
||||
// EXIST: reified
|
||||
/*why?*/
|
||||
// EXIST: override
|
||||
// EXIST: private
|
||||
// EXIST: protected
|
||||
@@ -30,7 +24,6 @@ public class Test {
|
||||
// EXIST: interface
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: vararg
|
||||
// EXIST: constructor
|
||||
// EXIST: init
|
||||
/*why?*/
|
||||
@@ -41,10 +34,8 @@ public class Test {
|
||||
// EXIST: lateinit
|
||||
// EXIST: data
|
||||
// EXIST: inline
|
||||
// EXIST: noinline
|
||||
// EXIST: tailrec
|
||||
// EXIST: external
|
||||
// EXIST: annotation
|
||||
// EXIST: crossinline
|
||||
// EXIST: const
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -7,16 +7,10 @@ class TestClass {
|
||||
// EXIST: enum
|
||||
// EXIST: final
|
||||
// EXIST: fun
|
||||
// EXIST: in
|
||||
/*why?*/
|
||||
// EXIST: inner
|
||||
// EXIST: internal
|
||||
// EXIST: object
|
||||
// EXIST: open
|
||||
// EXIST: out
|
||||
/*why?*/
|
||||
// EXIST: reified
|
||||
/*why?*/
|
||||
// EXIST: override
|
||||
// EXIST: private
|
||||
// EXIST: protected
|
||||
@@ -24,8 +18,6 @@ class TestClass {
|
||||
// EXIST: interface
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: vararg
|
||||
/*why?*/
|
||||
// EXIST: constructor
|
||||
// EXIST: init
|
||||
// EXIST: companion object
|
||||
@@ -35,10 +27,8 @@ class TestClass {
|
||||
// EXIST: lateinit
|
||||
// EXIST: data
|
||||
// EXIST: inline
|
||||
// EXIST: noinline
|
||||
// EXIST: tailrec
|
||||
// EXIST: external
|
||||
// EXIST: annotation
|
||||
// EXIST: crossinline
|
||||
// EXIST: const
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -2,4 +2,5 @@ class T<<caret>>
|
||||
|
||||
// EXIST: in
|
||||
// EXIST: out
|
||||
// EXIST: reified
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -5,9 +5,10 @@ class TestSample() {
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: they all are not correct */
|
||||
// EXIST: vararg
|
||||
// EXIST: noinline
|
||||
// EXIST: crossinline
|
||||
/* TODO: val&var are not correct */
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: in
|
||||
// EXIST: out
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -4,4 +4,5 @@ fun testing() {}
|
||||
|
||||
// EXIST: in
|
||||
// EXIST: out
|
||||
// EXIST: reified
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -2,9 +2,10 @@ fun test(<caret>) {
|
||||
|
||||
}
|
||||
|
||||
// EXIST: vararg
|
||||
// EXIST: noinline
|
||||
// EXIST: crossinline
|
||||
/* TODO: they all are not correct */
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: in
|
||||
// EXIST: out
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -8,37 +8,24 @@ package Test
|
||||
// EXIST: final
|
||||
// EXIST: fun
|
||||
// EXIST: import
|
||||
// EXIST: in
|
||||
/*why?*/
|
||||
// EXIST: inner
|
||||
// EXIST: internal
|
||||
// EXIST: object
|
||||
// EXIST: open
|
||||
// EXIST: out
|
||||
/*why?*/
|
||||
// EXIST: reified
|
||||
/*why?*/
|
||||
// EXIST: override
|
||||
// EXIST: private
|
||||
// EXIST: protected
|
||||
// EXIST: public
|
||||
// EXIST: interface
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: vararg
|
||||
/*why?*/
|
||||
// EXIST: companion object
|
||||
// EXIST: operator
|
||||
// EXIST: infix
|
||||
// EXIST: sealed
|
||||
// EXIST: lateinit
|
||||
// EXIST: data
|
||||
// EXIST: inline
|
||||
// EXIST: noinline
|
||||
// EXIST: tailrec
|
||||
// EXIST: external
|
||||
// EXIST: annotation
|
||||
// EXIST: crossinline
|
||||
// EXIST: const
|
||||
/*TODO*/
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -10,16 +10,10 @@ class Some {
|
||||
// EXIST: final
|
||||
// EXIST: fun
|
||||
// EXIST: get
|
||||
// EXIST: in
|
||||
/*why?*/
|
||||
// EXIST: inner
|
||||
// EXIST: internal
|
||||
// EXIST: object
|
||||
// EXIST: open
|
||||
// EXIST: out
|
||||
/*why?*/
|
||||
// EXIST: reified
|
||||
/*why?*/
|
||||
// EXIST: override
|
||||
// EXIST: private
|
||||
// EXIST: protected
|
||||
@@ -28,8 +22,6 @@ class Some {
|
||||
// EXIST: interface
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: vararg
|
||||
/*why?*/
|
||||
// EXIST: constructor
|
||||
// EXIST: init
|
||||
// EXIST: companion object
|
||||
@@ -39,10 +31,8 @@ class Some {
|
||||
// EXIST: lateinit
|
||||
// EXIST: data
|
||||
// EXIST: inline
|
||||
// EXIST: noinline
|
||||
// EXIST: tailrec
|
||||
// EXIST: external
|
||||
// EXIST: annotation
|
||||
// EXIST: crossinline
|
||||
// EXIST: const
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -10,16 +10,10 @@ class Some {
|
||||
// EXIST: final
|
||||
// EXIST: fun
|
||||
// EXIST: get
|
||||
// EXIST: in
|
||||
/*why?*/
|
||||
// EXIST: inner
|
||||
// EXIST: internal
|
||||
// EXIST: object
|
||||
// EXIST: open
|
||||
// EXIST: out
|
||||
/*why?*/
|
||||
// EXIST: reified
|
||||
/*why?*/
|
||||
// EXIST: override
|
||||
// EXIST: private
|
||||
// EXIST: protected
|
||||
@@ -28,8 +22,6 @@ class Some {
|
||||
// EXIST: interface
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: vararg
|
||||
/*why?*/
|
||||
// EXIST: constructor
|
||||
// EXIST: init
|
||||
// EXIST: companion object
|
||||
@@ -39,10 +31,8 @@ class Some {
|
||||
// EXIST: lateinit
|
||||
// EXIST: data
|
||||
// EXIST: inline
|
||||
// EXIST: noinline
|
||||
// EXIST: tailrec
|
||||
// EXIST: external
|
||||
// EXIST: annotation
|
||||
// EXIST: crossinline
|
||||
// EXIST: const
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -12,16 +12,10 @@ class Some {
|
||||
// EXIST: fun
|
||||
// EXIST: get
|
||||
/*TODO*/
|
||||
// EXIST: in
|
||||
/*why?*/
|
||||
// EXIST: inner
|
||||
// EXIST: internal
|
||||
// EXIST: object
|
||||
// EXIST: open
|
||||
// EXIST: out
|
||||
/*why?*/
|
||||
// EXIST: reified
|
||||
/*why?*/
|
||||
// EXIST: override
|
||||
// EXIST: private
|
||||
// EXIST: protected
|
||||
@@ -30,8 +24,6 @@ class Some {
|
||||
// EXIST: interface
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: vararg
|
||||
/*why?*/
|
||||
// EXIST: constructor
|
||||
// EXIST: init
|
||||
// EXIST: companion object
|
||||
@@ -41,10 +33,8 @@ class Some {
|
||||
// EXIST: lateinit
|
||||
// EXIST: data
|
||||
// EXIST: inline
|
||||
// EXIST: noinline
|
||||
// EXIST: tailrec
|
||||
// EXIST: external
|
||||
// EXIST: annotation
|
||||
// EXIST: crossinline
|
||||
// EXIST: const
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -6,17 +6,10 @@
|
||||
// EXIST: final
|
||||
// EXIST: fun
|
||||
// EXIST: import
|
||||
// EXIST: in
|
||||
/*why?*/
|
||||
// EXIST: inner
|
||||
// EXIST: internal
|
||||
// EXIST: object
|
||||
// EXIST: open
|
||||
// EXIST: out
|
||||
/*why?*/
|
||||
// EXIST: reified
|
||||
/*why?*/
|
||||
// EXIST: override
|
||||
// EXIST: package
|
||||
// EXIST: private
|
||||
// EXIST: protected
|
||||
@@ -24,20 +17,14 @@
|
||||
// EXIST: interface
|
||||
// EXIST: val
|
||||
// EXIST: var
|
||||
// EXIST: vararg
|
||||
/*why?*/
|
||||
// EXIST: companion object
|
||||
// EXIST: operator
|
||||
// EXIST: infix
|
||||
// EXIST: sealed
|
||||
// EXIST: lateinit
|
||||
// EXIST: data
|
||||
// EXIST: inline
|
||||
// EXIST: noinline
|
||||
// EXIST: tailrec
|
||||
// EXIST: external
|
||||
// EXIST: annotation
|
||||
// EXIST: crossinline
|
||||
// EXIST: const
|
||||
/*TODO*/
|
||||
// NOTHING_ELSE
|
||||
|
||||
Reference in New Issue
Block a user