mirror of
https://github.com/revanced/smali.git
synced 2025-05-01 15:14:32 +02:00
Provide better register type information
This commit is contained in:
parent
6417e812e1
commit
ff4c85c5e4
@ -126,7 +126,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'org.smali:smali:2.1.2'
|
||||
compile 'org.smali:smali:2.1.2-205bf333'
|
||||
compile 'org.antlr:antlr-runtime:3.5.2'
|
||||
compile 'com.google.code.gson:gson:2.3.1'
|
||||
|
||||
|
@ -58,6 +58,7 @@ import org.jf.smalidea.SmaliLanguage;
|
||||
import org.jf.smalidea.debugging.value.LazyValue;
|
||||
import org.jf.smalidea.psi.impl.SmaliInstruction;
|
||||
import org.jf.smalidea.psi.impl.SmaliMethod;
|
||||
import org.jf.smalidea.util.NameUtils;
|
||||
import org.jf.smalidea.util.PsiUtil;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
@ -225,10 +226,12 @@ public class SmaliCodeFragmentFactory extends DefaultCodeFragmentFactory {
|
||||
case RegisterType.UNINIT_REF:
|
||||
case RegisterType.UNINIT_THIS:
|
||||
case RegisterType.REFERENCE:
|
||||
variablesText.append("Object v").append(i).append(";\n");
|
||||
registerMap.put("v" + i, "Ljava/lang/Object;");
|
||||
String smaliType = registerType.type.getType();
|
||||
String javaType = NameUtils.smaliToJavaType(smaliType);
|
||||
variablesText.append(javaType).append(" v").append(i).append(";\n");
|
||||
registerMap.put("v" + i, smaliType);
|
||||
if (parameterRegisterNumber >= 0) {
|
||||
variablesText.append("Object p").append(parameterRegisterNumber).append(";\n");
|
||||
variablesText.append(javaType).append(" p").append(parameterRegisterNumber).append(";\n");
|
||||
registerMap.put("p" + parameterRegisterNumber, "Ljava/lang/Object;");
|
||||
}
|
||||
break;
|
||||
|
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright 2016, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.jf.smalidea.dexlib;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiField;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiModifierList;
|
||||
import org.jf.dexlib2.AccessFlags;
|
||||
import org.jf.dexlib2.base.reference.BaseTypeReference;
|
||||
import org.jf.dexlib2.iface.Annotation;
|
||||
import org.jf.dexlib2.iface.ClassDef;
|
||||
import org.jf.dexlib2.iface.Field;
|
||||
import org.jf.dexlib2.iface.Method;
|
||||
import org.jf.smalidea.util.NameUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class SmalideaClassDef extends BaseTypeReference implements ClassDef {
|
||||
private final PsiClass psiClass;
|
||||
|
||||
public SmalideaClassDef(PsiClass psiClass) {
|
||||
this.psiClass = psiClass;
|
||||
}
|
||||
|
||||
@Override public int getAccessFlags() {
|
||||
PsiModifierList modifierList = psiClass.getModifierList();
|
||||
int flags = 0;
|
||||
|
||||
if (modifierList == null) {
|
||||
return flags;
|
||||
}
|
||||
|
||||
if (modifierList.hasModifierProperty("public")) {
|
||||
flags |= AccessFlags.PUBLIC.getValue();
|
||||
}
|
||||
|
||||
if (modifierList.hasModifierProperty("final")) {
|
||||
flags |= AccessFlags.FINAL.getValue();
|
||||
}
|
||||
|
||||
if (modifierList.hasModifierProperty("abstract")) {
|
||||
flags |= AccessFlags.ABSTRACT.getValue();
|
||||
}
|
||||
|
||||
if (psiClass.isInterface()) {
|
||||
flags |= AccessFlags.INTERFACE.getValue();
|
||||
}
|
||||
|
||||
if (psiClass.isEnum()) {
|
||||
flags |= AccessFlags.ENUM.getValue();
|
||||
}
|
||||
|
||||
if (psiClass.isAnnotationType()) {
|
||||
flags |= AccessFlags.ANNOTATION.getValue();
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
@Nonnull @Override public String getType() {
|
||||
// TODO: properly handle inner classes..
|
||||
String javaName = psiClass.getQualifiedName();
|
||||
if (javaName == null) {
|
||||
throw new RuntimeException("I don't know what to do here... Is this even possible?");
|
||||
}
|
||||
return NameUtils.javaToSmaliType(javaName);
|
||||
}
|
||||
|
||||
@Nullable @Override public String getSuperclass() {
|
||||
PsiClass superClass = psiClass.getSuperClass();
|
||||
if (superClass == null) {
|
||||
return null;
|
||||
}
|
||||
String javaName = superClass.getQualifiedName();
|
||||
if (javaName == null) {
|
||||
throw new RuntimeException("I don't know what to do here... Is this even possible?");
|
||||
}
|
||||
return NameUtils.javaToSmaliType(javaName);
|
||||
}
|
||||
|
||||
@Nonnull @Override public List<String> getInterfaces() {
|
||||
List<String> interfaceList = Lists.newArrayList();
|
||||
PsiClass[] interfaces = psiClass.getInterfaces();
|
||||
if (interfaces == null) {
|
||||
return interfaceList;
|
||||
}
|
||||
|
||||
for (PsiClass psiClass: interfaces) {
|
||||
String javaName = psiClass.getQualifiedName();
|
||||
if (javaName == null) {
|
||||
throw new RuntimeException("I don't know what to do here... Is this even possible?");
|
||||
}
|
||||
interfaceList.add(NameUtils.javaToSmaliType(javaName));
|
||||
}
|
||||
|
||||
return interfaceList;
|
||||
}
|
||||
|
||||
@Nullable @Override public String getSourceFile() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull @Override public Set<? extends Annotation> getAnnotations() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
@Nonnull @Override public Iterable<? extends Field> getStaticFields() {
|
||||
return Iterables.transform(
|
||||
Iterables.filter(Arrays.asList(psiClass.getFields()), new Predicate<PsiField>() {
|
||||
@Override public boolean apply(PsiField psiField) {
|
||||
PsiModifierList modifierList = psiField.getModifierList();
|
||||
if (modifierList == null) {
|
||||
return false;
|
||||
}
|
||||
return modifierList.hasModifierProperty("static");
|
||||
}
|
||||
}),
|
||||
new Function<PsiField, Field>() {
|
||||
@Nullable @Override public Field apply(@Nullable PsiField psiField) {
|
||||
return new SmalideaField(psiField);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nonnull @Override public Iterable<? extends Field> getInstanceFields() {
|
||||
return Iterables.transform(
|
||||
Iterables.filter(Arrays.asList(psiClass.getFields()), new Predicate<PsiField>() {
|
||||
@Override public boolean apply(PsiField psiField) {
|
||||
PsiModifierList modifierList = psiField.getModifierList();
|
||||
if (modifierList == null) {
|
||||
return true;
|
||||
}
|
||||
return !modifierList.hasModifierProperty("static");
|
||||
}
|
||||
}),
|
||||
new Function<PsiField, Field>() {
|
||||
@Nullable @Override public Field apply(@Nullable PsiField psiField) {
|
||||
return new SmalideaField(psiField);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nonnull @Override public Iterable<? extends Field> getFields() {
|
||||
return Iterables.concat(getStaticFields(), getInstanceFields());
|
||||
}
|
||||
|
||||
@Nonnull @Override public Iterable<? extends Method> getDirectMethods() {
|
||||
return Iterables.transform(
|
||||
Iterables.filter(
|
||||
Iterables.concat(
|
||||
Arrays.asList(psiClass.getConstructors()),
|
||||
Arrays.asList(psiClass.getMethods())),
|
||||
new Predicate<PsiMethod>() {
|
||||
@Override public boolean apply(PsiMethod psiMethod) {
|
||||
PsiModifierList modifierList = psiMethod.getModifierList();
|
||||
return modifierList.hasModifierProperty("static") ||
|
||||
modifierList.hasModifierProperty("private") ||
|
||||
modifierList.hasModifierProperty("constructor");
|
||||
}
|
||||
}),
|
||||
new Function<PsiMethod, Method>() {
|
||||
@Nullable @Override public Method apply(PsiMethod psiMethod) {
|
||||
return new SmalideaMethod(psiMethod);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nonnull @Override public Iterable<? extends Method> getVirtualMethods() {
|
||||
return Iterables.transform(
|
||||
Iterables.filter(Arrays.asList(psiClass.getMethods()), new Predicate<PsiMethod>() {
|
||||
@Override public boolean apply(PsiMethod psiMethod) {
|
||||
PsiModifierList modifierList = psiMethod.getModifierList();
|
||||
return !modifierList.hasModifierProperty("static") &&
|
||||
!modifierList.hasModifierProperty("private") &&
|
||||
!modifierList.hasModifierProperty("constructor");
|
||||
}
|
||||
}),
|
||||
new Function<PsiMethod, Method>() {
|
||||
@Nullable @Override public Method apply(PsiMethod psiMethod) {
|
||||
return new SmalideaMethod(psiMethod);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nonnull @Override public Iterable<? extends Method> getMethods() {
|
||||
return Iterables.concat(getDirectMethods(), getVirtualMethods());
|
||||
}
|
||||
}
|
121
smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaField.java
Normal file
121
smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaField.java
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2016, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.jf.smalidea.dexlib;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiField;
|
||||
import com.intellij.psi.PsiModifierList;
|
||||
import org.jf.dexlib2.AccessFlags;
|
||||
import org.jf.dexlib2.base.reference.BaseFieldReference;
|
||||
import org.jf.dexlib2.iface.Annotation;
|
||||
import org.jf.dexlib2.iface.Field;
|
||||
import org.jf.dexlib2.iface.value.EncodedValue;
|
||||
import org.jf.smalidea.psi.impl.SmaliField;
|
||||
import org.jf.smalidea.util.NameUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Set;
|
||||
|
||||
public class SmalideaField extends BaseFieldReference implements Field {
|
||||
private final PsiField psiField;
|
||||
|
||||
public SmalideaField(PsiField psiField) {
|
||||
this.psiField = psiField;
|
||||
}
|
||||
|
||||
@Override public int getAccessFlags() {
|
||||
if (psiField instanceof SmaliField) {
|
||||
return ((SmaliField)psiField).getModifierList().getAccessFlags();
|
||||
} else {
|
||||
int flags = 0;
|
||||
PsiModifierList modifierList = psiField.getModifierList();
|
||||
if (modifierList == null) {
|
||||
return flags;
|
||||
}
|
||||
if (modifierList.hasModifierProperty("public")) {
|
||||
flags |= AccessFlags.PUBLIC.getValue();
|
||||
} else if (modifierList.hasModifierProperty("protected")) {
|
||||
flags |= AccessFlags.PROTECTED.getValue();
|
||||
} else if (modifierList.hasModifierProperty("private")) {
|
||||
flags |= AccessFlags.PRIVATE.getValue();
|
||||
}
|
||||
|
||||
if (modifierList.hasModifierProperty("static")) {
|
||||
flags |= AccessFlags.STATIC.getValue();
|
||||
}
|
||||
|
||||
if (modifierList.hasModifierProperty("final")) {
|
||||
flags |= AccessFlags.FINAL.getValue();
|
||||
}
|
||||
|
||||
if (modifierList.hasModifierProperty("volatile")) {
|
||||
flags |= AccessFlags.VOLATILE.getValue();
|
||||
}
|
||||
// TODO: how do we tell if it's an enum?
|
||||
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull @Override public String getDefiningClass() {
|
||||
PsiClass containingClass = psiField.getContainingClass();
|
||||
if (containingClass == null) {
|
||||
throw new RuntimeException("I don't know what to do here... Is this even possible?");
|
||||
}
|
||||
String javaName = containingClass.getQualifiedName();
|
||||
if (javaName == null) {
|
||||
throw new RuntimeException("I don't know what to do here... Is this even possible?");
|
||||
}
|
||||
return NameUtils.javaToSmaliType(javaName);
|
||||
}
|
||||
|
||||
@Nonnull @Override public String getName() {
|
||||
return psiField.getNameIdentifier().getText();
|
||||
}
|
||||
|
||||
@Nonnull @Override public String getType() {
|
||||
String javaName = psiField.getType().getCanonicalText();
|
||||
return NameUtils.javaToSmaliType(javaName);
|
||||
}
|
||||
|
||||
@Nullable @Override public EncodedValue getInitialValue() {
|
||||
// TODO: implement this. Not needed for method analysis
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull @Override public Set<? extends Annotation> getAnnotations() {
|
||||
// TODO: implement this. Not needed for method analysis
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
}
|
@ -36,9 +36,12 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiModifierList;
|
||||
import com.intellij.psi.PsiParameter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jf.dexlib2.AccessFlags;
|
||||
import org.jf.dexlib2.base.reference.BaseMethodReference;
|
||||
import org.jf.dexlib2.iface.*;
|
||||
import org.jf.dexlib2.iface.debug.DebugItem;
|
||||
@ -47,7 +50,6 @@ import org.jf.smalidea.dexlib.instruction.SmalideaInstruction;
|
||||
import org.jf.smalidea.psi.impl.SmaliCatchStatement;
|
||||
import org.jf.smalidea.psi.impl.SmaliInstruction;
|
||||
import org.jf.smalidea.psi.impl.SmaliMethod;
|
||||
import org.jf.smalidea.psi.impl.SmaliMethodParameter;
|
||||
import org.jf.smalidea.util.NameUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@ -56,9 +58,9 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class SmalideaMethod extends BaseMethodReference implements Method {
|
||||
private final SmaliMethod psiMethod;
|
||||
private final PsiMethod psiMethod;
|
||||
|
||||
public SmalideaMethod(@NotNull SmaliMethod psiMethod) {
|
||||
public SmalideaMethod(@NotNull PsiMethod psiMethod) {
|
||||
this.psiMethod = psiMethod;
|
||||
}
|
||||
|
||||
@ -71,21 +73,72 @@ public class SmalideaMethod extends BaseMethodReference implements Method {
|
||||
}
|
||||
|
||||
@Nonnull @Override public List<? extends MethodParameter> getParameters() {
|
||||
SmaliMethodParameter[] parameters = psiMethod.getParameterList().getParameters();
|
||||
PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
|
||||
|
||||
return Lists.transform(Arrays.asList(parameters), new Function<SmaliMethodParameter, MethodParameter>() {
|
||||
return Lists.transform(Arrays.asList(parameters), new Function<PsiParameter, MethodParameter>() {
|
||||
@Nullable @Override
|
||||
public MethodParameter apply(@Nullable SmaliMethodParameter smaliParameter) {
|
||||
if (smaliParameter == null) {
|
||||
public MethodParameter apply(@Nullable PsiParameter psiParameter) {
|
||||
if (psiParameter == null) {
|
||||
return null;
|
||||
}
|
||||
return new SmalideaMethodParameter(smaliParameter);
|
||||
return new SmalideaMethodParameter(psiParameter);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override public int getAccessFlags() {
|
||||
return psiMethod.getModifierList().getAccessFlags();
|
||||
if (psiMethod instanceof SmaliMethod) {
|
||||
return ((SmaliMethod)psiMethod).getModifierList().getAccessFlags();
|
||||
} else {
|
||||
int flags = 0;
|
||||
PsiModifierList modifierList = psiMethod.getModifierList();
|
||||
if (modifierList.hasModifierProperty("public")) {
|
||||
flags |= AccessFlags.PUBLIC.getValue();
|
||||
} else if (modifierList.hasModifierProperty("protected")) {
|
||||
flags |= AccessFlags.PROTECTED.getValue();
|
||||
} else if (modifierList.hasModifierProperty("private")) {
|
||||
flags |= AccessFlags.PRIVATE.getValue();
|
||||
}
|
||||
|
||||
if (modifierList.hasModifierProperty("static")) {
|
||||
flags |= AccessFlags.STATIC.getValue();
|
||||
}
|
||||
|
||||
if (modifierList.hasModifierProperty("final")) {
|
||||
flags |= AccessFlags.FINAL.getValue();
|
||||
}
|
||||
|
||||
boolean isNative = false;
|
||||
if (modifierList.hasModifierProperty("native")) {
|
||||
flags |= AccessFlags.NATIVE.getValue();
|
||||
isNative = true;
|
||||
}
|
||||
|
||||
if (modifierList.hasModifierProperty("synchronized")) {
|
||||
if (isNative) {
|
||||
flags |= AccessFlags.SYNCHRONIZED.getValue();
|
||||
} else {
|
||||
flags |= AccessFlags.DECLARED_SYNCHRONIZED.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
if (psiMethod.isVarArgs()) {
|
||||
flags |= AccessFlags.VARARGS.getValue();
|
||||
}
|
||||
|
||||
if (modifierList.hasModifierProperty("abstract")) {
|
||||
flags |= AccessFlags.ABSTRACT.getValue();
|
||||
}
|
||||
|
||||
if (modifierList.hasModifierProperty("strictfp")) {
|
||||
flags |= AccessFlags.STRICTFP.getValue();
|
||||
}
|
||||
|
||||
if (psiMethod.isConstructor()) {
|
||||
flags |= AccessFlags.CONSTRUCTOR.getValue();
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull @Override public Set<? extends Annotation> getAnnotations() {
|
||||
@ -94,44 +147,49 @@ public class SmalideaMethod extends BaseMethodReference implements Method {
|
||||
}
|
||||
|
||||
@Nullable @Override public MethodImplementation getImplementation() {
|
||||
List<SmaliInstruction> instructions = psiMethod.getInstructions();
|
||||
if (instructions.size() == 0) {
|
||||
return null;
|
||||
if (psiMethod instanceof SmaliMethod) {
|
||||
final SmaliMethod smaliMethod = (SmaliMethod)this.psiMethod;
|
||||
|
||||
List<SmaliInstruction> instructions = smaliMethod.getInstructions();
|
||||
if (instructions.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: cache this?
|
||||
return new MethodImplementation() {
|
||||
@Override public int getRegisterCount() {
|
||||
return smaliMethod.getRegisterCount();
|
||||
}
|
||||
|
||||
@Nonnull @Override public Iterable<? extends Instruction> getInstructions() {
|
||||
return Lists.transform(smaliMethod.getInstructions(),
|
||||
new Function<SmaliInstruction, Instruction>() {
|
||||
@Override
|
||||
public Instruction apply(SmaliInstruction smaliInstruction) {
|
||||
return SmalideaInstruction.of(smaliInstruction);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nonnull @Override public List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks() {
|
||||
return Lists.transform(smaliMethod.getCatchStatements(),
|
||||
new Function<SmaliCatchStatement, TryBlock<? extends ExceptionHandler>>() {
|
||||
@Override
|
||||
public TryBlock<? extends ExceptionHandler> apply(
|
||||
SmaliCatchStatement smaliCatchStatement) {
|
||||
assert smaliCatchStatement != null;
|
||||
return new SmalideaTryBlock(smaliCatchStatement);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nonnull @Override public Iterable<? extends DebugItem> getDebugItems() {
|
||||
// TODO: implement this
|
||||
return ImmutableList.of();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: cache this?
|
||||
return new MethodImplementation() {
|
||||
@Override public int getRegisterCount() {
|
||||
return psiMethod.getRegisterCount();
|
||||
}
|
||||
|
||||
@Nonnull @Override public Iterable<? extends Instruction> getInstructions() {
|
||||
return Lists.transform(psiMethod.getInstructions(),
|
||||
new Function<SmaliInstruction, Instruction>() {
|
||||
@Override
|
||||
public Instruction apply(SmaliInstruction smaliInstruction) {
|
||||
return SmalideaInstruction.of(smaliInstruction);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nonnull @Override public List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks() {
|
||||
return Lists.transform(psiMethod.getCatchStatements(),
|
||||
new Function<SmaliCatchStatement, TryBlock<? extends ExceptionHandler>>() {
|
||||
@Override
|
||||
public TryBlock<? extends ExceptionHandler> apply(
|
||||
SmaliCatchStatement smaliCatchStatement) {
|
||||
assert smaliCatchStatement != null;
|
||||
return new SmalideaTryBlock(smaliCatchStatement);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nonnull @Override public Iterable<? extends DebugItem> getDebugItems() {
|
||||
// TODO: implement this
|
||||
return ImmutableList.of();
|
||||
}
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull @Override public String getName() {
|
||||
|
@ -32,19 +32,20 @@
|
||||
package org.jf.smalidea.dexlib;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.intellij.psi.PsiParameter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jf.dexlib2.base.BaseMethodParameter;
|
||||
import org.jf.dexlib2.iface.Annotation;
|
||||
import org.jf.smalidea.psi.impl.SmaliMethodParameter;
|
||||
import org.jf.smalidea.util.NameUtils;
|
||||
import org.jf.smalidea.util.StringUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Set;
|
||||
|
||||
public class SmalideaMethodParameter extends BaseMethodParameter {
|
||||
private final SmaliMethodParameter psiParameter;
|
||||
private final PsiParameter psiParameter;
|
||||
|
||||
public SmalideaMethodParameter(SmaliMethodParameter psiParameter) {
|
||||
public SmalideaMethodParameter(PsiParameter psiParameter) {
|
||||
this.psiParameter = psiParameter;
|
||||
}
|
||||
|
||||
@ -58,6 +59,6 @@ public class SmalideaMethodParameter extends BaseMethodParameter {
|
||||
}
|
||||
|
||||
@Nonnull @Override public String getType() {
|
||||
return psiParameter.getTypeElement().getText();
|
||||
return NameUtils.javaToSmaliType(psiParameter.getType().getCanonicalText());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,36 @@
|
||||
package org.jf.smalidea.dexlib.analysis;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.impl.ResolveScopeManager;
|
||||
import org.jf.dexlib2.analysis.ClassProvider;
|
||||
import org.jf.dexlib2.iface.ClassDef;
|
||||
import org.jf.smalidea.dexlib.SmalideaClassDef;
|
||||
import org.jf.smalidea.util.NameUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class SmalideaClassProvider implements ClassProvider {
|
||||
private final Project project;
|
||||
private final VirtualFile file;
|
||||
|
||||
public SmalideaClassProvider(@Nonnull Project project, @Nonnull VirtualFile file) {
|
||||
this.project = project;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Nullable @Override public ClassDef getClassDef(String type) {
|
||||
ResolveScopeManager manager = ResolveScopeManager.getInstance(project);
|
||||
|
||||
JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
|
||||
PsiClass psiClass = facade.findClass(NameUtils.smaliToJavaType(type),
|
||||
manager.getDefaultResolveScope(file));
|
||||
if (psiClass != null) {
|
||||
return new SmalideaClassDef(psiClass);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -53,6 +53,7 @@ import org.jf.dexlib2.analysis.AnalysisException;
|
||||
import org.jf.dexlib2.analysis.ClassPath;
|
||||
import org.jf.dexlib2.analysis.MethodAnalyzer;
|
||||
import org.jf.smalidea.dexlib.SmalideaMethod;
|
||||
import org.jf.smalidea.dexlib.analysis.SmalideaClassProvider;
|
||||
import org.jf.smalidea.psi.SmaliElementTypes;
|
||||
import org.jf.smalidea.psi.iface.SmaliModifierListOwner;
|
||||
import org.jf.smalidea.psi.stub.SmaliMethodStub;
|
||||
@ -316,7 +317,8 @@ public class SmaliMethod extends SmaliStubBasedPsiElement<SmaliMethodStub>
|
||||
if (!PsiTreeUtil.hasErrorElements(this)) {
|
||||
ClassPath classPath;
|
||||
try {
|
||||
classPath = new ClassPath();
|
||||
classPath = new ClassPath(
|
||||
new SmalideaClassProvider(getProject(), getContainingFile().getVirtualFile()));
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
@ -163,6 +163,12 @@ public class NameUtils {
|
||||
}
|
||||
}
|
||||
return;
|
||||
case 'U':
|
||||
if (smaliType.equals("Ujava/lang/Object;")) {
|
||||
dest.append("java.lang.Object");
|
||||
return;
|
||||
}
|
||||
// fall through
|
||||
default:
|
||||
throw new RuntimeException("Invalid smali type: " + smaliType);
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
package org.jf.smalidea;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.codeInsight.CodeInsightTestCase;
|
||||
import com.intellij.codeInsight.completion.CodeCompletionHandlerBase;
|
||||
import com.intellij.codeInsight.completion.CompletionType;
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
|
||||
@ -44,11 +45,13 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.JavaCodeFragment;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jf.smalidea.debugging.SmaliCodeFragmentFactory;
|
||||
import org.jf.smalidea.psi.impl.SmaliFile;
|
||||
@ -57,20 +60,20 @@ import org.junit.Assert;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class SmaliCodeFragmentFactoryTest extends LightCodeInsightFixtureTestCase {
|
||||
private static final String testClass =
|
||||
public class SmaliCodeFragmentFactoryTest extends CodeInsightTestCase {
|
||||
private static final String completionTestClass =
|
||||
".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
|
||||
".method public getRandomParentType(I)I\n" +
|
||||
" .registers 4\n" +
|
||||
" .param p1, \"edge\" # I\n" +
|
||||
"\n" +
|
||||
" .prologue\n" +
|
||||
" const/4 v1, 0x2\n" +
|
||||
" const/4 v1, 0x2\n" + // 0
|
||||
"\n" +
|
||||
" .line 179\n" +
|
||||
" if-nez p1, :cond_5\n" +
|
||||
"\n" +
|
||||
" move v0, v1\n" +
|
||||
" move v0, v1\n" + // 2
|
||||
"\n" +
|
||||
" .line 185\n" +
|
||||
" :goto_4\n" +
|
||||
@ -83,7 +86,7 @@ public class SmaliCodeFragmentFactoryTest extends LightCodeInsightFixtureTestCas
|
||||
" .line 183\n" +
|
||||
" sget-object v0, Lorg/jf/Penroser/PenroserApp;->random:Ljava/util/Random;\n" +
|
||||
"\n" +
|
||||
" const/4 v1, 0x3\n" +
|
||||
" const/4 v1, 0x3\n" + // 6
|
||||
"\n" +
|
||||
" invoke-virtual {v0, v1}, Ljava/util/Random;->nextInt(I)I\n" +
|
||||
"\n" +
|
||||
@ -103,7 +106,7 @@ public class SmaliCodeFragmentFactoryTest extends LightCodeInsightFixtureTestCas
|
||||
".end method";
|
||||
|
||||
public void testCompletion() throws NoDataException {
|
||||
SmaliFile smaliFile = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", testClass);
|
||||
SmaliFile smaliFile = (SmaliFile)configureByText(SmaliFileType.INSTANCE, completionTestClass);
|
||||
|
||||
PsiElement context = smaliFile.getPsiClass().getMethods()[0].getInstructions().get(0);
|
||||
assertCompletionContains("v", context, new String[] {"v2", "v3"}, new String[] {"v0", "v1", "p0", "p1"});
|
||||
@ -112,6 +115,112 @@ public class SmaliCodeFragmentFactoryTest extends LightCodeInsightFixtureTestCas
|
||||
context = smaliFile.getPsiClass().getMethods()[0].getInstructions().get(2);
|
||||
assertCompletionContains("v", context, new String[] {"v1", "v2", "v3"}, new String[] {"v0", "p0", "p1"});
|
||||
assertCompletionContains("p", context, new String[] {"p0", "p1"}, new String[] {"v0", "v1", "v2", "v3"});
|
||||
|
||||
context = smaliFile.getPsiClass().getMethods()[0].getInstructions().get(6);
|
||||
assertCompletionContains("v", context, new String[] {"v0", "v1", "v2", "v3"}, new String[] {"p0", "p1"});
|
||||
assertCompletionContains("p", context, new String[] {"p0", "p1"}, new String[] {});
|
||||
}
|
||||
|
||||
private static final String registerTypeTestText = "" +
|
||||
".class public LRegisterTypeTest;\n" +
|
||||
".super Ljava/lang/Object;\n" +
|
||||
"\n" +
|
||||
"# virtual methods\n" +
|
||||
".method public blah()V\n" +
|
||||
" .registers 6\n" +
|
||||
"\n" +
|
||||
" .prologue\n" +
|
||||
" const/16 v3, 0xa\n" +
|
||||
"\n" +
|
||||
" .line 7\n" +
|
||||
" new-instance v0, Ljava/util/Random;\n" +
|
||||
"\n" +
|
||||
" invoke-direct {v0}, Ljava/util/Random;-><init>()V\n" +
|
||||
"\n" +
|
||||
" .line 9\n" +
|
||||
" invoke-virtual {v0, v3}, Ljava/util/Random;->nextInt(I)I\n" +
|
||||
"\n" +
|
||||
" move-result v1\n" +
|
||||
"\n" +
|
||||
" const/4 v2, 0x5\n" +
|
||||
"\n" +
|
||||
" if-le v1, v2, :cond_26\n" +
|
||||
"\n" +
|
||||
" .line 10\n" +
|
||||
" new-instance v1, Ljava/security/SecureRandom;\n" +
|
||||
"\n" +
|
||||
" invoke-direct {v1}, Ljava/security/SecureRandom;-><init>()V\n" +
|
||||
"\n" +
|
||||
" .line 14\n" +
|
||||
" :goto_13\n" +
|
||||
" sget-o<ref>bject v2, Ljava/lang/System;->out:Ljava/io/PrintStream;\n" +
|
||||
"\n" +
|
||||
" invoke-virtual {v1, v3}, Ljava/util/Random;->nextInt(I)I\n" +
|
||||
"\n" +
|
||||
" move-result v1\n" +
|
||||
"\n" +
|
||||
" invoke-virtual {v2, v1}, Ljava/io/PrintStream;->println(I)V\n" +
|
||||
"\n" +
|
||||
" .line 15\n" +
|
||||
" sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;\n" +
|
||||
"\n" +
|
||||
" invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;\n" +
|
||||
"\n" +
|
||||
" move-result-object v0\n" +
|
||||
"\n" +
|
||||
" invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V\n" +
|
||||
"\n" +
|
||||
" .line 16\n" +
|
||||
" return-void\n" +
|
||||
"\n" +
|
||||
" .line 12\n" +
|
||||
" :cond_26\n" +
|
||||
" invoke-virtual {p0}, LRegisterTypeTest;->getSerializable()Ljava/io/Serializable;\n" +
|
||||
"\n" +
|
||||
" move-result-object v1\n" +
|
||||
"\n" +
|
||||
" move-object v4, v1\n" +
|
||||
"\n" +
|
||||
" move-object v1, v0\n" +
|
||||
"\n" +
|
||||
" move-object v0, v4\n" +
|
||||
"\n" +
|
||||
" goto :goto_13\n" +
|
||||
".end method\n" +
|
||||
"\n" +
|
||||
".method public getSerializable()Ljava/io/Serializable;\n" +
|
||||
" .registers 2\n" +
|
||||
"\n" +
|
||||
" .prologue\n" +
|
||||
" .line 19\n" +
|
||||
" new-instance v0, Ljava/util/Random;\n" +
|
||||
"\n" +
|
||||
" invoke-direct {v0}, Ljava/util/Random;-><init>()V\n" +
|
||||
"\n" +
|
||||
" return-object v0\n" +
|
||||
".end method\n";
|
||||
|
||||
public void testRegisterType() throws NoDataException {
|
||||
SmaliFile smaliFile = (SmaliFile)configureByText(SmaliFileType.INSTANCE,
|
||||
registerTypeTestText.replace("<ref>", ""));
|
||||
|
||||
int refOffset = registerTypeTestText.indexOf("<ref>");
|
||||
|
||||
PsiElement context = smaliFile.findElementAt(refOffset);
|
||||
assertVariableType(context.getParent(), "v1", "java.util.Random");
|
||||
assertVariableType(context.getParent(), "v0", "java.io.Serializable");
|
||||
}
|
||||
|
||||
public void testUnknownClass() {
|
||||
String modifiedText = registerTypeTestText.replace("Random", "Rnd");
|
||||
SmaliFile smaliFile = (SmaliFile)configureByText(SmaliFileType.INSTANCE,
|
||||
modifiedText.replace("<ref>", ""));
|
||||
|
||||
int refOffset = modifiedText.indexOf("<ref>");
|
||||
|
||||
PsiElement context = smaliFile.findElementAt(refOffset);
|
||||
assertVariableType(context.getParent(), "v1", "java.lang.Object");
|
||||
assertVariableType(context.getParent(), "v0", "java.lang.Object");
|
||||
}
|
||||
|
||||
private void assertCompletionContains(String completionText, PsiElement context, String[] expectedItems,
|
||||
@ -138,6 +247,21 @@ public class SmaliCodeFragmentFactoryTest extends LightCodeInsightFixtureTestCas
|
||||
Assert.assertTrue(expectedSet.size() == 0);
|
||||
}
|
||||
|
||||
private void assertVariableType(PsiElement context, String variableName, String expectedType) {
|
||||
SmaliCodeFragmentFactory codeFragmentFactory = new SmaliCodeFragmentFactory();
|
||||
JavaCodeFragment fragment = codeFragmentFactory.createCodeFragment(
|
||||
new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, variableName),
|
||||
context, getProject());
|
||||
|
||||
Editor editor = createEditor(fragment.getVirtualFile());
|
||||
editor.getCaretModel().moveToOffset(1);
|
||||
|
||||
PsiElement element = fragment.findElementAt(0);
|
||||
Assert.assertTrue(element.getParent() instanceof PsiReferenceExpressionImpl);
|
||||
PsiReferenceExpressionImpl reference = (PsiReferenceExpressionImpl)element.getParent();
|
||||
Assert.assertEquals(expectedType, reference.getType().getCanonicalText());
|
||||
}
|
||||
|
||||
protected Editor createEditor(@NotNull VirtualFile file) {
|
||||
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
|
||||
Editor editor = FileEditorManager.getInstance(getProject()).openTextEditor(
|
||||
@ -147,4 +271,9 @@ public class SmaliCodeFragmentFactoryTest extends LightCodeInsightFixtureTestCas
|
||||
((EditorImpl)editor).setCaretActive();
|
||||
return editor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sdk getTestProjectJdk() {
|
||||
return JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user