-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Inline single nested else statement & inverse else comparator inspect…
…ions
- Loading branch information
Showing
13 changed files
with
474 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
deobfuscation/src/inspectionDescriptions/InlineNestedElse.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<html> | ||
<body> | ||
This inspection reports when an else statement has a single if statement block which can be inlined, example 'else { if(i == 0) {'<br> | ||
</body> | ||
</html> |
5 changes: 5 additions & 0 deletions
5
deobfuscation/src/inspectionDescriptions/InverseElseComparator.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<html> | ||
<body> | ||
This inspection reports when any else if statements are used with a reversible expression, example 'if(i != 71) { } else { }'<br> | ||
</body> | ||
</html> |
10 changes: 10 additions & 0 deletions
10
deobfuscation/src/main/kotlin/world/gregs/intellij/plugins/DeobfuscateUtil.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package world.gregs.intellij.plugins | ||
|
||
import com.intellij.psi.PsiExpression | ||
import com.siyeh.ig.psiutils.JavaPsiMathUtil | ||
|
||
object DeobfuscateUtil { | ||
fun isNumber(expression: PsiExpression): Boolean { | ||
return JavaPsiMathUtil.getNumberFromLiteral(expression) != null | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
114 changes: 114 additions & 0 deletions
114
...fuscation/src/main/kotlin/world/gregs/intellij/plugins/flow/InlineNestedElseInspection.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package world.gregs.intellij.plugins.flow | ||
|
||
import com.intellij.codeInspection.ProblemDescriptor | ||
import com.intellij.openapi.project.Project | ||
import com.intellij.openapi.util.Pair | ||
import com.intellij.psi.* | ||
import com.intellij.psi.codeStyle.CodeStyleManager | ||
import com.intellij.psi.util.PsiTreeUtil | ||
import com.intellij.psi.util.PsiUtilCore | ||
import com.siyeh.ig.BaseInspectionVisitor | ||
import com.siyeh.ig.InspectionGadgetsFix | ||
import com.siyeh.ig.psiutils.CommentTracker | ||
import com.siyeh.ig.style.ControlFlowStatementVisitorBase | ||
import com.siyeh.ig.style.SingleStatementInBlockInspection | ||
import org.jetbrains.annotations.Nls | ||
import org.jetbrains.annotations.NotNull | ||
import world.gregs.intellij.plugins.DeobfuscateToolBundle | ||
|
||
class InlineNestedElseInspection : SingleStatementInBlockInspection() { | ||
|
||
override fun getDisplayName(): String { | ||
return DeobfuscateToolBundle.message("inline.nested.else.display.name") | ||
} | ||
|
||
public override fun buildErrorString(vararg infos: Any): String { | ||
return DeobfuscateToolBundle.message("inline.nested.else.problem.descriptor") | ||
} | ||
|
||
override fun isEnabledByDefault(): Boolean { | ||
return true | ||
} | ||
|
||
override fun buildVisitor(): BaseInspectionVisitor { | ||
return object : ControlFlowStatementVisitorBase() { | ||
override fun isApplicable(body: PsiStatement?): Boolean { | ||
//If body is else branch of parent | ||
val parent = body?.parent | ||
if(body is PsiBlockStatement && parent is PsiIfStatement && parent.elseBranch == body) { | ||
val codeBlock = body.codeBlock | ||
if (PsiUtilCore.hasErrorElementChild(codeBlock)) { | ||
return false | ||
} | ||
|
||
//Else block must only contain a single if statement | ||
val statement = codeBlock.statements.firstOrNull() | ||
if (codeBlock.statementCount == 1 && statement is PsiIfStatement) { | ||
if (PsiUtilCore.hasErrorElementChild(statement)) { | ||
return false | ||
} | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
override fun getOmittedBodyBounds(body: PsiStatement?): Pair<PsiElement, PsiElement>? { | ||
if (body is PsiBlockStatement) { | ||
val codeBlock = body.codeBlock | ||
if (codeBlock.statementCount == 1) { | ||
val statement = codeBlock.statements.firstOrNull() | ||
if (statement?.textContains('\n') == true) { | ||
return Pair(statement, statement) | ||
} | ||
} | ||
} | ||
return null | ||
} | ||
|
||
} | ||
} | ||
|
||
override fun buildFix(vararg infos: Any?): InspectionGadgetsFix? { | ||
return object : InspectionGadgetsFix() { | ||
@Nls | ||
@NotNull | ||
override fun getName(): String { | ||
return DeobfuscateToolBundle.message("inline.nested.else.quickfix") | ||
} | ||
|
||
@Nls | ||
@NotNull | ||
override fun getFamilyName(): String { | ||
return DeobfuscateToolBundle.message("inline.nested.else.family.quickfix") | ||
} | ||
|
||
override fun doFix(project: Project, descriptor: ProblemDescriptor) { | ||
var statement = PsiTreeUtil.getNonStrictParentOfType(descriptor.startElement, PsiStatement::class.java) | ||
?: return | ||
|
||
if (statement is PsiBlockStatement) { | ||
statement = PsiTreeUtil.getNonStrictParentOfType(statement.parent, PsiStatement::class.java) | ||
?: return | ||
} | ||
|
||
val body = when (statement) { | ||
is PsiLoopStatement -> statement.body | ||
is PsiIfStatement -> statement.elseBranch | ||
else -> null | ||
} as? PsiBlockStatement ?: return | ||
|
||
val child = body.codeBlock.statements.firstOrNull() | ||
if (body.codeBlock.statementCount != 1 || child == null) { | ||
return | ||
} | ||
|
||
val ct = CommentTracker() | ||
val text = ct.text(child) | ||
val replacementExp = ct.replace(body, text) | ||
CodeStyleManager.getInstance(project).reformat(replacementExp) | ||
ct.insertCommentsBefore(statement) | ||
} | ||
} | ||
} | ||
} |
155 changes: 155 additions & 0 deletions
155
...tion/src/main/kotlin/world/gregs/intellij/plugins/flow/InverseElseComparatorInspection.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
package world.gregs.intellij.plugins.flow | ||
|
||
import com.intellij.codeInspection.ProblemDescriptor | ||
import com.intellij.openapi.project.Project | ||
import com.intellij.psi.* | ||
import com.intellij.psi.JavaTokenType.* | ||
import com.intellij.util.containers.ContainerUtil | ||
import com.siyeh.ig.BaseInspection | ||
import com.siyeh.ig.BaseInspectionVisitor | ||
import com.siyeh.ig.InspectionGadgetsFix | ||
import com.siyeh.ig.PsiReplacementUtil | ||
import com.siyeh.ig.psiutils.CommentTracker | ||
import com.siyeh.ig.psiutils.ComparisonUtils | ||
import org.jetbrains.annotations.NonNls | ||
import world.gregs.intellij.plugins.DeobfuscateToolBundle | ||
import world.gregs.intellij.plugins.DeobfuscateUtil.isNumber | ||
|
||
class InverseElseComparatorInspection : BaseInspection() { | ||
|
||
override fun getDisplayName(): String { | ||
return DeobfuscateToolBundle.message("inverse.else.comparator.display.name") | ||
} | ||
|
||
public override fun buildErrorString(vararg infos: Any): String { | ||
val expression = infos[0] as PsiExpression | ||
val statement = infos[1] as PsiIfStatement | ||
val ct = CommentTracker() | ||
val replacement = calculateReplacementExpression(statement, ct) | ||
return DeobfuscateToolBundle.message( | ||
"comparator.can.be.inverted.problem.descriptor", | ||
ct.text(expression), | ||
replacement | ||
) | ||
} | ||
|
||
override fun isEnabledByDefault(): Boolean { | ||
return true | ||
} | ||
|
||
override fun buildVisitor(): BaseInspectionVisitor { | ||
return object : BaseInspectionVisitor() { | ||
override fun visitIfStatement(statement: PsiIfStatement) { | ||
super.visitIfStatement(statement) | ||
|
||
//Must have else block statement | ||
if(statement.elseBranch !is PsiBlockStatement) { | ||
return | ||
} | ||
|
||
val expression = statement.condition as? PsiBinaryExpression | ||
?: return | ||
|
||
//Check expression has operands | ||
val left = expression.lOperand | ||
val right = expression.rOperand | ||
?: return | ||
|
||
//Check format matches expected | ||
val sign = expression.operationTokenType | ||
val invalid = when (sign) { | ||
//Variable doesn't equal number or visa versa | ||
NE -> left is PsiReferenceExpression && !isNumber(right) || isNumber(left) && right !is PsiReferenceExpression | ||
//Both operands are binary expressions that have a range operation type | ||
OROR -> left !is PsiBinaryExpression || right !is PsiBinaryExpression || !comparisonTokens.contains(left.operationTokenType) || !comparisonTokens.contains(right.operationTokenType) | ||
//Both operands are binary expressions that both have a not-equal operators | ||
ANDAND -> left !is PsiBinaryExpression || right !is PsiBinaryExpression || left.operationTokenType != NE || right.operationTokenType != NE | ||
else -> true | ||
} | ||
|
||
//If format invalid; ignore | ||
if (invalid) { | ||
return | ||
} | ||
|
||
registerError(statement, expression, statement) | ||
} | ||
} | ||
} | ||
|
||
public override fun buildFix(vararg infos: Any): InspectionGadgetsFix? { | ||
return object : InspectionGadgetsFix() { | ||
|
||
override fun getFamilyName(): String { | ||
return DeobfuscateToolBundle.message("inverse.else.comparator.invert.quickfix") | ||
} | ||
|
||
public override fun doFix(project: Project, descriptor: ProblemDescriptor) { | ||
val statement = descriptor.psiElement as PsiIfStatement | ||
|
||
val expression = statement.condition as? PsiBinaryExpression | ||
?: return | ||
|
||
val ct = CommentTracker() | ||
|
||
//Replace expression with negative comparator | ||
val expected = calculateReplacementExpression(statement, ct) | ||
PsiReplacementUtil.replaceExpression(expression, expected, ct) | ||
|
||
//Switch branches | ||
val branch = statement.thenBranch | ||
val elseBranch = statement.elseBranch?.copy() as? PsiStatement | ||
if(branch != null) { | ||
statement.setElseBranch(branch) | ||
} | ||
if(elseBranch != null) { | ||
statement.setThenBranch(elseBranch) | ||
} | ||
} | ||
} | ||
} | ||
|
||
@NonNls | ||
internal fun calculateReplacementExpression(statement: PsiIfStatement, ct: CommentTracker): String { | ||
val expression = statement.condition as? PsiBinaryExpression | ||
?: return "" | ||
|
||
val sign = expression.operationTokenType | ||
return when (sign) { | ||
NE -> replaceOperation(expression, ComparisonUtils.getNegatedComparison(sign), ct) | ||
OROR, ANDAND -> { | ||
//Get operands as expressions | ||
val left = expression.lOperand as? PsiBinaryExpression | ||
?: return "" | ||
val right = expression.rOperand as? PsiBinaryExpression | ||
?: return "" | ||
//Replace expressions with negated operators | ||
val leftNew = replaceOperation(left, ComparisonUtils.getNegatedComparison(left.operationTokenType), ct) | ||
val rightNew = replaceOperation(right, ComparisonUtils.getNegatedComparison(right.operationTokenType), ct) | ||
//Change statement operator | ||
val opposite = when (sign) { | ||
OROR -> "&&" | ||
ANDAND -> "||" | ||
else -> throw IllegalStateException() | ||
} | ||
"$leftNew $opposite $rightNew" | ||
} | ||
else -> "" | ||
} | ||
} | ||
|
||
/** | ||
* Replaces [expression] operator | ||
* @param expression The binary expression who's operator to replace | ||
* @param operator The new operator | ||
* @param ct CommentTracker | ||
* @return [expression] as a string with the new [operator] | ||
*/ | ||
private fun replaceOperation(expression: PsiBinaryExpression, operator: String, ct: CommentTracker): String { | ||
return "${ct.text(expression.lOperand)} $operator ${ct.text(expression.rOperand!!)}" | ||
} | ||
|
||
companion object { | ||
internal val comparisonTokens = ContainerUtil.immutableSet(LT, GT, LE, GE) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
<idea-plugin> | ||
<id>world.gregs.intellij.plugins.deobfuscation</id> | ||
<name>Java Bitwise Deobsfuscator</name> | ||
<name>Greg's Deobsfuscation Tools</name> | ||
<vendor email="[email protected]" url="http://gregs.world">Greg</vendor> | ||
|
||
<description><![CDATA[ | ||
Highlights pointless bitwise comparator obfuscation to be simplified<br> | ||
A few intellij plugins to assist refactoring obfuscated code<br> | ||
]]></description> | ||
|
||
<!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html | ||
|
@@ -19,6 +19,16 @@ | |
groupKey="group.names.bitwise.operation.issues" enabledByDefault="true" level="WARNING" | ||
hasStaticDescription="true" | ||
implementationClass="world.gregs.intellij.plugins.bitwise.PointlessBitwiseComparatorInspection"/> | ||
<localInspection groupPath="Java" language="JAVA" shortName="InverseElseComparator" bundle="world.gregs.intellij.plugins.DeobfuscateToolBundle" | ||
key="inverse.else.comparator.display.name" groupBundle="messages.InspectionsBundle" | ||
groupKey="group.names.control.flow.issues" enabledByDefault="true" level="WARNING" | ||
hasStaticDescription="true" | ||
implementationClass="world.gregs.intellij.plugins.flow.InverseElseComparatorInspection"/> | ||
<localInspection groupPath="Java" language="JAVA" shortName="InlineNestedElse" bundle="world.gregs.intellij.plugins.DeobfuscateToolBundle" | ||
key="inline.nested.else.display.name" groupBundle="messages.InspectionsBundle" | ||
groupKey="group.names.control.flow.issues" enabledByDefault="true" level="WARNING" | ||
hasStaticDescription="true" | ||
implementationClass="world.gregs.intellij.plugins.flow.InlineNestedElseInspection"/> | ||
</extensions> | ||
|
||
<actions> | ||
|
11 changes: 10 additions & 1 deletion
11
...uscation/src/main/resources/world/gregs/intellij/plugins/DeobfuscateToolBundle.properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,12 @@ | ||
pointless.bitwise.comparator.display.name=Pointless bitwise comparator | ||
expression.can.be.replaced.problem.descriptor=<code>#ref</code> can be replaced with ''{0}'' #loc | ||
pointless.bitwise.comparator.simplify.quickfix=Simplify | ||
pointless.bitwise.comparator.simplify.quickfix=Simplify | ||
|
||
inverse.else.comparator.display.name=Inverse if else comparator | ||
comparator.can.be.inverted.problem.descriptor=''{0}'' can be inverted to ''{1}'' #loc | ||
inverse.else.comparator.invert.quickfix=Invert | ||
|
||
inline.nested.else.display.name=Inline nested else statement | ||
inline.nested.else.problem.descriptor=<code>#ref</code> can be inlined #loc | ||
inline.nested.else.quickfix=Inline 'else' statement | ||
inline.nested.else.family.quickfix=Inline statements |
Oops, something went wrong.