mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Don't crash when reporting some cases of missing standard APIs
This commit is contained in:
parent
9fd7b9c4e2
commit
b1ddf163d7
|
@ -316,8 +316,8 @@ public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeIncomingsFrom(BasicBlock predecessor) {
|
public void removeIncomingsFrom(BasicBlock predecessor) {
|
||||||
for (Phi phi : getPhis()) {
|
for (var phi : getPhis()) {
|
||||||
List<Incoming> incomings = phi.getIncomings();
|
var incomings = phi.getIncomings();
|
||||||
for (int i = 0; i < incomings.size(); ++i) {
|
for (int i = 0; i < incomings.size(); ++i) {
|
||||||
if (incomings.get(i).getSource() == predecessor) {
|
if (incomings.get(i).getSource() == predecessor) {
|
||||||
incomings.remove(i--);
|
incomings.remove(i--);
|
||||||
|
|
|
@ -15,158 +15,200 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.model.instructions;
|
package org.teavm.model.instructions;
|
||||||
|
|
||||||
|
import org.teavm.model.Instruction;
|
||||||
import org.teavm.model.InvokeDynamicInstruction;
|
import org.teavm.model.InvokeDynamicInstruction;
|
||||||
|
|
||||||
public abstract class AbstractInstructionVisitor implements InstructionVisitor {
|
public abstract class AbstractInstructionVisitor implements InstructionVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(EmptyInstruction insn) {
|
public void visit(EmptyInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ClassConstantInstruction insn) {
|
public void visit(ClassConstantInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(NullConstantInstruction insn) {
|
public void visit(NullConstantInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(IntegerConstantInstruction insn) {
|
public void visit(IntegerConstantInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(LongConstantInstruction insn) {
|
public void visit(LongConstantInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(FloatConstantInstruction insn) {
|
public void visit(FloatConstantInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(DoubleConstantInstruction insn) {
|
public void visit(DoubleConstantInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(StringConstantInstruction insn) {
|
public void visit(StringConstantInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BinaryInstruction insn) {
|
public void visit(BinaryInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(NegateInstruction insn) {
|
public void visit(NegateInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(AssignInstruction insn) {
|
public void visit(AssignInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(CastInstruction insn) {
|
public void visit(CastInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(CastNumberInstruction insn) {
|
public void visit(CastNumberInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(CastIntegerInstruction insn) {
|
public void visit(CastIntegerInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BranchingInstruction insn) {
|
public void visit(BranchingInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BinaryBranchingInstruction insn) {
|
public void visit(BinaryBranchingInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(JumpInstruction insn) {
|
public void visit(JumpInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(SwitchInstruction insn) {
|
public void visit(SwitchInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ExitInstruction insn) {
|
public void visit(ExitInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(RaiseInstruction insn) {
|
public void visit(RaiseInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ConstructArrayInstruction insn) {
|
public void visit(ConstructArrayInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ConstructInstruction insn) {
|
public void visit(ConstructInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ConstructMultiArrayInstruction insn) {
|
public void visit(ConstructMultiArrayInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(GetFieldInstruction insn) {
|
public void visit(GetFieldInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(PutFieldInstruction insn) {
|
public void visit(PutFieldInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ArrayLengthInstruction insn) {
|
public void visit(ArrayLengthInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(CloneArrayInstruction insn) {
|
public void visit(CloneArrayInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(UnwrapArrayInstruction insn) {
|
public void visit(UnwrapArrayInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(GetElementInstruction insn) {
|
public void visit(GetElementInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(PutElementInstruction insn) {
|
public void visit(PutElementInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(InvokeInstruction insn) {
|
public void visit(InvokeInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(InvokeDynamicInstruction insn) {
|
public void visit(InvokeDynamicInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(IsInstanceInstruction insn) {
|
public void visit(IsInstanceInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(InitClassInstruction insn) {
|
public void visit(InitClassInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(NullCheckInstruction insn) {
|
public void visit(NullCheckInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorEnterInstruction insn) {
|
public void visit(MonitorEnterInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorExitInstruction insn) {
|
public void visit(MonitorExitInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BoundCheckInstruction insn) {
|
public void visit(BoundCheckInstruction insn) {
|
||||||
|
visitDefault(insn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitDefault(Instruction insn) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
183
core/src/main/java/org/teavm/model/util/AssignmentExtractor.java
Normal file
183
core/src/main/java/org/teavm/model/util/AssignmentExtractor.java
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.model.util;
|
||||||
|
|
||||||
|
import org.teavm.model.Instruction;
|
||||||
|
import org.teavm.model.Variable;
|
||||||
|
import org.teavm.model.instructions.AbstractInstructionVisitor;
|
||||||
|
import org.teavm.model.instructions.ArrayLengthInstruction;
|
||||||
|
import org.teavm.model.instructions.AssignInstruction;
|
||||||
|
import org.teavm.model.instructions.BinaryInstruction;
|
||||||
|
import org.teavm.model.instructions.BoundCheckInstruction;
|
||||||
|
import org.teavm.model.instructions.CastInstruction;
|
||||||
|
import org.teavm.model.instructions.CastIntegerInstruction;
|
||||||
|
import org.teavm.model.instructions.CastNumberInstruction;
|
||||||
|
import org.teavm.model.instructions.ClassConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.CloneArrayInstruction;
|
||||||
|
import org.teavm.model.instructions.ConstructArrayInstruction;
|
||||||
|
import org.teavm.model.instructions.ConstructInstruction;
|
||||||
|
import org.teavm.model.instructions.ConstructMultiArrayInstruction;
|
||||||
|
import org.teavm.model.instructions.DoubleConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.FloatConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.GetElementInstruction;
|
||||||
|
import org.teavm.model.instructions.GetFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
|
import org.teavm.model.instructions.IsInstanceInstruction;
|
||||||
|
import org.teavm.model.instructions.LongConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.NegateInstruction;
|
||||||
|
import org.teavm.model.instructions.NullCheckInstruction;
|
||||||
|
import org.teavm.model.instructions.NullConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.StringConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.UnwrapArrayInstruction;
|
||||||
|
|
||||||
|
public class AssignmentExtractor extends AbstractInstructionVisitor {
|
||||||
|
private Variable result;
|
||||||
|
|
||||||
|
public Variable getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(IntegerConstantInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(LongConstantInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(FloatConstantInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(DoubleConstantInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(StringConstantInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ClassConstantInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(NullConstantInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(CastInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(CastIntegerInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(IsInstanceInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(AssignInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(BinaryInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(InvokeInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(NegateInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(CastNumberInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(NullCheckInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(BoundCheckInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(GetFieldInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(GetElementInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(UnwrapArrayInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ArrayLengthInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(CloneArrayInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ConstructInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ConstructArrayInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ConstructMultiArrayInstruction insn) {
|
||||||
|
result = insn.getReceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitDefault(Instruction insn) {
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.teavm.dependency.DependencyInfo;
|
import org.teavm.dependency.DependencyInfo;
|
||||||
|
@ -54,9 +55,9 @@ public class MissingItemsProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processClass(ClassHolder cls) {
|
public void processClass(ClassHolder cls) {
|
||||||
for (MethodHolder method : cls.getMethods()) {
|
for (var method : cls.getMethods()) {
|
||||||
if (reachableMethods.contains(method.getReference()) && method.getProgram() != null) {
|
if (reachableMethods.contains(method.getReference()) && method.getProgram() != null) {
|
||||||
MethodDependencyInfo methodDep = dependencyInfo.getMethod(method.getReference());
|
var methodDep = dependencyInfo.getMethod(method.getReference());
|
||||||
if (methodDep != null && methodDep.isUsed()) {
|
if (methodDep != null && methodDep.isUsed()) {
|
||||||
processMethod(method);
|
processMethod(method);
|
||||||
}
|
}
|
||||||
|
@ -76,7 +77,7 @@ public class MissingItemsProcessor {
|
||||||
BasicBlock block = program.basicBlockAt(i);
|
BasicBlock block = program.basicBlockAt(i);
|
||||||
instructionsToAdd.clear();
|
instructionsToAdd.clear();
|
||||||
boolean missing = false;
|
boolean missing = false;
|
||||||
for (Instruction insn : block) {
|
for (var insn : block) {
|
||||||
insn.acceptVisitor(instructionProcessor);
|
insn.acceptVisitor(instructionProcessor);
|
||||||
if (!instructionsToAdd.isEmpty()) {
|
if (!instructionsToAdd.isEmpty()) {
|
||||||
wasModified = true;
|
wasModified = true;
|
||||||
|
@ -86,7 +87,7 @@ public class MissingItemsProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!missing) {
|
if (!missing) {
|
||||||
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
|
for (var tryCatch : block.getTryCatchBlocks()) {
|
||||||
checkClass(null, tryCatch.getExceptionType());
|
checkClass(null, tryCatch.getExceptionType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,14 +98,42 @@ public class MissingItemsProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void truncateBlock(Instruction instruction) {
|
private void truncateBlock(Instruction instruction) {
|
||||||
TransitionExtractor transitionExtractor = new TransitionExtractor();
|
var transitionExtractor = new TransitionExtractor();
|
||||||
BasicBlock block = instruction.getBasicBlock();
|
var block = instruction.getBasicBlock();
|
||||||
if (block.getLastInstruction() != null) {
|
if (block.getLastInstruction() != null) {
|
||||||
block.getLastInstruction().acceptVisitor(transitionExtractor);
|
block.getLastInstruction().acceptVisitor(transitionExtractor);
|
||||||
}
|
}
|
||||||
for (BasicBlock successor : transitionExtractor.getTargets()) {
|
for (var successor : transitionExtractor.getTargets()) {
|
||||||
successor.removeIncomingsFrom(block);
|
successor.removeIncomingsFrom(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!block.getTryCatchBlocks().isEmpty()) {
|
||||||
|
var handlers = new LinkedHashSet<BasicBlock>();
|
||||||
|
for (var tryCatch : block.getTryCatchBlocks()) {
|
||||||
|
handlers.add(tryCatch.getHandler());
|
||||||
|
}
|
||||||
|
|
||||||
|
var next = instruction;
|
||||||
|
var assignExtractor = new AssignmentExtractor();
|
||||||
|
while (next != null) {
|
||||||
|
next.acceptVisitor(assignExtractor);
|
||||||
|
var definition = assignExtractor.getResult();
|
||||||
|
if (definition != null) {
|
||||||
|
for (var handler : handlers) {
|
||||||
|
for (var phi : handler.getPhis()) {
|
||||||
|
for (var iter = phi.getIncomings().iterator(); iter.hasNext();) {
|
||||||
|
var incoming = iter.next();
|
||||||
|
if (incoming.getSource() == block && incoming.getValue() == definition) {
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next = next.getNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (instruction.getNext() != null) {
|
while (instruction.getNext() != null) {
|
||||||
instruction.getNext().delete();
|
instruction.getNext().delete();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user