From bdf19b5691342567d3fc63769d784243b12e77e0 Mon Sep 17 00:00:00 2001 From: astrelsky Date: Thu, 24 Sep 2020 14:51:35 -0400 Subject: [PATCH 1/3] Added ConvertToClassAction --- .../core/symboltree/SymbolTreeProvider.java | 2 + .../actions/ConvertToClassAction.java | 75 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/ConvertToClassAction.java diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java index 349011a304..1189c9f80d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java @@ -208,6 +208,7 @@ public class SymbolTreeProvider extends ComponentProviderAdapter { DockingAction editExternalLocationAction = new EditExternalLocationAction(plugin); DockingAction createClassAction = new CreateClassAction(plugin); DockingAction createNamespaceAction = new CreateNamespaceAction(plugin); + DockingAction convertToClassAction = new ConvertToClassAction(plugin); DockingAction renameAction = new RenameAction(plugin); DockingAction cutAction = new CutAction(plugin, this); @@ -231,6 +232,7 @@ public class SymbolTreeProvider extends ComponentProviderAdapter { tool.addLocalAction(this, editExternalLocationAction); tool.addLocalAction(this, createClassAction); tool.addLocalAction(this, createNamespaceAction); + tool.addLocalAction(this, convertToClassAction); tool.addLocalAction(this, renameAction); tool.addLocalAction(this, cutAction); tool.addLocalAction(this, pasteAction); 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 new file mode 100644 index 0000000000..00efa2b857 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/ConvertToClassAction.java @@ -0,0 +1,75 @@ +package ghidra.app.plugin.core.symboltree.actions; + +import javax.swing.tree.TreePath; + +import ghidra.app.plugin.core.symboltree.SymbolTreeActionContext; +import ghidra.app.plugin.core.symboltree.SymbolTreePlugin; +import ghidra.app.plugin.core.symboltree.nodes.SymbolNode; +import ghidra.app.util.NamespaceUtils; +import ghidra.program.model.listing.Program; +import ghidra.program.model.symbol.Namespace; +import ghidra.program.model.symbol.Symbol; +import ghidra.program.model.symbol.SymbolType; +import ghidra.util.exception.AssertException; +import ghidra.util.exception.InvalidInputException; + +import docking.action.MenuData; +import docking.widgets.tree.GTreeNode; + +public class ConvertToClassAction extends SymbolTreeContextAction { + + public ConvertToClassAction(SymbolTreePlugin plugin) { + super("Convert To Class", plugin.getName()); + setPopupMenuData(new MenuData(new String[] { "Convert To Class" }, "0Create")); + setEnabled(false); + } + + @Override + public boolean isEnabledForContext(SymbolTreeActionContext context) { + TreePath[] selectionPaths = context.getSelectedSymbolTreePaths(); + if (selectionPaths.length != 1) { + return false; + } + + Object object = selectionPaths[0].getLastPathComponent(); + if (object instanceof SymbolNode) { + SymbolNode symbolNode = (SymbolNode) object; + Symbol symbol = symbolNode.getSymbol(); + return symbol.getSymbolType() == SymbolType.NAMESPACE; + } + return false; + } + + @Override + protected void actionPerformed(SymbolTreeActionContext context) { + TreePath[] selectionPaths = context.getSelectedSymbolTreePaths(); + + 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()); + } + } + } + + private static void convertToClass(Program program, Namespace ns) { + int id = program.startTransaction("Convert To Class"); + boolean success = false; + try { + NamespaceUtils.convertNamespaceToClass(ns); + success = true; + } catch (InvalidInputException e) { + // can't occur, checked in isEnabledForContext + throw new AssertException(e); + } finally { + program.endTransaction(id, success); + } + } + +} From 239f400fe1f17f73e184388be0447bca55da57a4 Mon Sep 17 00:00:00 2001 From: astrelsky Date: Sun, 4 Oct 2020 19:12:39 -0400 Subject: [PATCH 2/3] Added ConvertToClassAction help documentation and tests --- .../topics/SymbolTreePlugin/SymbolTree.htm | 7 +++++ .../actions/ConvertToClassAction.java | 28 +++++++++++-------- .../symboltree/SymbolTreePlugin2Test.java | 19 +++++++++++++ 3 files changed, 42 insertions(+), 12 deletions(-) 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.

+

Convert Namespace to Class

+ +
+

You can convert a Namespace to a Class. + Right mouse click on a namespace and choose the Convert To Class option.

+
+

Create a Class

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); From 54a5843703b7c9555fd5abdc64d273a60a9178cc Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Mon, 5 Oct 2020 14:13:37 -0400 Subject: [PATCH 3/3] GP-225 - Convert to Class Action --- .../topics/SymbolTreePlugin/SymbolTree.htm | 2 +- .../core/symboltree/SymbolTreeProvider.java | 12 +++- .../actions/ConvertToClassAction.java | 54 ++++++++++----- .../symboltree/actions/CreateClassAction.java | 40 ++++++----- .../actions/CreateNamespaceAction.java | 6 +- .../symboltree/SymbolTreePlugin2Test.java | 67 ++++++++----------- 6 files changed, 102 insertions(+), 79 deletions(-) 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 fdd9fefb87..d09178d123 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,7 +184,7 @@

Shows all locations that reference the given symbol.

-

Convert Namespace to Class

+

Convert Namespace to Class

You can convert a Namespace to a Class. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java index 1189c9f80d..ab81ad4a09 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java @@ -206,9 +206,15 @@ public class SymbolTreeProvider extends ComponentProviderAdapter { DockingAction setExternalProgramAction = new SetExternalProgramAction(plugin, this); DockingAction createExternalLocationAction = new CreateExternalLocationAction(plugin); DockingAction editExternalLocationAction = new EditExternalLocationAction(plugin); - DockingAction createClassAction = new CreateClassAction(plugin); - DockingAction createNamespaceAction = new CreateNamespaceAction(plugin); - DockingAction convertToClassAction = new ConvertToClassAction(plugin); + + String createGroup = "0Create"; + int createGroupIndex = 0; + DockingAction createNamespaceAction = new CreateNamespaceAction(plugin, createGroup, + Integer.toString(createGroupIndex++)); + DockingAction createClassAction = new CreateClassAction(plugin, createGroup, + Integer.toString(createGroupIndex++)); + DockingAction convertToClassAction = new ConvertToClassAction(plugin, createGroup, + Integer.toString(createGroupIndex++)); DockingAction renameAction = new RenameAction(plugin); DockingAction cutAction = new CutAction(plugin, this); 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 6d69e1582e..935715b2ba 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 @@ -1,31 +1,44 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package ghidra.app.plugin.core.symboltree.actions; import javax.swing.tree.TreePath; -import ghidra.app.plugin.core.symboltree.SymbolTreeActionContext; -import ghidra.app.plugin.core.symboltree.SymbolTreePlugin; +import docking.action.MenuData; +import docking.widgets.tree.GTreeNode; +import ghidra.app.plugin.core.symboltree.*; import ghidra.app.plugin.core.symboltree.nodes.SymbolNode; import ghidra.app.util.NamespaceUtils; import ghidra.program.model.listing.Program; -import ghidra.program.model.symbol.Namespace; -import ghidra.program.model.symbol.Symbol; -import ghidra.program.model.symbol.SymbolType; +import ghidra.program.model.symbol.*; import ghidra.util.exception.AssertException; 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"; + private static final String NAME = "Convert to Class"; - public ConvertToClassAction(SymbolTreePlugin plugin) { + public ConvertToClassAction(SymbolTreePlugin plugin, String group, String subGroup) { super(NAME, plugin.getName()); - setPopupMenuData(new MenuData(new String[] { NAME }, "1Convert")); + MenuData menuData = new MenuData(new String[] { NAME }, group); + menuData.setMenuSubGroup(subGroup); + setPopupMenuData(menuData); setEnabled(false); } @@ -52,12 +65,17 @@ public class ConvertToClassAction extends SymbolTreeContextAction { Program program = context.getProgram(); GTreeNode node = (GTreeNode) selectionPaths[0].getLastPathComponent(); + SymbolGTree tree = context.getSymbolTree(); + GTreeNode root = tree.getViewRoot(); + GTreeNode classesNode = root.getChild(SymbolCategory.CLASS_CATEGORY.getName()); + Symbol symbol = ((SymbolNode) node).getSymbol(); - Namespace parent = (Namespace) symbol.getObject(); - if (parent != null) { - convertToClass(program, parent); + Namespace namespace = (Namespace) symbol.getObject(); + if (namespace != null) { + String name = namespace.getName(); + convertToClass(program, namespace); program.flushEvents(); - context.getSymbolTree().startEditing(node, parent.getName()); + context.getSymbolTree().startEditing(classesNode, name); } } @@ -67,11 +85,13 @@ public class ConvertToClassAction extends SymbolTreeContextAction { try { NamespaceUtils.convertNamespaceToClass(ns); success = true; - } catch (InvalidInputException e) { + } + catch (InvalidInputException e) { // This is thrown when the provided namespace is a function // It was checked in isEnabledForContext and thus cannot occur throw new AssertException(e); - } finally { + } + finally { program.endTransaction(id, success); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/CreateClassAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/CreateClassAction.java index 64e1603810..7ebdaef8ca 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/CreateClassAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/CreateClassAction.java @@ -33,9 +33,11 @@ import ghidra.util.exception.InvalidInputException; public class CreateClassAction extends SymbolTreeContextAction { - public CreateClassAction(SymbolTreePlugin plugin) { + public CreateClassAction(SymbolTreePlugin plugin, String group, String subGroup) { super("Create Class", plugin.getName()); - setPopupMenuData(new MenuData(new String[] { "Create Class" }, "0Create")); + MenuData menuData = new MenuData(new String[] { "Create Class" }, group); + menuData.setMenuSubGroup(subGroup); + setPopupMenuData(menuData); setEnabled(false); } @@ -54,23 +56,25 @@ public class CreateClassAction extends SymbolTreeContextAction { protected boolean isEnabledForContext(SymbolTreeActionContext context) { TreePath[] selectionPaths = context.getSelectedSymbolTreePaths(); - if (selectionPaths.length == 1) { - Object object = selectionPaths[0].getLastPathComponent(); - if (object instanceof ClassCategoryNode) { - return true; - } - else if (object instanceof SymbolNode) { - SymbolNode symbolNode = (SymbolNode) object; - Symbol symbol = symbolNode.getSymbol(); - SymbolType symbolType = symbol.getSymbolType(); - if (symbolType == SymbolType.NAMESPACE) { - // allow SymbolType to perform additional checks - Namespace parentNamespace = (Namespace) symbol.getObject(); - return SymbolType.CLASS.isValidParent(context.getProgram(), parentNamespace, - Address.NO_ADDRESS, parentNamespace.isExternal()); - } - return (symbolType == SymbolType.CLASS || symbolType == SymbolType.LIBRARY); + if (selectionPaths.length != 1) { + return false; + } + + Object object = selectionPaths[0].getLastPathComponent(); + if (object instanceof ClassCategoryNode) { + return true; + } + else if (object instanceof SymbolNode) { + SymbolNode symbolNode = (SymbolNode) object; + Symbol symbol = symbolNode.getSymbol(); + SymbolType symbolType = symbol.getSymbolType(); + if (symbolType == SymbolType.NAMESPACE) { + // allow SymbolType to perform additional checks + Namespace parentNamespace = (Namespace) symbol.getObject(); + return SymbolType.CLASS.isValidParent(context.getProgram(), parentNamespace, + Address.NO_ADDRESS, parentNamespace.isExternal()); } + return (symbolType == SymbolType.CLASS || symbolType == SymbolType.LIBRARY); } return false; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/CreateNamespaceAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/CreateNamespaceAction.java index 22e8d30e9a..25e301db59 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/CreateNamespaceAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/CreateNamespaceAction.java @@ -32,9 +32,11 @@ import ghidra.util.exception.InvalidInputException; public class CreateNamespaceAction extends SymbolTreeContextAction { - public CreateNamespaceAction(SymbolTreePlugin plugin) { + public CreateNamespaceAction(SymbolTreePlugin plugin, String group, String subGroup) { super("Create Namespace", plugin.getName()); - setPopupMenuData(new MenuData(new String[] { "Create Namespace" }, "0Create")); + MenuData menuData = new MenuData(new String[] { "Create Namespace" }, group); + menuData.setMenuSubGroup(subGroup); + setPopupMenuData(menuData); setEnabled(false); } 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 c8bdc6d797..835f471892 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 @@ -226,7 +226,7 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest { for (int i = 0; i < count - 1; i++) { GTreeNode n = ghidraNode.getChild(i); Symbol s = ((SymbolNode) n).getSymbol(); - assertTrue(!s.getName().equals("AnotherLocal")); + assertFalse(s.getName().equals("AnotherLocal")); } // test undo/redo @@ -255,7 +255,7 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest { for (int i = 0; i < count - 1; i++) { GTreeNode n = ghidraNode.getChild(i); Symbol s = ((SymbolNode) n).getSymbol(); - assertTrue(!s.getName().equals("AnotherLocal")); + assertNotEquals("AnotherLocal", s.getName()); } } @@ -297,26 +297,20 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testConvertToClass() throws Exception { + public void testConvertNamespaceToClass() throws Exception { String classNodeName = "MyClass"; - GTreeNode nsParentNode = rootNode.getChild(5); + GTreeNode nsNode = rootNode.getChild(SymbolCategory.NAMESPACE_CATEGORY.getName()); GTreeNode classNode = util.createObject( - nsParentNode, classNodeName, createNamespaceAction); + nsNode, classNodeName, createNamespaceAction); util.selectNode(classNode); ActionContext context = util.getSymbolTreeContext(); performTreeAction(convertToClassAction, context); - nsParentNode = rootNode.getChild(4); - classNode = nsParentNode.getChild(classNodeName); + GTreeNode classRootNode = rootNode.getChild(SymbolCategory.CLASS_CATEGORY.getName()); + classNode = classRootNode.getChild(classNodeName); assertNotNull(classNode); - } - - private void performTreeAction(DockingActionIf action, ActionContext context) { - assertTrue(action.isEnabledForContext(context)); - performAction(action, context, true); - program.flushEvents(); - util.waitForTree(); + waitForCondition(tree::isEditing); } @Test @@ -330,13 +324,13 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest { util.selectNode(lNode); ActionContext context = util.getSymbolTreeContext(); - assertTrue(!renameAction.isEnabledForContext(context)); - assertTrue(!cutAction.isEnabledForContext(context)); - assertTrue(!pasteAction.isEnabledForContext(context)); - assertTrue(!deleteAction.isEnabledForContext(context)); - assertTrue(!selectionAction.isEnabledForContext(context)); - assertTrue(!createNamespaceAction.isEnabledForContext(context)); - assertTrue(!createClassAction.isEnabledForContext(context)); + assertFalse(renameAction.isEnabledForContext(context)); + assertFalse(cutAction.isEnabledForContext(context)); + assertFalse(pasteAction.isEnabledForContext(context)); + assertFalse(deleteAction.isEnabledForContext(context)); + assertFalse(selectionAction.isEnabledForContext(context)); + assertFalse(createNamespaceAction.isEnabledForContext(context)); + assertFalse(createClassAction.isEnabledForContext(context)); } @Test @@ -346,16 +340,11 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest { util.expandNode(lNode); // add a label - SymbolTable symTable = program.getSymbolTable(); - int transactionID = program.startTransaction("test"); - try { + tx(program, () -> { + SymbolTable symTable = program.getSymbolTable(); symTable.createLabel(util.addr(0x010048a1L), "abcdefg", SourceType.USER_DEFINED); - } - finally { - program.endTransaction(transactionID, true); - } + }); - program.flushEvents(); util.waitForTree(); lNode = rootNode.getChild(3); @@ -372,18 +361,13 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest { // verify that the tree updates Function f = program.getFunctionManager().getFunctionAt(util.addr(0x01002cf5L)); - Symbol s = getUniqueSymbol(program, "AnotherLocal", f); assertNotNull(s); - int transactionID = program.startTransaction("test"); - try { + + tx(program, () -> { s.setName("MyAnotherLocal", SourceType.USER_DEFINED); - } - finally { - program.endTransaction(transactionID, true); - } - program.flushEvents(); - waitForSwing(); + }); + util.waitForTree(); GTreeNode fNode = getFunctionsNode(); @@ -445,6 +429,13 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest { assertNotNull(goToToggleAction); } + private void performTreeAction(DockingActionIf action, ActionContext context) { + assertTrue(action.isEnabledForContext(context)); + performAction(action, context, true); + program.flushEvents(); + util.waitForTree(); + } + private void clickOnNode(GTreeNode node) throws Exception { JTree jTree = (JTree) AbstractGenericTest.getInstanceField("tree", tree);