|
|
|
|
@@ -61,106 +61,310 @@ public class VariableAccessDR extends DecompilerReference {
|
|
|
|
|
public void accumulateMatches(DataType dt, FieldMatcher fieldMatcher,
|
|
|
|
|
List<DataTypeReference> results) {
|
|
|
|
|
|
|
|
|
|
if (fields.isEmpty()) {
|
|
|
|
|
DecompilerVariable var = getMatch(dt, fieldMatcher, variable, null);
|
|
|
|
|
if (var != null) {
|
|
|
|
|
String fieldName = null;
|
|
|
|
|
DataTypeReference ref = createReference(var, fieldName);
|
|
|
|
|
results.add(ref);
|
|
|
|
|
}
|
|
|
|
|
// simplify how we search depending on whether a field is required and if we have fields
|
|
|
|
|
if (fieldMatcher.isIgnored()) {
|
|
|
|
|
accumulateMatchesForTypeOnly(dt, results);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Walk each pair of type and variables in order to see if any of them match our
|
|
|
|
|
// criteria
|
|
|
|
|
//
|
|
|
|
|
DecompilerVariable start = variable;
|
|
|
|
|
if (fields.isEmpty()) {
|
|
|
|
|
// We have a valid field matcher, but no fields. Look for special case direct field
|
|
|
|
|
// usage, such as an enum name used inline, without its containing class.
|
|
|
|
|
accumulateMatchesDirectFields(dt, fieldMatcher, results);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
This variable may have fields being accessed. We need to check for the data type usage
|
|
|
|
|
in this variable and each of the fields that we find. We need to make sure the fields
|
|
|
|
|
match as well. For the given text below we will ask the following questions:
|
|
|
|
|
|
|
|
|
|
Foo->bar->baz
|
|
|
|
|
|
|
|
|
|
- Does Foo match the type and 'bar' match the field matcher?
|
|
|
|
|
- Does bar match the type and 'baz' match the field matcher?
|
|
|
|
|
- Does baz match the type?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Known Special Cases:
|
|
|
|
|
|
|
|
|
|
A) Foo is reported as the same type as bar:
|
|
|
|
|
i. both are actually the desired type
|
|
|
|
|
ii. the field is not really the desired type
|
|
|
|
|
B) Foo's type is not a Foo, bar's type is Foo instead
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
DecompilerVariable parent = variable;
|
|
|
|
|
for (DecompilerVariable field : fields) {
|
|
|
|
|
|
|
|
|
|
DecompilerVariable next = field;
|
|
|
|
|
DecompilerVariable var = getMatch(dt, fieldMatcher, start, next);
|
|
|
|
|
if (var != null) {
|
|
|
|
|
DataTypeReference ref = createReference(var, next);
|
|
|
|
|
// 1) See if the variable matches the type
|
|
|
|
|
DataTypeReference ref = createStandardReference(dt, parent, field, fieldMatcher);
|
|
|
|
|
if (ref != null) {
|
|
|
|
|
results.add(ref);
|
|
|
|
|
parent = field;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
start = next;
|
|
|
|
|
// 2) See if both types match (case A from above)
|
|
|
|
|
// (At this point, either the parent type does not match, or the parent and the field
|
|
|
|
|
// share the same type.)
|
|
|
|
|
ref = createReferenceWhenVariableAndFieldMatch(dt, parent, field, fieldMatcher);
|
|
|
|
|
if (ref != null) {
|
|
|
|
|
results.add(ref);
|
|
|
|
|
parent = field;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3) See if the field matches the type (case B from above)
|
|
|
|
|
// (At this point the variable doesn't match, or the field doesn't match.)
|
|
|
|
|
ref = createFieldReference(dt, parent, field, fieldMatcher);
|
|
|
|
|
if (ref != null) {
|
|
|
|
|
results.add(ref);
|
|
|
|
|
parent = field;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fieldMatcher.isIgnored()) {
|
|
|
|
|
// Note: since the last field in the loop above does not itself have a field, then it
|
|
|
|
|
// cannot match the requirement of a parent type followed by a field match.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void accumulateMatchesForTypeOnly(DataType dt, List<DataTypeReference> results) {
|
|
|
|
|
|
|
|
|
|
if (fields.isEmpty()) {
|
|
|
|
|
// No fields to check. See if this class's variable is a match.
|
|
|
|
|
DecompilerVariable var = getMatchingVariable(dt, variable);
|
|
|
|
|
if (var != null) {
|
|
|
|
|
String fieldName = null;
|
|
|
|
|
DataTypeReference ref = createReferenceToVariable(var, fieldName);
|
|
|
|
|
results.add(ref);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DecompilerVariable var = getMatch(dt, fieldMatcher, start, null);
|
|
|
|
|
// This class's variable and each field may match the type. In this loop we will check each
|
|
|
|
|
// combination of a data type and the field, making a reference for all matches. Each pass
|
|
|
|
|
// through the loop makes the next field become the parent for the following field. The last
|
|
|
|
|
// field is handled below the loop.
|
|
|
|
|
DecompilerVariable parent = variable;
|
|
|
|
|
for (DecompilerVariable field : fields) {
|
|
|
|
|
DecompilerVariable var = getMatchingVariable(dt, parent);
|
|
|
|
|
parent = field;
|
|
|
|
|
if (var == null) {
|
|
|
|
|
continue; // the current 'parent' does not match
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Note: handle the bug condition where the variable and the field both have the type of
|
|
|
|
|
// interest.
|
|
|
|
|
DataTypeReference ref;
|
|
|
|
|
DecompilerVariable preferred = updateVarForBugCondition(var, field);
|
|
|
|
|
if (preferred == var) {
|
|
|
|
|
String fieldName = field.getName();
|
|
|
|
|
ref = createReferenceToVariable(var, fieldName);
|
|
|
|
|
}
|
|
|
|
|
else { // preferred == field
|
|
|
|
|
|
|
|
|
|
// if we encounter the bug condition where the field is the actual type we seek,
|
|
|
|
|
// then don't use the field name, as the field is the reference.
|
|
|
|
|
String fieldName = null;
|
|
|
|
|
ref = createReferenceToField(preferred, fieldName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
results.add(ref);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handle the last field. In this case, we cannot have a parent and field match, only a
|
|
|
|
|
// match on the data type with no field.
|
|
|
|
|
DecompilerVariable var = getMatchingVariable(dt, parent);
|
|
|
|
|
if (var != null) {
|
|
|
|
|
DataTypeReference ref = createReference(var, fieldMatcher.getFieldName());
|
|
|
|
|
String fieldName = null;
|
|
|
|
|
DataTypeReference ref = createReferenceToVariable(var, fieldName);
|
|
|
|
|
results.add(ref);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DecompilerVariable updateVarForBugCondition(DecompilerVariable var,
|
|
|
|
|
DecompilerVariable field) {
|
|
|
|
|
|
|
|
|
|
if (isFieldTheBetterMatch(var, field)) {
|
|
|
|
|
// assume a real match for a self-referencing structure
|
|
|
|
|
return field;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return var;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean isFieldTheBetterMatch(DecompilerVariable var, DecompilerVariable field) {
|
|
|
|
|
|
|
|
|
|
// This is an odd case where both the parent and the field have the same type. This may be
|
|
|
|
|
// valid, such as when a structure contains a reference to itself. But, this also can
|
|
|
|
|
// happen when the decompiler makes mistakes when setting the data type.
|
|
|
|
|
|
|
|
|
|
// This type may not be the actual field type. We check on that below when these types are
|
|
|
|
|
// the same.
|
|
|
|
|
DataType fdt = field.getDataType();
|
|
|
|
|
DataType vdt = var.getDataType();
|
|
|
|
|
if (!isEqual(vdt, fdt)) {
|
|
|
|
|
return false; // the original var is the correct variable
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We have the same type. If the 2 types are really the same (self-refernecing structure),
|
|
|
|
|
// then we want a match for the parent to the field. If the types are not really the same,
|
|
|
|
|
// then for now assume the field itself is the correct match.
|
|
|
|
|
|
|
|
|
|
// Note: this had been using 'sourceToken', which doesn't seem right. If we find missed
|
|
|
|
|
// cases where 'field.variable' is not working, then revisit using 'sourceToken' as a
|
|
|
|
|
// fallback check.
|
|
|
|
|
//ClangFieldToken fieldToken = (ClangFieldToken) sourceToken;
|
|
|
|
|
if (!(field.variable instanceof ClangFieldToken fieldToken)) {
|
|
|
|
|
return false; // cannot check the field's type
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DataType actualFieldDt = DecompilerReference.getFieldDataType(fieldToken);
|
|
|
|
|
boolean matchesFieldType = isEqual(vdt, actualFieldDt);
|
|
|
|
|
if (matchesFieldType) {
|
|
|
|
|
// assume a real match for a self-referencing structure
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void accumulateMatchesDirectFields(DataType dt, FieldMatcher fieldMatcher,
|
|
|
|
|
List<DataTypeReference> results) {
|
|
|
|
|
|
|
|
|
|
DecompilerVariable var = getMatch(dt, fieldMatcher, variable);
|
|
|
|
|
if (var != null) {
|
|
|
|
|
String fieldName = fieldMatcher.getFieldName();
|
|
|
|
|
DataTypeReference ref = createReferenceToField(var, fieldName);
|
|
|
|
|
results.add(ref);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DataTypeReference createStandardReference(DataType dt, DecompilerVariable parent,
|
|
|
|
|
DecompilerVariable field, FieldMatcher fieldMatcher) {
|
|
|
|
|
|
|
|
|
|
// a standard reference is the case where the parent is the type we seek and the field
|
|
|
|
|
// matches the matcher
|
|
|
|
|
DecompilerVariable var = getMatchingVariable(dt, parent);
|
|
|
|
|
if (var == null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DataType vdt = var.getDataType();
|
|
|
|
|
DataType fdt = field.getDataType();
|
|
|
|
|
if (isEqual(vdt, fdt)) {
|
|
|
|
|
return null; // this may be an error case; handled by a different method later
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String fieldName = field.getName();
|
|
|
|
|
int offset = field.getOffset();
|
|
|
|
|
if (fieldMatcher.matches(fieldName, offset)) {
|
|
|
|
|
return createReference(var, field, fieldMatcher);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DataTypeReference createFieldReference(DataType dt, DecompilerVariable parent,
|
|
|
|
|
DecompilerVariable field, FieldMatcher fieldMatcher) {
|
|
|
|
|
|
|
|
|
|
// Note: this method should only be called if we did not create a 'standard reference',
|
|
|
|
|
// which is when the parent type matches 'dt' and the field type does not match. Getting
|
|
|
|
|
// into this method means either the parent type did not match, or the parent and field both
|
|
|
|
|
// match the type.
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
This is the case where the parent variable was not the correct type, but we need to see
|
|
|
|
|
if the field itself is the type we seek. I believe this comment describes this case:
|
|
|
|
|
|
|
|
|
|
// check for the case where the given 'field' may be the type we seek, such as in an if
|
|
|
|
|
// statement like this:
|
|
|
|
|
// if (color == RED)
|
|
|
|
|
// where 'RED' is the variable we are checking
|
|
|
|
|
*/
|
|
|
|
|
HighVariable highVariable = parent.variable.getHighVariable();
|
|
|
|
|
if (highVariable == null) {
|
|
|
|
|
return null; // not sure of the significance of this check
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!matchesParentType(field, dt)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String fieldName = field.getName();
|
|
|
|
|
int offset = field.getOffset();
|
|
|
|
|
if (fieldMatcher.matches(fieldName, offset)) {
|
|
|
|
|
// the field matches the type and the name
|
|
|
|
|
return createReference(field, field, fieldMatcher);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DataTypeReference createReferenceWhenVariableAndFieldMatch(DataType dt,
|
|
|
|
|
DecompilerVariable parent, DecompilerVariable field, FieldMatcher fieldMatcher) {
|
|
|
|
|
|
|
|
|
|
// This is an odd case where both the parent and the field have the same type. This may be
|
|
|
|
|
// valid, such as when a structure contains a reference to itself. But, this also can
|
|
|
|
|
// happen when the decompiler makes mistakes when setting the data type.
|
|
|
|
|
DecompilerVariable var = getMatchingVariable(dt, parent);
|
|
|
|
|
if (var == null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String name = field.getName();
|
|
|
|
|
int offset = field.getOffset();
|
|
|
|
|
if (!fieldMatcher.matches(name, offset)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isFieldTheBetterMatch(var, field)) {
|
|
|
|
|
// this implies a self-referential structure; create a reference to the field
|
|
|
|
|
return createReference(field, field, fieldMatcher);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// At this point, the parent matches the data type, but the field itself is not actually
|
|
|
|
|
// a data type match. Also, since we checked above, we know the field name matches. Create
|
|
|
|
|
// a standard reference.
|
|
|
|
|
return createReference(var, field, fieldMatcher);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DecompilerVariable getMatch(DataType dt, FieldMatcher fieldMatcher,
|
|
|
|
|
DecompilerVariable var, DecompilerVariable potentialField) {
|
|
|
|
|
DecompilerVariable var) {
|
|
|
|
|
|
|
|
|
|
String indent = "\t\t\t";
|
|
|
|
|
|
|
|
|
|
// Note: for now, I ignore the precedence of casting; if any cast type is a match, then
|
|
|
|
|
// signal hooray
|
|
|
|
|
boolean searchForField = !fieldMatcher.isIgnored();
|
|
|
|
|
DecompilerVariable fieldVar = searchForField ? potentialField : null;
|
|
|
|
|
DecompilerVariable match = getMatchingVarialbe(dt, var, fieldVar);
|
|
|
|
|
DecompilerVariable match = getMatchingVariable(dt, var);
|
|
|
|
|
if (match == null) {
|
|
|
|
|
DtrfDbg.println(getFunction(), this, indent + "NO MATCHING VARIABLE");
|
|
|
|
|
return null; // wrong type, nothing to do
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Matches on the type, does the field match?
|
|
|
|
|
if (fieldMatcher.isIgnored()) {
|
|
|
|
|
DtrfDbg.println(getFunction(), this,
|
|
|
|
|
indent + "field macher is ignored; returning match");
|
|
|
|
|
return match; // no field to match
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (potentialField == null) {
|
|
|
|
|
|
|
|
|
|
DtrfDbg.println(getFunction(), this,
|
|
|
|
|
indent + "No potential field to match; name / offset match?");
|
|
|
|
|
|
|
|
|
|
// check for the case where we have not been passed a 'potential field', but the given
|
|
|
|
|
// 'var' is itself may be the field we seek, such as in an if statement like this:
|
|
|
|
|
// if (color == RED)
|
|
|
|
|
// where 'RED' is the variable we are checking
|
|
|
|
|
String name = var.getName();
|
|
|
|
|
int offset = var.getOffset();
|
|
|
|
|
if (fieldMatcher.matches(name, offset)) {
|
|
|
|
|
StringUtilities.indentLines(var.toString(), indent + '\t');
|
|
|
|
|
DtrfDbg.println(getFunction(), this,
|
|
|
|
|
indent + "\tfield matcher matched on variable: " + var);
|
|
|
|
|
return var;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DtrfDbg.println(getFunction(), this, indent + "\tNO FIELD MATCHER MATCH");
|
|
|
|
|
return null; // we seek a field, but there is none
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DtrfDbg.println(getFunction(), this, indent + "Checking 'potential field' match...");
|
|
|
|
|
|
|
|
|
|
String name = potentialField.getName();
|
|
|
|
|
int offset = potentialField.getOffset();
|
|
|
|
|
// check for the case where we have not been passed a 'potential field', but the given
|
|
|
|
|
// 'var' is itself may be the field we seek, such as in an if statement like this:
|
|
|
|
|
// if (color == RED)
|
|
|
|
|
// where 'RED' is the variable we are checking
|
|
|
|
|
String name = var.getName();
|
|
|
|
|
int offset = var.getOffset();
|
|
|
|
|
if (fieldMatcher.matches(name, offset)) {
|
|
|
|
|
DtrfDbg.println(getFunction(), this, indent + "\tMATCHED");
|
|
|
|
|
return match;
|
|
|
|
|
StringUtilities.indentLines(var.toString(), indent + '\t');
|
|
|
|
|
DtrfDbg.println(getFunction(), this,
|
|
|
|
|
indent + "\tfield matcher matched on variable: " + var);
|
|
|
|
|
return var;
|
|
|
|
|
}
|
|
|
|
|
DtrfDbg.println(getFunction(), this, indent + "\tNO MATCH");
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
DtrfDbg.println(getFunction(), this, indent + "\tNO FIELD MATCHER MATCH");
|
|
|
|
|
return null; // we seek a field, but there is none
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DecompilerVariable getMatchingVarialbe(DataType dt, DecompilerVariable var,
|
|
|
|
|
DecompilerVariable potentialField) {
|
|
|
|
|
// return the first matching cast for the given variable, if any
|
|
|
|
|
private DecompilerVariable getFirstMatchingCast(DataType dt, DecompilerVariable var) {
|
|
|
|
|
|
|
|
|
|
String indent = "\t\t\t";
|
|
|
|
|
|
|
|
|
|
DtrfDbg.println(getFunction(), this, indent + "Checking for matching variable; any casts?");
|
|
|
|
|
DtrfDbg.println(getFunction(), this, indent +
|
|
|
|
|
"Checking for matching variable (no fields); any casts?");
|
|
|
|
|
List<DecompilerVariable> castVariables = var.getCasts();
|
|
|
|
|
for (DecompilerVariable cast : castVariables) {
|
|
|
|
|
if (matchesType(cast, dt)) {
|
|
|
|
|
@@ -168,6 +372,20 @@ public class VariableAccessDR extends DecompilerReference {
|
|
|
|
|
return cast;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DecompilerVariable getMatchingVariable(DataType dt, DecompilerVariable var) {
|
|
|
|
|
|
|
|
|
|
String indent = "\t\t\t";
|
|
|
|
|
|
|
|
|
|
// Note: for now, we ignore the precedence of casting; if any cast type is a match, then
|
|
|
|
|
// signal hooray
|
|
|
|
|
DecompilerVariable cast = getFirstMatchingCast(dt, var);
|
|
|
|
|
if (cast != null) {
|
|
|
|
|
// assume that any match in the cast implies we will not match a variable access
|
|
|
|
|
return cast;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String dtString = dt == null ? "null" : dt.toString();
|
|
|
|
|
DtrfDbg.println(getFunction(), this,
|
|
|
|
|
@@ -178,29 +396,6 @@ public class VariableAccessDR extends DecompilerReference {
|
|
|
|
|
DtrfDbg.println(getFunction(), this, indent + "MATCHED type: ");
|
|
|
|
|
return var;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DtrfDbg.println(getFunction(), this,
|
|
|
|
|
indent + "Type did not match; checking High Variable: ");
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Unusual Code Alert!
|
|
|
|
|
// It is a bit odd to check the field when you are looking for the type that contains the
|
|
|
|
|
// field. BUT, in the Decompiler, SOMETIMES the 'field' happens to have the data type of
|
|
|
|
|
// the thing that contains it. So, if you have:
|
|
|
|
|
// foo.bar
|
|
|
|
|
// then the 'bar' field will have a data type of Foo. Unfortunately, this is not always
|
|
|
|
|
// the case. For now, if there is a high variable, we need to check the field. Sad face
|
|
|
|
|
// emoji.
|
|
|
|
|
//
|
|
|
|
|
HighVariable highVariable = var.variable.getHighVariable();
|
|
|
|
|
if (highVariable != null) {
|
|
|
|
|
if (matchesParentType(potentialField, dt)) {
|
|
|
|
|
DtrfDbg.println(getFunction(), this, indent + "MATCHED on parent type: " + dt);
|
|
|
|
|
return potentialField;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DtrfDbg.println(getFunction(), this, indent + "NOT MATCHED");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -227,37 +422,70 @@ public class VariableAccessDR extends DecompilerReference {
|
|
|
|
|
if (varType == null) {
|
|
|
|
|
// it seems odd to me that there is no type, but I have seen this in the case
|
|
|
|
|
// statement of a switch
|
|
|
|
|
DtrfDbg.println(getFunction(), this, indent + "ypes Match? no variable TYPE to check");
|
|
|
|
|
DtrfDbg.println(getFunction(), this, indent + "Types Match? no variable TYPE to check");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
boolean matches = isEqual(varType, dt);
|
|
|
|
|
return matches;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected DataTypeReference createReference(DecompilerVariable var, String fieldName) {
|
|
|
|
|
|
|
|
|
|
protected DataTypeReference createReferenceToVariable(DecompilerVariable var,
|
|
|
|
|
String fieldName) {
|
|
|
|
|
DataType dataType = var.getDataType();
|
|
|
|
|
SearchLocationContext context = getContext(var);
|
|
|
|
|
SearchLocationContext context = getContextForVariable(var);
|
|
|
|
|
Function function = var.getFunction();
|
|
|
|
|
Address address = getAddress(var);
|
|
|
|
|
return new DataTypeReference(dataType, fieldName, function, address, context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DataTypeReference createReference(DecompilerVariable var, DecompilerVariable field) {
|
|
|
|
|
protected DataTypeReference createReferenceToField(DecompilerVariable field,
|
|
|
|
|
String fieldName) {
|
|
|
|
|
DataType dataType = field.getDataType();
|
|
|
|
|
SearchLocationContext context = getContextForField(field);
|
|
|
|
|
Function function = field.getFunction();
|
|
|
|
|
Address address = getAddress(field);
|
|
|
|
|
return new DataTypeReference(dataType, fieldName, function, address, context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DataTypeReference createReference(DecompilerVariable var, DecompilerVariable field,
|
|
|
|
|
FieldMatcher fieldMatcher) {
|
|
|
|
|
DataType dataType = var.getDataType();
|
|
|
|
|
SearchLocationContext context = getContext(var);
|
|
|
|
|
SearchLocationContext context = getContext(var, fieldMatcher);
|
|
|
|
|
Function function = var.getFunction();
|
|
|
|
|
Address address = getAddress(var);
|
|
|
|
|
return new DataTypeReference(dataType, field.getName(), function, address, context);
|
|
|
|
|
String fieldName = field != null ? field.getName() : null;
|
|
|
|
|
return new DataTypeReference(dataType, fieldName, function, address, context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected SearchLocationContext getContext(DecompilerVariable var) {
|
|
|
|
|
// Default to highlighting the field that is being called on the given variable. Clients of
|
|
|
|
|
// this method may choose to highlight the variable itself, in which case they should call
|
|
|
|
|
// getContextForVariable(var).
|
|
|
|
|
return getContextForField(var);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private SearchLocationContext getContextForVariable(DecompilerVariable var) {
|
|
|
|
|
return super.getContext(var);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected SearchLocationContext getContextForField(DecompilerVariable var) {
|
|
|
|
|
DecompilerVariable field = findFieldFor(var);
|
|
|
|
|
SearchLocationContext context = super.getContext(field);
|
|
|
|
|
return context;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected SearchLocationContext getContext(DecompilerVariable var, FieldMatcher fieldMatcher) {
|
|
|
|
|
if (fieldMatcher.isIgnored()) {
|
|
|
|
|
// when there is not field to match, we only want to highlight the variable itself
|
|
|
|
|
return super.getContext(var);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// assume that a valid field matcher means that we have already matched before this call,
|
|
|
|
|
// so use the matching field for the context highlight
|
|
|
|
|
return getContextForField(var);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DecompilerVariable findFieldFor(DecompilerVariable var) {
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
@@ -308,6 +536,10 @@ public class VariableAccessDR extends DecompilerReference {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String toString() {
|
|
|
|
|
if (variable == null) {
|
|
|
|
|
return "<uninialized>";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String subFieldsString = fields.isEmpty() ? ""
|
|
|
|
|
: "\tsub fields: " + StringUtilities.toStringWithIndent(fields) + ",\n";
|
|
|
|
|
|
|
|
|
|
|