diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java index 5aff60a93b..bd24c964fa 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java @@ -202,7 +202,7 @@ public class BookmarkPlugin extends ProgramPlugin implements PopupActionProvider */ public void filterBookmarks() { FilterDialog d = new FilterDialog(provider, currentProgram); - tool.showDialog(d, provider); + tool.showDialog(d, provider.getComponent()); provider.contextChanged(); } @@ -282,9 +282,7 @@ public class BookmarkPlugin extends ProgramPlugin implements PopupActionProvider } private void disposeAllBookmarkers() { - Iterator it = bookmarkNavigators.values().iterator(); - while (it.hasNext()) { - BookmarkNavigator nav = it.next(); + for (BookmarkNavigator nav : bookmarkNavigators.values()) { nav.dispose(); } bookmarkNavigators.clear(); @@ -624,9 +622,8 @@ public class BookmarkPlugin extends ProgramPlugin implements PopupActionProvider types.add(type); } else { - Iterator it = bookmarkNavigators.keySet().iterator(); - while (it.hasNext()) { - types.add(it.next()); + for (String element : bookmarkNavigators.keySet()) { + types.add(element); } } updateMgr.update(); @@ -655,9 +652,7 @@ public class BookmarkPlugin extends ProgramPlugin implements PopupActionProvider running = true; } try { - Iterator it = myTypes.iterator(); - while (it.hasNext()) { - String type = it.next(); + for (String type : myTypes) { updateNav(type); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DtFilterAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DtFilterAction.java index a91704c5f6..5067bf078a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DtFilterAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/DtFilterAction.java @@ -57,7 +57,7 @@ public class DtFilterAction extends DockingAction { DataTypesProvider provider = (DataTypesProvider) context.getComponentProvider(); DtFilterState currentFilterState = provider.getFilterState(); DtFilterDialog dialog = new DtFilterDialog(currentFilterState); - plugin.getTool().showDialog(dialog); + plugin.getTool().showDialog(dialog, provider.getComponent()); // if not cancelled if (dialog.isCancelled()) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/CategoryNode.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/CategoryNode.java index 11af543e08..6b14333592 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/CategoryNode.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/CategoryNode.java @@ -22,8 +22,6 @@ import javax.swing.Icon; import docking.widgets.tree.GTreeNode; import ghidra.app.plugin.core.datamgr.util.DataTypeUtils; import ghidra.program.model.data.*; -import ghidra.program.model.data.Enum; -import ghidra.program.model.listing.Function; import ghidra.util.*; import ghidra.util.exception.AssertException; import ghidra.util.exception.DuplicateNameException; @@ -61,7 +59,7 @@ public class CategoryNode extends DataTypeTreeNode { } for (DataType dataType : dataTypes) { - if (!isFilteredType(dataType)) { + if (passesFilters(dataType)) { list.add(new DataTypeNode(dataType)); } } @@ -71,33 +69,8 @@ public class CategoryNode extends DataTypeTreeNode { return list; } - private boolean isFilteredType(DataType dataType) { - if (!filterState.isShowArrays() && dataType instanceof Array) { - return true; - } - - if (!filterState.isShowPointers() && (dataType instanceof Pointer) && - !(dataType.getDataTypeManager() instanceof BuiltInDataTypeManager)) { - return true; - } - - if (!filterState.isShowEnums() && (dataType instanceof Enum)) { - return true; - } - - if (!filterState.isShowFunctions() && (dataType instanceof Function)) { - return true; - } - - if (!filterState.isShowStructures() && (dataType instanceof Structure)) { - return true; - } - - if (!filterState.isShowUnions() && (dataType instanceof Union)) { - return true; - } - - return false; + private boolean passesFilters(DataType dataType) { + return filterState.passesFilters(dataType); } @Override @@ -212,7 +185,7 @@ public class CategoryNode extends DataTypeTreeNode { return; } - if (isFilteredType(dataType)) { + if (!passesFilters(dataType)) { return; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DtFilterDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DtFilterDialog.java index 13280cae53..dcdc8ba196 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DtFilterDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DtFilterDialog.java @@ -15,25 +15,29 @@ */ package ghidra.app.plugin.core.datamgr.tree; -import javax.swing.JPanel; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.util.List; + +import javax.swing.*; import docking.DialogComponentProvider; +import docking.widgets.button.GButton; import docking.widgets.checkbox.GCheckBox; import ghidra.app.util.HelpTopics; import ghidra.util.HelpLocation; -import ghidra.util.layout.PairLayout; /** * Data Types provider dialog to allow users to change the types that are filtered. */ public class DtFilterDialog extends DialogComponentProvider { - private GCheckBox arraysCheckBox = new GCheckBox("Show Arrays"); - private GCheckBox enumsCheckBox = new GCheckBox("Show Enums"); - private GCheckBox functionsCheckBox = new GCheckBox("Show Functions"); - private GCheckBox pointersCheckBox = new GCheckBox("Show Pointers"); - private GCheckBox structuresCheckBox = new GCheckBox("Show Structures"); - private GCheckBox unionsCheckBox = new GCheckBox("Show Unions"); + private TypeComponent arraysComponent = new TypeComponent("Arrays"); + private TypeComponent enumsComponent = new TypeComponent("Enums"); + private TypeComponent functionsComponent = new TypeComponent("Functions"); + private TypeComponent pointersComponent = new TypeComponent("Pointers"); + private TypeComponent structuresComponent = new TypeComponent("Structures"); + private TypeComponent unionsComponent = new TypeComponent("Unions"); private DtFilterState filterState; private boolean isCancelled; @@ -47,7 +51,7 @@ public class DtFilterDialog extends DialogComponentProvider { addOKButton(); addCancelButton(); - setHelpLocation(new HelpLocation(HelpTopics.DATA_MANAGER, "Set Filter")); + setHelpLocation(new HelpLocation(HelpTopics.DATA_MANAGER, "Show Filter")); initCheckBoxes(); setRememberSize(false); @@ -70,39 +74,136 @@ public class DtFilterDialog extends DialogComponentProvider { public DtFilterState getFilterState() { DtFilterState newState = new DtFilterState(); - - newState.setShowArrays(arraysCheckBox.isSelected()); - newState.setShowEnums(enumsCheckBox.isSelected()); - newState.setShowFunctions(functionsCheckBox.isSelected()); - newState.setShowPointers(pointersCheckBox.isSelected()); - newState.setShowStructures(structuresCheckBox.isSelected()); - newState.setShowUnions(unionsCheckBox.isSelected()); - + newState.setArraysFilter(arraysComponent.getFilter()); + newState.setEnumsFilter(enumsComponent.getFilter()); + newState.setFunctionsFilter(functionsComponent.getFilter()); + newState.setPointersFilter(pointersComponent.getFilter()); + newState.setStructuresFilter(structuresComponent.getFilter()); + newState.setUnionsFilter(unionsComponent.getFilter()); return newState; } private JPanel buildWorkPanel() { - JPanel panel = new JPanel(new PairLayout(5, 10)); + JPanel panel = new JPanel(); + panel.setLayout(new GridLayout(0, 2)); - panel.add(arraysCheckBox); - panel.add(enumsCheckBox); - panel.add(functionsCheckBox); - panel.add(pointersCheckBox); - panel.add(structuresCheckBox); - panel.add(unionsCheckBox); + JLabel l1 = new JLabel("Show"); + l1.setHorizontalAlignment(SwingConstants.LEFT); + panel.add(l1); + + JLabel l2 = new JLabel("Include Typedefs"); + l2.setHorizontalAlignment(SwingConstants.CENTER); + panel.add(l2); + + panel.add(arraysComponent.getLeft()); + panel.add(arraysComponent.getRight()); + panel.add(enumsComponent.getLeft()); + panel.add(enumsComponent.getRight()); + panel.add(functionsComponent.getLeft()); + panel.add(functionsComponent.getRight()); + panel.add(pointersComponent.getLeft()); + panel.add(pointersComponent.getRight()); + panel.add(structuresComponent.getLeft()); + panel.add(structuresComponent.getRight()); + panel.add(unionsComponent.getLeft()); + panel.add(unionsComponent.getRight()); + + GButton selectAll = new GButton("Select All"); + GButton deselectAll = new GButton("Deselect All"); + selectAll.addActionListener(e -> { + allButtons().forEach(b -> b.setSelected(true)); + }); + deselectAll.addActionListener(e -> { + allButtons().forEach(b -> b.setSelected(false)); + }); + + // spacer above buttons + panel.add(Box.createRigidArea(new Dimension(10, 10))); + panel.add(Box.createRigidArea(new Dimension(10, 10))); + + JPanel p1 = new JPanel(); + p1.setLayout(new BoxLayout(p1, BoxLayout.LINE_AXIS)); + p1.add(Box.createHorizontalGlue()); + p1.add(selectAll); + p1.add(Box.createHorizontalGlue()); + + JPanel p2 = new JPanel(); + p2.setLayout(new BoxLayout(p2, BoxLayout.LINE_AXIS)); + p2.add(Box.createHorizontalGlue()); + p2.add(deselectAll); + p2.add(Box.createHorizontalGlue()); + + panel.add(p1); + panel.add(p2); return panel; } - private void initCheckBoxes() { - - arraysCheckBox.setSelected(filterState.isShowArrays()); - enumsCheckBox.setSelected(filterState.isShowEnums()); - functionsCheckBox.setSelected(filterState.isShowFunctions()); - pointersCheckBox.setSelected(filterState.isShowPointers()); - structuresCheckBox.setSelected(filterState.isShowStructures()); - unionsCheckBox.setSelected(filterState.isShowUnions()); + private List allButtons() { + //@formatter:off + return List.of( + arraysComponent.typeCb, + arraysComponent.typeDefCb, + enumsComponent.typeCb, + enumsComponent.typeDefCb, + functionsComponent.typeCb, + functionsComponent.typeDefCb, + pointersComponent.typeCb, + pointersComponent.typeDefCb, + structuresComponent.typeCb, + structuresComponent.typeDefCb, + unionsComponent.typeCb, + unionsComponent.typeDefCb + ); + //@formatter:on } + private void initCheckBoxes() { + arraysComponent.init(filterState.getArraysFilter()); + enumsComponent.init(filterState.getEnumsFilter()); + functionsComponent.init(filterState.getFunctionsFilter()); + pointersComponent.init(filterState.getPointersFilter()); + structuresComponent.init(filterState.getStructuresFilter()); + unionsComponent.init(filterState.getUnionsFilter()); + } + + private class TypeComponent { + + private String type; + private GCheckBox typeCb; + private GCheckBox typeDefCb; + + TypeComponent(String type) { + this.type = type; + this.typeCb = new GCheckBox(type); + this.typeDefCb = new GCheckBox(); + this.typeDefCb.setName(type + "Typedefs"); + } + + JComponent getLeft() { + return typeCb; + } + + JComponent getRight() { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS)); + panel.add(Box.createHorizontalGlue()); + panel.add(typeDefCb); + panel.add(Box.createHorizontalGlue()); + return panel; + } + + void init(DtTypeFilter typeFilter) { + typeCb.setSelected(typeFilter.isTypeActive()); + typeDefCb.setSelected(typeFilter.isTypeDefActive()); + } + + DtTypeFilter getFilter() { + DtTypeFilter filter = new DtTypeFilter(type); + filter.setTypeActive(typeCb.isSelected()); + filter.setTypeDefActive(typeDefCb.isSelected()); + return filter; + } + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DtFilterState.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DtFilterState.java index 547e6c1169..235d892e45 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DtFilterState.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DtFilterState.java @@ -17,7 +17,11 @@ package ghidra.app.plugin.core.datamgr.tree; import java.util.Objects; +import ghidra.app.plugin.core.datamgr.util.DataTypeUtils; import ghidra.framework.options.SaveState; +import ghidra.program.model.data.*; +import ghidra.program.model.data.Enum; +import ghidra.program.model.listing.Function; /** * A simple object to store various filter settings for the data type provider. @@ -26,118 +30,178 @@ public class DtFilterState { private static final String XML_NAME = "DATA_TYPES_FILTER"; - private boolean showArrays = false; - private boolean showEnums = true; - private boolean showFunctions = true; - private boolean showStructures = true; - private boolean showTypedefs = true; - private boolean showPointers = false; - private boolean showUnions = true; + private DtTypeFilter arraysFilter = new DtTypeFilter("Arrays"); + private DtTypeFilter enumsFilter = new DtTypeFilter("Enums"); + private DtTypeFilter functionsFilter = new DtTypeFilter("Functions"); + private DtTypeFilter structuresFilter = new DtTypeFilter("Structures"); + private DtTypeFilter pointersFilter = new DtTypeFilter("Pointers"); + private DtTypeFilter unionsFilter = new DtTypeFilter("Unions"); + + public DtFilterState() { + // these types are off by default, since users typically are not working with them + arraysFilter.setTypeActive(false); + pointersFilter.setTypeActive(false); + } public DtFilterState copy() { DtFilterState filterState = new DtFilterState(); - filterState.setShowArrays(showArrays); - filterState.setShowEnums(showEnums); - filterState.setShowFunctions(showFunctions); - filterState.setShowStructures(showStructures); - filterState.setShowTypedefs(showTypedefs); - filterState.setShowPointers(showPointers); - filterState.setShowUnions(showUnions); + filterState.arraysFilter = arraysFilter.copy(); + filterState.enumsFilter = enumsFilter.copy(); + filterState.functionsFilter = functionsFilter.copy(); + filterState.structuresFilter = structuresFilter.copy(); + filterState.pointersFilter = pointersFilter.copy(); + filterState.unionsFilter = unionsFilter.copy(); return filterState; } - public boolean isShowPointers() { - return showPointers; + public boolean isShowArrays() { + return arraysFilter.isTypeActive(); } - public void setShowPointers(boolean showPointers) { - this.showPointers = showPointers; + public DtTypeFilter getArraysFilter() { + return arraysFilter; } - public boolean isShowStructures() { - return showStructures; - } - - public void setShowStructures(boolean showStructures) { - this.showStructures = showStructures; - } - - public boolean isShowTypedefs() { - return showStructures; - } - - public void setShowTypedefs(boolean showTypedefs) { - this.showTypedefs = showTypedefs; + public void setArraysFilter(DtTypeFilter filter) { + this.arraysFilter = filter; } public boolean isShowEnums() { - return showEnums; + return enumsFilter.isTypeActive(); } - public void setShowEnums(boolean showEnums) { - this.showEnums = showEnums; + public DtTypeFilter getEnumsFilter() { + return enumsFilter; + } + + public void setEnumsFilter(DtTypeFilter filter) { + this.enumsFilter = filter; } public boolean isShowFunctions() { - return showFunctions; + return functionsFilter.isTypeActive(); } - public void setShowFunctions(boolean showFunctions) { - this.showFunctions = showFunctions; + public DtTypeFilter getFunctionsFilter() { + return functionsFilter; + } + + public void setFunctionsFilter(DtTypeFilter filter) { + this.functionsFilter = filter; + } + + public boolean isShowPointers() { + return pointersFilter.isTypeActive(); + } + + public DtTypeFilter getPointersFilter() { + return pointersFilter; + } + + public void setPointersFilter(DtTypeFilter filter) { + this.pointersFilter = filter; + } + + public boolean isShowStructures() { + return structuresFilter.isTypeActive(); + } + + public DtTypeFilter getStructuresFilter() { + return structuresFilter; + } + + public void setStructuresFilter(DtTypeFilter filter) { + this.structuresFilter = filter; } public boolean isShowUnions() { - return showUnions; + return unionsFilter.isTypeActive(); } - public void setShowUnions(boolean showUnions) { - this.showUnions = showUnions; + public DtTypeFilter getUnionsFilter() { + return unionsFilter; } - public boolean isShowArrays() { - return showArrays; + public void setUnionsFilter(DtTypeFilter filter) { + this.unionsFilter = filter; } - public void setShowArrays(boolean showArrays) { - this.showArrays = showArrays; + public boolean passesFilters(DataType dt) { + + DataTypeManager dtm = dt.getDataTypeManager(); + if (dtm instanceof BuiltInDataTypeManager) { + // never filter built-in types here; users can filter them using the text filter + return true; + } + + DataType baseDt = DataTypeUtils.getBaseDataType(dt); + + if (dt instanceof Array) { + return passes(arraysFilter, dt, baseDt); + } + + if (dt instanceof Pointer) { + return passes(pointersFilter, dt, baseDt); + } + + if (baseDt instanceof Enum) { + return passes(enumsFilter, dt, baseDt); + } + + if (baseDt instanceof Function) { + return passes(functionsFilter, dt, baseDt); + } + + if (baseDt instanceof Structure) { + return passes(structuresFilter, dt, baseDt); + } + + if (baseDt instanceof Union) { + return passes(unionsFilter, dt, baseDt); + } + + return true; } - public void setshowPointers(boolean showPointers) { - this.showPointers = showPointers; + private boolean passes(DtTypeFilter filter, DataType dt, DataType baseDt) { + if (filter.isTypeActive()) { + return true; + } + if (filter.isTypeDefActive() && dt instanceof TypeDef) { + return true; + } + return false; } public void save(SaveState parentSaveState) { - SaveState saveState = new SaveState(XML_NAME); - saveState.putBoolean("SHOW_ARRAYS", showArrays); - saveState.putBoolean("SHOW_ENUMS", showEnums); - saveState.putBoolean("SHOW_FUNCTIONS", showFunctions); - saveState.putBoolean("SHOW_POINTERS", showPointers); - saveState.putBoolean("SHOW_STRUCTURES", showStructures); - saveState.putBoolean("SHOW_TYPEDEFS", showTypedefs); - saveState.putBoolean("SHOW_UNIONS", showUnions); + SaveState ss = new SaveState(XML_NAME); + ss.putSaveState(arraysFilter.getName(), arraysFilter.save()); + ss.putSaveState(enumsFilter.getName(), enumsFilter.save()); + ss.putSaveState(functionsFilter.getName(), functionsFilter.save()); + ss.putSaveState(pointersFilter.getName(), pointersFilter.save()); + ss.putSaveState(structuresFilter.getName(), structuresFilter.save()); + ss.putSaveState(unionsFilter.getName(), unionsFilter.save()); - parentSaveState.putSaveState(XML_NAME, saveState); + parentSaveState.putSaveState(XML_NAME, ss); } public void restore(SaveState parentSaveState) { - parentSaveState.getSaveState(XML_NAME); - SaveState saveState = new SaveState(); + SaveState ss = parentSaveState.getSaveState(XML_NAME); - showArrays = saveState.getBoolean("SHOW_ARRAYS", false); - showEnums = saveState.getBoolean("SHOW_ENUMS", true); - showFunctions = saveState.getBoolean("SHOW_FUNCTIONS", true); - showPointers = saveState.getBoolean("SHOW_POINTERS", false); - showStructures = saveState.getBoolean("SHOW_STRUCTURES", true); - showTypedefs = saveState.getBoolean("SHOW_TYPEDEFS", true); - showUnions = saveState.getBoolean("SHOW_UNIONS", true); + arraysFilter = DtTypeFilter.restore("Arrays", ss.getSaveState("Arrays")); + enumsFilter = DtTypeFilter.restore("Enums", ss.getSaveState("Enums")); + functionsFilter = DtTypeFilter.restore("Functions", ss.getSaveState("Functions")); + pointersFilter = DtTypeFilter.restore("Pointers", ss.getSaveState("Pointers")); + structuresFilter = DtTypeFilter.restore("Structures", ss.getSaveState("Structures")); + unionsFilter = DtTypeFilter.restore("Unions", ss.getSaveState("Unions")); } @Override public int hashCode() { - return Objects.hash(showArrays, showEnums, showFunctions, showPointers, showStructures, - showTypedefs, showUnions); + return Objects.hash(arraysFilter, enumsFilter, functionsFilter, pointersFilter, + structuresFilter, unionsFilter); } @Override @@ -152,10 +216,12 @@ public class DtFilterState { return false; } DtFilterState other = (DtFilterState) obj; - return showArrays == other.showArrays && showEnums == other.showEnums && - showFunctions == other.showFunctions && showPointers == other.showPointers && - showStructures == other.showStructures && showTypedefs == other.showTypedefs && - showUnions == other.showUnions; + return Objects.equals(arraysFilter, other.arraysFilter) && + Objects.equals(enumsFilter, other.enumsFilter) && + Objects.equals(functionsFilter, other.functionsFilter) && + Objects.equals(pointersFilter, other.pointersFilter) && + Objects.equals(structuresFilter, other.structuresFilter) && + Objects.equals(unionsFilter, other.unionsFilter); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DtTypeFilter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DtTypeFilter.java new file mode 100644 index 0000000000..6fa2a8162a --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DtTypeFilter.java @@ -0,0 +1,111 @@ +/* ### + * 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.datamgr.tree; + +import java.util.Objects; + +import generic.json.Json; +import ghidra.framework.options.SaveState; + +/** + * A class that holds enabled state for a type and related typedefs. + */ +public class DtTypeFilter { + + private static final String IS_TYPE_ACTIVE_KEY = "IS_TYPE_ACTIVE"; + private static final String IS_TYPE_DEF_ACTIVE_KEY = "IS_TYPE_DEF_ACTIVE"; + + private String name; + private boolean isTypeActive = true; + private boolean isTypeDefActive = true; + + static DtTypeFilter restore(String typeName, SaveState ss) { + if (ss == null) { + return new DtTypeFilter(typeName); + } + return new DtTypeFilter(ss); + } + + DtTypeFilter(String name) { + this.name = name; + } + + private DtTypeFilter(SaveState ss) { + name = ss.getName(); + isTypeActive = ss.getBoolean(IS_TYPE_ACTIVE_KEY, true); + isTypeDefActive = ss.getBoolean(IS_TYPE_DEF_ACTIVE_KEY, true); + } + + SaveState save() { + SaveState ss = new SaveState(name); + ss.putBoolean(IS_TYPE_ACTIVE_KEY, isTypeActive); + ss.putBoolean(IS_TYPE_DEF_ACTIVE_KEY, isTypeDefActive); + return ss; + } + + DtTypeFilter copy() { + DtTypeFilter filter = new DtTypeFilter(name); + filter.isTypeActive = isTypeActive; + filter.isTypeDefActive = isTypeDefActive; + return filter; + } + + public String getName() { + return name; + } + + public boolean isTypeActive() { + return isTypeActive; + } + + public boolean isTypeDefActive() { + return isTypeDefActive; + } + + public void setTypeActive(boolean b) { + this.isTypeActive = b; + } + + public void setTypeDefActive(boolean b) { + this.isTypeDefActive = b; + } + + @Override + public String toString() { + return Json.toString(this); + } + + @Override + public int hashCode() { + return Objects.hash(isTypeActive, isTypeDefActive, name); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + DtTypeFilter other = (DtTypeFilter) obj; + return isTypeActive == other.isTypeActive && isTypeDefActive == other.isTypeDefActive && + Objects.equals(name, other.name); + } +} diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java index e18720aae2..fd8f7d7556 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java @@ -166,6 +166,14 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe myStruct.setCategoryPath(cat2Path); builder.addDataType(myStruct); + TypedefDataType typeDefMyStruct = new TypedefDataType("TypeDefToMyStruct", myStruct); + builder.addDataType(typeDefMyStruct); + + Pointer16DataType ptr16 = new Pointer16DataType(new CharDataType()); + builder.addDataType(ptr16); + ArrayDataType charDt = new ArrayDataType(new CharDataType(), 10); + builder.addDataType(charDt); + return builder.getProgram(); } @@ -912,20 +920,51 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe } @Test - public void testFilter() { + public void testFilter_DefaultFilter() { + + DtFilterState filterState = provider.getFilterState(); + assertFalse(filterState.getArraysFilter().isTypeActive()); + assertFalse(filterState.getPointersFilter().isTypeActive()); + + DataTypeManager[] dtms = plugin.getDataTypeManagers(); + for (DataTypeManager dtm : dtms) { + if (dtm instanceof BuiltInDataTypeManager) { + assertAllTypesInTree(dtm); + } + else { + assertNoArrays(dtm); + assertNoPointers(dtm); + } + } + } + + @Test + public void testFilter_Structures() { + + assertStructures(true); + assertType("TypeDefToMyStruct", true); // press the filter button DockingActionIf action = getAction(plugin, "Show Filter"); performAction(action, provider, false); - assertStructures(true); - DtFilterDialog dialog = waitForDialogComponent(DtFilterDialog.class); - setToggleButtonSelected(dialog.getComponent(), "Show Structures", false); + setToggleButtonSelected(dialog.getComponent(), "Structures", false); pressButtonByText(dialog, "OK"); waitForTree(); assertStructures(false); + assertType("TypeDefToMyStruct", true); + + // Now also turn off typedefs + performAction(action, provider, false); + dialog = waitForDialogComponent(DtFilterDialog.class); + setToggleButtonSelected(dialog.getComponent(), "StructuresTypedefs", false); + pressButtonByText(dialog, "OK"); + waitForTree(); + + assertStructures(false); + assertType("TypeDefToMyStruct", false); } @Test @@ -935,7 +974,7 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe // press the filter button DtFilterDialog mainDialog = showFilterDialog(provider); boolean isShowingStructures = false; - updateFilter(mainDialog, "Show Structures", isShowingStructures); + updateFilter(mainDialog, "Structures", isShowingStructures); // // Launch a new data types provider window to verify it has the same settings as the main @@ -954,7 +993,7 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe // now change the new provider's filter for a different option and then make sure that the // main provider is not changed - updateFilter(otherFilterDialog, "Show Functions", false); + updateFilter(otherFilterDialog, "Functions", false); DtFilterState mainFilterState = runSwing(() -> provider.getFilterState()); DtFilterState otherFilterState = runSwing(() -> otherProvider.getFilterState()); @@ -967,11 +1006,11 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe public void testSaveRestoreFilterStates() throws Exception { DtFilterDialog dialog = showFilterDialog(provider); - boolean isShowingEnums = getFilterState(dialog, "Show Enums"); - boolean isShowingUnions = getFilterState(dialog, "Show Unions"); + boolean isShowingEnums = getFilterState(dialog, "Enums"); + boolean isShowingUnions = getFilterState(dialog, "Unions"); - setToggleButtonSelected(dialog.getComponent(), "Show Enums", !isShowingEnums); - setToggleButtonSelected(dialog.getComponent(), "Show Unions", !isShowingUnions); + setToggleButtonSelected(dialog.getComponent(), "Enums", !isShowingEnums); + setToggleButtonSelected(dialog.getComponent(), "Unions", !isShowingUnions); pressButtonByText(dialog, "OK"); waitForSwing(); @@ -988,6 +1027,88 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe // Private methods //================================================================================================== + private void assertNoArrays(DataTypeManager dtm) { + Map nodesByName = getNodes(dtm); + Collection values = nodesByName.values(); + for (DataTypeNode node : values) { + DataType dt = node.getDataType(); + assertTrue("Found an array in '%s'".formatted(dtm.getName()), + !(dt instanceof Array)); + } + } + + private void assertNoPointers(DataTypeManager dtm) { + Map nodesByName = getNodes(dtm); + Collection values = nodesByName.values(); + for (DataTypeNode node : values) { + DataType dt = node.getDataType(); + assertTrue("Found a pointer in '%s'".formatted(dtm.getName()), + !(dt instanceof Pointer)); + } + } + + private void assertAllTypesInTree(DataTypeManager dtm) { + Iterator types = dtm.getAllDataTypes(); + Map nodesByName = getNodes(dtm); + for (DataType dt : CollectionUtils.asIterable(types)) { + assertNotNull( + "Node not found for type '%s' in dtm '%s'".formatted(dt.getName(), dtm.getName()), + nodesByName.get(dt.getName())); + } + } + + private Map getNodes(DataTypeManager dtm) { + + DataTypeArchiveGTree gTree = provider.getGTree(); + GTreeNode rootNode = gTree.getViewRoot(); + GTreeNode dtmNode = rootNode.getChild(dtm.getName()); + assertNotNull(dtmNode); + + expandNode(dtmNode); + + Map nodesByName = new HashMap<>(); + Iterator it = dtmNode.iterator(true); + for (GTreeNode node : CollectionUtils.asIterable(it)) { + if (!(node instanceof DataTypeNode)) { + continue; + } + DataTypeNode dtNode = (DataTypeNode) node; + DataType dt = dtNode.getDataType(); + nodesByName.put(dt.getName(), dtNode); + } + + return nodesByName; + } + + private void assertType(String name, boolean isShowing) { + + DataType dt = getTypeFromTree(name); + if (isShowing) { + assertNotNull("Data type not found: '%s'", dt); + } + else { + assertNull(dt); + } + } + + private DataType getTypeFromTree(String name) { + DataTypeArchiveGTree gTree = provider.getGTree(); + GTreeNode rootNode = gTree.getViewRoot(); + Iterator it = rootNode.iterator(true); + for (GTreeNode node : CollectionUtils.asIterable(it)) { + if (!(node instanceof DataTypeNode)) { + continue; + } + DataTypeNode dtNode = (DataTypeNode) node; + DataType dt = dtNode.getDataType(); + String dtName = dt.getName(); + if (dtName.equals(name)) { + return dt; + } + } + return null; + } + private boolean getFilterState(DtFilterDialog dialog, String optionName) { return isToggleButttonSelected(dialog.getComponent(), optionName); } @@ -1265,7 +1386,7 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe performAction(action, provider, false); DtFilterDialog dialog = waitForDialogComponent(DtFilterDialog.class); - setToggleButtonSelected(dialog.getComponent(), "Show Pointers", true); + setToggleButtonSelected(dialog.getComponent(), "Pointers", true); pressButtonByText(dialog, "OK"); waitForTree(); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToAddressLabelPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToAddressLabelPluginTest.java index 74f315c6f0..49b3a96b7a 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToAddressLabelPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/GoToAddressLabelPluginTest.java @@ -383,7 +383,8 @@ public class GoToAddressLabelPluginTest extends AbstractGhidraHeadedIntegrationT // The default space and 'Test Overlay 1' each have an address for 1002000. The // 'Test Overlay 2' does not. So, put the cursor there. String name = overlay2Block.getName(); - assertTrue(cbPlugin.goTo(new ProgramLocation(program, addr(name + "::1003000")))); + ProgramLocation location = new ProgramLocation(program, addr(name + "::1003000")); + assertTrue(cbPlugin.goTo(location)); showDialog(); setText("1002000"); diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/GProperties.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/GProperties.java index 126713ef58..fe9500c689 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/GProperties.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/GProperties.java @@ -4,9 +4,9 @@ * 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. @@ -494,9 +494,7 @@ public class GProperties { */ public Element saveToXml() { Element root = new Element(propertiesName); - Iterator iter = map.keySet().iterator(); - while (iter.hasNext()) { - String key = iter.next(); + for (String key : map.keySet()) { Object value = map.get(key); Element elem = createElement(key, value); root.addContent(elem); @@ -638,9 +636,7 @@ public class GProperties { JsonObject types = new JsonObject(); JsonObject values = new JsonObject(); JsonObject enumClasses = new JsonObject(); - Iterator iter = map.keySet().iterator(); - while (iter.hasNext()) { - String key = iter.next(); + for (String key : map.keySet()) { Object value = map.get(key); if (value == null) { types.addProperty(key, "null"); @@ -835,15 +831,22 @@ public class GProperties { } /** - * Return the names of the properties in this GProperties. - * @return the names of the properties in this GProperties. + * Returns the name of this GProperties + * @return the name of this GProperties + */ + public String getName() { + return propertiesName; + } + + /** + * Return the names of the properties in this GProperties + * @return the names of the properties in this GProperties */ public String[] getNames() { String[] names = new String[map.size()]; int idx = 0; - Iterator iter = map.keySet().iterator(); - while (iter.hasNext()) { - names[idx] = iter.next(); + for (String element : map.keySet()) { + names[idx] = element; ++idx; } return names; diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/SaveState.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/SaveState.java index 3bef330802..e90e3c28b6 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/SaveState.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/SaveState.java @@ -4,9 +4,9 @@ * 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. @@ -114,6 +114,7 @@ public class SaveState extends XmlProperties { return getAsType(name, null, SaveState.class); } + @Override protected void processElement(Element element) { String tag = element.getName(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinition.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinition.java index 62900d3134..0bf061d858 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinition.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FunctionDefinition.java @@ -69,6 +69,7 @@ public interface FunctionDefinition extends DataType, FunctionSignature { * @deprecated Use of {@link GenericCallingConvention} is deprecated since arbitrary calling * convention names are now supported. {@link #setCallingConvention(String)} should be used. */ + @Deprecated public void setGenericCallingConvention(GenericCallingConvention genericCallingConvention); /**