diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/actions/GoToAction.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/actions/GoToAction.java index a71e625cd..75f0198e1 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/actions/GoToAction.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/components/actions/GoToAction.java @@ -1,6 +1,7 @@ package the.bytecode.club.bytecodeviewer.gui.components.actions; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rsyntaxtextarea.Token; import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.BytecodeViewPanel; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer; @@ -8,6 +9,9 @@ import the.bytecode.club.bytecodeviewer.resources.ResourceContainer; import the.bytecode.club.bytecodeviewer.resources.classcontainer.ClassFileContainer; import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassFieldLocation; +import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassMethodLocation; +import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassReferenceLocation; +import the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.TokenUtil; import javax.swing.*; import javax.swing.event.CaretEvent; @@ -45,7 +49,7 @@ public void actionPerformed(ActionEvent e) // Open the class that is associated with the field's owner. if (!field.owner.equals(container.getName())) { - openFieldClass(field, textArea); + open(textArea, false, true, false); return; } @@ -98,88 +102,247 @@ public void actionPerformed(ActionEvent e) } } })); + + container.methodMembers.values().forEach(methods -> methods.forEach(method -> { + if (method.line == line && method.columnStart - 1 <= column && method.columnEnd >= column) + { + Element root = textArea.getDocument().getDefaultRootElement(); + if (method.decRef.equalsIgnoreCase("declaration")) + { + int startOffset = root.getElement(method.line - 1).getStartOffset() + (method.columnStart - 1); + textArea.setCaretPosition(startOffset); + } else + { + methods.stream().filter(classMethodLocation -> classMethodLocation.owner.equals(method.owner)).forEach(classMethodLocation -> { + if (classMethodLocation.decRef.equalsIgnoreCase("declaration")) + { + int startOffset = root.getElement(classMethodLocation.line - 1).getStartOffset() + (classMethodLocation.columnStart - 1); + textArea.setCaretPosition(startOffset); + } + }); + + + open(textArea, false, false, true); + } + } + })); + + container.classReferences.values().forEach(classes -> classes.forEach(clazz -> { + String name; + if (clazz.line == line && clazz.columnStart - 1 <= column && clazz.columnEnd - 1 >= column) + { + name = clazz.owner; + Element root = textArea.getDocument().getDefaultRootElement(); + if (clazz.type.equals("declaration")) + { + int startOffset = root.getElement(clazz.line - 1).getStartOffset() + (clazz.columnStart - 1); + textArea.setCaretPosition(startOffset); + } else + { + classes.stream().filter(classReferenceLocation -> classReferenceLocation.owner.equals(name)).forEach(classReferenceLocation -> { + if (classReferenceLocation.type.equals("declaration")) + { + int startOffset = root.getElement(classReferenceLocation.line - 1).getStartOffset() + (classReferenceLocation.columnStart - 1); + textArea.setCaretPosition(startOffset); + } + }); + + // Should not really do anything when the class is already open + open(textArea, true, false, false); + } + } + })); } - /** - * Open a class that contains the declaration of a field. - * - * @param field The field to jump to - * @param textArea The text area of the current class (not the class we are opening) - */ - private void openFieldClass(ClassFieldLocation field, RSyntaxTextArea textArea) + private ClassFileContainer openClass(String lexeme, boolean field, boolean method) { - String token = textArea.modelToToken(textArea.getCaretPosition()).getLexeme(); + if (lexeme.equals(container.getName())) + return null; + ResourceContainer resourceContainer = BytecodeViewer.getFileContainer(container.getParentContainer()); - if (resourceContainer != null) + if (resourceContainer == null) + return null; + + if (field) { - String className = container.getImport(field.owner); + String className = container.getClassForField(lexeme); BytecodeViewer.viewer.workPane.addClassResource(resourceContainer, className + ".class"); ClassViewer activeResource = (ClassViewer) BytecodeViewer.viewer.workPane.getActiveResource(); HashMap classFiles = BytecodeViewer.viewer.workPane.classFiles; - Thread thread = new Thread(() -> { - try - { - BytecodeViewer.updateBusyStatus(true); - Thread.sleep(1000); - } catch (InterruptedException e) - { - throw new RuntimeException(e); - } finally - { - BytecodeViewer.updateBusyStatus(false); - } + return wait(classFiles, activeResource); + } else if (method) + { + ClassMethodLocation classMethodLocation = container.getMethodLocationsFor(lexeme).get(0); + ClassReferenceLocation classReferenceLocation = null; + try + { + classReferenceLocation = container.getClassReferenceLocationsFor(classMethodLocation.owner).get(0); + } catch (Exception ignored) + { + } - String containerName = activeResource.resource.workingName + "-" + this.container.getDecompiler(); - ClassFileContainer classFileContainer = classFiles.get(containerName); - classFileContainer.fieldMembers.forEach((field1, field2) -> { - if (field1.equals(token)) + if (classReferenceLocation == null) + return null; + + String packagePath = classReferenceLocation.packagePath; + if (packagePath.startsWith("java") || packagePath.startsWith("javax") || packagePath.startsWith("com.sun")) + return null; + + String resourceName = packagePath + "/" + classMethodLocation.owner; + if (resourceContainer.resourceClasses.containsKey(resourceName)) + { + BytecodeViewer.viewer.workPane.addClassResource(resourceContainer, resourceName + ".class"); + ClassViewer activeResource = (ClassViewer) BytecodeViewer.viewer.workPane.getActiveResource(); + HashMap classFiles = BytecodeViewer.viewer.workPane.classFiles; + return wait(classFiles, activeResource); + } + } else + { + ClassReferenceLocation classReferenceLocation = container.getClassReferenceLocationsFor(lexeme).get(0); + String packagePath = classReferenceLocation.packagePath; + if (packagePath.startsWith("java") || packagePath.startsWith("javax") || packagePath.startsWith("com.sun")) + return null; + + String resourceName = packagePath + "/" + lexeme; + if (resourceContainer.resourceClasses.containsKey(resourceName)) + { + BytecodeViewer.viewer.workPane.addClassResource(resourceContainer, resourceName + ".class"); + ClassViewer activeResource = (ClassViewer) BytecodeViewer.viewer.workPane.getActiveResource(); + HashMap classFiles = BytecodeViewer.viewer.workPane.classFiles; + return wait(classFiles, activeResource); + } + } + + return null; + } + + private void open(RSyntaxTextArea textArea, boolean isClass, boolean isField, boolean isMethod) + { + Thread thread = new Thread(() -> { + Token token = textArea.modelToToken(textArea.getCaretPosition()); + token = TokenUtil.getToken(textArea, token); + String lexeme = token.getLexeme(); + ClassFileContainer classFileContainer; + if (isClass) + { + classFileContainer = openClass(lexeme, false, false); + if (classFileContainer == null) + return; + + classFileContainer.classReferences.forEach((className, classReference) -> { + if (className.equals(lexeme)) + { + classReference.forEach(classReferenceLocation -> { + if (classReferenceLocation.type.equals("declaration")) + { + moveCursor(classReferenceLocation.line, classReferenceLocation.columnStart); + } + }); + } + }); + } else if (isField) + { + classFileContainer = openClass(lexeme, true, false); + if (classFileContainer == null) + return; + + classFileContainer.fieldMembers.forEach((fieldName, fields) -> { + if (fieldName.equals(lexeme)) { - field2.forEach(classFieldLocation -> { + fields.forEach(classFieldLocation -> { if (classFieldLocation.type.equals("declaration")) { - for (int i = 0; i < 3; i++) - { - BytecodeViewPanel panel = activeResource.getPanel(i); - if (panel.textArea != null) - { - if (panel.decompiler.getDecompilerName().equals(this.container.getDecompiler())) - { - Element root = panel.textArea.getDocument().getDefaultRootElement(); - int startOffset = root.getElement(classFieldLocation.line - 1).getStartOffset() + (classFieldLocation.columnStart - 1); - panel.textArea.setCaretPosition(startOffset); - for (CaretListener caretListener : panel.textArea.getCaretListeners()) - { - if (caretListener instanceof BytecodeViewPanelUpdater.MarkerCaretListener) - { - BytecodeViewPanelUpdater.MarkerCaretListener markerCaretListener = (BytecodeViewPanelUpdater.MarkerCaretListener) caretListener; - markerCaretListener.caretUpdate(new CaretEvent(panel.textArea) - { - @Override - public int getDot() - { - return panel.textArea.getCaret().getDot(); - } - - @Override - public int getMark() - { - return 0; - } - }); - } - } - - panel.textArea.requestFocusInWindow(); - break; - } - } - } + moveCursor(classFieldLocation.line, classFieldLocation.columnStart); } }); } }); + } else if (isMethod) + { + classFileContainer = openClass(lexeme, false, true); + if (classFileContainer == null) + return; + + classFileContainer.methodMembers.forEach((methodName, methods) -> { + if (methodName.equals(lexeme)) + { + methods.forEach(method -> { + if (method.decRef.equalsIgnoreCase("declaration")) + { + moveCursor(method.line, method.columnStart); + } + }); + } + }); + } + }, "Open Class"); + thread.start(); + } + + private ClassFileContainer wait(HashMap classFiles, ClassViewer activeResource) + { + String containerName = activeResource.resource.workingName + "-" + this.container.getDecompiler(); + try + { + BytecodeViewer.updateBusyStatus(true); + Thread.getAllStackTraces().forEach((name, stackTrace) -> { + if (name.getName().equals("Pane Update")) + { + try + { + name.join(); + } catch (InterruptedException e) + { + throw new RuntimeException(e); + } + } }); - thread.start(); + } catch (Exception e) + { + throw new RuntimeException(e); + } finally + { + BytecodeViewer.updateBusyStatus(false); + } + + return classFiles.get(containerName); + } + + private void moveCursor(int line, int columnStart) + { + for (int i = 0; i < 3; i++) + { + BytecodeViewPanel panel = ((ClassViewer) BytecodeViewer.viewer.workPane.getActiveResource()).getPanel(i); + if (panel.decompiler.getDecompilerName().equals(this.container.getDecompiler())) + { + Element root = panel.textArea.getDocument().getDefaultRootElement(); + int startOffset = root.getElement(line - 1).getStartOffset() + (columnStart - 1); + panel.textArea.setCaretPosition(startOffset); + for (CaretListener caretListener : panel.textArea.getCaretListeners()) + { + if (caretListener instanceof BytecodeViewPanelUpdater.MarkerCaretListener) + { + BytecodeViewPanelUpdater.MarkerCaretListener markerCaretListener = (BytecodeViewPanelUpdater.MarkerCaretListener) caretListener; + markerCaretListener.caretUpdate(new CaretEvent(panel.textArea) + { + @Override + public int getDot() + { + return panel.textArea.getCaret().getDot(); + } + + @Override + public int getMark() + { + return 0; + } + }); + } + } + + panel.textArea.requestFocusInWindow(); + break; + } } } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/gui/util/BytecodeViewPanelUpdater.java b/src/main/java/the/bytecode/club/bytecodeviewer/gui/util/BytecodeViewPanelUpdater.java index 9d59d87ed..cf6f73ebd 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/gui/util/BytecodeViewPanelUpdater.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/gui/util/BytecodeViewPanelUpdater.java @@ -34,9 +34,7 @@ import the.bytecode.club.bytecodeviewer.gui.resourceviewer.BytecodeViewPanel; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ClassViewer; import the.bytecode.club.bytecodeviewer.resources.classcontainer.ClassFileContainer; -import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassFieldLocation; -import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassLocalVariableLocation; -import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassParameterLocation; +import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.*; import the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.TokenUtil; import the.bytecode.club.bytecodeviewer.util.MethodParser; @@ -117,7 +115,7 @@ public void processDisplay() final String decompiledSource = decompiler.getDecompiler().decompileClassNode(viewer.resource.getResourceClassNode(), classBytes); ClassFileContainer container = new ClassFileContainer(viewer.resource.workingName + "-" + decompiler.getDecompilerName(), decompiledSource, viewer.resource.container); - if (!container.hasBeenParsed) + if (!BytecodeViewer.viewer.workPane.classFiles.containsKey(viewer.resource.workingName + "-" + decompiler.getDecompilerName())) { container.parse(); BytecodeViewer.viewer.workPane.classFiles.put(viewer.resource.workingName + "-" + decompiler.getDecompilerName(), container); @@ -446,9 +444,13 @@ private void markOccurrences(RSyntaxTextArea textArea, ClassFileContainer classF Token token = textArea.modelToToken(textArea.getCaretPosition()); if (token == null) { - highlighterEx.clearMarkOccurrencesHighlights(); - errorStripe.refreshMarkers(); - return; + token = textArea.modelToToken(textArea.getCaretPosition() - 1); + if (token == null) + { + highlighterEx.clearMarkOccurrencesHighlights(); + errorStripe.refreshMarkers(); + return; + } } token = TokenUtil.getToken(textArea, token); @@ -468,6 +470,11 @@ private void markOccurrences(RSyntaxTextArea textArea, ClassFileContainer classF */ markField(textArea, classFileContainer, line, column, finalToken, highlighterEx); + /* + Methods + */ + markMethod(textArea, classFileContainer, line, column, finalToken, highlighterEx); + /* Method parameters */ @@ -478,6 +485,11 @@ private void markOccurrences(RSyntaxTextArea textArea, ClassFileContainer classF */ markMethodLocalVariable(textArea, classFileContainer, line, column, finalToken, highlighterEx); + /* + Class references + */ + markClasses(textArea, classFileContainer, line, column, finalToken, highlighterEx); + errorStripe.refreshMarkers(); } @@ -489,20 +501,11 @@ private void markField(RSyntaxTextArea textArea, ClassFileContainer classFileCon try { Element root = textArea.getDocument().getDefaultRootElement(); - for ( - ClassFieldLocation location : - classFileContainer.getFieldLocationsFor(finalToken.getLexeme()) - ) + for (ClassFieldLocation location : classFileContainer.getFieldLocationsFor(finalToken.getLexeme())) { - int startOffset = root - .getElement(location.line - 1) - .getStartOffset() + (location.columnStart - 1); - int endOffset = root - .getElement(location.line - 1) - .getStartOffset() + (location.columnEnd - 1); - highlighterEx.addMarkedOccurrenceHighlight( - startOffset, endOffset, new SmartHighlightPainter() - ); + int startOffset = root.getElement(location.line - 1).getStartOffset() + (location.columnStart - 1); + int endOffset = root.getElement(location.line - 1).getStartOffset() + (location.columnEnd - 1); + highlighterEx.addMarkedOccurrenceHighlight(startOffset, endOffset, new SmartHighlightPainter()); } } catch (BadLocationException ex) { @@ -512,6 +515,35 @@ startOffset, endOffset, new SmartHighlightPainter() })); } + private void markMethod(RSyntaxTextArea textArea, ClassFileContainer classFileContainer, int line, int column, Token finalToken, RSyntaxTextAreaHighlighterEx highlighterEx) + { + classFileContainer.methodMembers.values().forEach(methods -> methods.forEach(method -> { + String owner; + String parameters; + if (method.line == line && method.columnStart - 1 <= column && method.columnEnd >= column) + { + owner = method.owner; + parameters = method.methodParameterTypes; + Element root = textArea.getDocument().getDefaultRootElement(); + for (ClassMethodLocation location : classFileContainer.getMethodLocationsFor(finalToken.getLexeme())) + { + try + { + if (Objects.equals(owner, location.owner) && Objects.equals(parameters, location.methodParameterTypes)) + { + int startOffset = root.getElement(location.line - 1).getStartOffset() + (location.columnStart - 1); + int endOffset = root.getElement(location.line - 1).getStartOffset() + (location.columnEnd - 1); + highlighterEx.addMarkedOccurrenceHighlight(startOffset, endOffset, new SmartHighlightPainter()); + } + } catch (BadLocationException e) + { + throw new RuntimeException(e); + } + } + } + })); + } + /** * Search through the text area and mark all occurrences that match the selected token. * @@ -522,14 +554,7 @@ startOffset, endOffset, new SmartHighlightPainter() * @param finalToken the token * @param highlighterEx the highlighter */ - private static void markMethodParameter( - RSyntaxTextArea textArea, - ClassFileContainer classFileContainer, - int line, - int column, - Token finalToken, - RSyntaxTextAreaHighlighterEx highlighterEx - ) + private static void markMethodParameter(RSyntaxTextArea textArea, ClassFileContainer classFileContainer, int line, int column, Token finalToken, RSyntaxTextAreaHighlighterEx highlighterEx) { classFileContainer.methodParameterMembers.values().forEach(parameters -> parameters.forEach(parameter -> { String method; @@ -539,23 +564,14 @@ private static void markMethodParameter( try { Element root = textArea.getDocument().getDefaultRootElement(); - for ( - ClassParameterLocation location : - classFileContainer.getParameterLocationsFor(finalToken.getLexeme()) - ) + for (ClassParameterLocation location : classFileContainer.getParameterLocationsFor(finalToken.getLexeme())) { if (Objects.equals(method, location.method)) { - int startOffset = root - .getElement(location.line - 1) - .getStartOffset() + (location.columnStart - 1); - int endOffset = root - .getElement(location.line - 1) - .getStartOffset() + (location.columnEnd - 1); - - highlighterEx.addMarkedOccurrenceHighlight( - startOffset, endOffset, new SmartHighlightPainter() - ); + int startOffset = root.getElement(location.line - 1).getStartOffset() + (location.columnStart - 1); + int endOffset = root.getElement(location.line - 1).getStartOffset() + (location.columnEnd - 1); + + highlighterEx.addMarkedOccurrenceHighlight(startOffset, endOffset, new SmartHighlightPainter()); } } } catch (BadLocationException ex) @@ -576,14 +592,7 @@ startOffset, endOffset, new SmartHighlightPainter() * @param finalToken the token * @param highlighterEx the highlighter */ - private static void markMethodLocalVariable( - RSyntaxTextArea textArea, - ClassFileContainer classFileContainer, - int line, - int column, - Token finalToken, - RSyntaxTextAreaHighlighterEx highlighterEx - ) + private static void markMethodLocalVariable(RSyntaxTextArea textArea, ClassFileContainer classFileContainer, int line, int column, Token finalToken, RSyntaxTextAreaHighlighterEx highlighterEx) { classFileContainer.methodLocalMembers.values().forEach(localVariables -> localVariables.forEach(localVariable -> { String method; @@ -593,23 +602,14 @@ private static void markMethodLocalVariable( try { Element root = textArea.getDocument().getDefaultRootElement(); - for ( - ClassLocalVariableLocation location : - classFileContainer.getLocalLocationsFor(finalToken.getLexeme()) - ) + for (ClassLocalVariableLocation location : classFileContainer.getLocalLocationsFor(finalToken.getLexeme())) { if (Objects.equals(method, location.method)) { - int startOffset = root - .getElement(location.line - 1) - .getStartOffset() + (location.columnStart - 1); - int endOffset = root - .getElement(location.line - 1) - .getStartOffset() + (location.columnEnd - 1); - - highlighterEx.addMarkedOccurrenceHighlight( - startOffset, endOffset, new SmartHighlightPainter() - ); + int startOffset = root.getElement(location.line - 1).getStartOffset() + (location.columnStart - 1); + int endOffset = root.getElement(location.line - 1).getStartOffset() + (location.columnEnd - 1); + + highlighterEx.addMarkedOccurrenceHighlight(startOffset, endOffset, new SmartHighlightPainter()); } } } catch (BadLocationException ex) @@ -620,9 +620,29 @@ startOffset, endOffset, new SmartHighlightPainter() })); } - public class MarkerCaretListener implements CaretListener + private void markClasses(RSyntaxTextArea textArea, ClassFileContainer classFileContainer, int line, int column, Token finalToken, RSyntaxTextAreaHighlighterEx highlighterEx) { + classFileContainer.classReferences.values().forEach(classes -> classes.forEach(clazz -> { + if (clazz.line == line && clazz.columnStart - 1 <= column && clazz.columnEnd - 1 >= column) + { + try + { + Element root = textArea.getDocument().getDefaultRootElement(); + for (ClassReferenceLocation location : classFileContainer.getClassReferenceLocationsFor(finalToken.getLexeme())) + { + int startOffset = root.getElement(location.line - 1).getStartOffset() + (location.columnStart - 1); + int endOffset = root.getElement(location.line - 1).getStartOffset() + (location.columnEnd - 1); + highlighterEx.addMarkedOccurrenceHighlight(startOffset, endOffset, new SmartHighlightPainter()); + } + } catch (Exception ignored) + { + } + } + })); + } + public class MarkerCaretListener implements CaretListener + { private final String classContainerName; public MarkerCaretListener(String classContainerName) diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/ClassFileContainer.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/ClassFileContainer.java index 78265f241..f9b68eb5f 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/ClassFileContainer.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/ClassFileContainer.java @@ -9,10 +9,7 @@ import com.github.javaparser.symbolsolver.resolution.typesolvers.JarTypeSolver; import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; import the.bytecode.club.bytecodeviewer.resources.ResourceContainer; -import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassFieldLocation; -import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassLocalVariableLocation; -import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassMethodLocation; -import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassParameterLocation; +import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.*; import the.bytecode.club.bytecodeviewer.resources.classcontainer.parser.MyVoidVisitor; import java.io.IOException; @@ -20,6 +17,7 @@ import java.util.List; import java.util.NavigableMap; import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicReference; /** * This is a container for a specific class. The container name is based on the actual class name and the decompiler used. @@ -33,7 +31,7 @@ public class ClassFileContainer public transient NavigableMap> methodParameterMembers = new TreeMap<>(); public transient NavigableMap> methodLocalMembers = new TreeMap<>(); public transient NavigableMap> methodMembers = new TreeMap<>(); - public transient NavigableMap imports = new TreeMap<>(); + public transient NavigableMap> classReferences = new TreeMap<>(); public boolean hasBeenParsed = false; public final String className; @@ -56,7 +54,7 @@ public void parse() { try { - TypeSolver typeSolver = new CombinedTypeSolver(new ReflectionTypeSolver(), new JarTypeSolver(path)); + TypeSolver typeSolver = new CombinedTypeSolver(new ReflectionTypeSolver(false), new JarTypeSolver(path)); StaticJavaParser.getParserConfiguration().setSymbolResolver(new JavaSymbolSolver(typeSolver)); CompilationUnit compilationUnit = StaticJavaParser.parse(this.content); compilationUnit.accept(new MyVoidVisitor(this, compilationUnit), null); @@ -71,12 +69,12 @@ public void parse() public String getName() { - return this.className.substring(this.className.lastIndexOf('.') + 1); + return this.className.substring(this.className.lastIndexOf('/') + 1, this.className.lastIndexOf('.')); } public String getDecompiler() { - return getName().substring(6); + return this.className.substring(this.className.lastIndexOf('-') + 1); } public String getParentContainer() @@ -124,14 +122,28 @@ public List getMethodLocationsFor(String key) return methodMembers.getOrDefault(key, new ArrayList<>()); } - public void putImport(String key, String value) + public void putClassReference(String key, ClassReferenceLocation value) { - this.imports.put(key, value); + this.classReferences.computeIfAbsent(key, v -> new ArrayList<>()).add(value); } - public String getImport(String key) + public List getClassReferenceLocationsFor(String key) { - String value = this.imports.get(key); - return value + "/" + key; + return classReferences.getOrDefault(key, null); + } + + public String getClassForField(String fieldName) + { + AtomicReference className = new AtomicReference<>(""); + this.classReferences.forEach((s, v) -> { + v.forEach(classReferenceLocation -> { + if (classReferenceLocation.fieldName.equals(fieldName)) + { + className.set(classReferenceLocation.packagePath + "/" + s); + } + }); + }); + + return className.get(); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/locations/ClassMethodLocation.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/locations/ClassMethodLocation.java index 34b821d44..38b474e1b 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/locations/ClassMethodLocation.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/locations/ClassMethodLocation.java @@ -7,15 +7,17 @@ public class ClassMethodLocation { public final String owner; + public final String signature; public final String methodParameterTypes; public final String decRef; public final int line; public final int columnStart; public final int columnEnd; - public ClassMethodLocation(String owner, String methodParameterTypes, String decRef, int line, int columnStart, int columnEnd) + public ClassMethodLocation(String owner, String signature, String methodParameterTypes, String decRef, int line, int columnStart, int columnEnd) { this.owner = owner; + this.signature = signature; this.methodParameterTypes = methodParameterTypes; this.decRef = decRef; this.line = line; diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/locations/ClassReferenceLocation.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/locations/ClassReferenceLocation.java new file mode 100644 index 000000000..620e3b2db --- /dev/null +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/locations/ClassReferenceLocation.java @@ -0,0 +1,33 @@ +package the.bytecode.club.bytecodeviewer.resources.classcontainer.locations; + +/** + * Created by Bl3nd. + * Date: 9/20/2024 + */ +public class ClassReferenceLocation +{ + public final String owner; + public final String packagePath; + public final String fieldName; + public final String type; + public final int line; + public final int columnStart; + public final int columnEnd; + + public ClassReferenceLocation(String owner, String packagePath, String fieldName, String type, int line, int columnStart, int columnEnd) + { + this.owner = owner; + this.packagePath = packagePath; + this.fieldName = fieldName; + this.type = type; + this.line = line; + this.columnStart = columnStart; + this.columnEnd = columnEnd; + } + + @Override + public String toString() + { + return "ClassClassLocation{" + "owner='" + owner + '\'' + ", fieldName='" + fieldName + '\'' + ", type='" + type + '\'' + ", line=" + line + ", columnStart=" + columnStart + ", columnEnd=" + columnEnd + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/MyVoidVisitor.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/MyVoidVisitor.java index 99b6dfba1..ae5a2ec8a 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/MyVoidVisitor.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/MyVoidVisitor.java @@ -2,22 +2,19 @@ import com.github.javaparser.Range; import com.github.javaparser.ast.CompilationUnit; -import com.github.javaparser.ast.ImportDeclaration; import com.github.javaparser.ast.body.*; import com.github.javaparser.ast.expr.*; import com.github.javaparser.ast.stmt.*; +import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import com.github.javaparser.resolution.UnsolvedSymbolException; +import com.github.javaparser.resolution.declarations.ResolvedConstructorDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; import com.github.javaparser.resolution.types.ResolvedType; import the.bytecode.club.bytecodeviewer.resources.classcontainer.ClassFileContainer; -import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassFieldLocation; -import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassLocalVariableLocation; -import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassMethodLocation; -import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassParameterLocation; - -import java.util.Objects; -import java.util.concurrent.atomic.AtomicInteger; +import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.*; /** * Our custom visitor that allows us to get the information from JavaParser we need. @@ -47,6 +44,19 @@ private String getMethod(CallableDeclaration method) return method.getDeclarationAsString(false, false); } + @Override + public void visit(ClassOrInterfaceDeclaration n, Object arg) + { + super.visit(n, arg); + SimpleName name = n.getName(); + Range range = name.getRange().get(); + ResolvedReferenceTypeDeclaration resolve = n.resolve(); + int line = range.begin.line; + int columnStart = range.begin.column; + int columnEnd = range.end.column; + this.classFileContainer.putClassReference(resolve.getName(), new ClassReferenceLocation(getOwner(), resolve.getPackageName(), "", "declaration", line, columnStart, columnEnd + 1)); + } + /** * Visit all {@link FieldDeclaration}s. *

