diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/CodeBrowserClipboardProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/CodeBrowserClipboardProvider.java index eb3e5a4c09..216a85bbd6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/CodeBrowserClipboardProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/CodeBrowserClipboardProvider.java @@ -24,6 +24,8 @@ import java.util.concurrent.CopyOnWriteArraySet; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import org.apache.commons.lang3.StringUtils; + import docking.ActionContext; import docking.ComponentProvider; import docking.dnd.GenericDataFlavor; @@ -303,12 +305,9 @@ public class CodeBrowserClipboardProvider extends ByteCopier private Transferable copyAddress() { AddressSetView addressSet = getSelectedAddresses(); - StringBuilder buffy = new StringBuilder(); AddressIterator it = addressSet.getAddresses(true); - while (it.hasNext()) { - buffy.append(it.next()).append('\n'); - } - return createStringTransferable(buffy.toString()); + String joined = StringUtils.join((Iterator
) it, "\n"); + return createStringTransferable(joined); } protected Transferable copyCode(TaskMonitor monitor) { @@ -377,8 +376,8 @@ public class CodeBrowserClipboardProvider extends ByteCopier private boolean pasteLabelsComments(Transferable pasteData, boolean pasteLabels, boolean pasteComments) { try { - List list = (List) pasteData.getTransferData( - CodeUnitInfoTransferable.localDataTypeFlavor); + List list = + (List) pasteData.getTransferData(CodeUnitInfoTransferable.localDataTypeFlavor); List infos = CollectionUtils.asList(list, CodeUnitInfo.class); Command cmd = new CodeUnitInfoPasteCmd(currentLocation.getAddress(), infos, pasteLabels, pasteComments); @@ -420,7 +419,7 @@ public class CodeBrowserClipboardProvider extends ByteCopier return pasteOperandField((OperandFieldLocation) currentLocation, labelName); } - // try pasting onto something that is not a label + // try pasting onto something that is not a label return maybePasteNonLabelString(labelName); } @@ -451,12 +450,12 @@ public class CodeBrowserClipboardProvider extends ByteCopier String oldName = symbol.getName(); Namespace namespace = symbol.getParentNamespace(); Address symbolAddress = symbol.getAddress(); - RenameLabelCmd cmd = new RenameLabelCmd(symbolAddress, oldName, labelName, - namespace, SourceType.USER_DEFINED); + RenameLabelCmd cmd = new RenameLabelCmd(symbolAddress, oldName, labelName, namespace, + SourceType.USER_DEFINED); return tool.execute(cmd, currentProgram); } - // try pasting onto something that is not a label + // try pasting onto something that is not a label return maybePasteNonLabelString(labelName); } @@ -646,7 +645,7 @@ public class CodeBrowserClipboardProvider extends ByteCopier //================================================================================================== // Unsupported Operations -//================================================================================================== +//================================================================================================== @Override public void lostOwnership(Transferable transferable) { diff --git a/Ghidra/Features/FunctionGraphDecompilerExtension/src/main/java/ghidra/app/plugin/core/functiongraph/graph/layout/DecompilerNestedLayout.java b/Ghidra/Features/FunctionGraphDecompilerExtension/src/main/java/ghidra/app/plugin/core/functiongraph/graph/layout/DecompilerNestedLayout.java index 761c18f743..e3a40d8ff3 100644 --- a/Ghidra/Features/FunctionGraphDecompilerExtension/src/main/java/ghidra/app/plugin/core/functiongraph/graph/layout/DecompilerNestedLayout.java +++ b/Ghidra/Features/FunctionGraphDecompilerExtension/src/main/java/ghidra/app/plugin/core/functiongraph/graph/layout/DecompilerNestedLayout.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. @@ -38,6 +38,7 @@ import ghidra.app.plugin.core.functiongraph.graph.jung.renderer.DNLArticulatedEd import ghidra.app.plugin.core.functiongraph.graph.vertex.FGVertex; import ghidra.app.plugin.core.functiongraph.graph.vertex.GroupedFunctionGraphVertex; import ghidra.graph.VisualGraph; +import ghidra.graph.viewer.GraphViewerUtils; import ghidra.graph.viewer.layout.*; import ghidra.graph.viewer.vertex.VisualGraphVertexShapeTransformer; import ghidra.program.model.address.Address; @@ -52,19 +53,19 @@ import ghidra.util.task.TaskMonitor; /** * A layout that uses the decompiler to show code nesting based upon conditional logic. - * + * *

Edges returning to the default code flow are painted lighter to de-emphasize them. This * could be made into an option. - * - *

Edge routing herein defaults to 'simple routing'; 'complex routing' is a user option. + * + *

Edge routing herein defaults to 'simple routing'; 'complex routing' is a user option. * Simple routing will reduce edge noise as much as possible by combining/overlapping edges that * flow towards the bottom of the function (returning code flow). Also, edges may fall behind * vertices for some functions. Complex routing allows the user to visually follow the flow * of an individual edge. Complex routing will prevent edges from overlapping and will route - * edges around vertices. Simple routing is better when the layout of the vertices is - * important to the user; complex routing is better when edges/relationships are more + * edges around vertices. Simple routing is better when the layout of the vertices is + * important to the user; complex routing is better when edges/relationships are more * important to the user. - * + * * TODO ideas: * -paint fallthrough differently for all, or just for those returning to the baseline */ @@ -113,7 +114,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout { @Override protected double getCondenseFactor() { - // our layout needs more spacing because we have custom edge routing that we want to + // our layout needs more spacing because we have custom edge routing that we want to // stand out return .3; } @@ -201,7 +202,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout { continue; } - // + // // Special case: fallthrough--don't label this...not sure how to tell fallthrough. For // now assume that any column below or backwards is fallthrough. However, // do label fallthrough if it is the only edge. @@ -231,10 +232,10 @@ public class DecompilerNestedLayout extends AbstractFGLayout { Map> newEdgeArticulations = new HashMap<>(); - // Condensing Note: we have guilty knowledge that our parent class my condense the + // Condensing Note: we have guilty knowledge that our parent class my condense the // vertices and edges towards the center of the graph after we calculate positions. // To prevent the edges from moving to far behind the vertices, we will compensate a - // bit for that effect using this offset value. The getEdgeOffset() method below is + // bit for that effect using this offset value. The getEdgeOffset() method below is // updated for the condense factor. int edgeOffset = isCondensedLayout() ? (int) (VERTEX_TO_EDGE_ARTICULATION_PADDING * (1 - getCondenseFactor())) @@ -242,7 +243,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout { Vertex2dFactory vertex2dFactory = new Vertex2dFactory(transformer, vertexLayoutLocations, layoutToGridMap, edgeOffset); - // + // // Route our edges! // for (FGEdge e : edges) { @@ -262,11 +263,8 @@ public class DecompilerNestedLayout extends AbstractFGLayout { DecompilerBlock loop = block.getParentLoop(); if (loop != null) { - Set vertices = loop.getVertices(); - - Column outermostCol = getOutermostCol(layoutToGridMap, vertices); - Column loopEndColumn = layoutToGridMap.nextColumn(outermostCol); - List articulations = routeLoopEdge(start, end, loopEndColumn); + List articulations = + routeUpwardLoop(layoutToGridMap, vertex2dFactory, start, end, loop); newEdgeArticulations.put(e, articulations); continue; } @@ -275,31 +273,31 @@ public class DecompilerNestedLayout extends AbstractFGLayout { List articulations = new ArrayList<>(); // - // Basic routing: + // Basic routing: // -leave the bottom of the start vertex // -first bend at some constant offset // -move to right or left, to above the end vertex // -second bend above the end vertex at previous constant offset - // - // Edges start/end on the vertex center. If we offset them to avoid + // + // Edges start/end on the vertex center. If we offset them to avoid // overlapping, then they produce angles when only using two articulations. // Thus, we create articulations that are behind the vertices to remove // the angles. This points will not be seen. // - // + // // Complex routing: // -this mode will route edges around vertices - // + // // One goal for complex edge routing is to prevent overlapping (simple edge routing // prefers overlapping to reduce lines). To prevent overlapping we will use different - // offset x and y values, depending upon the start and end vertex row and column + // offset x and y values, depending upon the start and end vertex row and column // locations. Specifically, for a given edge direction there will be a bias: // -Edge to the right - leave from the right; arrive to the left // -Edge to the left - leave from the left; arrive to the right // -Edge straight down - go straight down // // For each of the above offsets, there will be an amplifier based upon row/column - // distance from start to end vertex. This has the effect that larger vertex + // distance from start to end vertex. This has the effect that larger vertex // distances will have a larger offset/spacing. // @@ -331,14 +329,78 @@ public class DecompilerNestedLayout extends AbstractFGLayout { return newEdgeArticulations; } + private List routeUpwardLoop(LayoutLocationMap layoutToGridMap, + Vertex2dFactory vertex2dFactory, Vertex2d start, Vertex2d end, DecompilerBlock loop) { + Set loopVertices = loop.getVertices(); + FGVertex rightmostLoopVertex = + getRightmostVertex(layoutToGridMap, vertex2dFactory, loopVertices); + + int startRow = start.rowIndex; + int endRow = end.rowIndex; + int startColumn = Math.min(start.columnIndex, end.columnIndex); + int endColumn = Math.max(start.columnIndex, end.columnIndex); + + Column rightmostLoopColumn = layoutToGridMap.col(rightmostLoopVertex); + endColumn = Math.max(endColumn, rightmostLoopColumn.index); + + // Look for any vertices that are no part of the loop, but are placed inside + // of the loop bounds. This can happen in a graph when the decompiler uses + // goto statements. Use the loop's rightmost vertex to establish the loops + // right edge and then use that to check for any stray non-loop vertices. + List interlopers = + getVerticesInBounds(vertex2dFactory, startRow, endRow, startColumn, endColumn); + + // place the right x position to the right of the rightmost vertex, not + // extending past the next column + FGVertex rightmostVertex = getRightmostVertex(interlopers); + Column rightmostColumn = layoutToGridMap.col(rightmostVertex); + Column nextColumn = layoutToGridMap.nextColumn(rightmostColumn); + Vertex2d rightmostV2d = vertex2dFactory.get(rightmostVertex); + + // the padding used for these two lines is somewhat arbitrary and may be changed + double rightSide = rightmostV2d.getRight() + GraphViewerUtils.EXTRA_LAYOUT_COLUMN_SPACING; + double x = Math.min(rightSide, + nextColumn.x - GraphViewerUtils.EXTRA_LAYOUT_COLUMN_SPACING_CONDENSED); + + List articulations = routeLoopEdge(start, end, x); + return articulations; + } + + private List getVerticesInBounds(Vertex2dFactory vertex2dFactory, int startRow, + int endRow, int startColumn, int endColumn) { + + if (startRow > endRow) { // going upwards + int temp = endRow; + endRow = startRow; + startRow = temp; + } + + List toCheck = new LinkedList<>(); + for (int row = startRow; row < endRow + 1; row++) { + + for (int col = startColumn; col < endColumn + 1; col++) { + + // assume any other vertex in our column can clip (it will not clip when + // the 'spacing' above pushes the edge away from this column, like for + // large row delta values) + Vertex2d otherVertex = vertex2dFactory.get(row, col); + if (otherVertex != null) { + toCheck.add(otherVertex); + } + } + } + + return toCheck; + } + private void routeToTheRightGoingUpwards(Vertex2d start, Vertex2d end, Vertex2dFactory vertex2dFactory, List articulations) { // - // For routing to the right and back up we will leave the start vertex from the right side + // For routing to the right and back up we will leave the start vertex from the right side // and enter the end vertex on the right side. As the vertices get further apart, we will - // space them further in towards the center. - // + // space them further in towards the center. + // int delta = start.rowIndex - end.rowIndex; int multiplier = EDGE_ENDPOINT_DISTANCE_MULTIPLIER; @@ -347,11 +409,9 @@ public class DecompilerNestedLayout extends AbstractFGLayout { } int distanceSpacing = delta * multiplier; - // Condensing Note: we have guilty knowledge that our parent class my condense the - // vertices and edges towards the center of the graph after we calculate positions. - // To prevent the edges from moving to far behind the vertices, we will compensate a - // bit for that effect using this offset value. The getEdgeOffset() method is - // updated for the condense factor. + // Condensing is when the graph will pull nodes closer together on the x axis to + // reduce whitespace and make the entire graph easier to see. In this case, update + // the offset to avoid running into the moved vertices. int exaggerationFactor = 1; if (isCondensedLayout()) { exaggerationFactor = 2; // determined by trial-and-error; can be made into an option @@ -369,7 +429,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout { y1 = Math.min(y1, startCenterY); articulations.add(new Point2D.Double(x1, y1)); // point is hidden behind the vertex - // Use the spacing to move the y value towards the top of the vertex. Just like with + // Use the spacing to move the y value towards the top of the vertex. Just like with // the x value, restrict the y to the range between the edge and the center. double startRightX = start.getRight(); double x2 = startRightX + VERTEX_BORDER_THICKNESS; // start at the end @@ -434,10 +494,10 @@ public class DecompilerNestedLayout extends AbstractFGLayout { // // For routing to the left we will leave the start vertex from just left of center and - // enter the end vertex on the top, towards the right. As the vertices get further apart, - // we will space them further in towards the center of the end vertex. This will keep + // enter the end vertex on the top, towards the right. As the vertices get further apart, + // we will space them further in towards the center of the end vertex. This will keep // edges with close endpoints from intersecting edges with distant endpoints. - // + // int delta = end.rowIndex - start.rowIndex; int multiplier = EDGE_ENDPOINT_DISTANCE_MULTIPLIER; @@ -499,7 +559,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout { // enter the end vertex on the left side. As the vertices get further apart, we will // space them further in towards the center. This will keep edges with close endpoints // from intersecting edges with distant endpoints. - // + // int delta = end.rowIndex - start.rowIndex; if (delta < 0) { @@ -529,7 +589,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout { double y1 = start.getY(); articulations.add(new Point2D.Double(x1, y1)); // point is hidden behind the vertex - // Use the spacing to move the y value towards the top of the vertex. Just like with + // Use the spacing to move the y value towards the top of the vertex. Just like with // the x value, restrict the y to the range between the edge and the center. double x2 = x1; double y2 = end.getTop() + VERTEX_BORDER_THICKNESS; @@ -556,19 +616,6 @@ public class DecompilerNestedLayout extends AbstractFGLayout { private void routeAroundColumnVertices(Vertex2d start, Vertex2d end, Vertex2dFactory vertex2dFactory, List articulations, double edgeX) { - Column column = vertex2dFactory.getColumn(edgeX); - int columnIndex = 0; - if (column != null) { - // a null column happens with a negative x value that is outside of any column - columnIndex = column.index; - } - - routeAroundColumnVertices(start, end, columnIndex, vertex2dFactory, articulations, edgeX); - } - - private void routeAroundColumnVertices(Vertex2d start, Vertex2d end, int column, - Vertex2dFactory vertex2dFactory, List articulations, double edgeX) { - if (useSimpleRouting()) { return; } @@ -582,14 +629,34 @@ public class DecompilerNestedLayout extends AbstractFGLayout { startRow = end.rowIndex; } + int startColumn = Math.min(start.columnIndex, end.columnIndex); + int endColumn = Math.max(start.columnIndex, end.columnIndex); + if (goingDown) { + endRow -= 1; + endColumn -= 1; + + if (start.columnIndex <= end.columnIndex) { + startRow += 1; + } + } + else { + // going up we swing out to the right; grab the column that is out to the right + Column rightColumn = vertex2dFactory.getColumn(edgeX); + endColumn = rightColumn.index; + } + List toCheck = new LinkedList<>(); - for (int row = startRow + 1; row < endRow; row++) { - // assume any other vertex in our column can clip (it will not clip when - // the 'spacing' above pushes the edge away from this column, like for - // large row delta values) - Vertex2d otherVertex = vertex2dFactory.get(row, column); - if (otherVertex != null) { - toCheck.add(otherVertex); + for (int row = startRow; row < endRow + 1; row++) { + + for (int col = startColumn; col < endColumn + 1; col++) { + + // assume any other vertex in our column can clip (it will not clip when + // the 'spacing' above pushes the edge away from this column, like for + // large row delta values) + Vertex2d otherVertex = vertex2dFactory.get(row, col); + if (otherVertex != null) { + toCheck.add(otherVertex); + } } } @@ -605,11 +672,9 @@ public class DecompilerNestedLayout extends AbstractFGLayout { int padding = VERTEX_TO_EDGE_AVOIDANCE_PADDING; int distanceSpacing = padding + delta; // adding the delta makes overlap less likely - // Condensing Note: we have guilty knowledge that our parent class my condense the - // vertices and edges towards the center of the graph after we calculate positions. - // To prevent the edges from moving to far behind the vertices, we will compensate a - // bit for that effect using this offset value. The getEdgeOffset() method is - // updated for the condense factor. + // Condensing is when the graph will pull nodes closer together on the x axis to + // reduce whitespace and make the entire graph easier to see. In this case, update + // the offset to avoid running into the moved vertices. int vertexToEdgeOffset = otherVertex.getEdgeOffset(); int exaggerationFactor = 1; if (isCondensedLayout()) { @@ -629,20 +694,20 @@ public class DecompilerNestedLayout extends AbstractFGLayout { // no need to check the 'y' value, as the end vertex is above/below this one if (vertexClipper.isClippingX(otherVertex, edgeX)) { - /* + /* Must route around this vertex - new points: -p1 - just above the intersection point -p2 - just past the left edge -p3 - just past the bottom of the vertex -p4 - back at the original x value - + | .___| | .-----. | | | | '-----' '---. - | + | */ // p1 - same x; y just above vertex @@ -650,19 +715,19 @@ public class DecompilerNestedLayout extends AbstractFGLayout { double y = vertexClipper.getTopOffset(otherVertex, vertexToEdgeOffset); articulations.add(new Point2D.Double(x, y)); - // Maybe merge points if they are too close together. Visually, many lines - // moving around intersecting vertices looks busy. When the intersecting + // Maybe merge points if they are too close together. Visually, many lines + // moving around intersecting vertices looks busy. When the intersecting // vertices are close together, we remove some of the articulations in order to // smooth out the edges. if (articulations.size() > 2) { - /* + /* The last articulation is the one added before this method was called, which - lies just below the intersecting vertex. The articulation before that is - the one that is the one that is sending the x value straight into the + lies just below the intersecting vertex. The articulation before that is + the one that is the one that is sending the x value straight into the intersecting vertex. Delete that point as well so that the entire edge is shifted to the outside of the intersecting vertex. This will get repeated - for each vertex that is intersecting. + for each vertex that is intersecting. */ Point2D previousArticulation = articulations.get(articulations.size() - 2); int closenessHeight = 50; @@ -696,15 +761,11 @@ public class DecompilerNestedLayout extends AbstractFGLayout { return !getLayoutOptions().useEdgeRoutingAroundVertices(); } - private List routeLoopEdge(Vertex2d start, Vertex2d end, Column loopEndColumn) { + private List routeLoopEdge(Vertex2d start, Vertex2d end, double x) { // going backwards List articulations = new ArrayList<>(); - // loop first point - same y coord as the vertex; x is the middle of the next col - int halfWidth = loopEndColumn.getPaddedWidth(isCondensedLayout()) >> 1; - double x = loopEndColumn.x + halfWidth; // middle of the column - int startRow = start.rowIndex; int endRow = end.rowIndex; if (startRow > endRow) { // going upwards @@ -720,7 +781,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout { Point2D first = new Point2D.Double(x, y1); articulations.add(first); - // loop second point - same y coord as destination; + // loop second point - same y coord as destination; // x is the col after the outermost dominated vertex Point2D endVertexPoint = end.center; @@ -739,21 +800,37 @@ public class DecompilerNestedLayout extends AbstractFGLayout { e.setDefaultAlpha(.25); } - private Column getOutermostCol(LayoutLocationMap layoutLocations, - Set vertices) { + private FGVertex getRightmostVertex(LayoutLocationMap layoutLocations, + Vertex2dFactory vertex2dFactory, Set vertices) { - Column outermost = null; + List points = new ArrayList<>(); for (FGVertex v : vertices) { - Column col = layoutLocations.col(v); - if (outermost == null) { - outermost = col; + Vertex2d v2d = vertex2dFactory.get(v); + points.add(v2d); + } + + FGVertex v = getRightmostVertex(points); + return v; + } + + private FGVertex getRightmostVertex(Collection points) { + + Vertex2d rightmost = null; + for (Vertex2d v2d : points) { + if (rightmost == null) { + rightmost = v2d; } - else if (col.x > outermost.x) { - outermost = col; + else { + // the rightmost is that which extends furthest to the right + double current = rightmost.getRight(); + double other = v2d.getRight(); + if (other > current) { + rightmost = v2d; + } } } - return outermost; + return rightmost.v; } @Override @@ -840,8 +917,11 @@ public class DecompilerNestedLayout extends AbstractFGLayout { BlockCopy copy = (BlockCopy) child; StringBuilder buffy = new StringBuilder(); - buffy.append(printDepth(depth, depth + 1)).append(' ').append(ID).append( - " plain - ").append(copy.getRef()); + buffy.append(printDepth(depth, depth + 1)) + .append(' ') + .append(ID) + .append(" plain - ") + .append(copy.getRef()); debug(buffy.toString()); } @@ -958,7 +1038,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout { //================================================================================================== // Inner Classes -//================================================================================================== +//================================================================================================== /** * Encapsulates knowledge of edge direction (up/down, left/right) and uses that knowledge @@ -1060,7 +1140,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout { } /** - * A class that represents 2D information about the contained vertex, such as location, + * A class that represents 2D information about the contained vertex, such as location, * bounds, row and column of the layout grid. */ private class Vertex2d { @@ -1207,8 +1287,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout { int row = startRow; - for (int i = 0; i < allChildren.size(); i++) { - DecompilerBlock block = allChildren.get(i); + for (DecompilerBlock block : allChildren) { if (block instanceof DecompilerBlockGraph) { row = ((DecompilerBlockGraph) block).setRows(row); } @@ -1229,8 +1308,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout { String getChildrenString(int depth) { StringBuilder buffy = new StringBuilder(); int childCount = 0; - for (int i = 0; i < allChildren.size(); i++) { - DecompilerBlock block = allChildren.get(i); + for (DecompilerBlock block : allChildren) { if (block instanceof DecompilerBlockGraph) { String blockName = block.getName(); @@ -1315,8 +1393,8 @@ public class DecompilerNestedLayout extends AbstractFGLayout { @Override DecompilerBlock getBlock(FGVertex vertex) { // - // Note: we currently allow grouping in this layout. When we search for a vertex, - // we have to check each vertex inside of the given group *and* each vertex + // Note: we currently allow grouping in this layout. When we search for a vertex, + // we have to check each vertex inside of the given group *and* each vertex // inside of the vertex that belongs to this decompiler block. // if (vertex instanceof GroupedFunctionGraphVertex) { @@ -1447,9 +1525,8 @@ public class DecompilerNestedLayout extends AbstractFGLayout { // The 'list' structure for children's nesting: // -all nodes are at the same level // - for (int i = 0; i < allChildren.size(); i++) { + for (DecompilerBlock block : allChildren) { int column = col; - DecompilerBlock block = allChildren.get(i); block.setCol(column); } @@ -1477,8 +1554,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout { // -each successive condition is another level nested // int column = col; - for (int i = 0; i < allChildren.size(); i++) { - DecompilerBlock block = allChildren.get(i); + for (DecompilerBlock block : allChildren) { block.setCol(column); column++; } @@ -1515,11 +1591,10 @@ public class DecompilerNestedLayout extends AbstractFGLayout { // // The 'do' structure for children's nesting: - // -all blocks nested + // -all blocks nested // int column = col + 1; - for (int i = 0; i < allChildren.size(); i++) { - DecompilerBlock block = allChildren.get(i); + for (DecompilerBlock block : allChildren) { block.setCol(column); } diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/layout/AbstractVisualGraphLayout.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/layout/AbstractVisualGraphLayout.java index 0fba3848f2..afecdf2477 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/layout/AbstractVisualGraphLayout.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/layout/AbstractVisualGraphLayout.java @@ -44,36 +44,36 @@ import ghidra.util.task.TaskMonitor; * A base layout that marries the Visual Graph and Jung layout interfaces. This class allows * you to create new layouts while stubbing the Jung layout methods. * - *

This class essentially takes in client-produced grid row and column indices and + *

This class essentially takes in client-produced grid row and column indices and * produces layout locations for those values. * - *

This an implementation the Jung {@link Layout} interface that handles most of the + *

This an implementation the Jung {@link Layout} interface that handles most of the * layout implementation for you. Things to know: *

- * + * *

By default, this class will create x-position values that - * are aligned with the column's x-position. You can override + * are aligned with the column's x-position. You can override * {@link #getVertexLocation(VisualVertex, Column, Row, Rectangle)} in order to center the * vertex within its column - * {@link #getCenteredVertexLocation(VisualVertex, Column, Row, Rectangle)}. Also note though + * {@link #getCenteredVertexLocation(VisualVertex, Column, Row, Rectangle)}. Also note though * that if your layout returns true for {@link #isCondensedLayout()}, - * then the centering will be condensed and slightly off. - * + * then the centering will be condensed and slightly off. + * * @param the vertex type * @param the edge type - * + * * @see GridLocationMap * @see LayoutPositions */ //@formatter:off -public abstract class AbstractVisualGraphLayout> extends AbstractLayout implements VisualGraphLayout { @@ -106,9 +106,9 @@ public abstract class AbstractVisualGraphLayout newLayout) { @@ -260,7 +260,7 @@ public abstract class AbstractVisualGraphLayout bends = edgesToBends.get(e); if (bends == null) { - // New edge is not in the old graph. This can happen if the old graph has + // New edge is not in the old graph. This can happen if the old graph has // grouped vertices and some edges have been removed. continue; } @@ -313,14 +313,7 @@ public abstract class AbstractVisualGraphLayout vertexLayoutLocations = positionVerticesInLayoutSpace(transformer, vertices, layoutLocations); - Map> edgeLayoutArticulationLocations = - positionEdgeArticulationsInLayoutSpace(transformer, vertexLayoutLocations, edges, - layoutLocations); - - // DEGUG triggers grid lines to be printed; useful for debugging -// VisualGraphRenderer.DEBUG_ROW_COL_MAP.put((Graph) visualGraph, -// layoutLocations.copy()); - + Map> edgeLayoutArticulationLocations = new HashMap<>(); Rectangle graphBounds = getTotalGraphSize(vertexLayoutLocations, edgeLayoutArticulationLocations, transformer); double centerX = graphBounds.getCenterX(); @@ -332,6 +325,12 @@ public abstract class AbstractVisualGraphLayout> 1); int y = row.y + (row.getPaddedHeight(isCondensed) >> 1); @@ -464,8 +463,8 @@ public abstract class AbstractVisualGraphLayout transformer, double centerX, double centerY) { // - // Note: we move the articulations and vertices closer together on the x-axis. We do - // not move the y-axis, as that is already as close together as we would like at + // Note: we move the articulations and vertices closer together on the x-axis. We do + // not move the y-axis, as that is already as close together as we would like at // this point. // double condenseFactor = getCondenseFactor(); @@ -496,14 +495,14 @@ public abstract class AbstractVisualGraphLayout> 1; // half width int myHeight = vertexBounds.height >> 1; // half height double x = vertexPoint.getX(); @@ -635,20 +634,20 @@ public abstract class AbstractVisualGraphLayout the vertex type - * @param the edge type + * @param the edge type */ public class VisualGraphRenderer> extends edu.uci.ics.jung.visualization.renderers.BasicRenderer { @@ -44,7 +44,8 @@ public class VisualGraphRenderer /** * Used for displaying grid information for graph layouts */ - public static Map, LayoutLocationMap> DEBUG_ROW_COL_MAP = new HashMap<>(); + public static Map, LayoutLocationMap> DEBUG_ROW_COL_MAP = + new HashMap<>(); private Renderer.EdgeLabel edgeLabelRenderer = new BasicEdgeLabelRenderer<>(); @@ -122,11 +123,15 @@ public class VisualGraphRenderer edgeLabelRenderer.labelEdge(rc, layout, e, xform.apply(e)); } + @SuppressWarnings({ "unchecked", "rawtypes" }) // the types in the cast matter not private void paintLayoutGridCells(RenderContext renderContext, Layout layout) { // to enable this debug, search java files for commented-out uses of 'DEBUG_ROW_COL_MAP' - Graph graph = layout.getGraph(); - LayoutLocationMap locationMap = DEBUG_ROW_COL_MAP.get(graph); + Layout key = layout; + if (layout instanceof ObservableCachingLayout) { + key = ((ObservableCachingLayout) layout).getDelegate(); + } + LayoutLocationMap locationMap = DEBUG_ROW_COL_MAP.get(key); if (locationMap == null) { return; }