Skip to content

Commit

Permalink
Implement structure view for Smali files
Browse files Browse the repository at this point in the history
  • Loading branch information
donlon committed Dec 31, 2020
1 parent 8601753 commit 18f1c28
Show file tree
Hide file tree
Showing 9 changed files with 284 additions and 9 deletions.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#Thu Feb 06 21:22:32 PST 2020
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
Expand Down
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

0 comments on commit 18f1c28

Please sign in to comment.