mirror of
https://github.com/revanced/smali.git
synced 2025-05-30 20:40:11 +02:00
Add usage type support for field usages
This commit is contained in:
parent
9b86fcabff
commit
9bedfc8e3e
@ -687,9 +687,10 @@ subannotation
|
|||||||
: SUBANNOTATION_DIRECTIVE CLASS_DESCRIPTOR annotation_element* END_SUBANNOTATION_DIRECTIVE
|
: SUBANNOTATION_DIRECTIVE CLASS_DESCRIPTOR annotation_element* END_SUBANNOTATION_DIRECTIVE
|
||||||
-> ^(I_SUBANNOTATION[$start, "I_SUBANNOTATION"] CLASS_DESCRIPTOR annotation_element*);
|
-> ^(I_SUBANNOTATION[$start, "I_SUBANNOTATION"] CLASS_DESCRIPTOR annotation_element*);
|
||||||
|
|
||||||
|
// TODO: how does dalvik handle a primitive or array type, or a non-enum type?
|
||||||
enum_literal
|
enum_literal
|
||||||
: ENUM_DIRECTIVE reference_type_descriptor ARROW simple_name COLON reference_type_descriptor
|
: ENUM_DIRECTIVE field_reference
|
||||||
-> ^(I_ENCODED_ENUM reference_type_descriptor simple_name reference_type_descriptor);
|
-> ^(I_ENCODED_ENUM field_reference);
|
||||||
|
|
||||||
type_field_method_literal
|
type_field_method_literal
|
||||||
: reference_type_descriptor
|
: reference_type_descriptor
|
||||||
|
@ -693,7 +693,7 @@ array_literal
|
|||||||
|
|
||||||
enum_literal
|
enum_literal
|
||||||
@init { Marker marker = mark(); }
|
@init { Marker marker = mark(); }
|
||||||
: ENUM_DIRECTIVE reference_type_descriptor arrow simple_name colon reference_type_descriptor
|
: ENUM_DIRECTIVE fully_qualified_field
|
||||||
{ marker.done(SmaliElementTypes.LITERAL); };
|
{ marker.done(SmaliElementTypes.LITERAL); };
|
||||||
catch [RecognitionException re] {
|
catch [RecognitionException re] {
|
||||||
recover(input, re);
|
recover(input, re);
|
||||||
@ -702,15 +702,9 @@ enum_literal
|
|||||||
|
|
||||||
type_field_method_literal
|
type_field_method_literal
|
||||||
@init { Marker marker = mark(); }
|
@init { Marker marker = mark(); }
|
||||||
: ( reference_type_descriptor
|
: ( type_descriptor
|
||||||
( arrow
|
| fully_qualified_field
|
||||||
( member_name colon nonvoid_type_descriptor
|
| fully_qualified_method)
|
||||||
| member_name method_prototype_reference
|
|
||||||
)
|
|
||||||
| /* epsilon */
|
|
||||||
)
|
|
||||||
| primitive_type
|
|
||||||
| void_type)
|
|
||||||
{ marker.done(SmaliElementTypes.LITERAL); };
|
{ marker.done(SmaliElementTypes.LITERAL); };
|
||||||
catch [RecognitionException re] {
|
catch [RecognitionException re] {
|
||||||
recover(input, re);
|
recover(input, re);
|
||||||
|
@ -33,6 +33,7 @@ package org.jf.smalidea.findUsages;
|
|||||||
|
|
||||||
import com.intellij.psi.PsiClass;
|
import com.intellij.psi.PsiClass;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiField;
|
||||||
import com.intellij.psi.PsiReference;
|
import com.intellij.psi.PsiReference;
|
||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
import com.intellij.usages.impl.rules.UsageType;
|
import com.intellij.usages.impl.rules.UsageType;
|
||||||
@ -63,6 +64,8 @@ public class SmaliUsageTypeProvider implements UsageTypeProvider {
|
|||||||
if (referenced != null) {
|
if (referenced != null) {
|
||||||
if (referenced instanceof PsiClass) {
|
if (referenced instanceof PsiClass) {
|
||||||
return findClassUsageType(element);
|
return findClassUsageType(element);
|
||||||
|
} else if (referenced instanceof PsiField) {
|
||||||
|
return findFieldUsageType(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,6 +75,18 @@ public class SmaliUsageTypeProvider implements UsageTypeProvider {
|
|||||||
private final Set<Opcode> newArrayInstructions = EnumSet.of(Opcode.FILLED_NEW_ARRAY, Opcode.NEW_ARRAY,
|
private final Set<Opcode> newArrayInstructions = EnumSet.of(Opcode.FILLED_NEW_ARRAY, Opcode.NEW_ARRAY,
|
||||||
Opcode.FILLED_NEW_ARRAY_RANGE);
|
Opcode.FILLED_NEW_ARRAY_RANGE);
|
||||||
|
|
||||||
|
private final Set<Opcode> fieldReadInstructions = EnumSet.of(Opcode.IGET, Opcode.IGET_BOOLEAN, Opcode.IGET_BYTE,
|
||||||
|
Opcode.IGET_CHAR, Opcode.IGET_OBJECT, Opcode.IGET_OBJECT_VOLATILE, Opcode.IGET_SHORT, Opcode.IGET_VOLATILE,
|
||||||
|
Opcode.IGET_WIDE, Opcode.IGET_WIDE_VOLATILE, Opcode.SGET, Opcode.SGET_BOOLEAN, Opcode.SGET_BYTE,
|
||||||
|
Opcode.SGET_CHAR, Opcode.SGET_OBJECT, Opcode.SGET_OBJECT_VOLATILE, Opcode.SGET_SHORT, Opcode.SGET_VOLATILE,
|
||||||
|
Opcode.SGET_WIDE, Opcode.SGET_WIDE_VOLATILE);
|
||||||
|
|
||||||
|
private final Set<Opcode> fieldWriteInstructions = EnumSet.of(Opcode.IPUT, Opcode.IPUT_BOOLEAN, Opcode.IPUT_BYTE,
|
||||||
|
Opcode.IPUT_CHAR, Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT_VOLATILE, Opcode.IPUT_SHORT, Opcode.IPUT_VOLATILE,
|
||||||
|
Opcode.IPUT_WIDE, Opcode.IPUT_WIDE_VOLATILE, Opcode.SPUT, Opcode.SPUT_BOOLEAN, Opcode.SPUT_BYTE,
|
||||||
|
Opcode.SPUT_CHAR, Opcode.SPUT_OBJECT, Opcode.SPUT_OBJECT_VOLATILE, Opcode.SPUT_SHORT, Opcode.SPUT_VOLATILE,
|
||||||
|
Opcode.SPUT_WIDE, Opcode.SPUT_WIDE_VOLATILE);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private UsageType findClassUsageType(@NotNull PsiElement element) {
|
private UsageType findClassUsageType(@NotNull PsiElement element) {
|
||||||
PsiElement originalElement = element;
|
PsiElement originalElement = element;
|
||||||
@ -141,4 +156,27 @@ public class SmaliUsageTypeProvider implements UsageTypeProvider {
|
|||||||
}
|
}
|
||||||
return UsageType.UNCLASSIFIED;
|
return UsageType.UNCLASSIFIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private UsageType findFieldUsageType(@NotNull PsiElement element) {
|
||||||
|
PsiElement originalElement = element;
|
||||||
|
|
||||||
|
while (element != null) {
|
||||||
|
element = element.getParent();
|
||||||
|
|
||||||
|
if (element instanceof SmaliInstruction) {
|
||||||
|
Opcode opcode = ((SmaliInstruction) element).getOpcode();
|
||||||
|
if (fieldReadInstructions.contains(opcode)) {
|
||||||
|
return UsageType.READ;
|
||||||
|
} else if (fieldWriteInstructions.contains(opcode)) {
|
||||||
|
return UsageType.WRITE;
|
||||||
|
} else if (opcode == Opcode.THROW_VERIFICATION_ERROR) {
|
||||||
|
return VERIFICATION_ERROR;
|
||||||
|
}
|
||||||
|
} if (element instanceof SmaliLiteral) {
|
||||||
|
return LITERAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UsageType.UNCLASSIFIED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,115 @@
|
|||||||
|
package org.jf.smalidea.findUsages;
|
||||||
|
|
||||||
|
import com.intellij.usages.impl.rules.UsageType;
|
||||||
|
|
||||||
|
public class FieldUsageTypeTest extends UsageTypeTest {
|
||||||
|
public FieldUsageTypeTest() {
|
||||||
|
super(new SmaliUsageTypeProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFieldUsageTypes() throws Exception {
|
||||||
|
doTest("blah.smali", "" +
|
||||||
|
".class public Lblah;\n" +
|
||||||
|
".super Ljava/lang/Object;\n" +
|
||||||
|
"\n" +
|
||||||
|
".annotation runtime Lblah;\n" +
|
||||||
|
" element = Lblah;->bl<ref:1>ah:Lblah;\n" +
|
||||||
|
" element2 = .enum Lblah;->bl<ref:2>ah:Lblah;\n" +
|
||||||
|
".end annotation\n" +
|
||||||
|
"\n" +
|
||||||
|
".field public blah:Lblah;\n" +
|
||||||
|
"\n" +
|
||||||
|
".method public blah(Lblah;)Lblah;\n" +
|
||||||
|
" .registers 2\n" +
|
||||||
|
"\n" +
|
||||||
|
" iget v0, v0, Lblah;->bl<ref:3>ah:Lblah;\n" +
|
||||||
|
" iget-object v0, v0, Lblah;->bl<ref:4>ah:Lblah;\n" +
|
||||||
|
" iget-byte v0, v0, Lblah;->bl<ref:5>ah:Lblah;\n" +
|
||||||
|
" iget-char v0, v0, Lblah;->bl<ref:6>ah:Lblah;\n" +
|
||||||
|
" iget-object v0, v0, Lblah;->bl<ref:7>ah:Lblah;\n" +
|
||||||
|
" iget-object-volatile v0, v0, Lblah;->bl<ref:8>ah:Lblah;\n" +
|
||||||
|
" iget-short v0, v0, Lblah;->bl<ref:9>ah:Lblah;\n" +
|
||||||
|
" iget-volatile v0, v0, Lblah;->bl<ref:10>ah:Lblah;\n" +
|
||||||
|
" iget-wide v0, v0, Lblah;->bl<ref:11>ah:Lblah;\n" +
|
||||||
|
" iget-wide-volatile v0, v0, Lblah;->bl<ref:12>ah:Lblah;\n" +
|
||||||
|
" sget v0, Lblah;->bl<ref:13>ah:Lblah;\n" +
|
||||||
|
" sget-boolean v0, Lblah;->bl<ref:14>ah:Lblah;\n" +
|
||||||
|
" sget-byte v0, Lblah;->bl<ref:15>ah:Lblah;\n" +
|
||||||
|
" sget-char v0, Lblah;->bl<ref:16>ah:Lblah;\n" +
|
||||||
|
" sget-object v0, Lblah;->bl<ref:17>ah:Lblah;\n" +
|
||||||
|
" sget-object-volatile v0, Lblah;->bl<ref:18>ah:Lblah;\n" +
|
||||||
|
" sget-short v0, Lblah;->bl<ref:19>ah:Lblah;\n" +
|
||||||
|
" sget-volatile v0, Lblah;->bl<ref:20>ah:Lblah;\n" +
|
||||||
|
" sget-wide v0, Lblah;->bl<ref:21>ah:Lblah;\n" +
|
||||||
|
" sget-wide-volatile v0, Lblah;->bl<ref:22>ah:Lblah;\n" +
|
||||||
|
" \n" +
|
||||||
|
" iput v0, v0, Lblah;->bl<ref:23>ah:Lblah;\n" +
|
||||||
|
" iput-object v0, v0, Lblah;->bl<ref:24>ah:Lblah;\n" +
|
||||||
|
" iput-byte v0, v0, Lblah;->bl<ref:25>ah:Lblah;\n" +
|
||||||
|
" iput-char v0, v0, Lblah;->bl<ref:26>ah:Lblah;\n" +
|
||||||
|
" iput-object v0, v0, Lblah;->bl<ref:27>ah:Lblah;\n" +
|
||||||
|
" iput-object-volatile v0, v0, Lblah;->bl<ref:28>ah:Lblah;\n" +
|
||||||
|
" iput-short v0, v0, Lblah;->bl<ref:29>ah:Lblah;\n" +
|
||||||
|
" iput-volatile v0, v0, Lblah;->bl<ref:30>ah:Lblah;\n" +
|
||||||
|
" iput-wide v0, v0, Lblah;->bl<ref:31>ah:Lblah;\n" +
|
||||||
|
" iput-wide-volatile v0, v0, Lblah;->bl<ref:32>ah:Lblah;\n" +
|
||||||
|
" sput v0, Lblah;->bl<ref:33>ah:Lblah;\n" +
|
||||||
|
" sput-boolean v0, Lblah;->bl<ref:34>ah:Lblah;\n" +
|
||||||
|
" sput-byte v0, Lblah;->bl<ref:35>ah:Lblah;\n" +
|
||||||
|
" sput-char v0, Lblah;->bl<ref:36>ah:Lblah;\n" +
|
||||||
|
" sput-object v0, Lblah;->bl<ref:37>ah:Lblah;\n" +
|
||||||
|
" sput-object-volatile v0, Lblah;->bl<ref:38>ah:Lblah;\n" +
|
||||||
|
" sput-short v0, Lblah;->bl<ref:39>ah:Lblah;\n" +
|
||||||
|
" sput-volatile v0, Lblah;->bl<ref:40>ah:Lblah;\n" +
|
||||||
|
" sput-wide v0, Lblah;->bl<ref:41>ah:Lblah;\n" +
|
||||||
|
" sput-wide-volatile v0, Lblah;->bl<ref:42>ah:Lblah;\n" +
|
||||||
|
"\n" +
|
||||||
|
" throw-verification-error generic-error, Lblah;->bl<ref:43>ah:Lblah;\n" +
|
||||||
|
"\n" +
|
||||||
|
" return-void\n" +
|
||||||
|
".end method\n",
|
||||||
|
1, SmaliUsageTypeProvider.LITERAL,
|
||||||
|
2, SmaliUsageTypeProvider.LITERAL,
|
||||||
|
3, UsageType.READ,
|
||||||
|
4, UsageType.READ,
|
||||||
|
5, UsageType.READ,
|
||||||
|
6, UsageType.READ,
|
||||||
|
7, UsageType.READ,
|
||||||
|
8, UsageType.READ,
|
||||||
|
9, UsageType.READ,
|
||||||
|
10, UsageType.READ,
|
||||||
|
11, UsageType.READ,
|
||||||
|
12, UsageType.READ,
|
||||||
|
13, UsageType.READ,
|
||||||
|
14, UsageType.READ,
|
||||||
|
15, UsageType.READ,
|
||||||
|
16, UsageType.READ,
|
||||||
|
17, UsageType.READ,
|
||||||
|
18, UsageType.READ,
|
||||||
|
19, UsageType.READ,
|
||||||
|
20, UsageType.READ,
|
||||||
|
21, UsageType.READ,
|
||||||
|
22, UsageType.READ,
|
||||||
|
23, UsageType.WRITE,
|
||||||
|
24, UsageType.WRITE,
|
||||||
|
25, UsageType.WRITE,
|
||||||
|
26, UsageType.WRITE,
|
||||||
|
27, UsageType.WRITE,
|
||||||
|
28, UsageType.WRITE,
|
||||||
|
29, UsageType.WRITE,
|
||||||
|
30, UsageType.WRITE,
|
||||||
|
31, UsageType.WRITE,
|
||||||
|
32, UsageType.WRITE,
|
||||||
|
33, UsageType.WRITE,
|
||||||
|
34, UsageType.WRITE,
|
||||||
|
35, UsageType.WRITE,
|
||||||
|
36, UsageType.WRITE,
|
||||||
|
37, UsageType.WRITE,
|
||||||
|
38, UsageType.WRITE,
|
||||||
|
39, UsageType.WRITE,
|
||||||
|
40, UsageType.WRITE,
|
||||||
|
41, UsageType.WRITE,
|
||||||
|
42, UsageType.WRITE,
|
||||||
|
43, SmaliUsageTypeProvider.VERIFICATION_ERROR);
|
||||||
|
}
|
||||||
|
}
|
@ -24,9 +24,11 @@ smali.FILE
|
|||||||
PsiElement(LITERAL)
|
PsiElement(LITERAL)
|
||||||
PsiElement(ENUM_DIRECTIVE)('.enum')
|
PsiElement(ENUM_DIRECTIVE)('.enum')
|
||||||
PsiWhiteSpace(' ')
|
PsiWhiteSpace(' ')
|
||||||
|
PsiElement(FIELD_REFERENCE)
|
||||||
PsiElement(CLASS_TYPE)
|
PsiElement(CLASS_TYPE)
|
||||||
PsiElement(CLASS_DESCRIPTOR)('Lblah;')
|
PsiElement(CLASS_DESCRIPTOR)('Lblah;')
|
||||||
PsiElement(ARROW)('->')
|
PsiElement(ARROW)('->')
|
||||||
|
PsiElement(MEMBER_NAME)
|
||||||
PsiElement(SIMPLE_NAME)('blah')
|
PsiElement(SIMPLE_NAME)('blah')
|
||||||
PsiWhiteSpace(' ')
|
PsiWhiteSpace(' ')
|
||||||
PsiErrorElement:mismatched input '.blah' expecting COLON
|
PsiErrorElement:mismatched input '.blah' expecting COLON
|
||||||
|
Loading…
x
Reference in New Issue
Block a user