From 2d5c0fda4a0c5d16207a5f48edb72e6efa7d5bbd Mon Sep 17 00:00:00 2001 From: Skylot Date: Tue, 5 Dec 2023 20:33:05 +0000 Subject: [PATCH] fix: prefer early return for 'if-else-if' block (#2052) --- .../java/jadx/core/codegen/RegionGen.java | 16 +- .../dex/visitors/regions/IfRegionVisitor.java | 57 +- .../java/jadx/core/utils/RegionUtils.java | 24 + .../conditions/TestIfCodeStyle.java | 10 +- .../conditions/TestIfCodeStyle2.java | 23 + .../smali/conditions/TestIfCodeStyle2.smali | 578 ++++++++++++++++++ 6 files changed, 672 insertions(+), 36 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/conditions/TestIfCodeStyle2.java create mode 100644 jadx-core/src/test/smali/conditions/TestIfCodeStyle2.smali diff --git a/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java b/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java index 6cb28eaa31d..01a9658a3f5 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java @@ -32,7 +32,6 @@ import jadx.core.dex.nodes.IBlock; import jadx.core.dex.nodes.IContainer; import jadx.core.dex.nodes.InsnNode; -import jadx.core.dex.regions.Region; import jadx.core.dex.regions.SwitchRegion; import jadx.core.dex.regions.SwitchRegion.CaseInfo; import jadx.core.dex.regions.SynchronizedRegion; @@ -147,15 +146,12 @@ public void makeIf(IfRegion region, ICodeWriter code, boolean newLine) throws Co * Connect if-else-if block */ private boolean connectElseIf(ICodeWriter code, IContainer els) throws CodegenException { - if (els.contains(AFlag.ELSE_IF_CHAIN) && els instanceof Region) { - List subBlocks = ((Region) els).getSubBlocks(); - if (subBlocks.size() == 1) { - IContainer elseBlock = subBlocks.get(0); - if (elseBlock instanceof IfRegion) { - declareVars(code, elseBlock); - makeIf((IfRegion) elseBlock, code, false); - return true; - } + if (els.contains(AFlag.ELSE_IF_CHAIN)) { + IContainer elseBlock = RegionUtils.getSingleSubBlock(els); + if (elseBlock instanceof IfRegion) { + declareVars(code, elseBlock); + makeIf((IfRegion) elseBlock, code, false); + return true; } } return false; diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfRegionVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfRegionVisitor.java index 757285023ec..711cad11a79 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfRegionVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/IfRegionVisitor.java @@ -13,6 +13,7 @@ import jadx.core.dex.regions.conditions.IfCondition.Mode; import jadx.core.dex.regions.conditions.IfRegion; import jadx.core.dex.visitors.AbstractVisitor; +import jadx.core.utils.InsnUtils; import jadx.core.utils.RegionUtils; import static jadx.core.utils.RegionUtils.insnsCount; @@ -81,21 +82,23 @@ private static void orderBranches(MethodNode mth, IfRegion ifRegion) { return; } } - boolean lastRegion = RegionUtils.hasExitEdge(ifRegion); - if (elseSize == 1 && lastRegion && mth.isVoidReturn()) { - InsnNode lastElseInsn = RegionUtils.getLastInsn(ifRegion.getElseRegion()); - if (lastElseInsn != null && lastElseInsn.getType() == InsnType.THROW) { - // move `throw` into `then` block + if (elseSize == 1) { + boolean lastRegion = RegionUtils.hasExitEdge(ifRegion); + if (lastRegion && mth.isVoidReturn()) { + InsnNode lastElseInsn = RegionUtils.getLastInsn(ifRegion.getElseRegion()); + if (InsnUtils.isInsnType(lastElseInsn, InsnType.THROW)) { + // move `throw` into `then` block + invertIfRegion(ifRegion); + } else { + // single return at method end will be removed later + } + return; + } + if (thenSize > 2 && !(lastRegion && thenSize < 4 /* keep small code block inside else */)) { invertIfRegion(ifRegion); - } else { - // single return at method end will be removed later + return; } - return; - } - if (!lastRegion) { - invertIfRegion(ifRegion); } - return; } boolean thenExit = RegionUtils.hasExitBlock(ifRegion.getThenRegion()); boolean elseExit = RegionUtils.hasExitBlock(ifRegion.getElseRegion()); @@ -155,22 +158,32 @@ public boolean visitRegion(MethodNode mth, IRegion region) { } } + @SuppressWarnings("StatementWithEmptyBody") private static boolean removeRedundantElseBlock(MethodNode mth, IfRegion ifRegion) { - if (ifRegion.getElseRegion() == null - || ifRegion.contains(AFlag.ELSE_IF_CHAIN) - || ifRegion.getElseRegion().contains(AFlag.ELSE_IF_CHAIN)) { + if (ifRegion.getElseRegion() == null) { return false; } if (!RegionUtils.hasExitBlock(ifRegion.getThenRegion())) { return false; } - // code style check: - // will remove 'return;' from 'then' and 'else' with one instruction - // see #jadx.tests.integration.conditions.TestConditions9 - if (mth.isVoidReturn() - && insnsCount(ifRegion.getThenRegion()) == 2 - && insnsCount(ifRegion.getElseRegion()) == 2) { - return false; + InsnNode lastThanInsn = RegionUtils.getLastInsn(ifRegion.getThenRegion()); + if (InsnUtils.isInsnType(lastThanInsn, InsnType.THROW)) { + // always omit else after 'throw' + } else { + // code style check: + // will remove 'return;' from 'then' and 'else' with one instruction + // see #jadx.tests.integration.conditions.TestConditions9 + if (mth.isVoidReturn()) { + int thenSize = insnsCount(ifRegion.getThenRegion()); + // keep small blocks with same or 'similar' size unchanged + if (thenSize < 5) { + int elseSize = insnsCount(ifRegion.getElseRegion()); + int range = ifRegion.getElseRegion().contains(AFlag.ELSE_IF_CHAIN) ? 4 : 2; + if (thenSize == elseSize || (thenSize * range > elseSize && thenSize < elseSize * range)) { + return false; + } + } + } } IRegion parent = ifRegion.getParent(); Region newRegion = new Region(parent); diff --git a/jadx-core/src/main/java/jadx/core/utils/RegionUtils.java b/jadx-core/src/main/java/jadx/core/utils/RegionUtils.java index 87539cc1ecd..e2cb14f3fda 100644 --- a/jadx-core/src/main/java/jadx/core/utils/RegionUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/RegionUtils.java @@ -324,6 +324,30 @@ public static boolean isRegionContainsBlock(IContainer container, BlockNode bloc } } + public static IContainer getSingleSubBlock(IContainer container) { + if (container instanceof Region) { + List subBlocks = ((Region) container).getSubBlocks(); + if (subBlocks.size() == 1) { + return ignoreSimpleRegionWrapper(subBlocks.get(0)); + } + } + return null; + } + + private static IContainer ignoreSimpleRegionWrapper(IContainer container) { + while (true) { + if (container instanceof Region) { + List subBlocks = ((Region) container).getSubBlocks(); + if (subBlocks.size() != 1) { + return container; + } + container = subBlocks.get(0); + } else { + return container; + } + } + } + public static List getExcHandlersForRegion(IContainer region) { TryCatchBlockAttr tb = region.get(AType.TRY_BLOCK); if (tb != null) { diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestIfCodeStyle.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestIfCodeStyle.java index 9fb5f1130ac..be0df673c7e 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestIfCodeStyle.java +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestIfCodeStyle.java @@ -129,8 +129,9 @@ public void test() { noDebugInfo(); assertThat(getClassNode(TestCls.class)) .code() - .doesNotContain("else") - .countString(8, "return;") + // allow one last 'else' + .oneOf(c -> c.doesNotContain("else").countString(8, "return;"), + c -> c.countString(1, "else").countString(7, "return;")) .containsLines(2, "if (readInt < 0) {", indent() + "if (dataPosition > Integer.MAX_VALUE - readInt) {", @@ -146,8 +147,9 @@ public void testSmali() { disableCompilation(); assertThat(getClassNodeFromSmali()) .code() - .doesNotContain("else") - .countString(8, "return;") + // allow one last 'else' + .oneOf(c -> c.doesNotContain("else").countString(8, "return;"), + c -> c.countString(1, "else").countString(7, "return;")) .containsLines(2, "if (_aidl_parcelable_size < 0) {", indent() + "if (_aidl_start_pos > Integer.MAX_VALUE - _aidl_parcelable_size) {", diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestIfCodeStyle2.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestIfCodeStyle2.java new file mode 100644 index 00000000000..d68b4f53247 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestIfCodeStyle2.java @@ -0,0 +1,23 @@ +package jadx.tests.integration.conditions; + +import org.junit.jupiter.api.Test; + +import jadx.tests.api.SmaliTest; + +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; + +/** + * Issue #2052 + */ +public class TestIfCodeStyle2 extends SmaliTest { + + @Test + public void testSmali() { + disableCompilation(); + assertThat(getClassNodeFromSmali()) + .code() + .countString(1, "} else if (") + .countString(1, "} else {") + .countString(19, "return "); + } +} diff --git a/jadx-core/src/test/smali/conditions/TestIfCodeStyle2.smali b/jadx-core/src/test/smali/conditions/TestIfCodeStyle2.smali new file mode 100644 index 00000000000..ba88edfa234 --- /dev/null +++ b/jadx-core/src/test/smali/conditions/TestIfCodeStyle2.smali @@ -0,0 +1,578 @@ +.class public Lconditions/TestIfCodeStyle2; +.super Ljava/lang/Object; + +.method public execute(Ltest/TestSender;Ljava/lang/String;[Ljava/lang/String;)Z + .registers 21 + .param p1, "sender" # Ltest/TestSender; + .param p2, "currentAlias" # Ljava/lang/String; + .param p3, "args" # [Ljava/lang/String; + .prologue + .line 33 + invoke-virtual/range {p0 .. p1}, Lconditions/TestIfCodeStyle2;->testPermission(Ltest/TestSender;)Z + move-result v4 + if-nez v4, :cond_8 + const/4 v4, 0x1 + .line 165 + :goto_7 + return v4 + .line 35 + :cond_8 + move-object/from16 v0, p3 + array-length v4, v0 + const/4 v5, 0x2 + if-ge v4, v5, :cond_32 + .line 36 + new-instance v4, Ljava/lang/StringBuilder; + invoke-direct {v4}, Ljava/lang/StringBuilder;->()V + sget-object v5, Ltest/ChatColor;->RED:Ltest/ChatColor; + invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder; + move-result-object v4 + const-string v5, "Usage: " + invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + move-result-object v4 + move-object/from16 v0, p0 + iget-object v5, v0, Lconditions/TestIfCodeStyle2;->usageMessage:Ljava/lang/String; + invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + move-result-object v4 + invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-interface {v0, v4}, Ltest/TestSender;->sendMessage(Ljava/lang/String;)V + .line 37 + const/4 v4, 0x0 + goto :goto_7 + .line 40 + :cond_32 + const/4 v4, 0x0 + aget-object v4, p3, v4 + const-string v5, "give" + invoke-virtual {v4, v5}, Ljava/lang/String;->equalsIgnoreCase(Ljava/lang/String;)Z + move-result v4 + if-nez v4, :cond_61 + .line 41 + new-instance v4, Ljava/lang/StringBuilder; + invoke-direct {v4}, Ljava/lang/StringBuilder;->()V + sget-object v5, Ltest/ChatColor;->RED:Ltest/ChatColor; + invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder; + move-result-object v4 + const-string v5, "Usage: " + invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + move-result-object v4 + move-object/from16 v0, p0 + iget-object v5, v0, Lconditions/TestIfCodeStyle2;->usageMessage:Ljava/lang/String; + invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + move-result-object v4 + invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-interface {v0, v4}, Ltest/TestSender;->sendMessage(Ljava/lang/String;)V + .line 42 + const/4 v4, 0x0 + goto :goto_7 + .line 45 + :cond_61 + const/4 v4, 0x1 + aget-object v16, p3, v4 + .line 46 + .local v16, "statisticString":Ljava/lang/String; + const/4 v2, 0x0 + .line 48 + .local v2, "player":Ltest/entity/Player; + move-object/from16 v0, p3 + array-length v4, v0 + const/4 v5, 0x2 + if-le v4, v5, :cond_7d + .line 49 + const/4 v4, 0x1 + aget-object v4, p3, v4 + invoke-static {v4}, Ltest/Bukkit;->getPlayer(Ljava/lang/String;)Ltest/entity/Player; + move-result-object v2 + .line 54 + :cond_72 + :goto_72 + if-nez v2, :cond_88 + .line 55 + const-string v4, "You must specify which player you wish to perform this action on." + move-object/from16 v0, p1 + invoke-interface {v0, v4}, Ltest/TestSender;->sendMessage(Ljava/lang/String;)V + .line 56 + const/4 v4, 0x1 + goto :goto_7 + .line 50 + :cond_7d + move-object/from16 v0, p1 + instance-of v4, v0, Ltest/entity/Player; + if-eqz v4, :cond_72 + move-object/from16 v2, p1 + .line 51 + check-cast v2, Ltest/entity/Player; + goto :goto_72 + .line 59 + :cond_88 + const-string v4, "*" + move-object/from16 v0, v16 + invoke-virtual {v0, v4}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z + move-result v4 + if-eqz v4, :cond_d7 + .line 60 + invoke-static {}, Ltest/Achievement;->values()[Ltest/Achievement; + move-result-object v5 + array-length v7, v5 + const/4 v4, 0x0 + :goto_98 + if-ge v4, v7, :cond_bf + aget-object v13, v5, v4 + .line 61 + .local v13, "achievement":Ltest/Achievement; + invoke-interface {v2, v13}, Ltest/entity/Player;->hasAchievement(Ltest/Achievement;)Z + move-result v8 + if-eqz v8, :cond_a5 + .line 60 + :cond_a2 + :goto_a2 + add-int/lit8 v4, v4, 0x1 + goto :goto_98 + .line 64 + :cond_a5 + new-instance v1, Ltest/event/player/PlayerAchievementAwardedEvent; + invoke-direct {v1, v2, v13}, Ltest/event/player/PlayerAchievementAwardedEvent;->(Ltest/entity/Player;Ltest/Achievement;)V + .line 65 + .local v1, "event":Ltest/event/player/PlayerAchievementAwardedEvent; + invoke-static {}, Ltest/Bukkit;->getServer()Ltest/Server; + move-result-object v8 + invoke-interface {v8}, Ltest/Server;->getPluginManager()Ltest/plugin/PluginManager; + move-result-object v8 + invoke-interface {v8, v1}, Ltest/plugin/PluginManager;->callEvent(Ltest/event/Event;)V + .line 66 + invoke-virtual {v1}, Ltest/event/player/PlayerAchievementAwardedEvent;->isCancelled()Z + move-result v8 + if-nez v8, :cond_a2 + .line 67 + invoke-interface {v2, v13}, Ltest/entity/Player;->awardAchievement(Ltest/Achievement;)V + goto :goto_a2 + .line 70 + .end local v1 # "event":Ltest/event/player/PlayerAchievementAwardedEvent; + .end local v13 # "achievement":Ltest/Achievement; + :cond_bf + const-string v4, "Successfully given all achievements to %s" + const/4 v5, 0x1 + new-array v5, v5, [Ljava/lang/Object; + const/4 v7, 0x0 + invoke-interface {v2}, Ltest/entity/Player;->getName()Ljava/lang/String; + move-result-object v8 + aput-object v8, v5, v7 + invoke-static {v4, v5}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-static {v0, v4}, Ltest/command/Command;->broadcastCommandMessage(Ltest/TestSender;Ljava/lang/String;)V + .line 71 + const/4 v4, 0x1 + goto/16 :goto_7 + .line 74 + :cond_d7 + invoke-static {}, Ltest/Bukkit;->getUnsafe()Ltest/UnsafeValues; + move-result-object v4 + move-object/from16 v0, v16 + invoke-interface {v4, v0}, Ltest/UnsafeValues;->getAchievementFromInternalName(Ljava/lang/String;)Ltest/Achievement; + move-result-object v13 + .line 75 + .restart local v13 # "achievement":Ltest/Achievement; + invoke-static {}, Ltest/Bukkit;->getUnsafe()Ltest/UnsafeValues; + move-result-object v4 + move-object/from16 v0, v16 + invoke-interface {v4, v0}, Ltest/UnsafeValues;->getStatisticFromInternalName(Ljava/lang/String;)Ltest/Statistic; + move-result-object v3 + .line 77 + .local v3, "statistic":Ltest/Statistic; + if-eqz v13, :cond_15d + .line 78 + invoke-interface {v2, v13}, Ltest/entity/Player;->hasAchievement(Ltest/Achievement;)Z + move-result v4 + if-eqz v4, :cond_10e + .line 79 + const-string v4, "%s already has achievement %s" + const/4 v5, 0x2 + new-array v5, v5, [Ljava/lang/Object; + const/4 v7, 0x0 + invoke-interface {v2}, Ltest/entity/Player;->getName()Ljava/lang/String; + move-result-object v8 + aput-object v8, v5, v7 + const/4 v7, 0x1 + aput-object v16, v5, v7 + invoke-static {v4, v5}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-interface {v0, v4}, Ltest/TestSender;->sendMessage(Ljava/lang/String;)V + .line 80 + const/4 v4, 0x1 + goto/16 :goto_7 + .line 83 + :cond_10e + new-instance v1, Ltest/event/player/PlayerAchievementAwardedEvent; + invoke-direct {v1, v2, v13}, Ltest/event/player/PlayerAchievementAwardedEvent;->(Ltest/entity/Player;Ltest/Achievement;)V + .line 84 + .restart local v1 # "event":Ltest/event/player/PlayerAchievementAwardedEvent; + invoke-static {}, Ltest/Bukkit;->getServer()Ltest/Server; + move-result-object v4 + invoke-interface {v4}, Ltest/Server;->getPluginManager()Ltest/plugin/PluginManager; + move-result-object v4 + invoke-interface {v4, v1}, Ltest/plugin/PluginManager;->callEvent(Ltest/event/Event;)V + .line 85 + invoke-virtual {v1}, Ltest/event/player/PlayerAchievementAwardedEvent;->isCancelled()Z + move-result v4 + if-eqz v4, :cond_13f + .line 86 + const-string v4, "Unable to award %s the achievement %s" + const/4 v5, 0x2 + new-array v5, v5, [Ljava/lang/Object; + const/4 v7, 0x0 + invoke-interface {v2}, Ltest/entity/Player;->getName()Ljava/lang/String; + move-result-object v8 + aput-object v8, v5, v7 + const/4 v7, 0x1 + aput-object v16, v5, v7 + invoke-static {v4, v5}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-interface {v0, v4}, Ltest/TestSender;->sendMessage(Ljava/lang/String;)V + .line 87 + const/4 v4, 0x1 + goto/16 :goto_7 + .line 89 + :cond_13f + invoke-interface {v2, v13}, Ltest/entity/Player;->awardAchievement(Ltest/Achievement;)V + .line 91 + const-string v4, "Successfully given %s the stat %s" + const/4 v5, 0x2 + new-array v5, v5, [Ljava/lang/Object; + const/4 v7, 0x0 + invoke-interface {v2}, Ltest/entity/Player;->getName()Ljava/lang/String; + move-result-object v8 + aput-object v8, v5, v7 + const/4 v7, 0x1 + aput-object v16, v5, v7 + invoke-static {v4, v5}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-static {v0, v4}, Ltest/command/Command;->broadcastCommandMessage(Ltest/TestSender;Ljava/lang/String;)V + .line 92 + const/4 v4, 0x1 + goto/16 :goto_7 + .line 95 + .end local v1 # "event":Ltest/event/player/PlayerAchievementAwardedEvent; + :cond_15d + if-nez v3, :cond_173 + .line 96 + const-string v4, "Unknown achievement or statistic \'%s\'" + const/4 v5, 0x1 + new-array v5, v5, [Ljava/lang/Object; + const/4 v7, 0x0 + aput-object v16, v5, v7 + invoke-static {v4, v5}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-interface {v0, v4}, Ltest/TestSender;->sendMessage(Ljava/lang/String;)V + .line 97 + const/4 v4, 0x1 + goto/16 :goto_7 + .line 100 + :cond_173 + invoke-virtual {v3}, Ltest/Statistic;->getType()Ltest/Statistic$Type; + move-result-object v4 + sget-object v5, Ltest/Statistic$Type;->UNTYPED:Ltest/Statistic$Type; + if-ne v4, v5, :cond_1d4 + .line 101 + new-instance v1, Ltest/event/player/PlayerStatisticIncrementEvent; + invoke-interface {v2, v3}, Ltest/entity/Player;->getStatistic(Ltest/Statistic;)I + move-result v4 + invoke-interface {v2, v3}, Ltest/entity/Player;->getStatistic(Ltest/Statistic;)I + move-result v5 + add-int/lit8 v5, v5, 0x1 + invoke-direct {v1, v2, v3, v4, v5}, Ltest/event/player/PlayerStatisticIncrementEvent;->(Ltest/entity/Player;Ltest/Statistic;II)V + .line 102 + .local v1, "event":Ltest/event/player/PlayerStatisticIncrementEvent; + invoke-static {}, Ltest/Bukkit;->getServer()Ltest/Server; + move-result-object v4 + invoke-interface {v4}, Ltest/Server;->getPluginManager()Ltest/plugin/PluginManager; + move-result-object v4 + invoke-interface {v4, v1}, Ltest/plugin/PluginManager;->callEvent(Ltest/event/Event;)V + .line 103 + invoke-virtual {v1}, Ltest/event/player/PlayerStatisticIncrementEvent;->isCancelled()Z + move-result v4 + if-eqz v4, :cond_1b6 + .line 104 + const-string v4, "Unable to increment %s for %s" + const/4 v5, 0x2 + new-array v5, v5, [Ljava/lang/Object; + const/4 v7, 0x0 + aput-object v16, v5, v7 + const/4 v7, 0x1 + invoke-interface {v2}, Ltest/entity/Player;->getName()Ljava/lang/String; + move-result-object v8 + aput-object v8, v5, v7 + invoke-static {v4, v5}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-interface {v0, v4}, Ltest/TestSender;->sendMessage(Ljava/lang/String;)V + .line 105 + const/4 v4, 0x1 + goto/16 :goto_7 + .line 107 + :cond_1b6 + invoke-interface {v2, v3}, Ltest/entity/Player;->incrementStatistic(Ltest/Statistic;)V + .line 108 + const-string v4, "Successfully given %s the stat %s" + const/4 v5, 0x2 + new-array v5, v5, [Ljava/lang/Object; + const/4 v7, 0x0 + invoke-interface {v2}, Ltest/entity/Player;->getName()Ljava/lang/String; + move-result-object v8 + aput-object v8, v5, v7 + const/4 v7, 0x1 + aput-object v16, v5, v7 + invoke-static {v4, v5}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-static {v0, v4}, Ltest/command/Command;->broadcastCommandMessage(Ltest/TestSender;Ljava/lang/String;)V + .line 109 + const/4 v4, 0x1 + goto/16 :goto_7 + .line 112 + .end local v1 # "event":Ltest/event/player/PlayerStatisticIncrementEvent; + :cond_1d4 + invoke-virtual {v3}, Ltest/Statistic;->getType()Ltest/Statistic$Type; + move-result-object v4 + sget-object v5, Ltest/Statistic$Type;->ENTITY:Ltest/Statistic$Type; + if-ne v4, v5, :cond_274 + .line 113 + const-string v4, "." + move-object/from16 v0, v16 + invoke-virtual {v0, v4}, Ljava/lang/String;->lastIndexOf(Ljava/lang/String;)I + move-result v4 + add-int/lit8 v4, v4, 0x1 + move-object/from16 v0, v16 + invoke-virtual {v0, v4}, Ljava/lang/String;->substring(I)Ljava/lang/String; + move-result-object v4 + invoke-static {v4}, Ltest/entity/EntityType;->fromName(Ljava/lang/String;)Ltest/entity/EntityType; + move-result-object v6 + .line 115 + .local v6, "entityType":Ltest/entity/EntityType; + if-nez v6, :cond_206 + .line 116 + const-string v4, "Unknown achievement or statistic \'%s\'" + const/4 v5, 0x1 + new-array v5, v5, [Ljava/lang/Object; + const/4 v7, 0x0 + aput-object v16, v5, v7 + invoke-static {v4, v5}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-interface {v0, v4}, Ltest/TestSender;->sendMessage(Ljava/lang/String;)V + .line 117 + const/4 v4, 0x1 + goto/16 :goto_7 + .line 120 + :cond_206 + new-instance v1, Ltest/event/player/PlayerStatisticIncrementEvent; + invoke-interface {v2, v3}, Ltest/entity/Player;->getStatistic(Ltest/Statistic;)I + move-result v4 + invoke-interface {v2, v3}, Ltest/entity/Player;->getStatistic(Ltest/Statistic;)I + move-result v5 + add-int/lit8 v5, v5, 0x1 + invoke-direct/range {v1 .. v6}, Ltest/event/player/PlayerStatisticIncrementEvent;->(Ltest/entity/Player;Ltest/Statistic;IILtest/entity/EntityType;)V + .line 121 + .restart local v1 # "event":Ltest/event/player/PlayerStatisticIncrementEvent; + invoke-static {}, Ltest/Bukkit;->getServer()Ltest/Server; + move-result-object v4 + invoke-interface {v4}, Ltest/Server;->getPluginManager()Ltest/plugin/PluginManager; + move-result-object v4 + invoke-interface {v4, v1}, Ltest/plugin/PluginManager;->callEvent(Ltest/event/Event;)V + .line 122 + invoke-virtual {v1}, Ltest/event/player/PlayerStatisticIncrementEvent;->isCancelled()Z + move-result v4 + if-eqz v4, :cond_241 + .line 123 + const-string v4, "Unable to increment %s for %s" + const/4 v5, 0x2 + new-array v5, v5, [Ljava/lang/Object; + const/4 v7, 0x0 + aput-object v16, v5, v7 + const/4 v7, 0x1 + invoke-interface {v2}, Ltest/entity/Player;->getName()Ljava/lang/String; + move-result-object v8 + aput-object v8, v5, v7 + invoke-static {v4, v5}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-interface {v0, v4}, Ltest/TestSender;->sendMessage(Ljava/lang/String;)V + .line 124 + const/4 v4, 0x1 + goto/16 :goto_7 + .line 128 + :cond_241 + :try_start_241 + invoke-interface {v2, v3, v6}, Ltest/entity/Player;->incrementStatistic(Ltest/Statistic;Ltest/entity/EntityType;)V + :try_end_244 + .catch Ljava/lang/IllegalArgumentException; {:try_start_241 .. :try_end_244} :catch_25f + .line 164 + .end local v6 # "entityType":Ltest/entity/EntityType; + :goto_244 + const-string v4, "Successfully given %s the stat %s" + const/4 v5, 0x2 + new-array v5, v5, [Ljava/lang/Object; + const/4 v7, 0x0 + invoke-interface {v2}, Ltest/entity/Player;->getName()Ljava/lang/String; + move-result-object v8 + aput-object v8, v5, v7 + const/4 v7, 0x1 + aput-object v16, v5, v7 + invoke-static {v4, v5}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-static {v0, v4}, Ltest/command/Command;->broadcastCommandMessage(Ltest/TestSender;Ljava/lang/String;)V + .line 165 + const/4 v4, 0x1 + goto/16 :goto_7 + .line 129 + .restart local v6 # "entityType":Ltest/entity/EntityType; + :catch_25f + move-exception v14 + .line 130 + .local v14, "e":Ljava/lang/IllegalArgumentException; + const-string v4, "Unknown achievement or statistic \'%s\'" + const/4 v5, 0x1 + new-array v5, v5, [Ljava/lang/Object; + const/4 v7, 0x0 + aput-object v16, v5, v7 + invoke-static {v4, v5}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-interface {v0, v4}, Ltest/TestSender;->sendMessage(Ljava/lang/String;)V + .line 131 + const/4 v4, 0x1 + goto/16 :goto_7 + .line 136 + .end local v1 # "event":Ltest/event/player/PlayerStatisticIncrementEvent; + .end local v6 # "entityType":Ltest/entity/EntityType; + .end local v14 # "e":Ljava/lang/IllegalArgumentException; + :cond_274 + :try_start_274 + const-string v4, "." + move-object/from16 v0, v16 + invoke-virtual {v0, v4}, Ljava/lang/String;->lastIndexOf(Ljava/lang/String;)I + move-result v4 + add-int/lit8 v4, v4, 0x1 + move-object/from16 v0, v16 + invoke-virtual {v0, v4}, Ljava/lang/String;->substring(I)Ljava/lang/String; + move-result-object v9 + const/4 v10, 0x0 + const v11, 0x7fffffff + const/4 v12, 0x1 + move-object/from16 v7, p0 + move-object/from16 v8, p1 + invoke-virtual/range {v7 .. v12}, Lconditions/TestIfCodeStyle2;->getInteger(Ltest/TestSender;Ljava/lang/String;IIZ)I + :try_end_290 + .catch Ljava/lang/NumberFormatException; {:try_start_274 .. :try_end_290} :catch_2ab + move-result v15 + .line 142 + .local v15, "id":I + invoke-static {v15}, Ltest/Material;->getMaterial(I)Ltest/Material; + move-result-object v12 + .line 144 + .local v12, "material":Ltest/Material; + if-nez v12, :cond_2b8 + .line 145 + const-string v4, "Unknown achievement or statistic \'%s\'" + const/4 v5, 0x1 + new-array v5, v5, [Ljava/lang/Object; + const/4 v7, 0x0 + aput-object v16, v5, v7 + invoke-static {v4, v5}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-interface {v0, v4}, Ltest/TestSender;->sendMessage(Ljava/lang/String;)V + .line 146 + const/4 v4, 0x1 + goto/16 :goto_7 + .line 137 + .end local v12 # "material":Ltest/Material; + .end local v15 # "id":I + :catch_2ab + move-exception v14 + .line 138 + .local v14, "e":Ljava/lang/NumberFormatException; + invoke-virtual {v14}, Ljava/lang/NumberFormatException;->getMessage()Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-interface {v0, v4}, Ltest/TestSender;->sendMessage(Ljava/lang/String;)V + .line 139 + const/4 v4, 0x1 + goto/16 :goto_7 + .line 149 + .end local v14 # "e":Ljava/lang/NumberFormatException; + .restart local v12 # "material":Ltest/Material; + .restart local v15 # "id":I + :cond_2b8 + new-instance v1, Ltest/event/player/PlayerStatisticIncrementEvent; + invoke-interface {v2, v3}, Ltest/entity/Player;->getStatistic(Ltest/Statistic;)I + move-result v10 + invoke-interface {v2, v3}, Ltest/entity/Player;->getStatistic(Ltest/Statistic;)I + move-result v4 + add-int/lit8 v11, v4, 0x1 + move-object v7, v1 + move-object v8, v2 + move-object v9, v3 + invoke-direct/range {v7 .. v12}, Ltest/event/player/PlayerStatisticIncrementEvent;->(Ltest/entity/Player;Ltest/Statistic;IILtest/Material;)V + .line 150 + .restart local v1 # "event":Ltest/event/player/PlayerStatisticIncrementEvent; + invoke-static {}, Ltest/Bukkit;->getServer()Ltest/Server; + move-result-object v4 + invoke-interface {v4}, Ltest/Server;->getPluginManager()Ltest/plugin/PluginManager; + move-result-object v4 + invoke-interface {v4, v1}, Ltest/plugin/PluginManager;->callEvent(Ltest/event/Event;)V + .line 151 + invoke-virtual {v1}, Ltest/event/player/PlayerStatisticIncrementEvent;->isCancelled()Z + move-result v4 + if-eqz v4, :cond_2f6 + .line 152 + const-string v4, "Unable to increment %s for %s" + const/4 v5, 0x2 + new-array v5, v5, [Ljava/lang/Object; + const/4 v7, 0x0 + aput-object v16, v5, v7 + const/4 v7, 0x1 + invoke-interface {v2}, Ltest/entity/Player;->getName()Ljava/lang/String; + move-result-object v8 + aput-object v8, v5, v7 + invoke-static {v4, v5}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-interface {v0, v4}, Ltest/TestSender;->sendMessage(Ljava/lang/String;)V + .line 153 + const/4 v4, 0x1 + goto/16 :goto_7 + .line 157 + :cond_2f6 + :try_start_2f6 + invoke-interface {v2, v3, v12}, Ltest/entity/Player;->incrementStatistic(Ltest/Statistic;Ltest/Material;)V + :try_end_2f9 + .catch Ljava/lang/IllegalArgumentException; {:try_start_2f6 .. :try_end_2f9} :catch_2fb + goto/16 :goto_244 + .line 158 + :catch_2fb + move-exception v14 + .line 159 + .local v14, "e":Ljava/lang/IllegalArgumentException; + const-string v4, "Unknown achievement or statistic \'%s\'" + const/4 v5, 0x1 + new-array v5, v5, [Ljava/lang/Object; + const/4 v7, 0x0 + aput-object v16, v5, v7 + invoke-static {v4, v5}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; + move-result-object v4 + move-object/from16 v0, p1 + invoke-interface {v0, v4}, Ltest/TestSender;->sendMessage(Ljava/lang/String;)V + .line 160 + const/4 v4, 0x1 + goto/16 :goto_7 +.end method