Add usage type support for field usages

This commit is contained in:
Ben Gruver 2015-03-25 19:45:20 -07:00
parent 9b86fcabff
commit 9bedfc8e3e
5 changed files with 172 additions and 22 deletions

View File

@ -687,9 +687,10 @@ subannotation
: SUBANNOTATION_DIRECTIVE CLASS_DESCRIPTOR annotation_element* END_SUBANNOTATION_DIRECTIVE
-> ^(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_DIRECTIVE reference_type_descriptor ARROW simple_name COLON reference_type_descriptor
-> ^(I_ENCODED_ENUM reference_type_descriptor simple_name reference_type_descriptor);
: ENUM_DIRECTIVE field_reference
-> ^(I_ENCODED_ENUM field_reference);
type_field_method_literal
: reference_type_descriptor

View File

@ -693,7 +693,7 @@ array_literal
enum_literal
@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); };
catch [RecognitionException re] {
recover(input, re);
@ -702,15 +702,9 @@ enum_literal
type_field_method_literal
@init { Marker marker = mark(); }
: ( reference_type_descriptor
( arrow
( member_name colon nonvoid_type_descriptor
| member_name method_prototype_reference
)
| /* epsilon */
)
| primitive_type
| void_type)
: ( type_descriptor
| fully_qualified_field
| fully_qualified_method)
{ marker.done(SmaliElementTypes.LITERAL); };
catch [RecognitionException re] {
recover(input, re);

View File

@ -33,6 +33,7 @@ package org.jf.smalidea.findUsages;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiReference;
import com.intellij.psi.tree.IElementType;
import com.intellij.usages.impl.rules.UsageType;
@ -63,6 +64,8 @@ public class SmaliUsageTypeProvider implements UsageTypeProvider {
if (referenced != null) {
if (referenced instanceof PsiClass) {
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,
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
private UsageType findClassUsageType(@NotNull PsiElement element) {
PsiElement originalElement = element;
@ -141,4 +156,27 @@ public class SmaliUsageTypeProvider implements UsageTypeProvider {
}
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;
}
}

View File

@ -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);
}
}

View File

@ -24,13 +24,15 @@ smali.FILE
PsiElement(LITERAL)
PsiElement(ENUM_DIRECTIVE)('.enum')
PsiWhiteSpace(' ')
PsiElement(CLASS_TYPE)
PsiElement(CLASS_DESCRIPTOR)('Lblah;')
PsiElement(ARROW)('->')
PsiElement(SIMPLE_NAME)('blah')
PsiWhiteSpace(' ')
PsiErrorElement:mismatched input '.blah' expecting COLON
PsiElement(BAD_CHARACTER)('.blah')
PsiWhiteSpace(' ')
PsiElement(CLASS_TYPE)
PsiElement(CLASS_DESCRIPTOR)('Lblah;')
PsiElement(FIELD_REFERENCE)
PsiElement(CLASS_TYPE)
PsiElement(CLASS_DESCRIPTOR)('Lblah;')
PsiElement(ARROW)('->')
PsiElement(MEMBER_NAME)
PsiElement(SIMPLE_NAME)('blah')
PsiWhiteSpace(' ')
PsiErrorElement:mismatched input '.blah' expecting COLON
PsiElement(BAD_CHARACTER)('.blah')
PsiWhiteSpace(' ')
PsiElement(CLASS_TYPE)
PsiElement(CLASS_DESCRIPTOR)('Lblah;')