diff --git a/Ghidra/Features/Base/src/main/help/help/topics/SymbolTreePlugin/SymbolTree.htm b/Ghidra/Features/Base/src/main/help/help/topics/SymbolTreePlugin/SymbolTree.htm index cbf1d7a164..fdd9fefb87 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/SymbolTreePlugin/SymbolTree.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/SymbolTreePlugin/SymbolTree.htm @@ -184,6 +184,13 @@
Shows all locations that reference the given symbol.
+++You can convert a Namespace to a Class. + Right mouse click on a namespace and choose the Convert To Class option.
+
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/ConvertToClassAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/ConvertToClassAction.java index 00efa2b857..6d69e1582e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/ConvertToClassAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/ConvertToClassAction.java @@ -16,11 +16,16 @@ import ghidra.util.exception.InvalidInputException; import docking.action.MenuData; import docking.widgets.tree.GTreeNode; +/** + * Symbol tree action for converting a namespace to a class + */ public class ConvertToClassAction extends SymbolTreeContextAction { + private static final String NAME = "Convert To Class"; + public ConvertToClassAction(SymbolTreePlugin plugin) { - super("Convert To Class", plugin.getName()); - setPopupMenuData(new MenuData(new String[] { "Convert To Class" }, "0Create")); + super(NAME, plugin.getName()); + setPopupMenuData(new MenuData(new String[] { NAME }, "1Convert")); setEnabled(false); } @@ -47,25 +52,24 @@ public class ConvertToClassAction extends SymbolTreeContextAction { Program program = context.getProgram(); GTreeNode node = (GTreeNode) selectionPaths[0].getLastPathComponent(); - if (node instanceof SymbolNode) { - Symbol symbol = ((SymbolNode) node).getSymbol(); - Namespace parent = (Namespace) symbol.getObject(); - if (parent != null) { - convertToClass(program, parent); - program.flushEvents(); - context.getSymbolTree().startEditing(node, parent.getName()); - } + Symbol symbol = ((SymbolNode) node).getSymbol(); + Namespace parent = (Namespace) symbol.getObject(); + if (parent != null) { + convertToClass(program, parent); + program.flushEvents(); + context.getSymbolTree().startEditing(node, parent.getName()); } } private static void convertToClass(Program program, Namespace ns) { - int id = program.startTransaction("Convert To Class"); + int id = program.startTransaction(NAME); boolean success = false; try { NamespaceUtils.convertNamespaceToClass(ns); success = true; } catch (InvalidInputException e) { - // can't occur, checked in isEnabledForContext + // This is thrown when the provided namespace is a function + // It was checked in isEnabledForContext and thus cannot occur throw new AssertException(e); } finally { program.endTransaction(id, success); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symboltree/SymbolTreePlugin2Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symboltree/SymbolTreePlugin2Test.java index 7a023be384..c8bdc6d797 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symboltree/SymbolTreePlugin2Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/symboltree/SymbolTreePlugin2Test.java @@ -62,6 +62,7 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest { private DockingActionIf selectionAction; private DockingActionIf createNamespaceAction; private DockingActionIf createClassAction; + private DockingActionIf convertToClassAction; private ToggleDockingAction goToToggleAction; private SymbolTreeTestUtils util; private SymbolGTree tree; @@ -295,6 +296,22 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest { } + @Test + public void testConvertToClass() throws Exception { + String classNodeName = "MyClass"; + GTreeNode nsParentNode = rootNode.getChild(5); + GTreeNode classNode = util.createObject( + nsParentNode, classNodeName, createNamespaceAction); + + util.selectNode(classNode); + ActionContext context = util.getSymbolTreeContext(); + performTreeAction(convertToClassAction, context); + + nsParentNode = rootNode.getChild(4); + classNode = nsParentNode.getChild(classNodeName); + assertNotNull(classNode); + } + private void performTreeAction(DockingActionIf action, ActionContext context) { assertTrue(action.isEnabledForContext(context)); performAction(action, context, true); @@ -421,6 +438,8 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest { assertNotNull(createClassAction); createNamespaceAction = getAction(plugin, "Create Namespace"); assertNotNull(createNamespaceAction); + convertToClassAction = getAction(plugin, "Convert To Class"); + assertNotNull(convertToClassAction); goToToggleAction = (ToggleDockingAction) getAction(plugin, "Navigation"); assertNotNull(goToToggleAction);