Extended option 'dc4' to handle inlined class references (mainly Eclipse). See IDEA-135387 for an example.

This commit is contained in:
Stiver
2015-03-01 13:51:30 +01:00
parent c3b4a23fdb
commit b3962a09ca
14 changed files with 822 additions and 12 deletions

View File

@@ -0,0 +1,32 @@
package org.jetbrains.java.decompiler.struct.match;
public interface IMatchable {
public enum MatchProperties {
STATEMENT_TYPE,
STATEMENT_RET,
STATEMENT_STATSIZE,
STATEMENT_EXPRSIZE,
STATEMENT_POSITION,
STATEMENT_IFTYPE,
EXPRENT_TYPE,
EXPRENT_RET,
EXPRENT_POSITION,
EXPRENT_FUNCTYPE,
EXPRENT_EXITTYPE,
EXPRENT_CONSTTYPE,
EXPRENT_CONSTVALUE,
EXPRENT_INVOCATION_CLASS,
EXPRENT_INVOCATION_SIGNATURE,
EXPRENT_INVOCATION_PARAMETER,
EXPRENT_VAR_INDEX,
EXPRENT_FIELD_NAME,
}
public IMatchable findObject(MatchNode matchNode, int index);
public boolean match(MatchNode matchNode, MatchEngine engine);
}

View File

@@ -0,0 +1,239 @@
package org.jetbrains.java.decompiler.struct.match;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.struct.match.IMatchable.MatchProperties;
import org.jetbrains.java.decompiler.struct.match.MatchNode.RuleValue;
public class MatchEngine {
private MatchNode rootNode = null;
private Map<String, Object> variables = new HashMap<String, Object>();
private static Map<String, MatchProperties> stat_properties = new HashMap<String, MatchProperties>();
private static Map<String, MatchProperties> expr_properties = new HashMap<String, MatchProperties>();
private static Map<String, Integer> stat_type = new HashMap<String, Integer>();
private static Map<String, Integer> expr_type = new HashMap<String, Integer>();
private static Map<String, Integer> expr_func_type = new HashMap<String, Integer>();
private static Map<String, Integer> expr_exit_type = new HashMap<String, Integer>();
private static Map<String, Integer> stat_if_type = new HashMap<String, Integer>();
private static Map<String, VarType> expr_const_type = new HashMap<String, VarType>();
static {
stat_properties.put("type", MatchProperties.STATEMENT_TYPE);
stat_properties.put("ret", MatchProperties.STATEMENT_RET);
stat_properties.put("position", MatchProperties.STATEMENT_POSITION);
stat_properties.put("statsize", MatchProperties.STATEMENT_STATSIZE);
stat_properties.put("exprsize", MatchProperties.STATEMENT_EXPRSIZE);
stat_properties.put("iftype", MatchProperties.STATEMENT_IFTYPE);
expr_properties.put("type", MatchProperties.EXPRENT_TYPE);
expr_properties.put("ret", MatchProperties.EXPRENT_RET);
expr_properties.put("position", MatchProperties.EXPRENT_POSITION);
expr_properties.put("functype", MatchProperties.EXPRENT_FUNCTYPE);
expr_properties.put("exittype", MatchProperties.EXPRENT_EXITTYPE);
expr_properties.put("consttype", MatchProperties.EXPRENT_CONSTTYPE);
expr_properties.put("constvalue", MatchProperties.EXPRENT_CONSTVALUE);
expr_properties.put("invclass", MatchProperties.EXPRENT_INVOCATION_CLASS);
expr_properties.put("signature", MatchProperties.EXPRENT_INVOCATION_SIGNATURE);
expr_properties.put("parameter", MatchProperties.EXPRENT_INVOCATION_PARAMETER);
expr_properties.put("index", MatchProperties.EXPRENT_VAR_INDEX);
expr_properties.put("name", MatchProperties.EXPRENT_FIELD_NAME);
stat_type.put("if", Statement.TYPE_IF);
stat_type.put("do", Statement.TYPE_DO);
stat_type.put("switch", Statement.TYPE_SWITCH);
stat_type.put("trycatch", Statement.TYPE_TRYCATCH);
stat_type.put("basicblock", Statement.TYPE_BASICBLOCK);
stat_type.put("sequence", Statement.TYPE_SEQUENCE);
expr_type.put("array", Exprent.EXPRENT_ARRAY);
expr_type.put("assignment", Exprent.EXPRENT_ASSIGNMENT);
expr_type.put("constant", Exprent.EXPRENT_CONST);
expr_type.put("exit", Exprent.EXPRENT_EXIT);
expr_type.put("field", Exprent.EXPRENT_FIELD);
expr_type.put("function", Exprent.EXPRENT_FUNCTION);
expr_type.put("if", Exprent.EXPRENT_IF);
expr_type.put("invocation", Exprent.EXPRENT_INVOCATION);
expr_type.put("monitor", Exprent.EXPRENT_MONITOR);
expr_type.put("new", Exprent.EXPRENT_NEW);
expr_type.put("switch", Exprent.EXPRENT_SWITCH);
expr_type.put("var", Exprent.EXPRENT_VAR);
expr_type.put("annotation", Exprent.EXPRENT_ANNOTATION);
expr_type.put("assert", Exprent.EXPRENT_ASSERT);
expr_func_type.put("eq", FunctionExprent.FUNCTION_EQ);
expr_exit_type.put("return", ExitExprent.EXIT_RETURN);
expr_exit_type.put("throw", ExitExprent.EXIT_THROW);
stat_if_type.put("if", IfStatement.IFTYPE_IF);
stat_if_type.put("ifelse", IfStatement.IFTYPE_IFELSE);
expr_const_type.put("null", VarType.VARTYPE_NULL);
expr_const_type.put("string", VarType.VARTYPE_STRING);
}
public void parse(String description) {
// each line is a separate statement/exprent
String[] lines = description.split("\n");
int depth = 0;
LinkedList<MatchNode> stack = new LinkedList<MatchNode>();
for(String line : lines) {
List<String> properties = new ArrayList<String>(Arrays.asList(line.split("\\s+"))); // split on any number of whitespaces
if(properties.get(0).isEmpty()) {
properties.remove(0);
}
int node_type = "statement".equals(properties.get(0)) ? MatchNode.MATCHNODE_STATEMENT : MatchNode.MATCHNODE_EXPRENT;
// create new node
MatchNode matchNode = new MatchNode(node_type);
for(int i = 1; i < properties.size(); ++i) {
String[] values = properties.get(i).split(":");
MatchProperties property = (node_type == MatchNode.MATCHNODE_STATEMENT ? stat_properties : expr_properties).get(values[0]);
if(property == null) { // unknown property defined
throw new RuntimeException("Unknown matching property");
} else {
Object value = null;
int parameter = 0;
String strValue = values[1];
if(values.length == 3) {
parameter = Integer.parseInt(values[1]);
strValue = values[2];
}
switch(property) {
case STATEMENT_TYPE:
value = stat_type.get(strValue);
break;
case STATEMENT_STATSIZE:
case STATEMENT_EXPRSIZE:
value = Integer.valueOf(strValue);
break;
case STATEMENT_POSITION:
case EXPRENT_POSITION:
case EXPRENT_INVOCATION_CLASS:
case EXPRENT_INVOCATION_SIGNATURE:
case EXPRENT_INVOCATION_PARAMETER:
case EXPRENT_VAR_INDEX:
case EXPRENT_FIELD_NAME:
case EXPRENT_CONSTVALUE:
case STATEMENT_RET:
case EXPRENT_RET:
value = strValue;
break;
case STATEMENT_IFTYPE:
value = stat_if_type.get(strValue);
break;
case EXPRENT_FUNCTYPE:
value = expr_func_type.get(strValue);
break;
case EXPRENT_EXITTYPE:
value = expr_exit_type.get(strValue);
break;
case EXPRENT_CONSTTYPE:
value = expr_const_type.get(strValue);
break;
case EXPRENT_TYPE:
value = expr_type.get(strValue);
break;
default:
throw new RuntimeException("Unhandled matching property");
}
matchNode.addRule(property, new RuleValue(parameter, value));
}
}
if(stack.isEmpty()) { // first line, root node
stack.push(matchNode);
} else {
// return to the correct parent on the stack
int new_depth = line.lastIndexOf(' ', depth) + 1;
for(int i = new_depth; i <= depth; ++i) {
stack.pop();
}
// insert new node
stack.getFirst().addChild(matchNode);
stack.push(matchNode);
depth = new_depth;
}
}
this.rootNode = stack.getLast();
}
public boolean match(IMatchable object) {
variables.clear();
return match(this.rootNode, object);
}
private boolean match(MatchNode matchNode, IMatchable object) {
if(!object.match(matchNode, this)) {
return false;
}
int expr_index = 0;
int stat_index = 0;
for(MatchNode childNode : matchNode.getChildren()) {
boolean isStatement = childNode.getType() == MatchNode.MATCHNODE_STATEMENT;
IMatchable childObject = object.findObject(childNode, isStatement ? stat_index : expr_index);
if(childObject == null || !match(childNode, childObject)) {
return false;
}
if(isStatement) {
stat_index++;
} else {
expr_index++;
}
}
return true;
}
public boolean checkAndSetVariableValue(String name, Object value) {
Object old_value = variables.get(name);
if(old_value == null) {
variables.put(name, value);
} else if(!old_value.equals(value)) {
return false;
}
return true;
}
public Object getVariableValue(String name) {
return variables.get(name);
}
}

