Merge remote-tracking branch 'origin/GT-2956_caheckman_RetypeVariableAction'

This commit is contained in:
Ryan Kurtz 2019-07-02 12:07:59 -04:00
commit 8e78f72827

View file

@ -77,8 +77,9 @@ public class RetypeVariableAction extends DockingAction {
} }
if (tokenAtCursor instanceof ClangFieldToken) { if (tokenAtCursor instanceof ClangFieldToken) {
DataType dt = RenameVariableAction.getStructDataType(tokenAtCursor); DataType dt = RenameVariableAction.getStructDataType(tokenAtCursor);
if (dt == null) if (dt == null) {
return false; return false;
}
getPopupMenuData().setMenuItemName("Retype Field"); getPopupMenuData().setMenuItemName("Retype Field");
return true; return true;
} }
@ -92,11 +93,13 @@ public class RetypeVariableAction extends DockingAction {
HighVariable variable = tokenAtCursor.getHighVariable(); HighVariable variable = tokenAtCursor.getHighVariable();
if (variable == null) { if (variable == null) {
Address addr = RenameVariableAction.getStorageAddress(tokenAtCursor, controller); Address addr = RenameVariableAction.getStorageAddress(tokenAtCursor, controller);
if (addr == null) if (addr == null) {
return false; return false;
}
variable = RenameVariableAction.forgeHighVariable(addr, controller); variable = RenameVariableAction.forgeHighVariable(addr, controller);
if (variable == null) if (variable == null) {
return false; return false;
}
} }
if (variable instanceof HighConstant) { if (variable instanceof HighConstant) {
// getPopupMenuData().setMenuItemName("Retype Constant"); // getPopupMenuData().setMenuItemName("Retype Constant");
@ -146,10 +149,12 @@ public class RetypeVariableAction extends DockingAction {
return; return;
} }
comp = struct.getComponentAt(offset); comp = struct.getComponentAt(offset);
if (comp == null) if (comp == null) {
dataType = chooseDataType(DataType.DEFAULT); dataType = chooseDataType(DataType.DEFAULT);
else }
else {
dataType = chooseDataType(comp.getDataType()); dataType = chooseDataType(comp.getDataType());
}
} }
else if (tokenAtCursor.Parent() instanceof ClangReturnType) { else if (tokenAtCursor.Parent() instanceof ClangReturnType) {
ClangReturnType parent = (ClangReturnType) tokenAtCursor.Parent(); ClangReturnType parent = (ClangReturnType) tokenAtCursor.Parent();
@ -164,24 +169,30 @@ public class RetypeVariableAction extends DockingAction {
variable = tokenAtCursor.getHighVariable(); variable = tokenAtCursor.getHighVariable();
if (variable == null) { if (variable == null) {
Address addr = RenameVariableAction.getStorageAddress(tokenAtCursor, controller); Address addr = RenameVariableAction.getStorageAddress(tokenAtCursor, controller);
if (addr == null) if (addr == null) {
return; return;
}
variable = RenameVariableAction.forgeHighVariable(addr, controller); variable = RenameVariableAction.forgeHighVariable(addr, controller);
if (variable == null) if (variable == null) {
return; return;
}
} }
dataType = chooseDataType(variable.getDataType()); dataType = chooseDataType(variable.getDataType());
} }
if (dataType == null) if (dataType == null) {
return; return;
if (struct != null) }
if (struct != null) {
retypeStructVariable(struct, comp, dataType); retypeStructVariable(struct, comp, dataType);
else }
else {
retypeVariable(variable, tokenAtCursor.getVarnode(), dataType); retypeVariable(variable, tokenAtCursor.getVarnode(), dataType);
}
} }
private void retypeReturnType(DataType dataType, ClangReturnType parent) { private void retypeReturnType(DataType dataType, ClangReturnType parent) {
Program program = controller.getProgram(); Program program = controller.getProgram();
DataTypeManager dataTypeManager = program.getDataTypeManager();
HighFunction hfunction = getHighFunctionFromReturnTypeToken(parent); HighFunction hfunction = getHighFunctionFromReturnTypeToken(parent);
if (hfunction == null) { if (hfunction == null) {
return; return;
@ -199,8 +210,12 @@ public class RetypeVariableAction extends DockingAction {
} }
} }
Function function = hfunction.getFunction(); Function function = hfunction.getFunction();
boolean successfulMod = false;
int transactionID = program.startTransaction("Retype return type"); int transactionID = program.startTransaction("Retype return type");
try { try {
if (dataType.getDataTypeManager() != dataTypeManager) {
dataType = dataTypeManager.resolve(dataType, null);
}
if (commitRequired) { if (commitRequired) {
try { try {
HighFunctionDBUtil.commitParamsToDatabase(hfunction, true, HighFunctionDBUtil.commitParamsToDatabase(hfunction, true,
@ -214,12 +229,13 @@ public class RetypeVariableAction extends DockingAction {
} }
} }
function.setReturnType(dataType, SourceType.USER_DEFINED); function.setReturnType(dataType, SourceType.USER_DEFINED);
successfulMod = true;
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
Msg.showError(this, tool.getToolFrame(), "Retype Failed", Msg.showError(this, tool.getToolFrame(), "Retype Failed",
"Failed to re-type return type '" + getName() + "': " + e.getMessage()); "Failed to re-type return type '" + getName() + "': " + e.getMessage());
} }
program.endTransaction(transactionID, true); program.endTransaction(transactionID, successfulMod);
} }
private HighFunction getHighFunctionFromReturnTypeToken(ClangReturnType returnType) { private HighFunction getHighFunctionFromReturnTypeToken(ClangReturnType returnType) {
@ -278,8 +294,13 @@ public class RetypeVariableAction extends DockingAction {
} }
} }
Program program = controller.getProgram(); Program program = controller.getProgram();
DataTypeManager dataTypeManager = program.getDataTypeManager();
boolean successfulMod = false;
int transaction = program.startTransaction("Retype Variable"); int transaction = program.startTransaction("Retype Variable");
try { try {
if (dt.getDataTypeManager() != dataTypeManager) {
dt = dataTypeManager.resolve(dt, null);
}
if (commitRequired) { if (commitRequired) {
try { try {
HighFunctionDBUtil.commitParamsToDatabase(hfunction, true, HighFunctionDBUtil.commitParamsToDatabase(hfunction, true,
@ -294,6 +315,7 @@ public class RetypeVariableAction extends DockingAction {
} }
} }
HighFunctionDBUtil.updateDBVariable(var, null, dt, SourceType.USER_DEFINED); HighFunctionDBUtil.updateDBVariable(var, null, dt, SourceType.USER_DEFINED);
successfulMod = true;
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
throw new AssertException("Unexpected exception", e); throw new AssertException("Unexpected exception", e);
@ -303,7 +325,7 @@ public class RetypeVariableAction extends DockingAction {
"Failed to re-type variable '" + var.getName() + "': " + e.getMessage()); "Failed to re-type variable '" + var.getName() + "': " + e.getMessage());
} }
finally { finally {
program.endTransaction(transaction, true); program.endTransaction(transaction, successfulMod);
} }
} }
@ -317,17 +339,17 @@ public class RetypeVariableAction extends DockingAction {
*/ */
private int getEndComponentIndex(Structure struct, DataTypeComponent comp, DataType newtype) { private int getEndComponentIndex(Structure struct, DataTypeComponent comp, DataType newtype) {
int newlen = newtype.getLength(); int newlen = newtype.getLength();
if (newlen <= 0) if (newlen <= 0) {
return -1; // Don't support variable length types return -1; // Don't support variable length types
}
DataType curtype = comp.getDataType(); DataType curtype = comp.getDataType();
newlen -= curtype.getLength(); newlen -= curtype.getLength();
if (newlen < 0)
return -1; // new size is smaller than original size
int index = comp.getOrdinal(); int index = comp.getOrdinal();
while (newlen > 0) { while (newlen > 0) {
index += 1; index += 1;
if (index >= struct.getNumComponents()) if (index >= struct.getNumComponents()) {
return -1; // Not enough space in the structure return -1; // Not enough space in the structure
}
comp = struct.getComponent(index); comp = struct.getComponent(index);
// String nm = comp.getFieldName(); // String nm = comp.getFieldName();
// if ((nm !=null)&&(nm.length()!=0)) // if ((nm !=null)&&(nm.length()!=0))
@ -335,17 +357,18 @@ public class RetypeVariableAction extends DockingAction {
curtype = comp.getDataType(); curtype = comp.getDataType();
// if (!Undefined.isUndefined(curtype)) // if (!Undefined.isUndefined(curtype))
// return -1; // Overlaps non-undefined datatype // return -1; // Overlaps non-undefined datatype
if (curtype != DataType.DEFAULT) if (curtype != DataType.DEFAULT) {
return -1; // Only allow overwrite of placeholder components return -1; // Only allow overwrite of placeholder components
}
newlen -= curtype.getLength(); newlen -= curtype.getLength();
} }
if (newlen < 0)
return -1; // Partial field
return index; return index;
} }
private void retypeStructVariable(Structure dt, DataTypeComponent comp, DataType newtype) { private void retypeStructVariable(Structure dt, DataTypeComponent comp, DataType newtype) {
Program program = controller.getProgram(); Program program = controller.getProgram();
DataTypeManager dataTypeManager = program.getDataTypeManager();
boolean successfulMod = false;
if (comp == null) { if (comp == null) {
if (!dt.isNotYetDefined()) { if (!dt.isNotYetDefined()) {
Msg.showError(this, tool.getToolFrame(), "Retype Failed", Msg.showError(this, tool.getToolFrame(), "Retype Failed",
@ -355,72 +378,90 @@ public class RetypeVariableAction extends DockingAction {
// note if we reach here the offset must be zero, so assume we are inserting newtype // note if we reach here the offset must be zero, so assume we are inserting newtype
int transaction = program.startTransaction("Retype Structure Field"); int transaction = program.startTransaction("Retype Structure Field");
try { try {
// Make sure datatype is using the program's data organization before testing fit
if (newtype.getDataTypeManager() != dataTypeManager) {
newtype = dataTypeManager.resolve(newtype, null);
}
dt.insert(0, newtype); dt.insert(0, newtype);
successfulMod = true;
} }
finally { finally {
program.endTransaction(transaction, true); program.endTransaction(transaction, successfulMod);
} }
return; return;
} }
int startind = comp.getOrdinal();
int endind = getEndComponentIndex(dt, comp, newtype);
if (endind < 0) {
Msg.showError(this, tool.getToolFrame(), "Retype Failed",
"Failed to re-type structure '" + dt.getName() + "': Datatype did not fit");
return;
}
int transaction = program.startTransaction("Retype Structure Field"); int transaction = program.startTransaction("Retype Structure Field");
try { try {
// Make sure datatype is using the program's data organization before testing fit
if (newtype.getDataTypeManager() != dataTypeManager) {
newtype = dataTypeManager.resolve(newtype, null);
}
int startind = comp.getOrdinal();
int endind = getEndComponentIndex(dt, comp, newtype);
if (endind < 0) {
Msg.showError(this, tool.getToolFrame(), "Retype Failed",
"Failed to re-type structure '" + dt.getName() + "': Datatype did not fit");
return;
}
for (int i = endind; i > startind; --i) { // Clear all but first field for (int i = endind; i > startind; --i) { // Clear all but first field
dt.clearComponent(i); dt.clearComponent(i);
} }
dt.replaceAtOffset(comp.getOffset(), newtype, newtype.getLength(), comp.getFieldName(), dt.replaceAtOffset(comp.getOffset(), newtype, newtype.getLength(), comp.getFieldName(),
comp.getComment()); comp.getComment());
successfulMod = true;
} }
finally { finally {
program.endTransaction(transaction, true); program.endTransaction(transaction, successfulMod);
} }
} }
/** /**
* Compare a HighFunction's idea of what the signature is versus what the underlying Function thinks * Compare the given HighFunction's idea of the prototype with the Function's idea.
* and returns true if there is a difference. If all the input parameters have the same storage and type, * Return true if there is a difference. If a specific parameter is being changed,
* @param var * it can be passed in indicating that slot can be skipped during the comparison.
* @param hfunction * @param var (if not null) is a specific parameter to skip the check for
* @return true if a full commit is required * @param hfunction is the given HighFunction
* @return true if there is a difference (and a full commit is required)
*/ */
public static boolean checkFullCommit(HighVariable var, HighFunction hfunction) { public static boolean checkFullCommit(HighVariable var, HighFunction hfunction) {
if ((var != null) && (!(var instanceof HighParam))) if ((var != null) && (!(var instanceof HighParam))) {
return false; return false;
}
Function function = hfunction.getFunction(); Function function = hfunction.getFunction();
Parameter[] parameters = function.getParameters(); Parameter[] parameters = function.getParameters();
LocalSymbolMap localSymbolMap = hfunction.getLocalSymbolMap(); LocalSymbolMap localSymbolMap = hfunction.getLocalSymbolMap();
int numParams = localSymbolMap.getNumParams(); int numParams = localSymbolMap.getNumParams();
if (numParams != parameters.length) if (numParams != parameters.length) {
return true; return true;
}
int skipslot = -1; int skipslot = -1;
if (var != null) if (var != null) {
skipslot = ((HighParam) var).getSlot(); skipslot = ((HighParam) var).getSlot();
}
for (int i = 0; i < numParams; i++) { for (int i = 0; i < numParams; i++) {
HighParam param = localSymbolMap.getParam(i); HighParam param = localSymbolMap.getParam(i);
if (param.getSlot() != i) // Slot must match if (param.getSlot() != i) {
return true; return true;
}
VariableStorage storage = param.getStorage(); VariableStorage storage = param.getStorage();
if (!storage.equals(parameters[i].getVariableStorage())) // Storage must match if (!storage.equals(parameters[i].getVariableStorage())) {
return true; return true;
}
if (skipslot != i) { // Compare datatypes unless it is the specific -var- we are skipping if (skipslot != i) { // Compare datatypes unless it is the specific -var- we are skipping
if (!param.getDataType().isEquivalent(parameters[i].getDataType())) if (!param.getDataType().isEquivalent(parameters[i].getDataType())) {
return true; return true;
}
} }
} }
if (var != null) { // A null var indicates we are changing the returntype anyway, so we don't need to check it if (var != null) { // A null var indicates we are changing the return type anyway, so we don't need to check it
DataType funcReturnType = function.getReturnType(); DataType funcReturnType = function.getReturnType();
if (funcReturnType != DataType.DEFAULT) { if (funcReturnType != DataType.DEFAULT) {
DataType hfuncReturnType = hfunction.getFunctionPrototype().getReturnType(); DataType hfuncReturnType = hfunction.getFunctionPrototype().getReturnType();
if (!funcReturnType.equals(hfuncReturnType)) if (!funcReturnType.equals(hfuncReturnType)) {
return true; return true;
}
} }
} }