Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement structure view for Smali files #14

Merged
merged 1 commit into from
Feb 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@
import com.intellij.debugger.SourcePosition;
import com.intellij.lang.ASTNode;
import com.intellij.navigation.ItemPresentation;
import com.intellij.navigation.ItemPresentationProviders;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.PsiModifier.ModifierConstant;
import com.intellij.psi.impl.ElementPresentationUtil;
import com.intellij.psi.impl.InheritanceImplUtil;
import com.intellij.psi.impl.PsiClassImplUtil;
import com.intellij.psi.impl.PsiImplUtil;
Expand All @@ -59,13 +59,14 @@
import org.jf.smalidea.psi.iface.SmaliModifierListOwner;
import org.jf.smalidea.psi.leaf.SmaliClassDescriptor;
import org.jf.smalidea.psi.stub.SmaliClassStub;
import org.jf.smalidea.util.IconUtils;

import javax.annotation.Nonnull;
import javax.swing.*;
import java.util.Collection;
import java.util.List;

public class SmaliClass extends SmaliStubBasedPsiElement<SmaliClassStub> implements PsiClass, SmaliModifierListOwner {
public class SmaliClass extends SmaliStubBasedPsiElement<SmaliClassStub> implements PsiClass, SmaliModifierListOwner, ItemPresentation {
public SmaliClass(@NotNull SmaliClassStub stub) {
super(stub, SmaliElementTypes.CLASS);
}
Expand All @@ -89,7 +90,7 @@ public String getName() {
}

@Override public ItemPresentation getPresentation() {
return ItemPresentationProviders.getItemPresentation(this);
return this;
}

@Nullable @Override public String getQualifiedName() {
Expand Down Expand Up @@ -422,4 +423,23 @@ public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNul
@Nullable @Override protected Icon getElementIcon(@IconFlags int flags) {
return SmaliIcons.SmaliIcon;
}

@Nullable
@Override
public String getPresentableText() {
return getName();
}

@Nullable
@Override
public String getLocationString() {
return getPackageName();
}

@Nullable
@Override
public Icon getIcon(boolean unused) {
int basicClassKind = ElementPresentationUtil.getBasicClassKind(this);
return IconUtils.getElementIcon(this, ElementPresentationUtil.getClassIconOfKind(this, basicClassKind));
}
}
30 changes: 29 additions & 1 deletion src/main/java/org/jf/smalidea/psi/impl/SmaliField.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,25 @@
package org.jf.smalidea.psi.impl;

import com.intellij.lang.ASTNode;
import com.intellij.navigation.ItemPresentation;
import com.intellij.psi.*;
import com.intellij.psi.PsiModifier.ModifierConstant;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.PlatformIcons;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jf.smalidea.psi.SmaliElementTypes;
import org.jf.smalidea.psi.iface.SmaliModifierListOwner;
import org.jf.smalidea.psi.stub.SmaliFieldStub;
import org.jf.smalidea.util.IconUtils;
import org.jf.smalidea.util.NameUtils;

public class SmaliField extends SmaliStubBasedPsiElement<SmaliFieldStub> implements PsiField, SmaliModifierListOwner {
import javax.swing.*;

public class SmaliField extends SmaliStubBasedPsiElement<SmaliFieldStub> implements PsiField, SmaliModifierListOwner, ItemPresentation {
public SmaliField(@NotNull SmaliFieldStub stub) {
super(stub, SmaliElementTypes.FIELD);
}
Expand Down Expand Up @@ -79,6 +84,11 @@ public SmaliField(@NotNull ASTNode node) {
return memberName;
}

@Override
public ItemPresentation getPresentation() {
return this;
}

@Nullable @Override public PsiDocComment getDocComment() {
return null;
}
Expand Down Expand Up @@ -175,4 +185,22 @@ public SmaliField(@NotNull ASTNode node) {
}
return super.getTextOffset();
}

@Nullable
@Override
public String getPresentableText() {
return getName() + ": " + getType().getPresentableText();
}

@Nullable
@Override
public String getLocationString() {
return "";
}

@Nullable
@Override
public Icon getIcon(boolean unused) {
return IconUtils.getElementIcon(this, PlatformIcons.FIELD_ICON);
}
}
48 changes: 44 additions & 4 deletions src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,17 @@
import com.google.common.collect.Maps;
import com.intellij.debugger.SourcePosition;
import com.intellij.lang.ASTNode;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.editor.Document;
import com.intellij.psi.*;
import com.intellij.psi.PsiModifier.ModifierConstant;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.PsiSuperMethodImplUtil;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.*;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.PlatformIcons;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand All @@ -57,14 +58,16 @@
import org.jf.smalidea.psi.SmaliElementTypes;
import org.jf.smalidea.psi.iface.SmaliModifierListOwner;
import org.jf.smalidea.psi.stub.SmaliMethodStub;
import org.jf.smalidea.util.IconUtils;

import javax.swing.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class SmaliMethod extends SmaliStubBasedPsiElement<SmaliMethodStub>
implements PsiMethod, SmaliModifierListOwner, PsiAnnotationMethod {
implements PsiMethod, SmaliModifierListOwner, PsiAnnotationMethod, ItemPresentation {
public SmaliMethod(@NotNull SmaliMethodStub stub) {
super(stub, SmaliElementTypes.METHOD);
}
Expand All @@ -90,6 +93,10 @@ public SmaliMethod(@NotNull ASTNode node) {
return name;
}

@Override public ItemPresentation getPresentation() {
return this;
}

@Override public boolean hasTypeParameters() {
// TODO: (generics) implement this
return false;
Expand Down Expand Up @@ -372,4 +379,37 @@ public MethodAnalyzer getMethodAnalyzer() {
}
return null;
}

@Nullable
@Override
public String getPresentableText() {
return PsiFormatUtil.formatMethod(this, PsiSubstitutor.EMPTY,
PsiFormatUtilBase.SHOW_NAME
| PsiFormatUtilBase.SHOW_TYPE | PsiFormatUtilBase.TYPE_AFTER
| PsiFormatUtilBase.SHOW_PARAMETERS,
PsiFormatUtilBase.SHOW_TYPE);
}

@Nullable
@Override
public String getLocationString() {
PsiMethod superMethod = findDeepestSuperMethod();
if (superMethod != null) {
char upArrow = '\u2191';
PsiClass containingClass = superMethod.getContainingClass();
if (containingClass != null) {
String location = containingClass.getQualifiedName();
return UIUtil.getLabelFont().canDisplay(upArrow) ? upArrow + location : location;
}
}
return "";
}

@Nullable
@Override
public Icon getIcon(boolean unused) {
return IconUtils.getElementIcon(this, hasModifierProperty(PsiModifier.ABSTRACT)
? PlatformIcons.ABSTRACT_METHOD_ICON
: PlatformIcons.METHOD_ICON);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.jf.smalidea.structureView;

import com.intellij.ide.structureView.StructureViewModel;
import com.intellij.ide.structureView.StructureViewModelBase;
import com.intellij.ide.structureView.StructureViewTreeElement;
import com.intellij.ide.util.treeView.smartTree.Sorter;
import org.jetbrains.annotations.NotNull;
import org.jf.smalidea.psi.impl.SmaliFile;

public class SmaliFileTreeModel extends StructureViewModelBase implements
StructureViewModel.ElementInfoProvider {
public SmaliFileTreeModel(SmaliFile psiFile) {
super(psiFile, new SmaliStructureViewElement(psiFile));
}

@NotNull
public Sorter[] getSorters() {
return new Sorter[] {
Sorter.ALPHA_SORTER};
}

@Override
public boolean isAlwaysShowsPlus(StructureViewTreeElement element) {
return false;
}

@Override
public boolean isAlwaysLeaf(StructureViewTreeElement element) {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.jf.smalidea.structureView;

import com.intellij.ide.structureView.StructureViewBuilder;
import com.intellij.ide.structureView.StructureViewModel;
import com.intellij.ide.structureView.TreeBasedStructureViewBuilder;
import com.intellij.lang.PsiStructureViewFactory;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jf.smalidea.psi.impl.SmaliFile;

public class SmaliStructureViewBuilderFactory implements PsiStructureViewFactory {
@Nullable
@Override
public StructureViewBuilder getStructureViewBuilder(@NotNull final PsiFile psiFile) {
if (!(psiFile instanceof SmaliFile)) {
return null;
}
return new TreeBasedStructureViewBuilder() {
@Override
@NotNull
public StructureViewModel createStructureViewModel(@Nullable Editor editor) {
return new SmaliFileTreeModel((SmaliFile) psiFile);
}

@Override
public boolean isRootNodeShown() {
return false;
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package org.jf.smalidea.structureView;

import com.intellij.ide.projectView.PresentationData;
import com.intellij.ide.structureView.StructureViewTreeElement;
import com.intellij.ide.util.treeView.smartTree.SortableTreeElement;
import com.intellij.ide.util.treeView.smartTree.TreeElement;
import com.intellij.navigation.ItemPresentation;
import com.intellij.psi.NavigatablePsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMethod;
import org.jetbrains.annotations.NotNull;
import org.jf.smalidea.psi.impl.SmaliClass;
import org.jf.smalidea.psi.impl.SmaliFile;

import java.util.ArrayList;
import java.util.List;

public class SmaliStructureViewElement implements StructureViewTreeElement, SortableTreeElement {
private final NavigatablePsiElement element;

public SmaliStructureViewElement(NavigatablePsiElement element) {
this.element = element;
}

@Override
public Object getValue() {
return element;
}

@Override
public void navigate(boolean requestFocus) {
element.navigate(requestFocus);
}

@Override
public boolean canNavigate() {
return element.canNavigate();
}

@Override
public boolean canNavigateToSource() {
return element.canNavigateToSource();
}

@NotNull
@Override
public String getAlphaSortKey() {
String name = element.getName();
return name != null ? name : "";
}

@NotNull
@Override
public ItemPresentation getPresentation() {
ItemPresentation presentation = element.getPresentation();
return presentation != null ? presentation : new PresentationData();
}

@NotNull
@Override
public TreeElement[] getChildren() {
if (element instanceof SmaliFile) {
SmaliFile smaliFile = (SmaliFile) element;
SmaliClass[] classes = smaliFile.getClasses();
TreeElement[] treeElements = new TreeElement[classes.length];
for (int i = 0; i < classes.length; i++) {
treeElements[i] = new SmaliStructureViewElement(classes[i]);
}
return treeElements;
} else if (element instanceof SmaliClass) {
SmaliClass smaliClass = (SmaliClass) element;
PsiField[] fields = smaliClass.getFields();
PsiMethod[] methods = smaliClass.getMethods();

List<TreeElement> treeElements = new ArrayList<>(fields.length + methods.length);
for (PsiField field : fields) {
treeElements.add(new SmaliStructureViewElement(field));
}
for (PsiMethod method : methods) {
treeElements.add(new SmaliStructureViewElement(method));
}
return treeElements.toArray(new TreeElement[0]);
} else {
return EMPTY_ARRAY;
}
}
}
Loading