From a4544a8550d00dad8801233a28da10aa31fcce45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Mon, 5 Oct 2020 16:17:18 +0200 Subject: [PATCH] :sparkles: Prevent command arguments from being used in multiple commands Also get rid of some random annoying warnings. --- .../java/cloud/commandframework/Command.java | 5 +++++ .../arguments/CommandArgument.java | 20 +++++++++++++++++++ .../commandframework/CommandTreeTest.java | 10 ++++++++++ .../brigadier/CloudBrigadierManager.java | 10 ++++++++-- .../paper/PaperBrigadierListener.java | 1 + 5 files changed, 44 insertions(+), 2 deletions(-) diff --git a/cloud-core/src/main/java/cloud/commandframework/Command.java b/cloud-core/src/main/java/cloud/commandframework/Command.java index 16bfb173..a552c19c 100644 --- a/cloud-core/src/main/java/cloud/commandframework/Command.java +++ b/cloud-core/src/main/java/cloud/commandframework/Command.java @@ -384,6 +384,11 @@ public class Command { */ public @NonNull Builder argument(final @NonNull CommandArgument argument, final @NonNull Description description) { + if (argument.isArgumentRegistered()) { + throw new IllegalArgumentException("The provided argument has already been associated with a command." + + " Use CommandArgument#copy to create a copy of the argument."); + } + argument.setArgumentRegistered(); final Map, Description> commandArgumentMap = new LinkedHashMap<>(this.commandArguments); commandArgumentMap.put(argument, description); return new Builder<>(this.commandManager, diff --git a/cloud-core/src/main/java/cloud/commandframework/arguments/CommandArgument.java b/cloud-core/src/main/java/cloud/commandframework/arguments/CommandArgument.java index e04787d2..edebb486 100644 --- a/cloud-core/src/main/java/cloud/commandframework/arguments/CommandArgument.java +++ b/cloud-core/src/main/java/cloud/commandframework/arguments/CommandArgument.java @@ -82,6 +82,10 @@ public class CommandArgument implements Comparable> * Suggestion provider */ private final BiFunction, String, List> suggestionsProvider; + /** + * Whether or not the argument has been used before + */ + private boolean argumentRegistered = false; private Command owningCommand; @@ -328,6 +332,22 @@ public class CommandArgument implements Comparable> return builder.build(); } + /** + * Check whether or not the argument has been used in a command + * + * @return {@code true} if the argument has been used in a command, else {@code false} + */ + public boolean isArgumentRegistered() { + return this.argumentRegistered; + } + + /** + * Indicate that the argument has been associated with a command + */ + public void setArgumentRegistered() { + this.argumentRegistered = true; + } + /** * Mutable builder for {@link CommandArgument} instances diff --git a/cloud-core/src/test/java/cloud/commandframework/CommandTreeTest.java b/cloud-core/src/test/java/cloud/commandframework/CommandTreeTest.java index 9b21e7eb..77ae4d1e 100644 --- a/cloud-core/src/test/java/cloud/commandframework/CommandTreeTest.java +++ b/cloud-core/src/test/java/cloud/commandframework/CommandTreeTest.java @@ -23,6 +23,7 @@ // package cloud.commandframework; +import cloud.commandframework.arguments.CommandArgument; import cloud.commandframework.arguments.compound.ArgumentPair; import cloud.commandframework.arguments.standard.IntegerArgument; import cloud.commandframework.arguments.standard.StringArgument; @@ -213,6 +214,15 @@ class CommandTreeTest { manager.executeCommand(new TestCommandSender(), "flags --num 500"); } + @Test + void testDuplicateArgument() { + final CommandArgument argument = StringArgument.of("test"); + manager.command(manager.commandBuilder("one").argument(argument)); + Assertions.assertThrows(IllegalArgumentException.class, () -> + manager.command(manager.commandBuilder("two").argument(argument))); + } + + public static final class SpecificCommandSender extends TestCommandSender { } diff --git a/cloud-minecraft/cloud-brigadier/src/main/java/cloud/commandframework/brigadier/CloudBrigadierManager.java b/cloud-minecraft/cloud-brigadier/src/main/java/cloud/commandframework/brigadier/CloudBrigadierManager.java index fc3f76ad..05a8746b 100644 --- a/cloud-minecraft/cloud-brigadier/src/main/java/cloud/commandframework/brigadier/CloudBrigadierManager.java +++ b/cloud-minecraft/cloud-brigadier/src/main/java/cloud/commandframework/brigadier/CloudBrigadierManager.java @@ -85,7 +85,7 @@ public final class CloudBrigadierManager { private final Map, cloud.commandframework.types.tuples.Pair, ? extends ArgumentType>, Boolean>> mappers; - private final Map, Supplier>> defaultArgumentTypeSuppliers; + private final Map<@NonNull Class, @NonNull Supplier<@Nullable ArgumentType>> defaultArgumentTypeSuppliers; private final Supplier> dummyContextProvider; private final CommandManager commandManager; @@ -214,7 +214,7 @@ public final class CloudBrigadierManager { * @param supplier Supplier that supplies the argument type */ public void registerDefaultArgumentTypeSupplier(final @NonNull Class clazz, - final @NonNull Supplier<@NonNull ArgumentType> supplier) { + final @NonNull Supplier<@Nullable ArgumentType> supplier) { this.defaultArgumentTypeSuppliers.put(clazz, supplier); } @@ -238,7 +238,13 @@ public final class CloudBrigadierManager { final @NonNull ArgumentParser argument) { final Supplier> argumentTypeSupplier = this.defaultArgumentTypeSuppliers .get(GenericTypeReflector.erase(clazz.getType())); + @Nullable final ArgumentType defaultType; if (argumentTypeSupplier != null) { + defaultType = argumentTypeSupplier.get(); + } else { + defaultType = null; + } + if (defaultType != null) { return new Pair<>(argumentTypeSupplier.get(), true); } return new Pair<>(StringArgumentType.string(), false); diff --git a/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperBrigadierListener.java b/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperBrigadierListener.java index 43912ecf..8f9c79a0 100644 --- a/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperBrigadierListener.java +++ b/cloud-minecraft/cloud-paper/src/main/java/cloud/commandframework/paper/PaperBrigadierListener.java @@ -169,6 +169,7 @@ class PaperBrigadierListener implements Listener { } @EventHandler + @SuppressWarnings("deprecation") public void onCommandRegister(@Nonnull final CommandRegisteredEvent event) { if (!(event.getCommand() instanceof PluginIdentifiableCommand)) { return;