View File

@@ -0,0 +1,70 @@
package org.jetbrains.java.decompiler.struct.match;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jetbrains.java.decompiler.struct.match.IMatchable.MatchProperties;
public class MatchNode {
public static class RuleValue {
public int parameter;
public Object value;
public RuleValue(int parameter, Object value) {
this.parameter = parameter;
this.value = value;
}
public boolean isVariable() {
String strValue = value.toString();
return (strValue.charAt(0) == '$' && strValue.charAt(strValue.length() - 1) == '$');
}
public String toString() {
return value.toString();
}
}
public static final int MATCHNODE_STATEMENT = 0;
public static final int MATCHNODE_EXPRENT = 1;
private int type;
private Map<MatchProperties, RuleValue> rules = new HashMap<MatchProperties, RuleValue>();
private List<MatchNode> children = new ArrayList<MatchNode>();
public MatchNode(int type) {
this.type = type;
}
public void addChild(MatchNode child) {
children.add(child);
}
public void addRule(MatchProperties property, RuleValue value) {
rules.put(property, value);
}
public int getType() {
return type;
}
public List<MatchNode> getChildren() {
return children;
}
public Map<MatchProperties, RuleValue> getRules() {
return rules;
}
public Object getRuleValue(MatchProperties property) {
RuleValue rule = rules.get(property);
return rule == null ? null : rule.value;
}
}