@@ -72,16 +82,21 @@ public void visit(FieldDeclaration n, Object arg) } @Override - public void visit(ImportDeclaration n, Object arg) + public void visit(ClassOrInterfaceType n, Object arg) { super.visit(n, arg); - if (!n.isAsterisk()) + try { - Name class_ = n.getName(); - String className = class_.getIdentifier(); - String package_ = Objects.requireNonNull(class_.getQualifier().orElse(null)).asString(); - package_ = package_.replace('.', '/'); - this.classFileContainer.putImport(className, package_); + ResolvedType resolve = n.resolve(); + String nameAsString = n.getNameAsString(); + String qualifiedName = resolve.asReferenceType().getQualifiedName(); + String packagePath = qualifiedName.substring(0, qualifiedName.lastIndexOf('.')).replace('.', '/'); + Range range = n.getName().getRange().get(); + int line = range.begin.line; + int columnStart = range.begin.column; + int columnEnd = range.end.column; + this.classFileContainer.putClassReference(nameAsString, new ClassReferenceLocation(getOwner(), packagePath, "", "reference", line, columnStart, columnEnd + 1)); + } catch (Exception e) { } } @@ -144,9 +159,17 @@ public void visit(FieldAccessExpr n, Object arg) String qualifiedName = resolvedType.asReferenceType().getQualifiedName(); String className = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1); String packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf('.')); - this.classFileContainer.putImport(className, packageName.replace('.', '/')); + this.classFileContainer.putClassReference(className, new ClassReferenceLocation(getOwner(), packageName.replace('.', '/'), fieldName, "reference", line1, columnStart1, columnEnd1 + 1)); this.classFileContainer.putField(fieldName, new ClassFieldLocation(name1, "reference", line, columnStart, columnEnd + 1)); } + } else if (scope instanceof ThisExpr) { + ThisExpr thisExpr = (ThisExpr) scope; + ResolvedType resolvedType = n.getSymbolResolver().calculateType(thisExpr); + String qualifiedName = resolvedType.asReferenceType().getQualifiedName(); + String className = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1); + String packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf('.')); + this.classFileContainer.putClassReference(className, new ClassReferenceLocation(getOwner(), packageName.replace('.', '/'), fieldName, "reference", line, columnStart, columnEnd + 1)); + this.classFileContainer.putField(fieldName, new ClassFieldLocation(className, "reference", line, columnStart, columnEnd + 1)); } } } @@ -165,8 +188,6 @@ public void visit(FieldAccessExpr n, Object arg) public void visit(ConstructorDeclaration n, Object arg) { super.visit(n, arg); - StringBuilder parameterTypes = new StringBuilder(); - AtomicInteger count = new AtomicInteger(); n.getParameters().forEach(parameter -> { SimpleName name = parameter.getName(); String parameterName = name.getIdentifier(); @@ -174,25 +195,24 @@ public void visit(ConstructorDeclaration n, Object arg) int line = range.begin.line; int columnStart = range.begin.column; int columnEnd = range.end.column; - this.classFileContainer.putParameter(parameterName, new ClassParameterLocation(getOwner(), n.getDeclarationAsString(false, false), - "declaration", line, columnStart, columnEnd + 1)); - count.getAndIncrement(); - parameterTypes.append(parameter.getTypeAsString()); - if (n.getParameters().size() > 1 && count.get() != n.getParameters().size()) - { - parameterTypes.append(", "); - } + this.classFileContainer.putParameter(parameterName, new ClassParameterLocation(getOwner(), n.getDeclarationAsString(false, false), "declaration", line, columnStart, columnEnd + 1)); }); + ResolvedConstructorDeclaration resolve = n.resolve(); + String signature = resolve.getQualifiedSignature(); + String parameters = ""; + if (resolve.getNumberOfParams() != 0) + { + parameters = signature.substring(signature.indexOf('(') + 1, signature.lastIndexOf(')')); + } + SimpleName simpleName = n.getName(); String constructorName = simpleName.getIdentifier(); Range range = simpleName.getRange().get(); int line = range.begin.line; int columnStart = range.begin.column; int columnEnd = range.end.column; - this.classFileContainer.putMethod(constructorName, new ClassMethodLocation(getOwner(), parameterTypes.toString(), "declaration", line, - columnStart, - columnEnd + 1)); + this.classFileContainer.putMethod(constructorName, new ClassMethodLocation(resolve.getClassName(), signature, parameters, "declaration", line, columnStart, columnEnd + 1)); } /** @@ -261,33 +281,31 @@ public void visit(ExplicitConstructorInvocationStmt n, Object arg) public void visit(MethodDeclaration n, Object arg) { super.visit(n, arg); - StringBuilder parameterTypes = new StringBuilder(); - AtomicInteger count = new AtomicInteger(); - n.getParameters().forEach(parameter -> { - SimpleName name = parameter.getName(); - String parameterName = name.getIdentifier(); - Range range = name.getRange().get(); - int line = range.begin.line; - int columnStart = range.begin.column; - int columnEnd = range.end.column; - this.classFileContainer.putParameter(parameterName, new ClassParameterLocation(getOwner(), n.getDeclarationAsString(false, false), - "declaration", line, columnStart, columnEnd + 1)); - count.getAndIncrement(); - parameterTypes.append(parameter.getTypeAsString()); - if (n.getParameters().size() > 1 && count.get() != n.getParameters().size()) - { - parameterTypes.append(", "); - } - }); + ResolvedMethodDeclaration resolve = n.resolve(); + String signature = resolve.getQualifiedSignature(); + String parameters = ""; + if (resolve.getNumberOfParams() != 0) + { + parameters = signature.substring(signature.indexOf('(') + 1, signature.lastIndexOf(')')); + } SimpleName methodSimpleName = n.getName(); - String methodName = methodSimpleName.getIdentifier(); Range range = methodSimpleName.getRange().get(); int line = range.begin.line; int columnStart = range.begin.column; int columnEnd = range.end.column; - this.classFileContainer.putMethod(methodName, new ClassMethodLocation(getOwner(), parameterTypes.toString(), "declaration", line, columnStart, - columnEnd + 1)); + this.classFileContainer.putMethod(methodSimpleName.getIdentifier(), new ClassMethodLocation(resolve.getClassName(), signature, parameters, "declaration", line, columnStart, columnEnd + 1)); + + n.getParameters().forEach(parameter -> { + SimpleName name = parameter.getName(); + String parameterName = name.getIdentifier(); + Range range1 = name.getRange().get(); + int line1 = range1.begin.line; + int columnStart1 = range1.begin.column; + int columnEnd1 = range1.end.column; + this.classFileContainer.putParameter(parameterName, new ClassParameterLocation(getOwner(), n.getDeclarationAsString(false, false), + "declaration", line1, columnStart1, columnEnd1 + 1)); + }); } /** @@ -311,6 +329,26 @@ public void visit(MethodCallExpr n, Object arg) } } + try + { + ResolvedMethodDeclaration resolve = n.resolve(); + String signature = resolve.getQualifiedSignature(); + String parameters = ""; + if (resolve.getNumberOfParams() != 0) + { + parameters = signature.substring(signature.indexOf('(') + 1, signature.lastIndexOf(')')); + } + + SimpleName methodSimpleName = n.getName(); + Range range = methodSimpleName.getRange().get(); + int line = range.begin.line; + int columnStart = range.begin.column; + int columnEnd = range.end.column; + this.classFileContainer.putMethod(methodSimpleName.getIdentifier(), new ClassMethodLocation(resolve.getClassName(), signature, parameters, "reference", line, columnStart, columnEnd + 1)); + } catch (Exception e) + { + } + if (method != null) { if (n.hasScope()) @@ -319,28 +357,32 @@ public void visit(MethodCallExpr n, Object arg) if (scope instanceof NameExpr) { NameExpr nameExpr = (NameExpr) scope; + SimpleName simpleName = nameExpr.getName(); + String name = simpleName.getIdentifier(); + Range range1 = simpleName.getRange().get(); + int line1 = range1.begin.line; + int columnStart1 = range1.begin.column; + int columnEnd1 = range1.end.column; try { ResolvedValueDeclaration vd = nameExpr.resolve(); - SimpleName simpleName = nameExpr.getName(); - String name = simpleName.getIdentifier(); - Range range = simpleName.getRange().get(); - int line = range.begin.line; - int columnStart = range.begin.column; - int columnEnd = range.end.column; if (vd.isField()) { - this.classFileContainer.putField(name, new ClassFieldLocation(getOwner(), "reference", line, columnStart, columnEnd + 1)); + this.classFileContainer.putField(name, new ClassFieldLocation(getOwner(), "reference", line1, columnStart1, columnEnd1 + 1)); } else if (vd.isVariable()) { - this.classFileContainer.putLocalVariable(name, new ClassLocalVariableLocation(getOwner(), getMethod(method), "reference", line, columnStart, columnEnd + 1)); + this.classFileContainer.putLocalVariable(name, new ClassLocalVariableLocation(getOwner(), getMethod(method), "reference", line1, columnStart1, columnEnd1 + 1)); } else if (vd.isParameter()) { - this.classFileContainer.putParameter(name, new ClassParameterLocation(getOwner(), getMethod(method), "reference", line, columnStart, columnEnd + 1)); + this.classFileContainer.putParameter(name, new ClassParameterLocation(getOwner(), getMethod(method), "reference", line1, columnStart1, columnEnd1 + 1)); } } catch (UnsolvedSymbolException ignored) { - + ResolvedType resolvedType = n.getSymbolResolver().calculateType(nameExpr); + String qualifiedName = resolvedType.asReferenceType().getQualifiedName(); + String className = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1); + String packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf('.')); + this.classFileContainer.putClassReference(className, new ClassReferenceLocation(getOwner(), packageName.replace('.', '/'), "", "reference", line1, columnStart1, columnEnd1 + 1)); } } } @@ -353,19 +395,19 @@ public void visit(MethodCallExpr n, Object arg) ResolvedValueDeclaration vd = nameExpr.resolve(); SimpleName simpleName = nameExpr.getName(); String name = simpleName.getIdentifier(); - Range range = simpleName.getRange().get(); - int line = range.begin.line; - int columnStart = range.begin.column; - int columnEnd = range.end.column; + Range range1 = simpleName.getRange().get(); + int line1 = range1.begin.line; + int columnStart1 = range1.begin.column; + int columnEnd1 = range1.end.column; if (vd.isField()) { - this.classFileContainer.putField(name, new ClassFieldLocation(getOwner(), "reference", line, columnStart, columnEnd + 1)); + this.classFileContainer.putField(name, new ClassFieldLocation(getOwner(), "reference", line1, columnStart1, columnEnd1 + 1)); } else if (vd.isVariable()) { - this.classFileContainer.putLocalVariable(name, new ClassLocalVariableLocation(getOwner(), getMethod(finalMethod), "reference", line, columnStart, columnEnd + 1)); + this.classFileContainer.putLocalVariable(name, new ClassLocalVariableLocation(getOwner(), getMethod(finalMethod), "reference", line1, columnStart1, columnEnd1 + 1)); } else if (vd.isParameter()) { - this.classFileContainer.putParameter(name, new ClassParameterLocation(getOwner(), getMethod(finalMethod), "reference", line, columnStart, columnEnd + 1)); + this.classFileContainer.putParameter(name, new ClassParameterLocation(getOwner(), getMethod(finalMethod), "reference", line1, columnStart1, columnEnd1 + 1)); } } }); @@ -382,19 +424,19 @@ public void visit(MethodCallExpr n, Object arg) ResolvedValueDeclaration vd = nameExpr.resolve(); SimpleName simpleName = nameExpr.getName(); String name = simpleName.getIdentifier(); - Range range = simpleName.getRange().get(); - int line = range.begin.line; - int columnStart = range.begin.column; - int columnEnd = range.end.column; + Range range1 = simpleName.getRange().get(); + int line1 = range1.begin.line; + int columnStart1 = range1.begin.column; + int columnEnd1 = range1.end.column; if (vd.isField()) { - this.classFileContainer.putField(name, new ClassFieldLocation(getOwner(), "reference", line, columnStart, columnEnd + 1)); + this.classFileContainer.putField(name, new ClassFieldLocation(getOwner(), "reference", line1, columnStart1, columnEnd1 + 1)); } else if (vd.isVariable()) { - this.classFileContainer.putLocalVariable(name, new ClassLocalVariableLocation(getOwner(), "static", "reference", line, columnStart, columnEnd + 1)); + this.classFileContainer.putLocalVariable(name, new ClassLocalVariableLocation(getOwner(), "static", "reference", line1, columnStart1, columnEnd1 + 1)); } else if (vd.isParameter()) { - this.classFileContainer.putParameter(name, new ClassParameterLocation(getOwner(), "static", "reference", line, columnStart, columnEnd + 1)); + this.classFileContainer.putParameter(name, new ClassParameterLocation(getOwner(), "static", "reference", line1, columnStart1, columnEnd1 + 1)); } } catch (UnsolvedSymbolException ignored) { @@ -410,19 +452,19 @@ public void visit(MethodCallExpr n, Object arg) ResolvedValueDeclaration vd = nameExpr.resolve(); SimpleName simpleName = nameExpr.getName(); String name = simpleName.getIdentifier(); - Range range = simpleName.getRange().get(); - int line = range.begin.line; - int columnStart = range.begin.column; - int columnEnd = range.end.column; + Range range1 = simpleName.getRange().get(); + int line1 = range1.begin.line; + int columnStart1 = range1.begin.column; + int columnEnd1 = range1.end.column; if (vd.isField()) { - this.classFileContainer.putField(name, new ClassFieldLocation(getOwner(), "reference", line, columnStart, columnEnd + 1)); + this.classFileContainer.putField(name, new ClassFieldLocation(getOwner(), "reference", line1, columnStart1, columnEnd1 + 1)); } else if (vd.isVariable()) { - this.classFileContainer.putLocalVariable(name, new ClassLocalVariableLocation(getOwner(), "static", "reference", line, columnStart, columnEnd + 1)); + this.classFileContainer.putLocalVariable(name, new ClassLocalVariableLocation(getOwner(), "static", "reference", line1, columnStart1, columnEnd1 + 1)); } else if (vd.isParameter()) { - this.classFileContainer.putParameter(name, new ClassParameterLocation(getOwner(), "static", "reference", line, columnStart, columnEnd + 1)); + this.classFileContainer.putParameter(name, new ClassParameterLocation(getOwner(), "static", "reference", line1, columnStart1, columnEnd1 + 1)); } } }); @@ -640,9 +682,7 @@ public void visit(AssignExpr n, Object arg) } else if (vd.isVariable()) { this.classFileContainer.putLocalVariable(name, new ClassLocalVariableLocation(getOwner(), "static", "reference", line, columnStart, columnEnd + 1)); - }/* else if (vd.isParameter()) { - System.err.println("AssignExpr - parameter2"); - }*/ + } } catch (UnsolvedSymbolException e) { System.err.println(nameExpr.getName().getIdentifier() + " not resolved. " + e.getMessage()); diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/TokenUtil.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/TokenUtil.java index 5bb5b8ae0..0860efd7a 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/TokenUtil.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/TokenUtil.java @@ -24,6 +24,7 @@ public static Token getToken(final RSyntaxTextArea textArea, final @NotNull Toke || lexeme.equals(" ") || lexeme.equals(";") || lexeme.equals(",") + || lexeme.equals(">") ? textArea.modelToToken(textArea.getCaretPosition() - 1) : token; }