aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Light <allight@google.com>2016-04-08 14:42:05 -0700
committerAlex Light <allight@google.com>2016-04-08 14:42:05 -0700
commitedc88aff44ff80f969df61725a992680cd0c464c (patch)
tree53e8ba5a33270814a3df2bf493967a8eb15ca33f
parent504acc06a865d5b0e2d3e08111ffe71ccea8ca26 (diff)
parent267cf99aae855d3d8cbd2b919f3e9aeceabfb7c3 (diff)
downloadsmali-nougat-mr1.6-release.tar.gz
Merge commit 'refs/changes/32/214432/1' of persistent-https://android.git.corp.google.com/platform/external/smali into incr-dexandroid-cts_7.1_r1android-cts-7.1_r9android-cts-7.1_r8android-cts-7.1_r7android-cts-7.1_r6android-cts-7.1_r5android-cts-7.1_r4android-cts-7.1_r3android-cts-7.1_r29android-cts-7.1_r28android-cts-7.1_r27android-cts-7.1_r26android-cts-7.1_r25android-cts-7.1_r24android-cts-7.1_r23android-cts-7.1_r22android-cts-7.1_r21android-cts-7.1_r20android-cts-7.1_r2android-cts-7.1_r19android-cts-7.1_r18android-cts-7.1_r17android-cts-7.1_r16android-cts-7.1_r15android-cts-7.1_r14android-cts-7.1_r13android-cts-7.1_r12android-cts-7.1_r11android-cts-7.1_r10android-cts-7.1_r1android-cts-7.0_r9android-cts-7.0_r8android-cts-7.0_r7android-cts-7.0_r6android-cts-7.0_r5android-cts-7.0_r4android-cts-7.0_r33android-cts-7.0_r32android-cts-7.0_r31android-cts-7.0_r30android-cts-7.0_r3android-cts-7.0_r29android-cts-7.0_r28android-cts-7.0_r27android-cts-7.0_r26android-cts-7.0_r25android-cts-7.0_r24android-cts-7.0_r23android-cts-7.0_r22android-cts-7.0_r21android-cts-7.0_r20android-cts-7.0_r2android-cts-7.0_r19android-cts-7.0_r18android-cts-7.0_r17android-cts-7.0_r16android-cts-7.0_r15android-cts-7.0_r14android-cts-7.0_r13android-cts-7.0_r12android-cts-7.0_r11android-cts-7.0_r10android-cts-7.0_r1android-7.1.2_r9android-7.1.2_r8android-7.1.2_r6android-7.1.2_r5android-7.1.2_r4android-7.1.2_r39android-7.1.2_r38android-7.1.2_r37android-7.1.2_r36android-7.1.2_r33android-7.1.2_r32android-7.1.2_r30android-7.1.2_r3android-7.1.2_r29android-7.1.2_r28android-7.1.2_r27android-7.1.2_r25android-7.1.2_r24android-7.1.2_r23android-7.1.2_r2android-7.1.2_r19android-7.1.2_r18android-7.1.2_r17android-7.1.2_r16android-7.1.2_r15android-7.1.2_r14android-7.1.2_r13android-7.1.2_r12android-7.1.2_r11android-7.1.2_r10android-7.1.2_r1android-7.1.1_r9android-7.1.1_r8android-7.1.1_r7android-7.1.1_r61android-7.1.1_r60android-7.1.1_r6android-7.1.1_r59android-7.1.1_r58android-7.1.1_r57android-7.1.1_r56android-7.1.1_r55android-7.1.1_r54android-7.1.1_r53android-7.1.1_r52android-7.1.1_r51android-7.1.1_r50android-7.1.1_r49android-7.1.1_r48android-7.1.1_r47android-7.1.1_r46android-7.1.1_r45android-7.1.1_r44android-7.1.1_r43android-7.1.1_r42android-7.1.1_r41android-7.1.1_r40android-7.1.1_r4android-7.1.1_r39android-7.1.1_r38android-7.1.1_r35android-7.1.1_r33android-7.1.1_r32android-7.1.1_r31android-7.1.1_r3android-7.1.1_r28android-7.1.1_r27android-7.1.1_r26android-7.1.1_r25android-7.1.1_r24android-7.1.1_r23android-7.1.1_r22android-7.1.1_r21android-7.1.1_r20android-7.1.1_r2android-7.1.1_r17android-7.1.1_r16android-7.1.1_r15android-7.1.1_r14android-7.1.1_r13android-7.1.1_r12android-7.1.1_r11android-7.1.1_r10android-7.1.1_r1android-7.1.0_r7android-7.1.0_r6android-7.1.0_r5android-7.1.0_r4android-7.1.0_r3android-7.1.0_r2android-7.1.0_r1android-7.0.0_r9android-7.0.0_r8android-7.0.0_r7android-7.0.0_r6android-7.0.0_r5android-7.0.0_r4android-7.0.0_r36android-7.0.0_r35android-7.0.0_r34android-7.0.0_r33android-7.0.0_r32android-7.0.0_r31android-7.0.0_r30android-7.0.0_r3android-7.0.0_r29android-7.0.0_r28android-7.0.0_r27android-7.0.0_r24android-7.0.0_r21android-7.0.0_r19android-7.0.0_r17android-7.0.0_r15android-7.0.0_r14android-7.0.0_r13android-7.0.0_r12android-7.0.0_r11android-7.0.0_r10android-7.0.0_r1nougat-releasenougat-mr2.3-releasenougat-mr2.2-releasenougat-mr2.1-releasenougat-mr2-security-releasenougat-mr2-releasenougat-mr2-pixel-releasenougat-mr2-devnougat-mr1.8-releasenougat-mr1.7-releasenougat-mr1.6-releasenougat-mr1.5-releasenougat-mr1.4-releasenougat-mr1.3-releasenougat-mr1.2-releasenougat-mr1.1-releasenougat-mr1-volantis-releasenougat-mr1-security-releasenougat-mr1-releasenougat-mr1-flounder-releasenougat-mr1-devnougat-mr1-cts-releasenougat-mr0.5-releasenougat-dr1-releasenougat-devnougat-cts-releasenougat-bugfix-release
- Merges in upstream smali into nyc-dev for dex version 37 support. Bug: 27809626 Change-Id: Iff12b1e384355bcb261b55afd16af3bcac6ef1a0
-rw-r--r--.gitignore1
-rw-r--r--NOTICE20
-rw-r--r--README.md2
-rw-r--r--baksmali/build.gradle7
-rw-r--r--baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java3
-rw-r--r--baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java7
-rw-r--r--baksmali/src/main/java/org/jf/baksmali/Adaptors/PreInstructionRegisterInfoMethodItem.java6
-rw-r--r--baksmali/src/main/java/org/jf/baksmali/baksmali.java11
-rw-r--r--baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java9
-rw-r--r--baksmali/src/main/java/org/jf/baksmali/dump.java4
-rw-r--r--baksmali/src/main/java/org/jf/baksmali/main.java150
-rw-r--r--baksmali/src/test/java/org/jf/baksmali/AnalysisTest.java4
-rw-r--r--baksmali/src/test/java/org/jf/baksmali/DexTest.java78
-rw-r--r--baksmali/src/test/java/org/jf/baksmali/DisassemblyTest.java30
-rw-r--r--baksmali/src/test/java/org/jf/baksmali/FieldGapOrderTest.java70
-rw-r--r--baksmali/src/test/java/org/jf/baksmali/ParamListMethodNameTest.java42
-rw-r--r--baksmali/src/test/resources/FieldGapOrderTest/FieldGapOrderInput.dexbin0 -> 828 bytes
-rw-r--r--baksmali/src/test/resources/ParamListMethodNameTest/ParamListMethodName.smali5
-rw-r--r--build.gradle45
-rw-r--r--dexlib2/OatVersions.txt24
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java114
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/Opcode.java662
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java82
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/VersionMap.java50
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedInstruction.java138
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedMethodUtil.java70
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/ArrayProto.java7
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java159
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java300
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProvider.java40
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/DexClassProvider.java56
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java266
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/OdexedFieldInstructionMapper.java352
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/PrimitiveProto.java7
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/TypeProto.java4
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/UnknownClassProto.java7
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/util/TypeProtoUtils.java12
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java43
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java36
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java39
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java14
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedOdexFile.java5
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/dexbacked/OatFile.java496
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/HeaderItem.java24
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/RawDexFile.java3
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/iface/DexFile.java9
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableDexFile.java19
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/rewriter/DexRewriter.java5
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java13
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java90
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorResolver.java8
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java21
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java16
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java78
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java22
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java17
-rw-r--r--dexlib2/src/main/ragel/SyntheticAccessorFSM.rl11
-rw-r--r--dexlib2/src/test/java/org/jf/dexlib2/AccessorTest.java2
-rw-r--r--dexlib2/src/test/java/org/jf/dexlib2/analysis/CommonSuperclassTest.java70
-rw-r--r--dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java13
-rw-r--r--dexlib2/src/test/java/org/jf/dexlib2/analysis/util/SuperclassChainTest.java7
-rw-r--r--dexlib2/src/test/java/org/jf/dexlib2/builder/MutableMethodImplementationTest.java118
-rw-r--r--dexlib2/src/test/java/org/jf/dexlib2/writer/DexWriterTest.java8
-rw-r--r--dexlib2/src/test/java/org/jf/dexlib2/writer/JumboStringConversionTest.java8
-rw-r--r--gradle/wrapper/gradle-wrapper.properties4
-rw-r--r--settings.gradle6
-rw-r--r--smali/build.gradle16
-rw-r--r--smali/src/main/antlr/smaliParser.g45
-rw-r--r--smali/src/main/antlr/smaliTreeWalker.g24
-rw-r--r--smali/src/main/java/org/jf/smali/SmaliOptions.java52
-rw-r--r--smali/src/main/java/org/jf/smali/SmaliTestUtils.java5
-rw-r--r--smali/src/main/java/org/jf/smali/main.java244
-rw-r--r--smali/src/main/jflex/smaliLexer.jflex56
-rw-r--r--smali/src/test/resources/LexerTest/InstructionTest.smali5
-rw-r--r--smali/src/test/resources/LexerTest/InstructionTest.tokens5
-rw-r--r--smali/src/test/resources/LexerTest/RealSmaliFileTest.tokens12
-rw-r--r--smali/src/test/resources/LexerTest/TypeAndIdentifierTest.smali6
-rw-r--r--smali/src/test/resources/LexerTest/TypeAndIdentifierTest.tokens113
-rw-r--r--smalidea/.gitignore3
-rw-r--r--smalidea/build.gradle236
-rw-r--r--smalidea/src/main/antlr/smalideaParser.g1363
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/PsiBuilderTokenStream.java166
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/SmaliASTFactory.java19
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/SmaliColorsPage.java137
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/SmaliFileType.java66
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/SmaliFileTypeFactory.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/SmaliHighlighter.java54
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/SmaliHighlightingColors.java92
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/SmaliIcons.java40
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/SmaliLanguage.java46
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/SmaliLexer.java131
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/SmaliLexicalElementType.java46
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/SmaliParser.java64
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/SmaliParserDefinition.java95
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/SmaliTokens.java360
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/SmaliCodeFragmentFactory.java378
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/SmaliDebuggerSupport.java81
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/SmaliExpressionEvaluator.java70
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/SmaliPositionManager.java170
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/SmaliPositionManagerFactory.java44
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyArrayReference.java75
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyBooleanValue.java46
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyByteValue.java46
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyCharValue.java46
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyClassLoaderReference.java54
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyClassObjectReference.java48
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyComparablePrimitiveValue.java47
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyDoubleValue.java46
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyFloatValue.java46
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyIntegerValue.java46
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyLongValue.java46
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyObjectReference.java101
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyPrimitiveValue.java78
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyShortValue.java46
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyStringReference.java46
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyThreadGroupReference.java71
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyThreadReference.java120
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyValue.java179
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyVoidValue.java42
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaClassDef.java214
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaExceptionHandler.java64
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaField.java116
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaMethod.java214
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaMethodParameter.java64
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaTryBlock.java61
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/analysis/SmalideaClassProvider.java32
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaArrayPayload.java64
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction.java220
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction10t.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction10x.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction11n.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction11x.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction12x.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction20t.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21c.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21ih.java47
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21lh.java47
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21s.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21t.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22b.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22c.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22s.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22t.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22x.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction23x.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction30t.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction31c.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction31i.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction31t.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction32x.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction35c.java63
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction3rc.java51
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction51l.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaPackedSwitchPayload.java100
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaSparseSwitchPayload.java92
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/errorReporting/ErrorReporter.java127
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/errorReporting/GithubFeedbackTask.java172
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/errorReporting/ITNProxy.java90
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliClassReferenceSearcher.java122
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliFindUsagesProvider.java51
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliUsageTargetProvider.java76
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliUsageTypeProvider.java200
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliWordScanner.java118
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/SmaliCompositeElementFactory.java38
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/SmaliCompositeElementType.java53
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/SmaliElementTypes.java122
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/iface/SmaliModifierListOwner.java48
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/LightSmaliClassTypeElement.java187
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotation.java116
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotationElement.java94
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotationElementName.java135
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotationParameterList.java53
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliArrayDataElement.java53
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliArrayTypeElement.java73
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliBaseReferenceList.java114
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliCatchAllStatement.java52
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliCatchStatement.java81
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java415
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassStatement.java146
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassType.java185
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassTypeElement.java192
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliCompositeElement.java127
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliEndLocalDebugStatement.java47
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliEpilogueDebugStatement.java47
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliExtendsList.java96
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliField.java174
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliFieldInitializer.java47
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliFieldReference.java151
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliFile.java94
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliImplementsList.java81
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliImplementsStatement.java53
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliInstruction.java231
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLabel.java75
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLabelReference.java104
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLineDebugStatement.java47
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLiteral.java75
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLocalDebugStatement.java47
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLocalName.java53
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMemberName.java69
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java371
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodParamList.java80
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodParameter.java223
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodPrototype.java77
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodReference.java192
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodReferenceParamList.java52
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliModifierList.java166
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliPackedSwitchElement.java53
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliParameterStatement.java83
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliPrimitiveTypeElement.java72
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliPrologueDebugStatement.java47
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegisterReference.java70
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegistersStatement.java75
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRestartLocalDebugStatement.java47
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSourceDebugStatement.java47
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSourceStatement.java47
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSparseSwitchElement.java58
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliStubBasedPsiElement.java82
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSuperStatement.java53
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliThrowsList.java56
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliTypeElement.java73
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliVoidTypeElement.java53
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/index/SmaliClassFinder.java61
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/index/SmaliClassNameIndex.java51
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/leaf/SmaliClassDescriptor.java17
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/leaf/SmaliSimpleName.java10
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliAnnotationStub.java53
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliBaseReferenceListStub.java69
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliClassStatementStub.java62
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliClassStub.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliExtendsListStub.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliFieldStub.java58
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliFileStub.java41
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliImplementsListStub.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodParamListStub.java44
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodParameterStub.java58
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodPrototypeStub.java52
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodStub.java53
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliModifierListStub.java50
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliThrowsListStub.java43
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliAnnotationElementType.java80
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliBaseReferenceListElementType.java76
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliClassElementType.java97
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliClassStatementElementType.java80
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliExtendsListElementType.java66
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliFieldElementType.java97
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliFileElementType.java62
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliImplementsListElementType.java67
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodElementType.java80
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodParamListElementType.java82
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodParameterElementType.java85
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodPrototypeElementType.java90
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliModifierListElementType.java82
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliStubElementType.java63
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliThrowsListElementType.java67
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/util/InstructionUtils.java66
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/util/NameUtils.java334
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/util/PsiUtil.java73
-rw-r--r--smalidea/src/main/java/org/jf/smalidea/util/StringUtils.java64
-rw-r--r--smalidea/src/main/resources/META-INF/plugin.xml47
-rw-r--r--smalidea/src/main/resources/icons/smali.pngbin0 -> 261 bytes
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/AnnotationElementNameReferenceTest.java104
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/ClassMoveTest.java55
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/ClassReferenceTest.java112
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/ClassRenameTest.java51
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/FieldReferenceTest.java127
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/FieldRenameTest.java50
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/LightCodeInsightParsingTestCase.java209
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/MethodReferenceTest.java143
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/MethodRenameTest.java50
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/ParserTest.java67
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliAnnotationTest.java273
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliClassModifierListTest.java194
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliClassTest.java168
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliClassTypeElementTest.java172
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliCodeFragmentFactoryTest.java279
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliFieldTest.java250
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliFileTest.java57
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliFileTypeTest.java48
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliImplementsExtendsTest.java124
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliInstructionTest.java82
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliLabelReferenceTest.java102
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliLexerTest.java204
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliLiteralTest.java78
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliMethodTest.java309
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliPositionManagerTest.java237
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/SmaliRegisterTest.java61
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/dexlib/SmalideaMethodTest.java580
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/findUsages/ClassUsageTypeTest.java74
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/findUsages/FieldUsageTypeTest.java115
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/findUsages/FindAnnotationElementUsagesTest.java91
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/findUsages/FindClassUsagesTest.java76
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/findUsages/FindFieldUsagesTest.java91
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/findUsages/FindMethodUsagesTest.java95
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/findUsages/FindUsagesTest.java195
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/findUsages/HighlightLocalClassUsagesTest.java78
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/findUsages/MethodUsageTypeTest.java54
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/findUsages/UsageTypeTest.java73
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/util/NameUtilsTest.java87
-rw-r--r--smalidea/src/test/java/org/jf/smalidea/util/StringUtilsTest.java49
-rw-r--r--smalidea/testData/Empty.smalidea0
-rw-r--r--smalidea/testData/Empty.txt8
-rw-r--r--smalidea/testData/FieldAnnotations.smalidea15
-rw-r--r--smalidea/testData/FieldAnnotations.txt91
-rw-r--r--smalidea/testData/InvalidAnnotation.smalidea19
-rw-r--r--smalidea/testData/InvalidAnnotation.txt108
-rw-r--r--smalidea/testData/InvalidClassDirective.smalidea1
-rw-r--r--smalidea/testData/InvalidClassDirective.txt12
-rw-r--r--smalidea/testData/InvalidClassDirective2.smalidea2
-rw-r--r--smalidea/testData/InvalidClassDirective2.txt15
-rw-r--r--smalidea/testData/InvalidClassDirective3.smalidea1
-rw-r--r--smalidea/testData/InvalidClassDirective3.txt16
-rw-r--r--smalidea/testData/InvalidEnumLiteral.smalidea1
-rw-r--r--smalidea/testData/InvalidEnumLiteral.txt38
-rw-r--r--smalidea/testData/InvalidField.smalidea1
-rw-r--r--smalidea/testData/InvalidField.txt13
-rw-r--r--smalidea/testData/InvalidField2.smalidea1
-rw-r--r--smalidea/testData/InvalidField2.txt17
-rw-r--r--smalidea/testData/InvalidField3.smalidea3
-rw-r--r--smalidea/testData/InvalidField3.txt22
-rw-r--r--smalidea/testData/InvalidField4.smalidea1
-rw-r--r--smalidea/testData/InvalidField4.txt17
-rw-r--r--smalidea/testData/InvalidInstruction.smalidea31
-rw-r--r--smalidea/testData/InvalidInstruction.txt236
-rw-r--r--smalidea/testData/InvalidLocal.smalidea7
-rw-r--r--smalidea/testData/InvalidLocal.txt66
-rw-r--r--smalidea/testData/InvalidMethod.smalidea4
-rw-r--r--smalidea/testData/InvalidMethod.txt33
-rw-r--r--smalidea/testData/InvalidMethod2.smalidea6
-rw-r--r--smalidea/testData/InvalidMethod2.txt49
-rw-r--r--smalidea/testData/InvalidMethod3.smalidea11
-rw-r--r--smalidea/testData/InvalidMethod3.txt63
-rw-r--r--smalidea/testData/InvalidMethod4.smalidea8
-rw-r--r--smalidea/testData/InvalidMethod4.txt73
-rw-r--r--smalidea/testData/InvalidMethodReference.smalidea24
-rw-r--r--smalidea/testData/InvalidMethodReference.txt241
-rw-r--r--smalidea/testData/InvalidParameter.smalidea10
-rw-r--r--smalidea/testData/InvalidParameter.txt85
-rw-r--r--smalidea/testData/MissingDotDot.smalidea9
-rw-r--r--smalidea/testData/MissingDotDot.txt126
-rw-r--r--smalidea/testData/ParamListInvalidParameter.smalidea5
-rw-r--r--smalidea/testData/ParamListInvalidParameter.txt38
-rw-r--r--smalidea/testData/SuperClassInvalidSyntax.smalidea2
-rw-r--r--smalidea/testData/SuperClassInvalidSyntax.txt18
-rw-r--r--smalidea/testData/SuperClassInvalidSyntax2.smalidea5
-rw-r--r--smalidea/testData/SuperClassInvalidSyntax2.txt37
-rw-r--r--smalidea/testData/classMove/basicFromNoPackage/after/my/blah.smali36
-rw-r--r--smalidea/testData/classMove/basicFromNoPackage/before/blah.smali36
-rw-r--r--smalidea/testData/classMove/basicToNoPackage/after/blah.smali36
-rw-r--r--smalidea/testData/classMove/basicToNoPackage/after/my/placeholder.smali2
-rw-r--r--smalidea/testData/classMove/basicToNoPackage/before/my/blah.smali36
-rw-r--r--smalidea/testData/classMove/basicToNoPackage/before/my/placeholder.smali2
-rw-r--r--smalidea/testData/classRename/basicNoPackage/after/blah2.smali36
-rw-r--r--smalidea/testData/classRename/basicNoPackage/before/blah.smali36
-rw-r--r--smalidea/testData/classRename/basicWithPackage/after/my/blah2.smali36
-rw-r--r--smalidea/testData/classRename/basicWithPackage/before/my/blah.smali36
-rw-r--r--smalidea/testData/fieldRename/fieldRename/after/blah.smali59
-rw-r--r--smalidea/testData/fieldRename/fieldRename/before/blah.smali59
-rw-r--r--smalidea/testData/methodRename/methodRename/after/blah.smali27
-rw-r--r--smalidea/testData/methodRename/methodRename/before/blah.smali27
-rw-r--r--util/src/main/java/org/jf/util/BlankReader.java48
360 files changed, 27448 insertions, 1251 deletions
diff --git a/.gitignore b/.gitignore
index 45e097ee..b7db779a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
/dexlib2/accessorTestGenerator/build
/smali/build
/util/build
+/smalidea/build
*.iml
*.ipr
*.iws
diff --git a/NOTICE b/NOTICE
index 4ce4514b..e29e98b8 100644
--- a/NOTICE
+++ b/NOTICE
@@ -82,4 +82,24 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+*******************************************************************************
+
+
+Some parts of the smalidea plugin are based on code from the IDEA project, per the
+following license
+
+*******************************************************************************
+Copyright 2000-2014 JetBrains s.r.o.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
******************************************************************************* \ No newline at end of file
diff --git a/README.md b/README.md
index 57848991..ccae135d 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,8 @@ smali/baksmali is an assembler/disassembler for the dex format used by dalvik, A
Downloads are at https://bitbucket.org/JesusFreke/smali/downloads. If you are interested in submitting a patch, feel free to send me a pull request here.
+See [the wiki](https://github.com/JesusFreke/smali/wiki) for more info/news/release notes/etc.
+
#### Support
- [github Issue tracker](https://github.com/JesusFreke/smali/issues) - For any bugs/issues/feature requests
- [#smali on freenode](http://webchat.freenode.net/?channels=smali) - Free free to drop by and ask a question. Don't expect an instant response, but if you hang around someone will respond.
diff --git a/baksmali/build.gradle b/baksmali/build.gradle
index 4780cd76..f3a14b19 100644
--- a/baksmali/build.gradle
+++ b/baksmali/build.gradle
@@ -51,16 +51,13 @@ dependencies {
processResources.inputs.property('version', version)
processResources.expand('version': version)
-// This is the jar that gets uploaded to maven
-jar {
- baseName = 'maven'
-}
-
// Build a separate jar that contains all dependencies
task fatJar(type: Jar) {
from sourceSets.main.output
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
+ classifier = 'fat'
+
manifest {
attributes('Main-Class': 'org.jf.baksmali.main')
}
diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java
index b3f9ae17..fc43d6f1 100644
--- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java
+++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java
@@ -76,8 +76,7 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
return false;
}
- return opcode.isOdexedInstanceVolatile() || opcode.isOdexedStaticVolatile() ||
- opcode == Opcode.THROW_VERIFICATION_ERROR;
+ return opcode.isVolatileFieldAccessor() || opcode == Opcode.THROW_VERIFICATION_ERROR;
}
@Override
diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java
index 4081a75c..ef2110a8 100644
--- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java
+++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java
@@ -320,7 +320,7 @@ public class MethodDefinition {
String parameterType = parameter.getType();
String parameterName = parameter.getName();
Collection<? extends Annotation> annotations = parameter.getAnnotations();
- if (parameterName != null || annotations.size() != 0) {
+ if ((options.outputDebugInfo && parameterName != null) || annotations.size() != 0) {
writer.write(".param p");
writer.printSignedIntAsDec(registerNumber);
@@ -366,7 +366,8 @@ public class MethodDefinition {
private List<MethodItem> getMethodItems() {
ArrayList<MethodItem> methodItems = new ArrayList<MethodItem>();
- if ((classDef.options.registerInfo != 0) || (classDef.options.deodex && needsAnalyzed())) {
+ if ((classDef.options.registerInfo != 0) || (classDef.options.normalizeVirtualMethods) ||
+ (classDef.options.deodex && needsAnalyzed())) {
addAnalyzedInstructionMethodItems(methodItems);
} else {
addInstructionMethodItems(methodItems);
@@ -460,7 +461,7 @@ public class MethodDefinition {
private void addAnalyzedInstructionMethodItems(List<MethodItem> methodItems) {
MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classDef.options.classPath, method,
- classDef.options.inlineResolver);
+ classDef.options.inlineResolver, classDef.options.normalizeVirtualMethods);
AnalysisException analysisException = methodAnalyzer.getAnalysisException();
if (analysisException != null) {
diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/PreInstructionRegisterInfoMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/PreInstructionRegisterInfoMethodItem.java
index fa54f091..f5329388 100644
--- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/PreInstructionRegisterInfoMethodItem.java
+++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/PreInstructionRegisterInfoMethodItem.java
@@ -156,7 +156,8 @@ public class PreInstructionRegisterInfoMethodItem extends MethodItem {
RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) {
- RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum);
+ RegisterType predecessorRegisterType = analyzedInstruction.getPredecessorRegisterType(
+ predecessor, registerNum);
if (predecessorRegisterType.category != RegisterType.UNKNOWN &&
!predecessorRegisterType.equals(mergedRegisterType)) {
registers.set(registerNum);
@@ -179,7 +180,8 @@ public class PreInstructionRegisterInfoMethodItem extends MethodItem {
boolean first = true;
for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) {
- RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum);
+ RegisterType predecessorRegisterType = analyzedInstruction.getPredecessorRegisterType(
+ predecessor, registerNum);
if (!first) {
writer.write(',');
diff --git a/baksmali/src/main/java/org/jf/baksmali/baksmali.java b/baksmali/src/main/java/org/jf/baksmali/baksmali.java
index 47fa406d..50607340 100644
--- a/baksmali/src/main/java/org/jf/baksmali/baksmali.java
+++ b/baksmali/src/main/java/org/jf/baksmali/baksmali.java
@@ -44,19 +44,18 @@ import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
import java.io.*;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.*;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
public class baksmali {
public static boolean disassembleDexFile(DexFile dexFile, final baksmaliOptions options) {
- if (options.registerInfo != 0 || options.deodex) {
+ if (options.registerInfo != 0 || options.deodex || options.normalizeVirtualMethods) {
try {
Iterable<String> extraClassPathEntries;
if (options.extraClassPathEntries != null) {
@@ -136,7 +135,7 @@ public class baksmali {
List<? extends ClassDef> classDefs = Ordering.natural().sortedCopy(dexFile.getClasses());
if (!options.noAccessorComments) {
- options.syntheticAccessorResolver = new SyntheticAccessorResolver(classDefs);
+ options.syntheticAccessorResolver = new SyntheticAccessorResolver(dexFile.getOpcodes(), classDefs);
}
final ClassFileNameHandler fileNameHandler = new ClassFileNameHandler(outputDirectoryFile, ".smali");
diff --git a/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java b/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java
index b6cc1571..32685ddf 100644
--- a/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java
+++ b/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java
@@ -36,6 +36,7 @@ import org.jf.dexlib2.analysis.ClassPath;
import org.jf.dexlib2.analysis.InlineMethodResolver;
import org.jf.dexlib2.util.SyntheticAccessorResolver;
+import javax.annotation.Nullable;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
@@ -54,7 +55,7 @@ public class baksmaliOptions {
public int apiLevel = 15;
public String outputDirectory = "out";
- public String dexEntry = "classes.dex";
+ @Nullable public String dexEntry = null;
public List<String> bootClassPathDirs = Lists.newArrayList();
public List<String> bootClassPathEntries = Lists.newArrayList();
@@ -75,11 +76,15 @@ public class baksmaliOptions {
public boolean ignoreErrors = false;
public boolean checkPackagePrivateAccess = false;
public boolean useImplicitReferences = false;
+ public boolean normalizeVirtualMethods = false;
public File customInlineDefinitions = null;
public InlineMethodResolver inlineResolver = null;
public int registerInfo = 0;
public ClassPath classPath = null;
- public int jobs = -1;
+ public int jobs = Runtime.getRuntime().availableProcessors();
+ public boolean disassemble = true;
+ public boolean dump = false;
+ public String dumpFileName = null;
public SyntheticAccessorResolver syntheticAccessorResolver = null;
diff --git a/baksmali/src/main/java/org/jf/baksmali/dump.java b/baksmali/src/main/java/org/jf/baksmali/dump.java
index 1ef7df0e..79405e59 100644
--- a/baksmali/src/main/java/org/jf/baksmali/dump.java
+++ b/baksmali/src/main/java/org/jf/baksmali/dump.java
@@ -40,7 +40,7 @@ import java.io.IOException;
import java.io.Writer;
public class dump {
- public static void dump(DexBackedDexFile dexFile, String dumpFileName, int apiLevel, boolean experimental) throws IOException {
+ public static void dump(DexBackedDexFile dexFile, String dumpFileName, int apiLevel) throws IOException {
if (dumpFileName != null) {
Writer writer = null;
@@ -52,7 +52,7 @@ public class dump {
consoleWidth = 120;
}
- RawDexFile rawDexFile = new RawDexFile(new Opcodes(apiLevel, experimental), dexFile);
+ RawDexFile rawDexFile = new RawDexFile(Opcodes.forApi(apiLevel), dexFile);
DexAnnotator annotator = new DexAnnotator(rawDexFile, consoleWidth);
annotator.writeAnnotations(writer);
} catch (IOException ex) {
diff --git a/baksmali/src/main/java/org/jf/baksmali/main.java b/baksmali/src/main/java/org/jf/baksmali/main.java
index 71598fa6..2d6ed8c4 100644
--- a/baksmali/src/main/java/org/jf/baksmali/main.java
+++ b/baksmali/src/main/java/org/jf/baksmali/main.java
@@ -31,9 +31,12 @@ package org.jf.baksmali;
import com.google.common.collect.Lists;
import org.apache.commons.cli.*;
import org.jf.dexlib2.DexFileFactory;
+import org.jf.dexlib2.DexFileFactory.MultipleDexFilesException;
import org.jf.dexlib2.analysis.InlineMethodResolver;
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
import org.jf.dexlib2.dexbacked.DexBackedOdexFile;
+import org.jf.dexlib2.dexbacked.OatFile.OatDexFile;
+import org.jf.dexlib2.iface.DexFile;
import org.jf.util.ConsoleUtil;
import org.jf.util.SmaliHelpFormatter;
@@ -82,6 +85,45 @@ public class main {
}
/**
+ * A more programmatic-friendly entry point for baksmali
+ *
+ * @param options a baksmaliOptions object with the options to run baksmali with
+ * @param inputDexFile The DexFile to disassemble
+ * @return true if disassembly completed with no errors, or false if errors were encountered
+ */
+ public static boolean run(@Nonnull baksmaliOptions options, @Nonnull DexFile inputDexFile) throws IOException {
+ if (options.bootClassPathEntries.isEmpty() &&
+ (options.deodex || options.registerInfo != 0 || options.normalizeVirtualMethods)) {
+ if (inputDexFile instanceof DexBackedOdexFile) {
+ options.bootClassPathEntries = ((DexBackedOdexFile)inputDexFile).getDependencies();
+ } else {
+ options.bootClassPathEntries = getDefaultBootClassPathForApi(options.apiLevel,
+ options.experimental);
+ }
+ }
+
+ if (options.customInlineDefinitions == null && inputDexFile instanceof DexBackedOdexFile) {
+ options.inlineResolver =
+ InlineMethodResolver.createInlineMethodResolver(
+ ((DexBackedOdexFile)inputDexFile).getOdexVersion());
+ }
+
+ boolean errorOccurred = false;
+ if (options.disassemble) {
+ errorOccurred = !baksmali.disassembleDexFile(inputDexFile, options);
+ }
+
+ if (options.dump) {
+ if (!(inputDexFile instanceof DexBackedDexFile)) {
+ throw new IllegalArgumentException("Annotated hex-dumps require a DexBackedDexFile");
+ }
+ dump.dump((DexBackedDexFile)inputDexFile, options.dumpFileName, options.apiLevel);
+ }
+
+ return !errorOccurred;
+ }
+
+ /**
* Run!
*/
public static void main(String[] args) throws IOException {
@@ -100,11 +142,6 @@ public class main {
baksmaliOptions options = new baksmaliOptions();
- boolean disassemble = true;
- boolean doDump = false;
- String dumpFileName = null;
- boolean setBootClassPath = false;
-
String[] remainingArgs = commandLine.getArgs();
Option[] clOptions = commandLine.getOptions();
@@ -185,7 +222,6 @@ public class main {
if (bcp != null && bcp.charAt(0) == ':') {
options.addExtraClassPath(bcp);
} else {
- setBootClassPath = true;
options.setBootClassPath(bcp);
}
break;
@@ -217,12 +253,15 @@ public class main {
case 'k':
options.checkPackagePrivateAccess = true;
break;
+ case 'n':
+ options.normalizeVirtualMethods = true;
+ break;
case 'N':
- disassemble = false;
+ options.disassemble = false;
break;
case 'D':
- doDump = true;
- dumpFileName = commandLine.getOptionValue("D");
+ options.dump = true;
+ options.dumpFileName = commandLine.getOptionValue("D");
break;
case 'I':
options.ignoreErrors = true;
@@ -240,26 +279,29 @@ public class main {
return;
}
- if (options.jobs <= 0) {
- options.jobs = Runtime.getRuntime().availableProcessors();
- if (options.jobs > 6) {
- options.jobs = 6;
- }
- }
-
- String inputDexFileName = remainingArgs[0];
-
- File dexFileFile = new File(inputDexFileName);
+ String inputDexPath = remainingArgs[0];
+ File dexFileFile = new File(inputDexPath);
if (!dexFileFile.exists()) {
- System.err.println("Can't find the file " + inputDexFileName);
+ System.err.println("Can't find the file " + inputDexPath);
System.exit(1);
}
//Read in and parse the dex file
- DexBackedDexFile dexFile = DexFileFactory.loadDexFile(dexFileFile, options.dexEntry,
- options.apiLevel, options.experimental);
+ DexBackedDexFile dexFile = null;
+ try {
+ dexFile = DexFileFactory.loadDexFile(dexFileFile, options.dexEntry, options.apiLevel, options.experimental);
+ } catch (MultipleDexFilesException ex) {
+ System.err.println(String.format("%s contains multiple dex files. You must specify which one to " +
+ "disassemble with the -e option", dexFileFile.getName()));
+ System.err.println("Valid entries include:");
+
+ for (OatDexFile oatDexFile: ex.oatFile.getDexFiles()) {
+ System.err.println(oatDexFile.filename);
+ }
+ System.exit(1);
+ }
- if (dexFile.isOdexFile()) {
+ if (dexFile.hasOdexOpcodes()) {
if (!options.deodex) {
System.err.println("Warning: You are disassembling an odex file without deodexing it. You");
System.err.println("won't be able to re-assemble the results unless you deodex it with the -x");
@@ -270,34 +312,18 @@ public class main {
options.deodex = false;
}
- if (!setBootClassPath && (options.deodex || options.registerInfo != 0)) {
- if (dexFile instanceof DexBackedOdexFile) {
- options.bootClassPathEntries = ((DexBackedOdexFile)dexFile).getDependencies();
- } else {
- options.bootClassPathEntries = getDefaultBootClassPathForApi(options.apiLevel,
- options.experimental);
+ if (options.dump) {
+ if (options.dumpFileName == null) {
+ options.dumpFileName = inputDexPath + ".dump";
}
}
- if (options.customInlineDefinitions == null && dexFile instanceof DexBackedOdexFile) {
- options.inlineResolver =
- InlineMethodResolver.createInlineMethodResolver(
- ((DexBackedOdexFile)dexFile).getOdexVersion());
- }
-
- boolean errorOccurred = false;
- if (disassemble) {
- errorOccurred = !baksmali.disassembleDexFile(dexFile, options);
- }
-
- if (doDump) {
- if (dumpFileName == null) {
- dumpFileName = commandLine.getOptionValue(inputDexFileName + ".dump");
+ try {
+ if (!run(options, dexFile)) {
+ System.exit(1);
}
- dump.dump(dexFile, dumpFileName, options.apiLevel, options.experimental);
- }
-
- if (errorOccurred) {
+ } catch (IllegalArgumentException ex) {
+ System.err.println(ex.getMessage());
System.exit(1);
}
}
@@ -391,9 +417,9 @@ public class main {
.create("r");
Option classPathOption = OptionBuilder.withLongOpt("bootclasspath")
- .withDescription("the bootclasspath jars to use, for analysis. Defaults to " +
- "core.jar:ext.jar:framework.jar:android.policy.jar:services.jar. If the value begins with a " +
- ":, it will be appended to the default bootclasspath instead of replacing it")
+ .withDescription("A colon-separated list of bootclasspath jar/oat files to use for analysis. Add an " +
+ "initial colon to specify that the jars/oats should be appended to the default bootclasspath " +
+ "instead of replacing it")
.hasOptionalArg()
.withArgName("BOOTCLASSPATH")
.create("c");
@@ -445,6 +471,10 @@ public class main {
"4.2.1.")
.create("k");
+ Option normalizeVirtualMethods = OptionBuilder.withLongOpt("normalize-virtual-methods")
+ .withDescription("Normalize virtual method references to the reference the base method.")
+ .create("n");
+
Option dumpOption = OptionBuilder.withLongOpt("dump-to")
.withDescription("dumps the given dex file into a single annotated dump file named FILE" +
" (<dexfile>.dump by default), along with the normal disassembly")
@@ -494,6 +524,7 @@ public class main {
basicOptions.addOption(noImplicitReferencesOption);
basicOptions.addOption(dexEntryOption);
basicOptions.addOption(checkPackagePrivateAccessOption);
+ basicOptions.addOption(normalizeVirtualMethods);
debugOptions.addOption(dumpOption);
debugOptions.addOption(ignoreErrorsOption);
@@ -547,8 +578,7 @@ public class main {
"/system/framework/services.jar",
"/system/framework/apache-xml.jar",
"/system/framework/filterfw.jar");
-
- } else {
+ } else if (apiLevel < 21) {
// this is correct as of api 17/4.2.2
return Lists.newArrayList(
"/system/framework/core.jar",
@@ -561,6 +591,22 @@ public class main {
"/system/framework/android.policy.jar",
"/system/framework/services.jar",
"/system/framework/apache-xml.jar");
+ } else { // api >= 21
+ // TODO: verify, add new ones?
+ return Lists.newArrayList(
+ "/system/framework/core-libart.jar",
+ "/system/framework/conscrypt.jar",
+ "/system/framework/okhttp.jar",
+ "/system/framework/core-junit.jar",
+ "/system/framework/bouncycastle.jar",
+ "/system/framework/ext.jar",
+ "/system/framework/framework.jar",
+ "/system/framework/telephony-common.jar",
+ "/system/framework/voip-common.jar",
+ "/system/framework/ims-common.jar",
+ "/system/framework/mms-common.jar",
+ "/system/framework/android.policy.jar",
+ "/system/framework/apache-xml.jar");
}
}
}
diff --git a/baksmali/src/test/java/org/jf/baksmali/AnalysisTest.java b/baksmali/src/test/java/org/jf/baksmali/AnalysisTest.java
index 725032af..2bb04dda 100644
--- a/baksmali/src/test/java/org/jf/baksmali/AnalysisTest.java
+++ b/baksmali/src/test/java/org/jf/baksmali/AnalysisTest.java
@@ -106,8 +106,8 @@ public class AnalysisTest {
className.substring(1, className.length() - 1));
String smaliContents = readResource(smaliPath);
- Assert.assertEquals(TextUtils.normalizeNewlines(smaliContents),
- TextUtils.normalizeNewlines(stringWriter.toString()));
+ Assert.assertEquals(TextUtils.normalizeWhitespace(smaliContents),
+ TextUtils.normalizeWhitespace((stringWriter.toString())));
}
}
diff --git a/baksmali/src/test/java/org/jf/baksmali/DexTest.java b/baksmali/src/test/java/org/jf/baksmali/DexTest.java
new file mode 100644
index 00000000..5a4db658
--- /dev/null
+++ b/baksmali/src/test/java/org/jf/baksmali/DexTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2015, 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.baksmali;
+
+import org.jf.dexlib2.Opcodes;
+import org.jf.dexlib2.dexbacked.DexBackedDexFile;
+import org.junit.Assert;
+
+import javax.annotation.Nonnull;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * A base test class for performing a test using a dex file as input
+ */
+/**
+ * A base test class for performing a disassembly on a dex file and verifying the results
+ *
+ * The test accepts a single-class dex file as input. By default, the input dex file should be a resource at
+ * [testDir]/[testName]Input.dex
+ */
+public abstract class DexTest {
+ protected final String testDir;
+
+ protected DexTest(@Nonnull String testDir) {
+ this.testDir = testDir;
+ }
+
+ protected DexTest() {
+ this.testDir = this.getClass().getSimpleName();
+ }
+
+ @Nonnull
+ protected String getInputFilename(@Nonnull String testName) {
+ return String.format("%s%s%sInput.dex", testDir, File.separatorChar, testName);
+ }
+
+ @Nonnull
+ protected DexBackedDexFile getInputDexFile(@Nonnull String testName, @Nonnull baksmaliOptions options) {
+ try {
+ // Load file from resources as a stream
+ byte[] inputBytes = BaksmaliTestUtils.readResourceBytesFully(getInputFilename(testName));
+ return new DexBackedDexFile(Opcodes.forApi(options.apiLevel), inputBytes);
+ } catch (IOException ex) {
+ Assert.fail();
+ }
+ return null;
+ }
+}
diff --git a/baksmali/src/test/java/org/jf/baksmali/DisassemblyTest.java b/baksmali/src/test/java/org/jf/baksmali/DisassemblyTest.java
index 35304f7e..1a34e8c3 100644
--- a/baksmali/src/test/java/org/jf/baksmali/DisassemblyTest.java
+++ b/baksmali/src/test/java/org/jf/baksmali/DisassemblyTest.java
@@ -32,7 +32,6 @@
package org.jf.baksmali;
import com.google.common.collect.Iterables;
-import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
import org.jf.dexlib2.iface.ClassDef;
import org.junit.Assert;
@@ -50,21 +49,7 @@ import java.io.IOException;
* By default, the input and output files should be resources at [testDir]/[testName]Input.dex
* and [testDir]/[testName]Output.smali respectively
*/
-public class DisassemblyTest {
- protected final String testDir;
-
- protected DisassemblyTest(@Nonnull String testDir) {
- this.testDir = testDir;
- }
-
- protected DisassemblyTest() {
- this.testDir = this.getClass().getSimpleName();
- }
-
- @Nonnull
- protected String getInputFilename(@Nonnull String testName) {
- return String.format("%s%s%sInput.dex", testDir, File.separatorChar, testName);
- }
+public class DisassemblyTest extends DexTest {
@Nonnull
protected String getOutputFilename(@Nonnull String testName) {
@@ -77,22 +62,13 @@ public class DisassemblyTest {
protected void runTest(@Nonnull String testName, @Nonnull baksmaliOptions options) {
try {
- // Load file from resources as a stream
- String inputFilename = getInputFilename(testName);
- byte[] inputBytes = BaksmaliTestUtils.readResourceBytesFully(getInputFilename(testName));
-
- DexBackedDexFile inputDex = new DexBackedDexFile(new Opcodes(options.apiLevel, false), inputBytes);
+ DexBackedDexFile inputDex = getInputDexFile(testName, options);
Assert.assertEquals(1, inputDex.getClassCount());
ClassDef inputClass = Iterables.getFirst(inputDex.getClasses(), null);
Assert.assertNotNull(inputClass);
String input = BaksmaliTestUtils.getNormalizedSmali(inputClass, options, true);
- String output;
- if (getOutputFilename(testName).equals(inputFilename)) {
- output = input;
- } else {
- output = BaksmaliTestUtils.readResourceFully(getOutputFilename(testName));
- }
+ String output = BaksmaliTestUtils.readResourceFully(getOutputFilename(testName));
output = BaksmaliTestUtils.normalizeSmali(output, true);
// Run smali, baksmali, and then compare strings are equal (minus comments/whitespace)
diff --git a/baksmali/src/test/java/org/jf/baksmali/FieldGapOrderTest.java b/baksmali/src/test/java/org/jf/baksmali/FieldGapOrderTest.java
new file mode 100644
index 00000000..78fabc0b
--- /dev/null
+++ b/baksmali/src/test/java/org/jf/baksmali/FieldGapOrderTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2015, 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.baksmali;
+
+import com.google.common.collect.Lists;
+import org.jf.dexlib2.analysis.ClassPath;
+import org.jf.dexlib2.analysis.ClassProto;
+import org.jf.dexlib2.analysis.DexClassProvider;
+import org.jf.dexlib2.iface.DexFile;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class FieldGapOrderTest extends DexTest {
+ @Test
+ public void testOldOrder() {
+ DexFile dexFile = getInputDexFile("FieldGapOrder", new baksmaliOptions());
+ Assert.assertEquals(3, dexFile.getClasses().size());
+
+ ClassPath classPath = new ClassPath(Lists.newArrayList(new DexClassProvider(dexFile)), false, 66);
+ ClassProto classProto = (ClassProto)classPath.getClass("LGapOrder;");
+ Assert.assertEquals("r1", classProto.getFieldByOffset(12).getName());
+ Assert.assertEquals("r2", classProto.getFieldByOffset(16).getName());
+ Assert.assertEquals("d", classProto.getFieldByOffset(24).getName());
+ Assert.assertEquals("s", classProto.getFieldByOffset(36).getName());
+ Assert.assertEquals("i", classProto.getFieldByOffset(32).getName());
+ }
+
+ @Test
+ public void testNewOrder() {
+ DexFile dexFile = getInputDexFile("FieldGapOrder", new baksmaliOptions());
+ Assert.assertEquals(3, dexFile.getClasses().size());
+
+ ClassPath classPath = new ClassPath(Lists.newArrayList(new DexClassProvider(dexFile)), false, 67);
+ ClassProto classProto = (ClassProto)classPath.getClass("LGapOrder;");
+ Assert.assertEquals("s", classProto.getFieldByOffset(10).getName());
+ Assert.assertEquals("r1", classProto.getFieldByOffset(12).getName());
+ Assert.assertEquals("r2", classProto.getFieldByOffset(16).getName());
+ Assert.assertEquals("i", classProto.getFieldByOffset(20).getName());
+ Assert.assertEquals("d", classProto.getFieldByOffset(24).getName());
+ }
+}
diff --git a/baksmali/src/test/java/org/jf/baksmali/ParamListMethodNameTest.java b/baksmali/src/test/java/org/jf/baksmali/ParamListMethodNameTest.java
new file mode 100644
index 00000000..42f7239d
--- /dev/null
+++ b/baksmali/src/test/java/org/jf/baksmali/ParamListMethodNameTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015, 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.baksmali;
+
+import org.junit.Test;
+
+public class ParamListMethodNameTest extends IdenticalRoundtripTest {
+
+ @Test
+ public void testParamListMethodName() {
+ runTest("ParamListMethodName");
+ }
+}
diff --git a/baksmali/src/test/resources/FieldGapOrderTest/FieldGapOrderInput.dex b/baksmali/src/test/resources/FieldGapOrderTest/FieldGapOrderInput.dex
new file mode 100644
index 00000000..4e593516
--- /dev/null
+++ b/baksmali/src/test/resources/FieldGapOrderTest/FieldGapOrderInput.dex
Binary files differ
diff --git a/baksmali/src/test/resources/ParamListMethodNameTest/ParamListMethodName.smali b/baksmali/src/test/resources/ParamListMethodNameTest/ParamListMethodName.smali
new file mode 100644
index 00000000..85717155
--- /dev/null
+++ b/baksmali/src/test/resources/ParamListMethodNameTest/ParamListMethodName.smali
@@ -0,0 +1,5 @@
+.class Lblah;
+.super Ljava/lang/Object;
+
+.method public abstract II()V
+.end method \ No newline at end of file
diff --git a/build.gradle b/build.gradle
index edf156fe..80ac25f8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -31,9 +31,7 @@
apply plugin: 'idea'
-version = '2.0.8'
-
-def jarVersion = version
+version = '2.1.2'
if (!('release' in gradle.startParameter.taskNames)) {
def versionSuffix
@@ -51,12 +49,7 @@ if (!('release' in gradle.startParameter.taskNames)) {
versionSuffix = 'dev'
}
- def baseVersion = version
- version = baseVersion + '-' + versionSuffix
-
- // use something like module-1.2.3-dev.jar for the jar name, rather than the full
- // module-1.2.3-001afe02-dirty.jar
- jarVersion = baseVersion + '-dev'
+ version += "-${versionSuffix}"
} else {
if (System.env.JDK6_HOME == null && !JavaVersion.current().isJava6()) {
throw new InvalidUserDataException("bzzzzzzzt. Release builds must be performed with java 6. " +
@@ -69,6 +62,10 @@ if (!('release' in gradle.startParameter.taskNames)) {
task release() {
}
+task(install) << {
+ println "Installing version: ${version}"
+}
+
// The projects that get pushed to maven
def maven_release_projects = ['smali', 'baksmali', 'dexlib2', 'util']
@@ -100,24 +97,22 @@ subprojects {
version = parent.version
ext {
- depends = [guava: 'com.google.guava:guava:18.0',
- findbugs: 'com.google.code.findbugs:jsr305:1.3.9',
- junit: 'junit:junit:4.6',
- antlr_runtime: 'org.antlr:antlr-runtime:3.5.2',
- antlr: 'org.antlr:antlr:3.5.2',
- stringtemplate: 'org.antlr:stringtemplate:3.2.1',
- commons_cli: 'commons-cli:commons-cli:1.2',
- jflex: 'de.jflex:jflex:1.4.3',
- jflex_plugin: 'co.tomlee.gradle.plugins:gradle-jflex-plugin:0.0.2',
- proguard_gradle: 'net.sf.proguard:proguard-gradle:5.2.1',
- dx: 'com.google.android.tools:dx:1.7'
+ depends = [
+ guava: 'com.google.guava:guava:18.0',
+ findbugs: 'com.google.code.findbugs:jsr305:1.3.9',
+ junit: 'junit:junit:4.6',
+ antlr_runtime: 'org.antlr:antlr-runtime:3.5.2',
+ antlr: 'org.antlr:antlr:3.5.2',
+ stringtemplate: 'org.antlr:stringtemplate:3.2.1',
+ commons_cli: 'commons-cli:commons-cli:1.2',
+ jflex: 'de.jflex:jflex:1.4.3',
+ jflex_plugin: 'co.tomlee.gradle.plugins:gradle-jflex-plugin:0.0.2',
+ proguard_gradle: 'net.sf.proguard:proguard-gradle:5.2.1',
+ dx: 'com.google.android.tools:dx:1.7',
+ gson: 'com.google.code.gson:gson:2.3.1'
]
}
- jar {
- version = jarVersion
- }
-
repositories {
mavenCentral()
}
@@ -202,5 +197,5 @@ buildscript {
}
task wrapper(type: Wrapper) {
- gradleVersion = '2.3'
+ gradleVersion = '2.11'
} \ No newline at end of file
diff --git a/dexlib2/OatVersions.txt b/dexlib2/OatVersions.txt
new file mode 100644
index 00000000..8aa9ea96
--- /dev/null
+++ b/dexlib2/OatVersions.txt
@@ -0,0 +1,24 @@
+7642cfc90fc9c3ebfd8e3b5041915705c93b5cf0 - 56
+ - first version with all stability fixes needed for deodexing
+14691c5e786e8c2c5734f687e4c96217340771be - 57
+1558b577907b613864e98f05862543557263e864 - 58
+f3251d12dfa387493dbde4c4148a633802f5f7e3 - 59
+706cae36209932f258b2fe2e396f31d2dd7d585e - 58 (revert of f3251d12)
+d7cbf8a6629942e7bd315ffae7e1c77b082f3e11 - 60
+ - return-void-barrier -> return-void-no-barrier
+1412dfa4adcd511902e510fa0c948b168ab5840c - 61 (re-commit of f3251d12)
+9d6bf69ad3012a9d843268fdd5325b6719b6d5f2 - 62
+0de1133ba600f299b3d67938f650720d9f859eb2 - 63
+07785bb98dc8bbe192970e0f4c2cafd338a8dc68 - 64
+fa2c054b28d4b540c1b3651401a7a091282a015f - 65
+7070ccd8b6439477eafeea7ed3736645d78e003f - 64 (revert of fa2c054b)
+7bf2b4f1d08050f80782217febac55c8cfc5e4ef - 65 (re-commit of fa2c054b)
+0b71357fb52be9bb06d35396a3042b4381b01041 - 66
+fab6788358dfb64e5c370611ddbbbffab0ed0553 - 67
+- Change in FieldGap priority queue ordering
+1aee900d5a0b3a8d78725a7551356bda0d8554e1 - 68
+54b62480636ae846d705fc180c7bd6cd08ec1e42 - 69
+6e2d5747d00697a25251d25dd33b953e54709507 - 68 (revert of 54b62480)
+0747466fca310eedea5fc49e37d54f240a0b3c0f - 69 (re-commit of 54b62480)
+501fd635a557645ab05f893c56e1f358e21bab82 - 70
+99170c636dfae4908b102347cfe9f92bad1881cc - 71 \ No newline at end of file
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java b/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java
index 113b60a3..60488ba2 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java
@@ -31,51 +31,56 @@
package org.jf.dexlib2;
+import com.google.common.base.MoreObjects;
import com.google.common.io.ByteStreams;
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
import org.jf.dexlib2.dexbacked.DexBackedOdexFile;
+import org.jf.dexlib2.dexbacked.OatFile;
+import org.jf.dexlib2.dexbacked.OatFile.NotAnOatFileException;
+import org.jf.dexlib2.dexbacked.OatFile.OatDexFile;
import org.jf.dexlib2.iface.DexFile;
import org.jf.dexlib2.writer.pool.DexPool;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import java.io.*;
+import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public final class DexFileFactory {
@Nonnull
- public static DexBackedDexFile loadDexFile(String path, int api)
- throws IOException {
+ public static DexBackedDexFile loadDexFile(@Nonnull String path, int api) throws IOException {
return loadDexFile(path, api, false);
}
@Nonnull
- public static DexBackedDexFile loadDexFile(String path, int api, boolean experimental)
+ public static DexBackedDexFile loadDexFile(@Nonnull String path, int api, boolean experimental)
throws IOException {
- return loadDexFile(new File(path), "classes.dex", new Opcodes(api, experimental));
+ return loadDexFile(new File(path), "classes.dex", Opcodes.forApi(api, experimental));
}
@Nonnull
- public static DexBackedDexFile loadDexFile(File dexFile, int api) throws IOException {
+ public static DexBackedDexFile loadDexFile(@Nonnull File dexFile, int api) throws IOException {
return loadDexFile(dexFile, api, false);
}
@Nonnull
- public static DexBackedDexFile loadDexFile(File dexFile, int api, boolean experimental)
+ public static DexBackedDexFile loadDexFile(@Nonnull File dexFile, int api, boolean experimental)
throws IOException {
- return loadDexFile(dexFile, "classes.dex", new Opcodes(api, experimental));
+ return loadDexFile(dexFile, null, Opcodes.forApi(api, experimental));
}
@Nonnull
- public static DexBackedDexFile loadDexFile(File dexFile, String dexEntry, int api,
+ public static DexBackedDexFile loadDexFile(@Nonnull File dexFile, @Nullable String dexEntry, int api,
boolean experimental) throws IOException {
- return loadDexFile(dexFile, dexEntry, new Opcodes(api, experimental));
+ return loadDexFile(dexFile, dexEntry, Opcodes.forApi(api, experimental));
}
@Nonnull
- public static DexBackedDexFile loadDexFile(File dexFile, String dexEntry,
- @Nonnull Opcodes opcodes) throws IOException {
+ public static DexBackedDexFile loadDexFile(@Nonnull File dexFile, @Nullable String dexEntry,
+ @Nonnull Opcodes opcodes) throws IOException {
ZipFile zipFile = null;
boolean isZipFile = false;
try {
@@ -83,16 +88,18 @@ public final class DexFileFactory {
// if we get here, it's safe to assume we have a zip file
isZipFile = true;
- ZipEntry zipEntry = zipFile.getEntry(dexEntry);
+ String zipEntryName = MoreObjects.firstNonNull(dexEntry, "classes.dex");
+ ZipEntry zipEntry = zipFile.getEntry(zipEntryName);
if (zipEntry == null) {
- throw new NoClassesDexException("zip file %s does not contain a classes.dex file", dexFile.getName());
+ throw new DexFileNotFound("zip file %s does not contain a %s file", dexFile.getName(), zipEntryName);
}
long fileLength = zipEntry.getSize();
if (fileLength < 40) {
- throw new ExceptionWithContext(
- "The " + dexEntry + " file in %s is too small to be a valid dex file", dexFile.getName());
+ throw new ExceptionWithContext("The %s file in %s is too small to be a valid dex file",
+ zipEntryName, dexFile.getName());
} else if (fileLength > Integer.MAX_VALUE) {
- throw new ExceptionWithContext("The " + dexEntry + " file in %s is too large to read in", dexFile.getName());
+ throw new ExceptionWithContext("The %s file in %s is too large to read in",
+ zipEntryName, dexFile.getName());
}
byte[] dexBytes = new byte[(int)fileLength];
ByteStreams.readFully(zipFile.getInputStream(zipEntry), dexBytes);
@@ -127,30 +134,93 @@ public final class DexFileFactory {
} catch (DexBackedOdexFile.NotAnOdexFile ex) {
// just eat it
}
+
+ OatFile oatFile = null;
+ try {
+ oatFile = OatFile.fromInputStream(inputStream);
+ } catch (NotAnOatFileException ex) {
+ // just eat it
+ }
+
+ if (oatFile != null) {
+ if (oatFile.isSupportedVersion() == OatFile.UNSUPPORTED) {
+ throw new UnsupportedOatVersionException(oatFile);
+ }
+
+ List<OatDexFile> oatDexFiles = oatFile.getDexFiles();
+
+ if (oatDexFiles.size() == 0) {
+ throw new DexFileNotFound("Oat file %s contains no dex files", dexFile.getName());
+ }
+
+ if (dexEntry == null) {
+ if (oatDexFiles.size() > 1) {
+ throw new MultipleDexFilesException(oatFile);
+ }
+ return oatDexFiles.get(0);
+ } else {
+ // first check for an exact match
+ for (OatDexFile oatDexFile : oatFile.getDexFiles()) {
+ if (oatDexFile.filename.equals(dexEntry)) {
+ return oatDexFile;
+ }
+ }
+
+ if (!dexEntry.contains("/")) {
+ for (OatDexFile oatDexFile : oatFile.getDexFiles()) {
+ File oatEntryFile = new File(oatDexFile.filename);
+ if (oatEntryFile.getName().equals(dexEntry)) {
+ return oatDexFile;
+ }
+ }
+ }
+
+ throw new DexFileNotFound("oat file %s does not contain a dex file named %s",
+ dexFile.getName(), dexEntry);
+ }
+ }
} finally {
inputStream.close();
}
- throw new ExceptionWithContext("%s is not an apk, dex file or odex file.", dexFile.getPath());
+ throw new ExceptionWithContext("%s is not an apk, dex, odex or oat file.", dexFile.getPath());
}
- public static void writeDexFile(String path, DexFile dexFile) throws IOException {
+ public static void writeDexFile(@Nonnull String path, @Nonnull DexFile dexFile) throws IOException {
DexPool.writeTo(path, dexFile);
}
private DexFileFactory() {}
- public static class NoClassesDexException extends ExceptionWithContext {
- public NoClassesDexException(Throwable cause) {
+ public static class DexFileNotFound extends ExceptionWithContext {
+ public DexFileNotFound(@Nullable Throwable cause) {
super(cause);
}
- public NoClassesDexException(Throwable cause, String message, Object... formatArgs) {
+ public DexFileNotFound(@Nullable Throwable cause, @Nullable String message, Object... formatArgs) {
super(cause, message, formatArgs);
}
- public NoClassesDexException(String message, Object... formatArgs) {
+ public DexFileNotFound(@Nullable String message, Object... formatArgs) {
super(message, formatArgs);
}
}
+
+ public static class MultipleDexFilesException extends ExceptionWithContext {
+ @Nonnull public final OatFile oatFile;
+
+ public MultipleDexFilesException(@Nonnull OatFile oatFile) {
+ super("Oat file has multiple dex files.");
+ this.oatFile = oatFile;
+ }
+ }
+
+ public static class UnsupportedOatVersionException extends ExceptionWithContext {
+ @Nonnull public final OatFile oatFile;
+
+ public UnsupportedOatVersionException(@Nonnull OatFile oatFile) {
+ super("Unsupported oat version: %d", oatFile.getOatVersion());
+ this.oatFile = oatFile;
+ }
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java b/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java
index 3b082ee8..3a642358 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/Opcode.java
@@ -31,271 +31,289 @@
package org.jf.dexlib2;
+import com.google.common.collect.ImmutableRangeMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Range;
+import com.google.common.collect.RangeMap;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+
public enum Opcode
{
- NOP((short)0x00, "nop", ReferenceType.NONE, Format.Format10x, Opcode.CAN_CONTINUE),
- MOVE((short)0x01, "move", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MOVE_FROM16((short)0x02, "move/from16", ReferenceType.NONE, Format.Format22x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MOVE_16((short)0x03, "move/16", ReferenceType.NONE, Format.Format32x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MOVE_WIDE((short)0x04, "move-wide", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- MOVE_WIDE_FROM16((short)0x05, "move-wide/from16", ReferenceType.NONE, Format.Format22x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- MOVE_WIDE_16((short)0x06, "move-wide/16", ReferenceType.NONE, Format.Format32x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- MOVE_OBJECT((short)0x07, "move-object", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MOVE_OBJECT_FROM16((short)0x08, "move-object/from16", ReferenceType.NONE, Format.Format22x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MOVE_OBJECT_16((short)0x09, "move-object/16", ReferenceType.NONE, Format.Format32x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MOVE_RESULT((short)0x0a, "move-result", ReferenceType.NONE, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MOVE_RESULT_WIDE((short)0x0b, "move-result-wide", ReferenceType.NONE, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- MOVE_RESULT_OBJECT((short)0x0c, "move-result-object", ReferenceType.NONE, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MOVE_EXCEPTION((short)0x0d, "move-exception", ReferenceType.NONE, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- RETURN_VOID((short)0x0e, "return-void", ReferenceType.NONE, Format.Format10x),
- RETURN((short)0x0f, "return", ReferenceType.NONE, Format.Format11x),
- RETURN_WIDE((short)0x10, "return-wide", ReferenceType.NONE, Format.Format11x),
- RETURN_OBJECT((short)0x11, "return-object", ReferenceType.NONE, Format.Format11x),
- CONST_4((short)0x12, "const/4", ReferenceType.NONE, Format.Format11n, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- CONST_16((short)0x13, "const/16", ReferenceType.NONE, Format.Format21s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- CONST((short)0x14, "const", ReferenceType.NONE, Format.Format31i, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- CONST_HIGH16((short)0x15, "const/high16", ReferenceType.NONE, Format.Format21ih, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- CONST_WIDE_16((short)0x16, "const-wide/16", ReferenceType.NONE, Format.Format21s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- CONST_WIDE_32((short)0x17, "const-wide/32", ReferenceType.NONE, Format.Format31i, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- CONST_WIDE((short)0x18, "const-wide", ReferenceType.NONE, Format.Format51l, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- CONST_WIDE_HIGH16((short)0x19, "const-wide/high16", ReferenceType.NONE, Format.Format21lh, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- CONST_STRING((short)0x1a, "const-string", ReferenceType.STRING, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER, (short)0x1b),
- CONST_STRING_JUMBO((short)0x1b, "const-string/jumbo", ReferenceType.STRING, Format.Format31c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- CONST_CLASS((short)0x1c, "const-class", ReferenceType.TYPE, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MONITOR_ENTER((short)0x1d, "monitor-enter", ReferenceType.NONE, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- MONITOR_EXIT((short)0x1e, "monitor-exit", ReferenceType.NONE, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- CHECK_CAST((short)0x1f, "check-cast", ReferenceType.TYPE, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- INSTANCE_OF((short)0x20, "instance-of", ReferenceType.TYPE, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- ARRAY_LENGTH((short)0x21, "array-length", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- NEW_INSTANCE((short)0x22, "new-instance", ReferenceType.TYPE, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- NEW_ARRAY((short)0x23, "new-array", ReferenceType.TYPE, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- FILLED_NEW_ARRAY((short)0x24, "filled-new-array", ReferenceType.TYPE, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- FILLED_NEW_ARRAY_RANGE((short)0x25, "filled-new-array/range", ReferenceType.TYPE, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- FILL_ARRAY_DATA((short)0x26, "fill-array-data", ReferenceType.NONE, Format.Format31t, Opcode.CAN_CONTINUE),
- THROW((short)0x27, "throw", ReferenceType.NONE, Format.Format11x, Opcode.CAN_THROW),
- GOTO((short)0x28, "goto", ReferenceType.NONE, Format.Format10t),
- GOTO_16((short)0x29, "goto/16", ReferenceType.NONE, Format.Format20t),
- GOTO_32((short)0x2a, "goto/32", ReferenceType.NONE, Format.Format30t),
- PACKED_SWITCH((short)0x2b, "packed-switch", ReferenceType.NONE, Format.Format31t, Opcode.CAN_CONTINUE),
- SPARSE_SWITCH((short)0x2c, "sparse-switch", ReferenceType.NONE, Format.Format31t, Opcode.CAN_CONTINUE),
- CMPL_FLOAT((short)0x2d, "cmpl-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- CMPG_FLOAT((short)0x2e, "cmpg-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- CMPL_DOUBLE((short)0x2f, "cmpl-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- CMPG_DOUBLE((short)0x30, "cmpg-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- CMP_LONG((short)0x31, "cmp-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- IF_EQ((short)0x32, "if-eq", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE),
- IF_NE((short)0x33, "if-ne", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE),
- IF_LT((short)0x34, "if-lt", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE),
- IF_GE((short)0x35, "if-ge", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE),
- IF_GT((short)0x36, "if-gt", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE),
- IF_LE((short)0x37, "if-le", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE),
- IF_EQZ((short)0x38, "if-eqz", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE),
- IF_NEZ((short)0x39, "if-nez", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE),
- IF_LTZ((short)0x3a, "if-ltz", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE),
- IF_GEZ((short)0x3b, "if-gez", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE),
- IF_GTZ((short)0x3c, "if-gtz", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE),
- IF_LEZ((short)0x3d, "if-lez", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE),
- AGET((short)0x44, "aget", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- AGET_WIDE((short)0x45, "aget-wide", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- AGET_OBJECT((short)0x46, "aget-object", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- AGET_BOOLEAN((short)0x47, "aget-boolean", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- AGET_BYTE((short)0x48, "aget-byte", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- AGET_CHAR((short)0x49, "aget-char", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- AGET_SHORT((short)0x4a, "aget-short", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- APUT((short)0x4b, "aput", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- APUT_WIDE((short)0x4c, "aput-wide", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- APUT_OBJECT((short)0x4d, "aput-object", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- APUT_BOOLEAN((short)0x4e, "aput-boolean", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- APUT_BYTE((short)0x4f, "aput-byte", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- APUT_CHAR((short)0x50, "aput-char", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- APUT_SHORT((short)0x51, "aput-short", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- IGET((short)0x52, "iget", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- IGET_WIDE((short)0x53, "iget-wide", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- IGET_OBJECT((short)0x54, "iget-object", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- IGET_BOOLEAN((short)0x55, "iget-boolean", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- IGET_BYTE((short)0x56, "iget-byte", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- IGET_CHAR((short)0x57, "iget-char", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- IGET_SHORT((short)0x58, "iget-short", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- IPUT((short)0x59, "iput", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- IPUT_WIDE((short)0x5a, "iput-wide", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- IPUT_OBJECT((short)0x5b, "iput-object", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- IPUT_BOOLEAN((short)0x5c, "iput-boolean", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- IPUT_BYTE((short)0x5d, "iput-byte", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- IPUT_CHAR((short)0x5e, "iput-char", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- IPUT_SHORT((short)0x5f, "iput-short", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- SGET((short)0x60, "sget", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SGET_WIDE((short)0x61, "sget-wide", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- SGET_OBJECT((short)0x62, "sget-object", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SGET_BOOLEAN((short)0x63, "sget-boolean", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SGET_BYTE((short)0x64, "sget-byte", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SGET_CHAR((short)0x65, "sget-char", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SGET_SHORT((short)0x66, "sget-short", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SPUT((short)0x67, "sput", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- SPUT_WIDE((short)0x68, "sput-wide", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- SPUT_OBJECT((short)0x69, "sput-object", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- SPUT_BOOLEAN((short)0x6a, "sput-boolean", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- SPUT_BYTE((short)0x6b, "sput-byte", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- SPUT_CHAR((short)0x6c, "sput-char", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- SPUT_SHORT((short)0x6d, "sput-short", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- INVOKE_VIRTUAL((short)0x6e, "invoke-virtual", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- INVOKE_SUPER((short)0x6f, "invoke-super", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- INVOKE_DIRECT((short)0x70, "invoke-direct", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE),
- INVOKE_STATIC((short)0x71, "invoke-static", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- INVOKE_INTERFACE((short)0x72, "invoke-interface", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- INVOKE_VIRTUAL_RANGE((short)0x74, "invoke-virtual/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- INVOKE_SUPER_RANGE((short)0x75, "invoke-super/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- INVOKE_DIRECT_RANGE((short)0x76, "invoke-direct/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE),
- INVOKE_STATIC_RANGE((short)0x77, "invoke-static/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- INVOKE_INTERFACE_RANGE((short)0x78, "invoke-interface/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- NEG_INT((short)0x7b, "neg-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- NOT_INT((short)0x7c, "not-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- NEG_LONG((short)0x7d, "neg-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- NOT_LONG((short)0x7e, "not-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- NEG_FLOAT((short)0x7f, "neg-float", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- NEG_DOUBLE((short)0x80, "neg-double", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- INT_TO_LONG((short)0x81, "int-to-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- INT_TO_FLOAT((short)0x82, "int-to-float", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- INT_TO_DOUBLE((short)0x83, "int-to-double", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- LONG_TO_INT((short)0x84, "long-to-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- LONG_TO_FLOAT((short)0x85, "long-to-float", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- LONG_TO_DOUBLE((short)0x86, "long-to-double", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- FLOAT_TO_INT((short)0x87, "float-to-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- FLOAT_TO_LONG((short)0x88, "float-to-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- FLOAT_TO_DOUBLE((short)0x89, "float-to-double", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- DOUBLE_TO_INT((short)0x8a, "double-to-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- DOUBLE_TO_LONG((short)0x8b, "double-to-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- DOUBLE_TO_FLOAT((short)0x8c, "double-to-float", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- INT_TO_BYTE((short)0x8d, "int-to-byte", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- INT_TO_CHAR((short)0x8e, "int-to-char", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- INT_TO_SHORT((short)0x8f, "int-to-short", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- ADD_INT((short)0x90, "add-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SUB_INT((short)0x91, "sub-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MUL_INT((short)0x92, "mul-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- DIV_INT((short)0x93, "div-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- REM_INT((short)0x94, "rem-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- AND_INT((short)0x95, "and-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- OR_INT((short)0x96, "or-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- XOR_INT((short)0x97, "xor-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SHL_INT((short)0x98, "shl-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SHR_INT((short)0x99, "shr-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- USHR_INT((short)0x9a, "ushr-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- ADD_LONG((short)0x9b, "add-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- SUB_LONG((short)0x9c, "sub-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- MUL_LONG((short)0x9d, "mul-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- DIV_LONG((short)0x9e, "div-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- REM_LONG((short)0x9f, "rem-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- AND_LONG((short)0xa0, "and-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- OR_LONG((short)0xa1, "or-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- XOR_LONG((short)0xa2, "xor-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- SHL_LONG((short)0xa3, "shl-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- SHR_LONG((short)0xa4, "shr-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- USHR_LONG((short)0xa5, "ushr-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- ADD_FLOAT((short)0xa6, "add-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SUB_FLOAT((short)0xa7, "sub-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MUL_FLOAT((short)0xa8, "mul-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- DIV_FLOAT((short)0xa9, "div-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- REM_FLOAT((short)0xaa, "rem-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- ADD_DOUBLE((short)0xab, "add-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- SUB_DOUBLE((short)0xac, "sub-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- MUL_DOUBLE((short)0xad, "mul-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- DIV_DOUBLE((short)0xae, "div-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- REM_DOUBLE((short)0xaf, "rem-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- ADD_INT_2ADDR((short)0xb0, "add-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SUB_INT_2ADDR((short)0xb1, "sub-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MUL_INT_2ADDR((short)0xb2, "mul-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- DIV_INT_2ADDR((short)0xb3, "div-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- REM_INT_2ADDR((short)0xb4, "rem-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- AND_INT_2ADDR((short)0xb5, "and-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- OR_INT_2ADDR((short)0xb6, "or-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- XOR_INT_2ADDR((short)0xb7, "xor-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SHL_INT_2ADDR((short)0xb8, "shl-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SHR_INT_2ADDR((short)0xb9, "shr-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- USHR_INT_2ADDR((short)0xba, "ushr-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- ADD_LONG_2ADDR((short)0xbb, "add-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- SUB_LONG_2ADDR((short)0xbc, "sub-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- MUL_LONG_2ADDR((short)0xbd, "mul-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- DIV_LONG_2ADDR((short)0xbe, "div-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- REM_LONG_2ADDR((short)0xbf, "rem-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- AND_LONG_2ADDR((short)0xc0, "and-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- OR_LONG_2ADDR((short)0xc1, "or-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- XOR_LONG_2ADDR((short)0xc2, "xor-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- SHL_LONG_2ADDR((short)0xc3, "shl-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- SHR_LONG_2ADDR((short)0xc4, "shr-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- USHR_LONG_2ADDR((short)0xc5, "ushr-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- ADD_FLOAT_2ADDR((short)0xc6, "add-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SUB_FLOAT_2ADDR((short)0xc7, "sub-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MUL_FLOAT_2ADDR((short)0xc8, "mul-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- DIV_FLOAT_2ADDR((short)0xc9, "div-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- REM_FLOAT_2ADDR((short)0xca, "rem-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- ADD_DOUBLE_2ADDR((short)0xcb, "add-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- SUB_DOUBLE_2ADDR((short)0xcc, "sub-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- MUL_DOUBLE_2ADDR((short)0xcd, "mul-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- DIV_DOUBLE_2ADDR((short)0xce, "div-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- REM_DOUBLE_2ADDR((short)0xcf, "rem-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- ADD_INT_LIT16((short)0xd0, "add-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- RSUB_INT((short)0xd1, "rsub-int", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MUL_INT_LIT16((short)0xd2, "mul-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- DIV_INT_LIT16((short)0xd3, "div-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- REM_INT_LIT16((short)0xd4, "rem-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- AND_INT_LIT16((short)0xd5, "and-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- OR_INT_LIT16((short)0xd6, "or-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- XOR_INT_LIT16((short)0xd7, "xor-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- ADD_INT_LIT8((short)0xd8, "add-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- RSUB_INT_LIT8((short)0xd9, "rsub-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- MUL_INT_LIT8((short)0xda, "mul-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- DIV_INT_LIT8((short)0xdb, "div-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- REM_INT_LIT8((short)0xdc, "rem-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- AND_INT_LIT8((short)0xdd, "and-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- OR_INT_LIT8((short)0xde, "or-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- XOR_INT_LIT8((short)0xdf, "xor-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SHL_INT_LIT8((short)0xe0, "shl-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SHR_INT_LIT8((short)0xe1, "shr-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- USHR_INT_LIT8((short)0xe2, "ushr-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
-
- IGET_VOLATILE((short)0xe3, "iget-volatile", minApi(9), ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- IPUT_VOLATILE((short)0xe4, "iput-volatile", minApi(9), ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- SGET_VOLATILE((short)0xe5, "sget-volatile", minApi(9), ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SPUT_VOLATILE((short)0xe6, "sput-volatile", minApi(9), ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- IGET_OBJECT_VOLATILE((short)0xe7, "iget-object-volatile", minApi(9), ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- IGET_WIDE_VOLATILE((short)0xe8, "iget-wide-volatile", minApi(9), ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- IPUT_WIDE_VOLATILE((short)0xe9, "iput-wide-volatile", minApi(9), ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- SGET_WIDE_VOLATILE((short)0xea, "sget-wide-volatile", minApi(9), ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- SPUT_WIDE_VOLATILE((short)0xeb, "sput-wide-volatile", minApi(9), ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
-
- THROW_VERIFICATION_ERROR((short)0xed, "throw-verification-error", minApi(5), ReferenceType.NONE, Format.Format20bc, Opcode.ODEX_ONLY | Opcode.CAN_THROW),
- EXECUTE_INLINE((short)0xee, "execute-inline", ReferenceType.NONE, Format.Format35mi, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- EXECUTE_INLINE_RANGE((short)0xef, "execute-inline/range", minApi(8), ReferenceType.NONE, Format.Format3rmi, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- INVOKE_DIRECT_EMPTY((short)0xf0, "invoke-direct-empty", maxApi(13), ReferenceType.METHOD, Format.Format35c, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE),
- INVOKE_OBJECT_INIT_RANGE((short)0xf0, "invoke-object-init/range", minApi(14), ReferenceType.METHOD, Format.Format3rc, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE),
- RETURN_VOID_BARRIER((short)0xf1, "return-void-barrier", minApi(11), ReferenceType.NONE, Format.Format10x, Opcode.ODEX_ONLY),
- IGET_QUICK((short)0xf2, "iget-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- IGET_WIDE_QUICK((short)0xf3, "iget-wide-quick", maxApi(22), ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
- IGET_OBJECT_QUICK((short)0xf4, "iget-object-quick", maxApi(22), ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- IPUT_QUICK((short)0xf5, "iput-quick", maxApi(22), ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- IPUT_WIDE_QUICK((short)0xf6, "iput-wide-quick", maxApi(22), ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- IPUT_OBJECT_QUICK((short)0xf7, "iput-object-quick", maxApi(22), ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_QUICK | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- INVOKE_VIRTUAL_QUICK((short)0xf8, "invoke-virtual-quick", maxApi(22), ReferenceType.NONE, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- INVOKE_VIRTUAL_QUICK_RANGE((short)0xf9, "invoke-virtual-quick/range", maxApi(22), ReferenceType.NONE, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- INVOKE_SUPER_QUICK((short)0xfa, "invoke-super-quick", ReferenceType.NONE, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
- INVOKE_SUPER_QUICK_RANGE((short)0xfb, "invoke-super-quick/range", ReferenceType.NONE, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
-
- IPUT_OBJECT_VOLATILE((short)0xfc, "iput-object-volatile", minApi(9), ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.ODEXED_INSTANCE_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
- SGET_OBJECT_VOLATILE((short)0xfd, "sget-object-volatile", minApi(9), ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
- SPUT_OBJECT_VOLATILE((short)0xfe, "sput-object-volatile", minApi(9), ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.ODEXED_STATIC_VOLATILE | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
-
- PACKED_SWITCH_PAYLOAD((short)0x100, "packed-switch-payload", ReferenceType.NONE, Format.PackedSwitchPayload, 0),
- SPARSE_SWITCH_PAYLOAD((short)0x200, "sparse-switch-payload", ReferenceType.NONE, Format.SparseSwitchPayload, 0),
- ARRAY_PAYLOAD((short)0x300, "array-payload", ReferenceType.NONE, Format.ArrayPayload, 0),
+ NOP(0x00, "nop", ReferenceType.NONE, Format.Format10x, Opcode.CAN_CONTINUE),
+ MOVE(0x01, "move", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MOVE_FROM16(0x02, "move/from16", ReferenceType.NONE, Format.Format22x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MOVE_16(0x03, "move/16", ReferenceType.NONE, Format.Format32x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MOVE_WIDE(0x04, "move-wide", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ MOVE_WIDE_FROM16(0x05, "move-wide/from16", ReferenceType.NONE, Format.Format22x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ MOVE_WIDE_16(0x06, "move-wide/16", ReferenceType.NONE, Format.Format32x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ MOVE_OBJECT(0x07, "move-object", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MOVE_OBJECT_FROM16(0x08, "move-object/from16", ReferenceType.NONE, Format.Format22x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MOVE_OBJECT_16(0x09, "move-object/16", ReferenceType.NONE, Format.Format32x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MOVE_RESULT(0x0a, "move-result", ReferenceType.NONE, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MOVE_RESULT_WIDE(0x0b, "move-result-wide", ReferenceType.NONE, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ MOVE_RESULT_OBJECT(0x0c, "move-result-object", ReferenceType.NONE, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MOVE_EXCEPTION(0x0d, "move-exception", ReferenceType.NONE, Format.Format11x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ RETURN_VOID(0x0e, "return-void", ReferenceType.NONE, Format.Format10x),
+ RETURN(0x0f, "return", ReferenceType.NONE, Format.Format11x),
+ RETURN_WIDE(0x10, "return-wide", ReferenceType.NONE, Format.Format11x),
+ RETURN_OBJECT(0x11, "return-object", ReferenceType.NONE, Format.Format11x),
+ CONST_4(0x12, "const/4", ReferenceType.NONE, Format.Format11n, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ CONST_16(0x13, "const/16", ReferenceType.NONE, Format.Format21s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ CONST(0x14, "const", ReferenceType.NONE, Format.Format31i, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ CONST_HIGH16(0x15, "const/high16", ReferenceType.NONE, Format.Format21ih, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ CONST_WIDE_16(0x16, "const-wide/16", ReferenceType.NONE, Format.Format21s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ CONST_WIDE_32(0x17, "const-wide/32", ReferenceType.NONE, Format.Format31i, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ CONST_WIDE(0x18, "const-wide", ReferenceType.NONE, Format.Format51l, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ CONST_WIDE_HIGH16(0x19, "const-wide/high16", ReferenceType.NONE, Format.Format21lh, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ CONST_STRING(0x1a, "const-string", ReferenceType.STRING, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ CONST_STRING_JUMBO(0x1b, "const-string/jumbo", ReferenceType.STRING, Format.Format31c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ CONST_CLASS(0x1c, "const-class", ReferenceType.TYPE, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MONITOR_ENTER(0x1d, "monitor-enter", ReferenceType.NONE, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ MONITOR_EXIT(0x1e, "monitor-exit", ReferenceType.NONE, Format.Format11x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ CHECK_CAST(0x1f, "check-cast", ReferenceType.TYPE, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ INSTANCE_OF(0x20, "instance-of", ReferenceType.TYPE, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ ARRAY_LENGTH(0x21, "array-length", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ NEW_INSTANCE(0x22, "new-instance", ReferenceType.TYPE, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ NEW_ARRAY(0x23, "new-array", ReferenceType.TYPE, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ FILLED_NEW_ARRAY(0x24, "filled-new-array", ReferenceType.TYPE, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ FILLED_NEW_ARRAY_RANGE(0x25, "filled-new-array/range", ReferenceType.TYPE, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ FILL_ARRAY_DATA(0x26, "fill-array-data", ReferenceType.NONE, Format.Format31t, Opcode.CAN_CONTINUE),
+ THROW(0x27, "throw", ReferenceType.NONE, Format.Format11x, Opcode.CAN_THROW),
+ GOTO(0x28, "goto", ReferenceType.NONE, Format.Format10t),
+ GOTO_16(0x29, "goto/16", ReferenceType.NONE, Format.Format20t),
+ GOTO_32(0x2a, "goto/32", ReferenceType.NONE, Format.Format30t),
+ PACKED_SWITCH(0x2b, "packed-switch", ReferenceType.NONE, Format.Format31t, Opcode.CAN_CONTINUE),
+ SPARSE_SWITCH(0x2c, "sparse-switch", ReferenceType.NONE, Format.Format31t, Opcode.CAN_CONTINUE),
+ CMPL_FLOAT(0x2d, "cmpl-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ CMPG_FLOAT(0x2e, "cmpg-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ CMPL_DOUBLE(0x2f, "cmpl-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ CMPG_DOUBLE(0x30, "cmpg-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ CMP_LONG(0x31, "cmp-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ IF_EQ(0x32, "if-eq", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE),
+ IF_NE(0x33, "if-ne", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE),
+ IF_LT(0x34, "if-lt", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE),
+ IF_GE(0x35, "if-ge", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE),
+ IF_GT(0x36, "if-gt", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE),
+ IF_LE(0x37, "if-le", ReferenceType.NONE, Format.Format22t, Opcode.CAN_CONTINUE),
+ IF_EQZ(0x38, "if-eqz", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE),
+ IF_NEZ(0x39, "if-nez", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE),
+ IF_LTZ(0x3a, "if-ltz", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE),
+ IF_GEZ(0x3b, "if-gez", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE),
+ IF_GTZ(0x3c, "if-gtz", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE),
+ IF_LEZ(0x3d, "if-lez", ReferenceType.NONE, Format.Format21t, Opcode.CAN_CONTINUE),
+ AGET(0x44, "aget", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ AGET_WIDE(0x45, "aget-wide", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ AGET_OBJECT(0x46, "aget-object", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ AGET_BOOLEAN(0x47, "aget-boolean", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ AGET_BYTE(0x48, "aget-byte", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ AGET_CHAR(0x49, "aget-char", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ AGET_SHORT(0x4a, "aget-short", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ APUT(0x4b, "aput", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ APUT_WIDE(0x4c, "aput-wide", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ APUT_OBJECT(0x4d, "aput-object", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ APUT_BOOLEAN(0x4e, "aput-boolean", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ APUT_BYTE(0x4f, "aput-byte", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ APUT_CHAR(0x50, "aput-char", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ APUT_SHORT(0x51, "aput-short", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ IGET(0x52, "iget", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ IGET_WIDE(0x53, "iget-wide", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ IGET_OBJECT(0x54, "iget-object", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ IGET_BOOLEAN(0x55, "iget-boolean", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ IGET_BYTE(0x56, "iget-byte", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ IGET_CHAR(0x57, "iget-char", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ IGET_SHORT(0x58, "iget-short", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ IPUT(0x59, "iput", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ IPUT_WIDE(0x5a, "iput-wide", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ IPUT_OBJECT(0x5b, "iput-object", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ IPUT_BOOLEAN(0x5c, "iput-boolean", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ IPUT_BYTE(0x5d, "iput-byte", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ IPUT_CHAR(0x5e, "iput-char", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ IPUT_SHORT(0x5f, "iput-short", ReferenceType.FIELD, Format.Format22c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ SGET(0x60, "sget", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR),
+ SGET_WIDE(0x61, "sget-wide", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER | Opcode.STATIC_FIELD_ACCESSOR),
+ SGET_OBJECT(0x62, "sget-object", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR),
+ SGET_BOOLEAN(0x63, "sget-boolean", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR),
+ SGET_BYTE(0x64, "sget-byte", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR),
+ SGET_CHAR(0x65, "sget-char", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR),
+ SGET_SHORT(0x66, "sget-short", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR),
+ SPUT(0x67, "sput", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR),
+ SPUT_WIDE(0x68, "sput-wide", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR),
+ SPUT_OBJECT(0x69, "sput-object", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR),
+ SPUT_BOOLEAN(0x6a, "sput-boolean", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR),
+ SPUT_BYTE(0x6b, "sput-byte", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR),
+ SPUT_CHAR(0x6c, "sput-char", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR),
+ SPUT_SHORT(0x6d, "sput-short", ReferenceType.FIELD, Format.Format21c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR),
+ INVOKE_VIRTUAL(0x6e, "invoke-virtual", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ INVOKE_SUPER(0x6f, "invoke-super", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ INVOKE_DIRECT(0x70, "invoke-direct", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE),
+ INVOKE_STATIC(0x71, "invoke-static", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ INVOKE_INTERFACE(0x72, "invoke-interface", ReferenceType.METHOD, Format.Format35c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ INVOKE_VIRTUAL_RANGE(0x74, "invoke-virtual/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ INVOKE_SUPER_RANGE(0x75, "invoke-super/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ INVOKE_DIRECT_RANGE(0x76, "invoke-direct/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE),
+ INVOKE_STATIC_RANGE(0x77, "invoke-static/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ INVOKE_INTERFACE_RANGE(0x78, "invoke-interface/range", ReferenceType.METHOD, Format.Format3rc, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ NEG_INT(0x7b, "neg-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ NOT_INT(0x7c, "not-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ NEG_LONG(0x7d, "neg-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ NOT_LONG(0x7e, "not-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ NEG_FLOAT(0x7f, "neg-float", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ NEG_DOUBLE(0x80, "neg-double", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ INT_TO_LONG(0x81, "int-to-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ INT_TO_FLOAT(0x82, "int-to-float", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ INT_TO_DOUBLE(0x83, "int-to-double", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ LONG_TO_INT(0x84, "long-to-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ LONG_TO_FLOAT(0x85, "long-to-float", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ LONG_TO_DOUBLE(0x86, "long-to-double", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ FLOAT_TO_INT(0x87, "float-to-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ FLOAT_TO_LONG(0x88, "float-to-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ FLOAT_TO_DOUBLE(0x89, "float-to-double", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ DOUBLE_TO_INT(0x8a, "double-to-int", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ DOUBLE_TO_LONG(0x8b, "double-to-long", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ DOUBLE_TO_FLOAT(0x8c, "double-to-float", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ INT_TO_BYTE(0x8d, "int-to-byte", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ INT_TO_CHAR(0x8e, "int-to-char", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ INT_TO_SHORT(0x8f, "int-to-short", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ ADD_INT(0x90, "add-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ SUB_INT(0x91, "sub-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MUL_INT(0x92, "mul-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ DIV_INT(0x93, "div-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ REM_INT(0x94, "rem-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ AND_INT(0x95, "and-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ OR_INT(0x96, "or-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ XOR_INT(0x97, "xor-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ SHL_INT(0x98, "shl-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ SHR_INT(0x99, "shr-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ USHR_INT(0x9a, "ushr-int", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ ADD_LONG(0x9b, "add-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ SUB_LONG(0x9c, "sub-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ MUL_LONG(0x9d, "mul-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ DIV_LONG(0x9e, "div-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ REM_LONG(0x9f, "rem-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ AND_LONG(0xa0, "and-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ OR_LONG(0xa1, "or-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ XOR_LONG(0xa2, "xor-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ SHL_LONG(0xa3, "shl-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ SHR_LONG(0xa4, "shr-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ USHR_LONG(0xa5, "ushr-long", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ ADD_FLOAT(0xa6, "add-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ SUB_FLOAT(0xa7, "sub-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MUL_FLOAT(0xa8, "mul-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ DIV_FLOAT(0xa9, "div-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ REM_FLOAT(0xaa, "rem-float", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ ADD_DOUBLE(0xab, "add-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ SUB_DOUBLE(0xac, "sub-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ MUL_DOUBLE(0xad, "mul-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ DIV_DOUBLE(0xae, "div-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ REM_DOUBLE(0xaf, "rem-double", ReferenceType.NONE, Format.Format23x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ ADD_INT_2ADDR(0xb0, "add-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ SUB_INT_2ADDR(0xb1, "sub-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MUL_INT_2ADDR(0xb2, "mul-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ DIV_INT_2ADDR(0xb3, "div-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ REM_INT_2ADDR(0xb4, "rem-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ AND_INT_2ADDR(0xb5, "and-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ OR_INT_2ADDR(0xb6, "or-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ XOR_INT_2ADDR(0xb7, "xor-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ SHL_INT_2ADDR(0xb8, "shl-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ SHR_INT_2ADDR(0xb9, "shr-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ USHR_INT_2ADDR(0xba, "ushr-int/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ ADD_LONG_2ADDR(0xbb, "add-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ SUB_LONG_2ADDR(0xbc, "sub-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ MUL_LONG_2ADDR(0xbd, "mul-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ DIV_LONG_2ADDR(0xbe, "div-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ REM_LONG_2ADDR(0xbf, "rem-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ AND_LONG_2ADDR(0xc0, "and-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ OR_LONG_2ADDR(0xc1, "or-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ XOR_LONG_2ADDR(0xc2, "xor-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ SHL_LONG_2ADDR(0xc3, "shl-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ SHR_LONG_2ADDR(0xc4, "shr-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ USHR_LONG_2ADDR(0xc5, "ushr-long/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ ADD_FLOAT_2ADDR(0xc6, "add-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ SUB_FLOAT_2ADDR(0xc7, "sub-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MUL_FLOAT_2ADDR(0xc8, "mul-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ DIV_FLOAT_2ADDR(0xc9, "div-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ REM_FLOAT_2ADDR(0xca, "rem-float/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ ADD_DOUBLE_2ADDR(0xcb, "add-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ SUB_DOUBLE_2ADDR(0xcc, "sub-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ MUL_DOUBLE_2ADDR(0xcd, "mul-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ DIV_DOUBLE_2ADDR(0xce, "div-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ REM_DOUBLE_2ADDR(0xcf, "rem-double/2addr", ReferenceType.NONE, Format.Format12x, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ ADD_INT_LIT16(0xd0, "add-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ RSUB_INT(0xd1, "rsub-int", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MUL_INT_LIT16(0xd2, "mul-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ DIV_INT_LIT16(0xd3, "div-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ REM_INT_LIT16(0xd4, "rem-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ AND_INT_LIT16(0xd5, "and-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ OR_INT_LIT16(0xd6, "or-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ XOR_INT_LIT16(0xd7, "xor-int/lit16", ReferenceType.NONE, Format.Format22s, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ ADD_INT_LIT8(0xd8, "add-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ RSUB_INT_LIT8(0xd9, "rsub-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ MUL_INT_LIT8(0xda, "mul-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ DIV_INT_LIT8(0xdb, "div-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ REM_INT_LIT8(0xdc, "rem-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ AND_INT_LIT8(0xdd, "and-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ OR_INT_LIT8(0xde, "or-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ XOR_INT_LIT8(0xdf, "xor-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ SHL_INT_LIT8(0xe0, "shl-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ SHR_INT_LIT8(0xe1, "shr-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ USHR_INT_LIT8(0xe2, "ushr-int/lit8", ReferenceType.NONE, Format.Format22b, Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+
+ IGET_VOLATILE(firstApi(0xe3, 9), "iget-volatile", ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ IPUT_VOLATILE(firstApi(0xe4, 9), "iput-volatile", ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ SGET_VOLATILE(firstApi(0xe5, 9), "sget-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR),
+ SPUT_VOLATILE(firstApi(0xe6, 9), "sput-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR),
+ IGET_OBJECT_VOLATILE(firstApi(0xe7, 9), "iget-object-volatile", ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ IGET_WIDE_VOLATILE(firstApi(0xe8, 9), "iget-wide-volatile", ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ IPUT_WIDE_VOLATILE(firstApi(0xe9, 9), "iput-wide-volatile", ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ SGET_WIDE_VOLATILE(firstApi(0xea, 9), "sget-wide-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER | Opcode.STATIC_FIELD_ACCESSOR),
+ SPUT_WIDE_VOLATILE(firstApi(0xeb, 9), "sput-wide-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR),
+
+ THROW_VERIFICATION_ERROR(firstApi(0xed, 5), "throw-verification-error", ReferenceType.NONE, Format.Format20bc, Opcode.ODEX_ONLY | Opcode.CAN_THROW),
+ EXECUTE_INLINE(allApis(0xee), "execute-inline", ReferenceType.NONE, Format.Format35mi, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ EXECUTE_INLINE_RANGE(firstApi(0xef, 8), "execute-inline/range", ReferenceType.NONE, Format.Format3rmi, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ INVOKE_DIRECT_EMPTY(lastApi(0xf0, 13), "invoke-direct-empty", ReferenceType.METHOD, Format.Format35c, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE),
+ INVOKE_OBJECT_INIT_RANGE(firstApi(0xf0, 14), "invoke-object-init/range", ReferenceType.METHOD, Format.Format3rc, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.CAN_INITIALIZE_REFERENCE),
+ RETURN_VOID_BARRIER(combine(firstApi(0xf1, 11), lastArtVersion(0x73, 59)), "return-void-barrier", ReferenceType.NONE, Format.Format10x, Opcode.ODEX_ONLY),
+ RETURN_VOID_NO_BARRIER(firstArtVersion(0x73, 60), "return-void-no-barrier", ReferenceType.NONE, Format.Format10x, Opcode.ODEX_ONLY),
+ IGET_QUICK(combine(allApis(0xf2), allArtVersions(0xe3)), "iget-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ IGET_WIDE_QUICK(combine(allApis(0xf3), allArtVersions(0xe4)), "iget-wide-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER),
+ IGET_OBJECT_QUICK(combine(allApis(0xf4), allArtVersions(0xe5)), "iget-object-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ IPUT_QUICK(combine(allApis(0xf5), allArtVersions(0xe6)), "iput-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ IPUT_WIDE_QUICK(combine(allApis(0xf6), allArtVersions(0xe7)), "iput-wide-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ IPUT_OBJECT_QUICK(combine(allApis(0xf7), allArtVersions(0xe8)), "iput-object-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ IPUT_BOOLEAN_QUICK(allArtVersions(0xeb), "iput-boolean-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.QUICK_FIELD_ACCESSOR),
+ IPUT_BYTE_QUICK(allArtVersions(0xec), "iput-byte-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.QUICK_FIELD_ACCESSOR),
+ IPUT_CHAR_QUICK(allArtVersions(0xed), "iput-char-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.QUICK_FIELD_ACCESSOR),
+ IPUT_SHORT_QUICK(allArtVersions(0xee), "iput-short-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.QUICK_FIELD_ACCESSOR),
+ IGET_BOOLEAN_QUICK(allArtVersions(0xef), "iget-boolean-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ IGET_BYTE_QUICK(allArtVersions(0xf0), "iget-byte-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ IGET_CHAR_QUICK(allArtVersions(0xf1), "iget-char-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+ IGET_SHORT_QUICK(allArtVersions(0xf2), "iget-short-quick", ReferenceType.NONE, Format.Format22cs, Opcode.ODEX_ONLY | Opcode.QUICK_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER),
+
+ INVOKE_VIRTUAL_QUICK(combine(allApis(0xf8), allArtVersions(0xe9)), "invoke-virtual-quick", ReferenceType.NONE, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ INVOKE_VIRTUAL_QUICK_RANGE(combine(allApis(0xf9), allArtVersions(0xea)), "invoke-virtual-quick/range", ReferenceType.NONE, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ INVOKE_SUPER_QUICK(allApis(0xfa), "invoke-super-quick", ReferenceType.NONE, Format.Format35ms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+ INVOKE_SUPER_QUICK_RANGE(allApis(0xfb), "invoke-super-quick/range", ReferenceType.NONE, Format.Format3rms, Opcode.ODEX_ONLY | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT),
+
+ IPUT_OBJECT_VOLATILE(firstApi(0xfc, 9), "iput-object-volatile", ReferenceType.FIELD, Format.Format22c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE),
+ SGET_OBJECT_VOLATILE(firstApi(0xfd, 9), "sget-object-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.STATIC_FIELD_ACCESSOR),
+ SPUT_OBJECT_VOLATILE(firstApi(0xfe, 9), "sput-object-volatile", ReferenceType.FIELD, Format.Format21c, Opcode.ODEX_ONLY | Opcode.VOLATILE_FIELD_ACCESSOR | Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.STATIC_FIELD_ACCESSOR),
+
+ PACKED_SWITCH_PAYLOAD(0x100, "packed-switch-payload", ReferenceType.NONE, Format.PackedSwitchPayload, 0),
+ SPARSE_SWITCH_PAYLOAD(0x200, "sparse-switch-payload", ReferenceType.NONE, Format.SparseSwitchPayload, 0),
+ ARRAY_PAYLOAD(0x300, "array-payload", ReferenceType.NONE, Format.ArrayPayload, 0),
// Reuse the deprecated f3-ff opcodes in Art:
- INVOKE_LAMBDA((short)0xf3, "invoke-lambda", minApi(23), ReferenceType.NONE, Format.Format25x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.EXPERIMENTAL),
+ INVOKE_LAMBDA(allArtVersions(0xf3),"invoke-lambda", ReferenceType.NONE, Format.Format25x, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_RESULT | Opcode.EXPERIMENTAL),
// TODO: What about JUMBO support if the string ID is too large?
- CAPTURE_VARIABLE((short)0xf5, "capture-variable", minApi(23), ReferenceType.STRING, Format.Format21c, Opcode.EXPERIMENTAL),
- CREATE_LAMBDA((short)0xf6, "create-lambda", minApi(23), ReferenceType.METHOD, Format.Format21c, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL),
+ CAPTURE_VARIABLE(allArtVersions(0xf5), "capture-variable", ReferenceType.STRING, Format.Format21c, Opcode.EXPERIMENTAL),
+ CREATE_LAMBDA(allArtVersions(0xf6), "create-lambda", ReferenceType.METHOD, Format.Format21c, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL),
// TODO: do we need a capture/liberate wide?
- LIBERATE_VARIABLE((short)0xf7, "liberate-variable", minApi(23), ReferenceType.STRING, Format.Format22c, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL),
- BOX_LAMBDA((short)0xf8, "box-lambda", minApi(23), ReferenceType.NONE, Format.Format22x, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL),
- UNBOX_LAMBDA((short)0xf9, "unbox-lambda", minApi(23), ReferenceType.TYPE, Format.Format22c, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL);
+ LIBERATE_VARIABLE(allArtVersions(0xf7), "liberate-variable", ReferenceType.STRING, Format.Format22c, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL),
+ BOX_LAMBDA(allArtVersions(0xf8), "box-lambda", ReferenceType.NONE, Format.Format22x, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL),
+ UNBOX_LAMBDA(allArtVersions(0xf9), "unbox-lambda", ReferenceType.TYPE, Format.Format22c, Opcode.SETS_REGISTER | Opcode.EXPERIMENTAL);
//if the instruction can throw an exception
public static final int CAN_THROW = 0x1;
@@ -309,12 +327,12 @@ public enum Opcode
public static final int SETS_REGISTER = 0x10;
//if the instruction sets the value of it's first register to a wide type
public static final int SETS_WIDE_REGISTER = 0x20;
- //if the instruction is an odexed iget-quick/iput-quick instruction
- public static final int ODEXED_INSTANCE_QUICK = 0x40;
- //if the instruction is an odexed iget-volatile/iput-volatile instruction
- public static final int ODEXED_INSTANCE_VOLATILE = 0x80;
- //if the instruction is an odexed sget-volatile/sput-volatile instruction
- public static final int ODEXED_STATIC_VOLATILE = 0x100;
+ //if the instruction is an iget-quick/iput-quick instruction
+ public static final int QUICK_FIELD_ACCESSOR = 0x40;
+ //if the instruction is a *get-volatile/*put-volatile instruction
+ public static final int VOLATILE_FIELD_ACCESSOR = 0x80;
+ //if the instruction is a static sget-*/sput-*instruction
+ public static final int STATIC_FIELD_ACCESSOR = 0x100;
//if the instruction is a jumbo instruction
public static final int JUMBO_OPCODE = 0x200;
//if the instruction can initialize an uninitialized object reference
@@ -332,58 +350,81 @@ public enum Opcode
return api << 16;
}
- public final short value;
+ // values and minApis provide a mapping of api -> bytecode value.
+ // the apis in minApis are guaranteed to be
+ public final RangeMap<Integer, Short> apiToValueMap;
+ public final RangeMap<Integer, Short> artVersionToValueMap;
+
public final String name;
- // high 16-bits is the max api, low 16-bits is the min api
- public final int apiConstraints;
public final int referenceType;
public final Format format;
public final int flags;
- Opcode(short opcodeValue, String opcodeName, int referenceType, Format format) {
- this(opcodeValue, opcodeName, ALL_APIS, referenceType, format, 0, (short)-1);
+ Opcode(int opcodeValue, String opcodeName, int referenceType, Format format) {
+ this(opcodeValue, opcodeName, referenceType, format, 0);
}
- Opcode(short opcodeValue, String opcodeName, int referenceType, Format format, int flags) {
- this(opcodeValue, opcodeName, ALL_APIS, referenceType, format, flags, (short)-1);
+ Opcode(int opcodeValue, String opcodeName, int referenceType, Format format, int flags) {
+ this(allVersions(opcodeValue), opcodeName, referenceType, format, flags);
}
- Opcode(short opcodeValue, String opcodeName, int referenceType, Format format, int flags, short jumboOpcodeValue) {
- this(opcodeValue, opcodeName, ALL_APIS, referenceType, format, flags, jumboOpcodeValue);
+ Opcode(List<VersionConstraint> versionConstraints, String opcodeName, int referenceType, Format format, int flags) {
+ ImmutableRangeMap.Builder<Integer, Short> apiToValueBuilder = ImmutableRangeMap.builder();
+ ImmutableRangeMap.Builder<Integer, Short> artVersionToValueBuilder = ImmutableRangeMap.builder();
+
+ for (VersionConstraint versionConstraint : versionConstraints) {
+ if (!versionConstraint.apiRange.isEmpty()) {
+ apiToValueBuilder.put(versionConstraint.apiRange, (short)versionConstraint.opcodeValue);
+ }
+ if (!versionConstraint.artVersionRange.isEmpty()) {
+ artVersionToValueBuilder.put(versionConstraint.artVersionRange, (short)versionConstraint.opcodeValue);
+ }
+ }
+
+ this.apiToValueMap = apiToValueBuilder.build();
+ this.artVersionToValueMap = artVersionToValueBuilder.build();
+ this.name = opcodeName;
+ this.referenceType = referenceType;
+ this.format = format;
+ this.flags = flags;
}
- Opcode(short opcodeValue, String opcodeName, int apiConstraints, int referenceType, Format format) {
- this(opcodeValue, opcodeName, apiConstraints, referenceType, format, 0, (short)-1);
+ private static List<VersionConstraint> firstApi(int opcodeValue, int api) {
+ return Lists.newArrayList(new VersionConstraint(Range.atLeast(api), Range.openClosed(0, 0), opcodeValue));
}
- Opcode(short opcodeValue, String opcodeName, int apiConstraints, int referenceType, Format format, int flags) {
- this(opcodeValue, opcodeName, apiConstraints, referenceType, format, flags, (short)-1);
+ private static List<VersionConstraint> lastApi(int opcodeValue, int api) {
+ Range range;
+ return Lists.newArrayList(new VersionConstraint(Range.atMost(api), Range.openClosed(0, 0), opcodeValue));
}
- Opcode(short opcodeValue, String opcodeName, int apiConstraints, int referenceType, Format format, int flags,
- short jumboOpcodeValue) {
- this.value = opcodeValue;
- this.name = opcodeName;
- this.apiConstraints = apiConstraints;
- this.referenceType = referenceType;
- this.format = format;
- this.flags = flags;
- // TODO: implement jumbo opcodes for dexlib2 and uncomment
- // this.jumboOpcode = jumboOpcodeValue;
+ private static List<VersionConstraint> firstArtVersion(int opcodeValue, int artVersion) {
+ return Lists.newArrayList(new VersionConstraint(Range.openClosed(0, 0), Range.atLeast(artVersion), opcodeValue));
+ }
+
+ private static List<VersionConstraint> lastArtVersion(int opcodeValue, int artVersion) {
+ return Lists.newArrayList(new VersionConstraint(Range.openClosed(0, 0), Range.atMost(artVersion), opcodeValue));
+ }
+
+ private static List<VersionConstraint> allVersions(int opcodeValue) {
+ return Lists.newArrayList(new VersionConstraint(Range.<Integer>all(), Range.<Integer>all(), opcodeValue));
}
- /**
- * @return the minimum api level that can use this opcode (inclusive)
- */
- public int getMinApi() {
- return apiConstraints & 0xFFFF;
+ private static List<VersionConstraint> allApis(int opcodeValue) {
+ return Lists.newArrayList(new VersionConstraint(Range.<Integer>all(), Range.openClosed(0, 0), opcodeValue));
}
- /**
- * @return the maximum api level that can to use this opcode (inclusive)
- */
- public int getMaxApi() {
- return apiConstraints >>> 16;
+ private static List<VersionConstraint> allArtVersions(int opcodeValue) {
+ return Lists.newArrayList(new VersionConstraint(Range.openClosed(0, 0), Range.<Integer>all(), opcodeValue));
+ }
+
+ @SuppressWarnings("unchecked")
+ private static List<VersionConstraint> combine(List<VersionConstraint>... versionConstraints) {
+ List<VersionConstraint> combinedList = Lists.newArrayList();
+ for (List<VersionConstraint> versionConstraintList: versionConstraints) {
+ combinedList.addAll(versionConstraintList);
+ }
+ return combinedList;
}
public final boolean canThrow() {
@@ -410,16 +451,16 @@ public enum Opcode
return (flags & SETS_WIDE_REGISTER) != 0;
}
- public final boolean isOdexedInstanceQuick() {
- return (flags & ODEXED_INSTANCE_QUICK) != 0;
+ public final boolean isQuickFieldaccessor() {
+ return (flags & QUICK_FIELD_ACCESSOR) != 0;
}
- public final boolean isOdexedInstanceVolatile() {
- return (flags & ODEXED_INSTANCE_VOLATILE) != 0;
+ public final boolean isVolatileFieldAccessor() {
+ return (flags & VOLATILE_FIELD_ACCESSOR) != 0;
}
- public final boolean isOdexedStaticVolatile() {
- return (flags & ODEXED_STATIC_VOLATILE) != 0;
+ public final boolean isStaticFieldAccessor() {
+ return (flags & STATIC_FIELD_ACCESSOR) != 0;
}
public final boolean isJumboOpcode() {
@@ -433,4 +474,17 @@ public enum Opcode
public final boolean isExperimental() {
return (flags & EXPERIMENTAL) != 0;
}
+
+ private static class VersionConstraint {
+ @Nonnull public final Range<Integer> apiRange;
+ @Nonnull public final Range<Integer> artVersionRange;
+ public final int opcodeValue;
+
+ public VersionConstraint(@Nonnull Range<Integer> apiRange, @Nonnull Range<Integer> artVersionRange,
+ int opcodeValue) {
+ this.apiRange = apiRange;
+ this.artVersionRange = artVersionRange;
+ this.opcodeValue = opcodeValue;
+ }
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java b/dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java
index e718e275..17f80132 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/Opcodes.java
@@ -32,35 +32,90 @@
package org.jf.dexlib2;
import com.google.common.collect.Maps;
+import com.google.common.collect.RangeMap;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import java.util.EnumMap;
import java.util.HashMap;
public class Opcodes {
- private final Opcode[] opcodesByValue;
- private final HashMap<String, Opcode> opcodesByName;
+ /**
+ * Either the api level for dalvik opcodes, or the art version for art opcodes
+ */
+ public final int api;
+ public final int artVersion;
+ @Nonnull private final Opcode[] opcodesByValue = new Opcode[255];
+ @Nonnull private final EnumMap<Opcode, Short> opcodeValues;
+ @Nonnull private final HashMap<String, Opcode> opcodesByName;
+
+ @Nonnull
+ public static Opcodes forApi(int api) {
+ return new Opcodes(api, VersionMap.mapApiToArtVersion(api), false);
+ }
+
+ @Nonnull
+ public static Opcodes forApi(int api, boolean experimental) {
+ return new Opcodes(api, VersionMap.mapApiToArtVersion(api), experimental);
+ }
+
+ @Nonnull
+ public static Opcodes forArtVersion(int artVersion) {
+ return forArtVersion(artVersion, false);
+ }
+
+ @Nonnull
+ public static Opcodes forArtVersion(int artVersion, boolean experimental) {
+ return new Opcodes(VersionMap.mapArtVersionToApi(artVersion), artVersion, experimental);
+ }
+
+ @Deprecated
public Opcodes(int api) {
this(api, false);
}
+ @Deprecated
public Opcodes(int api, boolean experimental) {
- opcodesByValue = new Opcode[256];
+ this(api, VersionMap.mapApiToArtVersion(api), experimental);
+ }
+
+ private Opcodes(int api, int artVersion, boolean experimental) {
+ this.api = api;
+ this.artVersion = artVersion;
+
+ opcodeValues = new EnumMap<Opcode, Short>(Opcode.class);
opcodesByName = Maps.newHashMap();
+ int version;
+ if (isArt()) {
+ version = artVersion;
+ } else {
+ version = api;
+ }
+
for (Opcode opcode: Opcode.values()) {
- if (!opcode.format.isPayloadFormat) {
- if (api <= opcode.getMaxApi() && api >= opcode.getMinApi() &&
- (experimental || !opcode.isExperimental())) {
- opcodesByValue[opcode.value] = opcode;
- opcodesByName.put(opcode.name.toLowerCase(), opcode);
+ RangeMap<Integer, Short> versionToValueMap;
+
+ if (isArt()) {
+ versionToValueMap = opcode.artVersionToValueMap;
+ } else {
+ versionToValueMap = opcode.apiToValueMap;
+ }
+
+ Short opcodeValue = versionToValueMap.get(version);
+ if (opcodeValue != null && (!opcode.isExperimental() || experimental)) {
+ if (!opcode.format.isPayloadFormat) {
+ opcodesByValue[opcodeValue] = opcode;
}
+ opcodeValues.put(opcode, opcodeValue);
+ opcodesByName.put(opcode.name.toLowerCase(), opcode);
}
}
}
@Nullable
- public Opcode getOpcodeByName(String opcodeName) {
+ public Opcode getOpcodeByName(@Nonnull String opcodeName) {
return opcodesByName.get(opcodeName.toLowerCase());
}
@@ -80,4 +135,13 @@ public class Opcodes {
return null;
}
}
+
+ @Nullable
+ public Short getOpcodeValue(@Nonnull Opcode opcode) {
+ return opcodeValues.get(opcode);
+ }
+
+ public boolean isArt() {
+ return artVersion != VersionMap.NO_VERSION;
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/VersionMap.java b/dexlib2/src/main/java/org/jf/dexlib2/VersionMap.java
new file mode 100644
index 00000000..42802bc0
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/VersionMap.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2015, 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.dexlib2;
+
+public class VersionMap {
+ public static final int NO_VERSION = -1;
+
+ public static int mapArtVersionToApi(int artVersion) {
+ // TODO: implement this
+ return 20;
+ }
+
+ public static int mapApiToArtVersion(int api) {
+ // TODO: implement this
+ if (api < 20) {
+ return NO_VERSION;
+ } else {
+ return 56;
+ }
+ }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedInstruction.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedInstruction.java
index 30cc9067..f6fc95a1 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedInstruction.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedInstruction.java
@@ -31,12 +31,15 @@
package org.jf.dexlib2.analysis;
+import com.google.common.base.Objects;
+import com.google.common.collect.Maps;
import org.jf.dexlib2.iface.instruction.*;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.iface.reference.Reference;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import java.util.*;
public class AnalyzedInstruction implements Comparable<AnalyzedInstruction> {
@@ -71,6 +74,12 @@ public class AnalyzedInstruction implements Comparable<AnalyzedInstruction> {
protected final RegisterType[] postRegisterMap;
/**
+ * This contains optional register type overrides for register types from predecessors
+ */
+ @Nullable
+ protected Map<PredecessorOverrideKey, RegisterType> predecessorRegisterOverrides = null;
+
+ /**
* When deodexing, we might need to deodex this instruction multiple times, when we merge in new register
* information. When this happens, we need to restore the original (odexed) instruction, so we can deodex it again
*/
@@ -101,6 +110,17 @@ public class AnalyzedInstruction implements Comparable<AnalyzedInstruction> {
return Collections.unmodifiableSortedSet(predecessors);
}
+ public RegisterType getPredecessorRegisterType(@Nonnull AnalyzedInstruction predecessor, int registerNumber) {
+ if (predecessorRegisterOverrides != null) {
+ RegisterType override = predecessorRegisterOverrides.get(
+ new PredecessorOverrideKey(predecessor, registerNumber));
+ if (override != null) {
+ return override;
+ }
+ }
+ return predecessor.postRegisterMap[registerNumber];
+ }
+
protected boolean addPredecessor(AnalyzedInstruction predecessor) {
return predecessors.add(predecessor);
}
@@ -169,12 +189,19 @@ public class AnalyzedInstruction implements Comparable<AnalyzedInstruction> {
* register is a destination register for this instruction, or if the pre-instruction register type didn't change
* after merging in the given register type
*/
- protected boolean mergeRegister(int registerNumber, RegisterType registerType, BitSet verifiedInstructions) {
+ protected boolean mergeRegister(int registerNumber, RegisterType registerType, BitSet verifiedInstructions,
+ boolean override) {
assert registerNumber >= 0 && registerNumber < postRegisterMap.length;
assert registerType != null;
RegisterType oldRegisterType = preRegisterMap[registerNumber];
- RegisterType mergedRegisterType = oldRegisterType.merge(registerType);
+
+ RegisterType mergedRegisterType;
+ if (override) {
+ mergedRegisterType = getMergedPreRegisterTypeFromPredecessors(registerNumber);
+ } else {
+ mergedRegisterType = oldRegisterType.merge(registerType);
+ }
if (mergedRegisterType.equals(oldRegisterType)) {
return false;
@@ -193,39 +220,82 @@ public class AnalyzedInstruction implements Comparable<AnalyzedInstruction> {
/**
* Iterates over the predecessors of this instruction, and merges all the post-instruction register types for the
- * given register. Any dead, unreachable, or odexed predecessor is ignored
+ * given register. Any dead, unreachable, or odexed predecessor is ignored. This takes into account any overridden
+ * predecessor register types
+ *
* @param registerNumber the register number
* @return The register type resulting from merging the post-instruction register types from all predecessors
*/
- protected RegisterType mergePreRegisterTypeFromPredecessors(int registerNumber) {
+ protected RegisterType getMergedPreRegisterTypeFromPredecessors(int registerNumber) {
RegisterType mergedRegisterType = null;
for (AnalyzedInstruction predecessor: predecessors) {
- RegisterType predecessorRegisterType = predecessor.postRegisterMap[registerNumber];
- assert predecessorRegisterType != null;
- mergedRegisterType = predecessorRegisterType.merge(mergedRegisterType);
+ RegisterType predecessorRegisterType = getPredecessorRegisterType(predecessor, registerNumber);
+ if (predecessorRegisterType != null) {
+ if (mergedRegisterType == null) {
+ mergedRegisterType = predecessorRegisterType;
+ } else {
+ mergedRegisterType = predecessorRegisterType.merge(mergedRegisterType);
+ }
+ }
}
return mergedRegisterType;
}
+ /**
+ * Sets the "post-instruction" register type as indicated.
+ * @param registerNumber Which register to set
+ * @param registerType The "post-instruction" register type
+ * @return true if the given register type is different than the existing post-instruction register type
+ */
+ protected boolean setPostRegisterType(int registerNumber, RegisterType registerType) {
+ assert registerNumber >= 0 && registerNumber < postRegisterMap.length;
+ assert registerType != null;
- /*
- * Sets the "post-instruction" register type as indicated.
- * @param registerNumber Which register to set
- * @param registerType The "post-instruction" register type
- * @returns true if the given register type is different than the existing post-instruction register type
- */
- protected boolean setPostRegisterType(int registerNumber, RegisterType registerType) {
- assert registerNumber >= 0 && registerNumber < postRegisterMap.length;
- assert registerType != null;
+ RegisterType oldRegisterType = postRegisterMap[registerNumber];
+ if (oldRegisterType.equals(registerType)) {
+ return false;
+ }
+
+ postRegisterMap[registerNumber] = registerType;
+ return true;
+ }
+
+ /**
+ * Adds an override for a register type from a predecessor.
+ *
+ * This is used to set the register type for only one branch from a conditional jump.
+ *
+ * @param predecessor Which predecessor is being overriden
+ * @param registerNumber The register number of the register being overriden
+ * @param registerType The overridden register type
+ * @param verifiedInstructions
+ *
+ * @return true if the post-instruction register type for this instruction changed as a result of this override
+ */
+ protected boolean overridePredecessorRegisterType(@Nonnull AnalyzedInstruction predecessor, int registerNumber,
+ @Nonnull RegisterType registerType, BitSet verifiedInstructions) {
+ if (predecessorRegisterOverrides == null) {
+ predecessorRegisterOverrides = Maps.newHashMap();
+ }
+ predecessorRegisterOverrides.put(new PredecessorOverrideKey(predecessor, registerNumber), registerType);
+
+ RegisterType mergedType = getMergedPreRegisterTypeFromPredecessors(registerNumber);
- RegisterType oldRegisterType = postRegisterMap[registerNumber];
- if (oldRegisterType.equals(registerType)) {
- return false;
- }
+ if (preRegisterMap[registerNumber].equals(mergedType)) {
+ return false;
+ }
+
+ preRegisterMap[registerNumber] = mergedType;
+ verifiedInstructions.clear(instructionIndex);
- postRegisterMap[registerNumber] = registerType;
- return true;
- }
+ if (!setsRegister(registerNumber)) {
+ if (!postRegisterMap[registerNumber].equals(mergedType)) {
+ postRegisterMap[registerNumber] = mergedType;
+ return true;
+ }
+ }
+ return false;
+ }
protected boolean isInvokeInit() {
if (instruction == null || !instruction.getOpcode().canInitializeReference()) {
@@ -328,5 +398,27 @@ public class AnalyzedInstruction implements Comparable<AnalyzedInstruction> {
return 1;
}
}
+
+ private static class PredecessorOverrideKey {
+ public final AnalyzedInstruction analyzedInstruction;
+ public final int registerNumber;
+
+ public PredecessorOverrideKey(AnalyzedInstruction analyzedInstruction, int registerNumber) {
+ this.analyzedInstruction = analyzedInstruction;
+ this.registerNumber = registerNumber;
+ }
+
+ @Override public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ PredecessorOverrideKey that = (PredecessorOverrideKey)o;
+ return com.google.common.base.Objects.equal(registerNumber, that.registerNumber) &&
+ Objects.equal(analyzedInstruction, that.analyzedInstruction);
+ }
+
+ @Override public int hashCode() {
+ return Objects.hashCode(analyzedInstruction, registerNumber);
+ }
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedMethodUtil.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedMethodUtil.java
new file mode 100644
index 00000000..775a819d
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedMethodUtil.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2015, 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.dexlib2.analysis;
+
+import org.jf.dexlib2.AccessFlags;
+import org.jf.dexlib2.analysis.util.TypeProtoUtils;
+import org.jf.dexlib2.iface.ClassDef;
+import org.jf.dexlib2.iface.Method;
+import org.jf.dexlib2.util.MethodUtil;
+import org.jf.dexlib2.util.TypeUtils;
+
+import javax.annotation.Nonnull;
+
+public class AnalyzedMethodUtil {
+ public static boolean canAccess(@Nonnull TypeProto type, @Nonnull Method virtualMethod, boolean checkPackagePrivate,
+ boolean checkProtected, boolean checkClass) {
+ if (checkPackagePrivate && MethodUtil.isPackagePrivate(virtualMethod)) {
+ String otherPackage = TypeUtils.getPackage(virtualMethod.getDefiningClass());
+ String thisPackage = TypeUtils.getPackage(type.getType());
+ if (!otherPackage.equals(thisPackage)) {
+ return false;
+ }
+ }
+
+ if (checkProtected && (virtualMethod.getAccessFlags() & AccessFlags.PROTECTED.getValue()) != 0) {
+ if (!TypeProtoUtils.extendsFrom(type, virtualMethod.getDefiningClass())) {
+ return false;
+ }
+ }
+
+ if (checkClass) {
+ ClassPath classPath = type.getClassPath();
+ ClassDef methodClassDef = classPath.getClassDef(virtualMethod.getDefiningClass());
+ if (!TypeUtils.canAccessClass(type.getType(), methodClassDef)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ArrayProto.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ArrayProto.java
index 8fcfc8c5..4aa9a5e4 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ArrayProto.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ArrayProto.java
@@ -32,6 +32,7 @@
package org.jf.dexlib2.analysis;
import com.google.common.base.Strings;
+import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.immutable.reference.ImmutableFieldReference;
@@ -160,7 +161,11 @@ public class ArrayProto implements TypeProto {
@Override
@Nullable
- public MethodReference getMethodByVtableIndex(int vtableIndex) {
+ public Method getMethodByVtableIndex(int vtableIndex) {
return classPath.getClass("Ljava/lang/Object;").getMethodByVtableIndex(vtableIndex);
}
+
+ @Override public int findMethodIndexInVtable(@Nonnull MethodReference method) {
+ return classPath.getClass("Ljava/lang/Object;").findMethodIndexInVtable(method);
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java
index bd9cfb1b..9f9e396b 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java
@@ -31,15 +31,20 @@
package org.jf.dexlib2.analysis;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
import org.jf.dexlib2.DexFileFactory;
+import org.jf.dexlib2.DexFileFactory.DexFileNotFound;
+import org.jf.dexlib2.DexFileFactory.MultipleDexFilesException;
+import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.analysis.reflection.ReflectionClassDef;
+import org.jf.dexlib2.dexbacked.OatFile.OatDexFile;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.DexFile;
import org.jf.dexlib2.immutable.ImmutableDexFile;
@@ -49,48 +54,45 @@ import javax.annotation.Nonnull;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Arrays;
+import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ClassPath {
@Nonnull private final TypeProto unknownClass;
- @Nonnull private HashMap<String, ClassDef> availableClasses = Maps.newHashMap();
- private boolean checkPackagePrivateAccess;
+ @Nonnull private List<ClassProvider> classProviders;
+ private final boolean checkPackagePrivateAccess;
+ public final int oatVersion;
- /**
- * Creates a new ClassPath instance that can load classes from the given dex files
- *
- * @param classPath An array of DexFile objects. When loading a class, these dex files will be searched in order
- */
- public ClassPath(DexFile... classPath) throws IOException {
- this(Lists.newArrayList(classPath), 15);
- }
+ public static final int NOT_ART = -1;
/**
- * Creates a new ClassPath instance that can load classes from the given dex files
+ * Creates a new ClassPath instance that can load classes from the given providers
*
- * @param classPath An iterable of DexFile objects. When loading a class, these dex files will be searched in order
- * @param api API level
+ * @param classProviders An iterable of ClassProviders. When loading a class, these providers will be searched in
+ * order
*/
- public ClassPath(@Nonnull Iterable<DexFile> classPath, int api) {
- this(Lists.newArrayList(classPath), api == 17);
+ public ClassPath(ClassProvider... classProviders) throws IOException {
+ this(Arrays.asList(classProviders), false, NOT_ART);
}
/**
- * Creates a new ClassPath instance that can load classes from the given dex files
+ * Creates a new ClassPath instance that can load classes from the given providers
*
- * @param classPath An iterable of DexFile objects. When loading a class, these dex files will be searched in order
- * @param checkPackagePrivateAccess Whether checkPackagePrivateAccess is needed, enabled for ONLY early API 17 by default
+ * @param classProviders An iterable of ClassProviders. When loading a class, these providers will be searched in
+ * order
+ * @param checkPackagePrivateAccess Whether checkPackagePrivateAccess is needed, enabled for ONLY early API 17 by
+ * default
+ * @param oatVersion The applicable oat version, or NOT_ART
*/
- public ClassPath(@Nonnull Iterable<DexFile> classPath, boolean checkPackagePrivateAccess) {
+ public ClassPath(@Nonnull Iterable<? extends ClassProvider> classProviders, boolean checkPackagePrivateAccess,
+ int oatVersion) {
// add fallbacks for certain special classes that must be present
- Iterable<DexFile> dexFiles = Iterables.concat(classPath, Lists.newArrayList(getBasicClasses()));
-
unknownClass = new UnknownClassProto(this);
loadedClasses.put(unknownClass.getType(), unknownClass);
this.checkPackagePrivateAccess = checkPackagePrivateAccess;
+ this.oatVersion = oatVersion;
loadPrimitiveType("Z");
loadPrimitiveType("B");
@@ -102,33 +104,31 @@ public class ClassPath {
loadPrimitiveType("D");
loadPrimitiveType("L");
- for (DexFile dexFile: dexFiles) {
- for (ClassDef classDef: dexFile.getClasses()) {
- ClassDef prev = availableClasses.get(classDef.getType());
- if (prev == null) {
- availableClasses.put(classDef.getType(), classDef);
- }
- }
- }
+ this.classProviders = Lists.newArrayList(classProviders);
+ this.classProviders.add(getBasicClasses());
}
private void loadPrimitiveType(String type) {
loadedClasses.put(type, new PrimitiveProto(this, type));
}
- private static DexFile getBasicClasses() {
+ private static ClassProvider getBasicClasses() {
// fallbacks for some special classes that we assume are present
- return new ImmutableDexFile(ImmutableSet.of(
+ return new DexClassProvider(new ImmutableDexFile(Opcodes.forApi(19), ImmutableSet.of(
new ReflectionClassDef(Class.class),
new ReflectionClassDef(Cloneable.class),
new ReflectionClassDef(Object.class),
new ReflectionClassDef(Serializable.class),
new ReflectionClassDef(String.class),
- new ReflectionClassDef(Throwable.class)));
+ new ReflectionClassDef(Throwable.class))));
+ }
+
+ public boolean isArt() {
+ return oatVersion != NOT_ART;
}
@Nonnull
- public TypeProto getClass(CharSequence type) {
+ public TypeProto getClass(@Nonnull CharSequence type) {
return loadedClasses.getUnchecked(type.toString());
}
@@ -146,11 +146,13 @@ public class ClassPath {
@Nonnull
public ClassDef getClassDef(String type) {
- ClassDef ret = availableClasses.get(type);
- if (ret == null) {
- throw new UnresolvedClassException("Could not resolve class %s", type);
+ for (ClassProvider provider: classProviders) {
+ ClassDef classDef = provider.getClassDef(type);
+ if (classDef != null) {
+ return classDef;
+ }
}
- return ret;
+ throw new UnresolvedClassException("Could not resolve class %s", type);
}
@Nonnull
@@ -171,23 +173,52 @@ public class ClassPath {
@Nonnull
public static ClassPath fromClassPath(Iterable<String> classPathDirs, Iterable<String> classPath, DexFile dexFile,
int api, boolean checkPackagePrivateAccess, boolean experimental) {
- ArrayList<DexFile> dexFiles = Lists.newArrayList();
+ List<ClassProvider> providers = Lists.newArrayList();
+
+ int oatVersion = NOT_ART;
for (String classPathEntry: classPath) {
- try {
- dexFiles.add(loadClassPathEntry(classPathDirs, classPathEntry, api, experimental));
- } catch (ExceptionWithContext e){}
+ List<? extends DexFile> classPathDexFiles =
+ loadClassPathEntry(classPathDirs, classPathEntry, api, experimental);
+ if (oatVersion == NOT_ART) {
+ for (DexFile classPathDexFile: classPathDexFiles) {
+ if (classPathDexFile instanceof OatDexFile) {
+ oatVersion = ((OatDexFile)classPathDexFile).getOatVersion();
+ break;
+ }
+ }
+ }
+ for (DexFile classPathDexFile: classPathDexFiles) {
+ providers.add(new DexClassProvider(classPathDexFile));
+ }
}
- dexFiles.add(dexFile);
- return new ClassPath(dexFiles, checkPackagePrivateAccess);
+ providers.add(new DexClassProvider(dexFile));
+ return new ClassPath(providers, checkPackagePrivateAccess, oatVersion);
+ }
+
+ @Nonnull
+ public static ClassPath fromClassPath(Iterable<String> classPathDirs, Iterable<String> classPath, DexFile dexFile,
+ int api, boolean checkPackagePrivateAccess, boolean experimental,
+ int oatVersion) {
+ List<ClassProvider> providers = Lists.newArrayList();
+
+ for (String classPathEntry: classPath) {
+ List<? extends DexFile> classPathDexFiles =
+ loadClassPathEntry(classPathDirs, classPathEntry, api, experimental);
+ for (DexFile classPathDexFile: classPathDexFiles) {
+ providers.add(new DexClassProvider(classPathDexFile));
+ }
+ }
+ providers.add(new DexClassProvider(dexFile));
+ return new ClassPath(providers, checkPackagePrivateAccess, oatVersion);
}
private static final Pattern dalvikCacheOdexPattern = Pattern.compile("@([^@]+)@classes.dex$");
@Nonnull
- private static DexFile loadClassPathEntry(@Nonnull Iterable<String> classPathDirs,
- @Nonnull String bootClassPathEntry, int api,
- boolean experimental) {
+ private static List<? extends DexFile> loadClassPathEntry(@Nonnull Iterable<String> classPathDirs,
+ @Nonnull String bootClassPathEntry, int api,
+ boolean experimental) {
File rawEntry = new File(bootClassPathEntry);
// strip off the path - we only care about the filename
String entryName = rawEntry.getName();
@@ -213,7 +244,15 @@ public class ClassPath {
}
for (String classPathDir: classPathDirs) {
- for (String ext: new String[]{"", ".odex", ".jar", ".apk", ".zip"}) {
+ String[] extensions;
+
+ if (entryName.endsWith(".oat")) {
+ extensions = new String[] { ".oat" };
+ } else {
+ extensions = new String[] { "", ".odex", ".jar", ".apk", ".zip" };
+ }
+
+ for (String ext: extensions) {
File file = new File(classPathDir, baseEntryName + ext);
if (file.exists() && file.isFile()) {
@@ -222,9 +261,11 @@ public class ClassPath {
"warning: cannot open %s for reading. Will continue looking.", file.getPath()));
} else {
try {
- return DexFileFactory.loadDexFile(file, api, experimental);
- } catch (DexFileFactory.NoClassesDexException ex) {
+ return ImmutableList.of(DexFileFactory.loadDexFile(file, api, experimental));
+ } catch (DexFileNotFound ex) {
// ignore and continue
+ } catch (MultipleDexFilesException ex) {
+ return ex.oatFile.getDexFiles();
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex,
"Error while reading boot class path entry \"%s\"", bootClassPathEntry);
@@ -235,4 +276,16 @@ public class ClassPath {
}
throw new ExceptionWithContext("Cannot locate boot class path file %s", bootClassPathEntry);
}
+
+ private final Supplier<OdexedFieldInstructionMapper> fieldInstructionMapperSupplier = Suppliers.memoize(
+ new Supplier<OdexedFieldInstructionMapper>() {
+ @Override public OdexedFieldInstructionMapper get() {
+ return new OdexedFieldInstructionMapper(isArt());
+ }
+ });
+
+ @Nonnull
+ public OdexedFieldInstructionMapper getFieldInstructionMapper() {
+ return fieldInstructionMapperSupplier.get();
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java
index f4f1dc7b..e407de7e 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java
@@ -37,6 +37,7 @@ import com.google.common.base.Suppliers;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.common.primitives.Ints;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.analysis.util.TypeProtoUtils;
import org.jf.dexlib2.iface.ClassDef;
@@ -45,21 +46,24 @@ import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.immutable.ImmutableMethod;
+import org.jf.dexlib2.util.MethodUtil;
+import org.jf.util.AlignmentUtils;
import org.jf.util.ExceptionWithContext;
import org.jf.util.SparseArray;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
+import java.util.*;
/**
* A class "prototype". This contains things like the interfaces, the superclass, the vtable and the instance fields
* and their offsets.
*/
public class ClassProto implements TypeProto {
+ private static final byte REFERENCE = 0;
+ private static final byte WIDE = 1;
+ private static final byte OTHER = 2;
+
@Nonnull protected final ClassPath classPath;
@Nonnull protected final String type;
@@ -345,7 +349,7 @@ public class ClassProto implements TypeProto {
@Override
@Nullable
- public MethodReference getMethodByVtableIndex(int vtableIndex) {
+ public Method getMethodByVtableIndex(int vtableIndex) {
List<Method> vtable = getVtable();
if (vtableIndex < 0 || vtableIndex >= vtable.size()) {
return null;
@@ -354,21 +358,35 @@ public class ClassProto implements TypeProto {
return vtable.get(vtableIndex);
}
+ public int findMethodIndexInVtable(@Nonnull MethodReference method) {
+ List<Method> vtable = getVtable();
+ for (int i=0; i<vtable.size(); i++) {
+ Method candidate = vtable.get(i);
+ if (MethodUtil.methodSignaturesMatch(candidate, method)) {
+ if (!classPath.shouldCheckPackagePrivateAccess() ||
+ AnalyzedMethodUtil.canAccess(this, candidate, true, false, false)) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
@Nonnull SparseArray<FieldReference> getInstanceFields() {
- return instanceFieldsSupplier.get();
+ if (classPath.isArt()) {
+ return artInstanceFieldsSupplier.get();
+ } else {
+ return dalvikInstanceFieldsSupplier.get();
+ }
}
- @Nonnull private final Supplier<SparseArray<FieldReference>> instanceFieldsSupplier =
+ @Nonnull private final Supplier<SparseArray<FieldReference>> dalvikInstanceFieldsSupplier =
Suppliers.memoize(new Supplier<SparseArray<FieldReference>>() {
@Override public SparseArray<FieldReference> get() {
//This is a bit of an "involved" operation. We need to follow the same algorithm that dalvik uses to
//arrange fields, so that we end up with the same field offsets (which is needed for deodexing).
//See mydroid/dalvik/vm/oo/Class.c - computeFieldOffsets()
- final byte REFERENCE = 0;
- final byte WIDE = 1;
- final byte OTHER = 2;
-
ArrayList<Field> fields = getSortedInstanceFields(getClassDef());
final int fieldCount = fields.size();
//the "type" for each field in fields. 0=reference,1=wide,2=other
@@ -519,46 +537,225 @@ public class ClassProto implements TypeProto {
return fields;
}
- private byte getFieldType(@Nonnull FieldReference field) {
+ private void swap(byte[] fieldTypes, List<Field> fields, int position1, int position2) {
+ byte tempType = fieldTypes[position1];
+ fieldTypes[position1] = fieldTypes[position2];
+ fieldTypes[position2] = tempType;
+
+ Field tempField = fields.set(position1, fields.get(position2));
+ fields.set(position2, tempField);
+ }
+ });
+
+ private static abstract class FieldGap implements Comparable<FieldGap> {
+ public final int offset;
+ public final int size;
+
+ public static FieldGap newFieldGap(int offset, int size, int oatVersion) {
+ if (oatVersion >= 67) {
+ return new FieldGap(offset, size) {
+ @Override public int compareTo(FieldGap o) {
+ int result = Ints.compare(o.size, size);
+ if (result != 0) {
+ return result;
+ }
+ return Ints.compare(offset, o.offset);
+ }
+ };
+ } else {
+ return new FieldGap(offset, size) {
+ @Override public int compareTo(FieldGap o) {
+ int result = Ints.compare(size, o.size);
+ if (result != 0) {
+ return result;
+ }
+ return Ints.compare(o.offset, offset);
+ }
+ };
+ }
+ }
+
+ private FieldGap(int offset, int size) {
+ this.offset = offset;
+ this.size = size;
+ }
+ }
+
+ @Nonnull private final Supplier<SparseArray<FieldReference>> artInstanceFieldsSupplier =
+ Suppliers.memoize(new Supplier<SparseArray<FieldReference>>() {
+
+ @Override public SparseArray<FieldReference> get() {
+ // We need to follow the same algorithm that art uses to arrange fields, so that we end up with the
+ // same field offsets, which is needed for deodexing.
+ // See LinkFields() in art/runtime/class_linker.cc
+
+ PriorityQueue<FieldGap> gaps = new PriorityQueue<FieldGap>();
+
+ SparseArray<FieldReference> linkedFields = new SparseArray<FieldReference>();
+ ArrayList<Field> fields = getSortedInstanceFields(getClassDef());
+
+ int fieldOffset = 0;
+ String superclassType = getSuperclass();
+ if (superclassType != null) {
+ // TODO: what to do if superclass doesn't exist?
+ ClassProto superclass = (ClassProto) classPath.getClass(superclassType);
+ SparseArray<FieldReference> superFields = superclass.getInstanceFields();
+ FieldReference field = null;
+ int lastOffset = 0;
+ for (int i=0; i<superFields.size(); i++) {
+ int offset = superFields.keyAt(i);
+ field = superFields.valueAt(i);
+ linkedFields.put(offset, field);
+ lastOffset = offset;
+ }
+ if (field != null) {
+ fieldOffset = lastOffset + getFieldSize(field);
+ }
+ }
+
+ for (Field field: fields) {
+ int fieldSize = getFieldSize(field);
+
+ if (!AlignmentUtils.isAligned(fieldOffset, fieldSize)) {
+ int oldOffset = fieldOffset;
+ fieldOffset = AlignmentUtils.alignOffset(fieldOffset, fieldSize);
+ addFieldGap(oldOffset, fieldOffset, gaps);
+ }
+
+ FieldGap gap = gaps.peek();
+ if (gap != null && gap.size >= fieldSize) {
+ gaps.poll();
+ linkedFields.put(gap.offset, field);
+ if (gap.size > fieldSize) {
+ addFieldGap(gap.offset + fieldSize, gap.offset + gap.size, gaps);
+ }
+ } else {
+ linkedFields.append(fieldOffset, field);
+ fieldOffset += fieldSize;
+ }
+ }
+
+ return linkedFields;
+ }
+
+ private void addFieldGap(int gapStart, int gapEnd, @Nonnull PriorityQueue<FieldGap> gaps) {
+ int offset = gapStart;
+
+ while (offset < gapEnd) {
+ int remaining = gapEnd - offset;
+
+ if ((remaining >= 4) && (offset % 4 == 0)) {
+ gaps.add(FieldGap.newFieldGap(offset, 4, classPath.oatVersion));
+ offset += 4;
+ } else if (remaining >= 2 && (offset % 2 == 0)) {
+ gaps.add(FieldGap.newFieldGap(offset, 2, classPath.oatVersion));
+ offset += 2;
+ } else {
+ gaps.add(FieldGap.newFieldGap(offset, 1, classPath.oatVersion));
+ offset += 1;
+ }
+ }
+ }
+
+ @Nonnull
+ private ArrayList<Field> getSortedInstanceFields(@Nonnull ClassDef classDef) {
+ ArrayList<Field> fields = Lists.newArrayList(classDef.getInstanceFields());
+ Collections.sort(fields, new Comparator<Field>() {
+ @Override public int compare(Field field1, Field field2) {
+ int result = Ints.compare(getFieldSortOrder(field1), getFieldSortOrder(field2));
+ if (result != 0) {
+ return result;
+ }
+
+ result = field1.getName().compareTo(field2.getName());
+ if (result != 0) {
+ return result;
+ }
+ return field1.getType().compareTo(field2.getType());
+ }
+ });
+ return fields;
+ }
+
+ private int getFieldSortOrder(@Nonnull FieldReference field) {
+ // The sort order is based on type size (except references are first), and then based on the
+ // enum value of the primitive type for types of equal size. See: Primitive::Type enum
+ // in art/runtime/primitive.h
switch (field.getType().charAt(0)) {
+ /* reference */
case '[':
case 'L':
- return 0; //REFERENCE
+ return 0;
+ /* 64 bit */
case 'J':
+ return 1;
case 'D':
- return 1; //WIDE
- default:
- return 2; //OTHER
+ return 2;
+ /* 32 bit */
+ case 'I':
+ return 3;
+ case 'F':
+ return 4;
+ /* 16 bit */
+ case 'C':
+ return 5;
+ case 'S':
+ return 6;
+ /* 8 bit */
+ case 'Z':
+ return 7;
+ case 'B':
+ return 8;
}
+ throw new ExceptionWithContext("Invalid field type: %s", field.getType());
}
- private void swap(byte[] fieldTypes, List<Field> fields, int position1, int position2) {
- byte tempType = fieldTypes[position1];
- fieldTypes[position1] = fieldTypes[position2];
- fieldTypes[position2] = tempType;
-
- Field tempField = fields.set(position1, fields.get(position2));
- fields.set(position2, tempField);
+ private int getFieldSize(@Nonnull FieldReference field) {
+ return getTypeSize(field.getType().charAt(0));
}
});
private int getNextFieldOffset() {
SparseArray<FieldReference> instanceFields = getInstanceFields();
if (instanceFields.size() == 0) {
- return 8;
+ return classPath.isArt() ? 0 : 8;
}
int lastItemIndex = instanceFields.size()-1;
int fieldOffset = instanceFields.keyAt(lastItemIndex);
FieldReference lastField = instanceFields.valueAt(lastItemIndex);
- switch (lastField.getType().charAt(0)) {
+ if (classPath.isArt()) {
+ return fieldOffset + getTypeSize(lastField.getType().charAt(0));
+ } else {
+ switch (lastField.getType().charAt(0)) {
+ case 'J':
+ case 'D':
+ return fieldOffset + 8;
+ default:
+ return fieldOffset + 4;
+ }
+ }
+ }
+
+ private static int getTypeSize(char type) {
+ switch (type) {
case 'J':
case 'D':
- return fieldOffset + 8;
- default:
- return fieldOffset + 4;
+ return 8;
+ case '[':
+ case 'L':
+ case 'I':
+ case 'F':
+ return 4;
+ case 'C':
+ case 'S':
+ return 2;
+ case 'B':
+ case 'Z':
+ return 1;
}
+ throw new ExceptionWithContext("Invalid type: %s", type);
}
@Nonnull List<Method> getVtable() {
@@ -626,8 +823,9 @@ public class ClassProto implements TypeProto {
outer: for (Method virtualMethod: methods) {
for (int i=0; i<vtable.size(); i++) {
Method superMethod = vtable.get(i);
- if (methodSignaturesMatch(superMethod, virtualMethod)) {
- if (!classPath.shouldCheckPackagePrivateAccess() || canAccess(superMethod)) {
+ if (MethodUtil.methodSignaturesMatch(superMethod, virtualMethod)) {
+ if (!classPath.shouldCheckPackagePrivateAccess() ||
+ AnalyzedMethodUtil.canAccess(ClassProto.this, superMethod, true, false, false)) {
if (replaceExisting) {
vtable.set(i, virtualMethod);
}
@@ -639,36 +837,18 @@ public class ClassProto implements TypeProto {
vtable.add(virtualMethod);
}
}
+ });
- private boolean methodSignaturesMatch(@Nonnull Method a, @Nonnull Method b) {
- return (a.getName().equals(b.getName()) &&
- a.getReturnType().equals(b.getReturnType()) &&
- a.getParameters().equals(b.getParameters()));
- }
-
- private boolean canAccess(@Nonnull Method virtualMethod) {
- if (!methodIsPackagePrivate(virtualMethod.getAccessFlags())) {
- return true;
- }
-
- String otherPackage = getPackage(virtualMethod.getDefiningClass());
- String ourPackage = getPackage(getClassDef().getType());
- return otherPackage.equals(ourPackage);
- }
-
- @Nonnull
- private String getPackage(@Nonnull String classType) {
- int lastSlash = classType.lastIndexOf('/');
- if (lastSlash < 0) {
- return "";
- }
- return classType.substring(1, lastSlash);
- }
-
- private boolean methodIsPackagePrivate(int accessFlags) {
- return (accessFlags & (AccessFlags.PRIVATE.getValue() |
- AccessFlags.PROTECTED.getValue() |
- AccessFlags.PUBLIC.getValue())) == 0;
+ private static byte getFieldType(@Nonnull FieldReference field) {
+ switch (field.getType().charAt(0)) {
+ case '[':
+ case 'L':
+ return 0; //REFERENCE
+ case 'J':
+ case 'D':
+ return 1; //WIDE
+ default:
+ return 2; //OTHER
}
- });
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProvider.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProvider.java
new file mode 100644
index 00000000..7c823ff0
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProvider.java
@@ -0,0 +1,40 @@
+/*
+ * 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.dexlib2.analysis;
+
+import org.jf.dexlib2.iface.ClassDef;
+
+import javax.annotation.Nullable;
+
+public interface ClassProvider {
+ @Nullable ClassDef getClassDef(String type);
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/DexClassProvider.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/DexClassProvider.java
new file mode 100644
index 00000000..c460cc3f
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/DexClassProvider.java
@@ -0,0 +1,56 @@
+/*
+ * 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.dexlib2.analysis;
+
+import com.google.common.collect.Maps;
+import org.jf.dexlib2.iface.ClassDef;
+import org.jf.dexlib2.iface.DexFile;
+
+import javax.annotation.Nullable;
+import java.util.Map;
+
+public class DexClassProvider implements ClassProvider {
+ private final DexFile dexFile;
+ private Map<String, ClassDef> classMap = Maps.newHashMap();
+
+ public DexClassProvider(DexFile dexFile) {
+ this.dexFile = dexFile;
+
+ for (ClassDef classDef: dexFile.getClasses()) {
+ classMap.put(classDef.getType(), classDef);
+ }
+ }
+
+ @Nullable @Override public ClassDef getClassDef(String type) {
+ return classMap.get(type);
+ }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java
index 4402c624..f874f1b8 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java
@@ -49,6 +49,7 @@ import org.jf.dexlib2.immutable.reference.ImmutableMethodReference;
import org.jf.dexlib2.util.MethodUtil;
import org.jf.dexlib2.util.ReferenceUtil;
import org.jf.dexlib2.util.TypeUtils;
+import org.jf.dexlib2.writer.util.TryListBuilder;
import org.jf.util.BitSetUtils;
import org.jf.util.ExceptionWithContext;
import org.jf.util.SparseArray;
@@ -72,6 +73,8 @@ public class MethodAnalyzer {
@Nonnull private final Method method;
@Nonnull private final MethodImplementation methodImpl;
+ private final boolean normalizeVirtualMethods;
+
private final int paramRegisterCount;
@Nonnull private final ClassPath classPath;
@@ -93,9 +96,10 @@ public class MethodAnalyzer {
private final AnalyzedInstruction startOfMethod;
public MethodAnalyzer(@Nonnull ClassPath classPath, @Nonnull Method method,
- @Nullable InlineMethodResolver inlineResolver) {
+ @Nullable InlineMethodResolver inlineResolver, boolean normalizeVirtualMethods) {
this.classPath = classPath;
this.inlineResolver = inlineResolver;
+ this.normalizeVirtualMethods = normalizeVirtualMethods;
this.method = method;
@@ -251,7 +255,7 @@ public class MethodAnalyzer {
int objectRegisterNumber;
switch (instruction.getOpcode().format) {
case Format10x:
- analyzeReturnVoidBarrier(analyzedInstruction, false);
+ analyzeOdexReturnVoid(analyzedInstruction, false);
continue;
case Format21c:
case Format22c:
@@ -333,34 +337,60 @@ public class MethodAnalyzer {
registerType);
}
- private void setPostRegisterTypeAndPropagateChanges(@Nonnull AnalyzedInstruction analyzedInstruction,
- int registerNumber, @Nonnull RegisterType registerType) {
-
- BitSet changedInstructions = new BitSet(analyzedInstructions.size());
-
- if (!analyzedInstruction.setPostRegisterType(registerNumber, registerType)) {
- return;
- }
-
- propagateRegisterToSuccessors(analyzedInstruction, registerNumber, changedInstructions);
-
+ private void propagateChanges(@Nonnull BitSet changedInstructions, int registerNumber, boolean override) {
//Using a for loop inside the while loop optimizes for the common case of the successors of an instruction
//occurring after the instruction. Any successors that occur prior to the instruction will be picked up on
//the next iteration of the while loop.
- //This could also be done recursively, but in large methods it would likely cause very deep recursion,
- //which requires the user to specify a larger stack size. This isn't really a problem, but it is slightly
- //annoying.
+ //This could also be done recursively, but in large methods it would likely cause very deep recursion.
while (!changedInstructions.isEmpty()) {
for (int instructionIndex=changedInstructions.nextSetBit(0);
- instructionIndex>=0;
- instructionIndex=changedInstructions.nextSetBit(instructionIndex+1)) {
+ instructionIndex>=0;
+ instructionIndex=changedInstructions.nextSetBit(instructionIndex+1)) {
changedInstructions.clear(instructionIndex);
propagateRegisterToSuccessors(analyzedInstructions.valueAt(instructionIndex), registerNumber,
- changedInstructions);
+ changedInstructions, override);
}
}
+ }
+
+ private void overridePredecessorRegisterTypeAndPropagateChanges(
+ @Nonnull AnalyzedInstruction analyzedInstruction, @Nonnull AnalyzedInstruction predecessor,
+ int registerNumber, @Nonnull RegisterType registerType) {
+ BitSet changedInstructions = new BitSet(analyzedInstructions.size());
+
+ if (!analyzedInstruction.overridePredecessorRegisterType(
+ predecessor, registerNumber, registerType, analyzedState)) {
+ return;
+ }
+ changedInstructions.set(analyzedInstruction.instructionIndex);
+
+ propagateChanges(changedInstructions, registerNumber, true);
+
+ if (registerType.category == RegisterType.LONG_LO) {
+ checkWidePair(registerNumber, analyzedInstruction);
+ overridePredecessorRegisterTypeAndPropagateChanges(analyzedInstruction, predecessor, registerNumber + 1,
+ RegisterType.LONG_HI_TYPE);
+ } else if (registerType.category == RegisterType.DOUBLE_LO) {
+ checkWidePair(registerNumber, analyzedInstruction);
+ overridePredecessorRegisterTypeAndPropagateChanges(analyzedInstruction, predecessor, registerNumber + 1,
+ RegisterType.DOUBLE_HI_TYPE);
+ }
+ }
+
+ private void setPostRegisterTypeAndPropagateChanges(@Nonnull AnalyzedInstruction analyzedInstruction,
+ int registerNumber, @Nonnull RegisterType registerType) {
+
+ BitSet changedInstructions = new BitSet(analyzedInstructions.size());
+
+ if (!analyzedInstruction.setPostRegisterType(registerNumber, registerType)) {
+ return;
+ }
+
+ propagateRegisterToSuccessors(analyzedInstruction, registerNumber, changedInstructions, false);
+
+ propagateChanges(changedInstructions, registerNumber, false);
if (registerType.category == RegisterType.LONG_LO) {
checkWidePair(registerNumber, analyzedInstruction);
@@ -372,10 +402,10 @@ public class MethodAnalyzer {
}
private void propagateRegisterToSuccessors(@Nonnull AnalyzedInstruction instruction, int registerNumber,
- @Nonnull BitSet changedInstructions) {
+ @Nonnull BitSet changedInstructions, boolean override) {
RegisterType postRegisterType = instruction.getPostInstructionRegisterType(registerNumber);
for (AnalyzedInstruction successor: instruction.successors) {
- if (successor.mergeRegister(registerNumber, postRegisterType, analyzedState)) {
+ if (successor.mergeRegister(registerNumber, postRegisterType, analyzedState, override)) {
changedInstructions.set(successor.instructionIndex);
}
}
@@ -401,6 +431,7 @@ public class MethodAnalyzer {
//and is covered by a try block should be set to a list of the first instructions of each exception handler
//for the try block covering the instruction
List<? extends TryBlock<? extends ExceptionHandler>> tries = methodImpl.getTryBlocks();
+ tries = TryListBuilder.massageTryBlocks(tries);
int triesIndex = 0;
TryBlock currentTry = null;
AnalyzedInstruction[] currentExceptionHandlers = null;
@@ -468,11 +499,19 @@ public class MethodAnalyzer {
OffsetInstruction offsetInstruction = (OffsetInstruction)instruction.instruction;
if (instructionOpcode == Opcode.PACKED_SWITCH || instructionOpcode == Opcode.SPARSE_SWITCH) {
- SwitchPayload switchPayload = (SwitchPayload)analyzedInstructions.get(instructionCodeAddress +
- offsetInstruction.getCodeOffset()).instruction;
+ AnalyzedInstruction analyzedSwitchPayload = analyzedInstructions.get(
+ instructionCodeAddress + offsetInstruction.getCodeOffset());
+ if (analyzedSwitchPayload == null) {
+ throw new AnalysisException("Invalid switch payload offset");
+ }
+ SwitchPayload switchPayload = (SwitchPayload)analyzedSwitchPayload.instruction;
+
for (SwitchElement switchElement: switchPayload.getSwitchElements()) {
AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress +
switchElement.getOffset());
+ if (targetInstruction == null) {
+ throw new AnalysisException("Invalid switch target offset");
+ }
addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers,
instructionsToProcess);
@@ -578,7 +617,8 @@ public class MethodAnalyzer {
case RETURN_OBJECT:
return true;
case RETURN_VOID_BARRIER:
- analyzeReturnVoidBarrier(analyzedInstruction);
+ case RETURN_VOID_NO_BARRIER:
+ analyzeOdexReturnVoid(analyzedInstruction);
return true;
case CONST_4:
case CONST_16:
@@ -734,21 +774,32 @@ public class MethodAnalyzer {
case SPUT_OBJECT:
return true;
case INVOKE_VIRTUAL:
+ analyzeInvokeVirtual(analyzedInstruction, false);
+ return true;
case INVOKE_SUPER:
+ analyzeInvokeVirtual(analyzedInstruction, false);
return true;
case INVOKE_DIRECT:
analyzeInvokeDirect(analyzedInstruction);
return true;
case INVOKE_STATIC:
+ return true;
case INVOKE_INTERFACE:
+ // TODO: normalize interfaces
+ return true;
case INVOKE_VIRTUAL_RANGE:
+ analyzeInvokeVirtual(analyzedInstruction, true);
+ return true;
case INVOKE_SUPER_RANGE:
+ analyzeInvokeVirtual(analyzedInstruction, true);
return true;
case INVOKE_DIRECT_RANGE:
analyzeInvokeDirectRange(analyzedInstruction);
return true;
case INVOKE_STATIC_RANGE:
+ return true;
case INVOKE_INTERFACE_RANGE:
+ // TODO: normalize interfaces
return true;
case NEG_INT:
case NOT_INT:
@@ -955,6 +1006,14 @@ public class MethodAnalyzer {
case IPUT_QUICK:
case IPUT_WIDE_QUICK:
case IPUT_OBJECT_QUICK:
+ case IPUT_BOOLEAN_QUICK:
+ case IPUT_BYTE_QUICK:
+ case IPUT_CHAR_QUICK:
+ case IPUT_SHORT_QUICK:
+ case IGET_BOOLEAN_QUICK:
+ case IGET_BYTE_QUICK:
+ case IGET_CHAR_QUICK:
+ case IGET_SHORT_QUICK:
return analyzeIputIgetQuick(analyzedInstruction);
case INVOKE_VIRTUAL_QUICK:
return analyzeInvokeVirtualQuick(analyzedInstruction, false, false);
@@ -1014,8 +1073,11 @@ public class MethodAnalyzer {
}
private void analyzeMoveResult(@Nonnull AnalyzedInstruction analyzedInstruction) {
- AnalyzedInstruction previousInstruction = analyzedInstructions.valueAt(analyzedInstruction.instructionIndex-1);
- if (!previousInstruction.instruction.getOpcode().setsResult()) {
+ AnalyzedInstruction previousInstruction = null;
+ if (analyzedInstruction.instructionIndex > 0) {
+ previousInstruction = analyzedInstructions.valueAt(analyzedInstruction.instructionIndex-1);
+ }
+ if (previousInstruction == null || !previousInstruction.instruction.getOpcode().setsResult()) {
throw new AnalysisException(analyzedInstruction.instruction.getOpcode().name + " must occur after an " +
"invoke-*/fill-new-array instruction");
}
@@ -1061,11 +1123,11 @@ public class MethodAnalyzer {
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, exceptionType);
}
- private void analyzeReturnVoidBarrier(AnalyzedInstruction analyzedInstruction) {
- analyzeReturnVoidBarrier(analyzedInstruction, true);
+ private void analyzeOdexReturnVoid(AnalyzedInstruction analyzedInstruction) {
+ analyzeOdexReturnVoid(analyzedInstruction, true);
}
- private void analyzeReturnVoidBarrier(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) {
+ private void analyzeOdexReturnVoid(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) {
Instruction10x deodexedInstruction = new ImmutableInstruction10x(Opcode.RETURN_VOID);
analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
@@ -1109,6 +1171,44 @@ public class MethodAnalyzer {
private void analyzeInstanceOf(@Nonnull AnalyzedInstruction analyzedInstruction) {
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.BOOLEAN_TYPE);
+
+ int instructionIndex = analyzedInstruction.getInstructionIndex();
+ AnalyzedInstruction nextAnalyzedInstruction = analyzedInstructions.valueAt(instructionIndex + 1);
+
+ Instruction nextInstruction = nextAnalyzedInstruction.instruction;
+ if (nextInstruction.getOpcode() == Opcode.IF_EQZ) {
+ if (((Instruction21t)nextInstruction).getRegisterA() == analyzedInstruction.getDestinationRegister()) {
+ Reference reference = ((Instruction22c)analyzedInstruction.getInstruction()).getReference();
+ RegisterType registerType = RegisterType.getRegisterType(classPath, (TypeReference)reference);
+
+ if (registerType.type != null && !registerType.type.isInterface()) {
+ int objectRegister = ((TwoRegisterInstruction)analyzedInstruction.getInstruction()).getRegisterB();
+
+ RegisterType existingType = nextAnalyzedInstruction.getPostInstructionRegisterType(objectRegister);
+
+ if (existingType.type != null) {
+ boolean override = false;
+
+ // Only override if we're going from an interface to a class, or are going to a narrower class
+ if (existingType.type.isInterface()) {
+ override = true;
+ } else {
+ TypeProto commonSuperclass = registerType.type.getCommonSuperclass(existingType.type);
+ // only if it's a narrowing conversion
+ if (commonSuperclass.getType().equals(existingType.type.getType())) {
+ override = true;
+ }
+ }
+
+ if (override) {
+ overridePredecessorRegisterTypeAndPropagateChanges(
+ analyzedInstructions.valueAt(instructionIndex + 2), nextAnalyzedInstruction,
+ objectRegister, registerType);
+ }
+ }
+ }
+ }
+ }
}
private void analyzeArrayLength(@Nonnull AnalyzedInstruction analyzedInstruction) {
@@ -1536,12 +1636,12 @@ public class MethodAnalyzer {
ClassDef thisClass = classPath.getClassDef(method.getDefiningClass());
- if (!canAccessClass(thisClass, classPath.getClassDef(resolvedField.getDefiningClass()))) {
+ if (!TypeUtils.canAccessClass(thisClass.getType(), classPath.getClassDef(resolvedField.getDefiningClass()))) {
// the class is not accessible. So we start looking at objectRegisterTypeProto (which may be different
// than resolvedField.getDefiningClass()), and walk up the class hierarchy.
ClassDef fieldClass = classPath.getClassDef(objectRegisterTypeProto.getType());
- while (!canAccessClass(thisClass, fieldClass)) {
+ while (!TypeUtils.canAccessClass(thisClass.getType(), fieldClass)) {
String superclass = fieldClass.getSuperclass();
if (superclass == null) {
throw new ExceptionWithContext("Couldn't find accessible class while resolving field %s",
@@ -1564,8 +1664,8 @@ public class MethodAnalyzer {
String fieldType = resolvedField.getType();
- Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType,
- instruction.getOpcode());
+ Opcode opcode = classPath.getFieldInstructionMapper().getAndCheckDeodexedOpcode(
+ fieldType, instruction.getOpcode());
Instruction22c deodexedInstruction = new ImmutableInstruction22c(opcode, (byte)instruction.getRegisterA(),
(byte)instruction.getRegisterB(), resolvedField);
@@ -1576,6 +1676,75 @@ public class MethodAnalyzer {
return true;
}
+ private boolean analyzeInvokeVirtual(@Nonnull AnalyzedInstruction analyzedInstruction, boolean isRange) {
+ MethodReference targetMethod;
+
+ if (!normalizeVirtualMethods) {
+ return true;
+ }
+
+ if (isRange) {
+ Instruction3rc instruction = (Instruction3rc)analyzedInstruction.instruction;
+ targetMethod = (MethodReference)instruction.getReference();
+ } else {
+ Instruction35c instruction = (Instruction35c)analyzedInstruction.instruction;
+ targetMethod = (MethodReference)instruction.getReference();
+ }
+
+ TypeProto typeProto = classPath.getClass(targetMethod.getDefiningClass());
+ int methodIndex;
+ try {
+ methodIndex = typeProto.findMethodIndexInVtable(targetMethod);
+ } catch (UnresolvedClassException ex) {
+ return true;
+ }
+
+ if (methodIndex < 0) {
+ return true;
+ }
+
+ Method replacementMethod = typeProto.getMethodByVtableIndex(methodIndex);
+ assert replacementMethod != null;
+ while (true) {
+ String superType = typeProto.getSuperclass();
+ if (superType == null) {
+ break;
+ }
+ typeProto = classPath.getClass(superType);
+ Method resolvedMethod = typeProto.getMethodByVtableIndex(methodIndex);
+ if (resolvedMethod == null) {
+ break;
+ }
+
+ if (!resolvedMethod.equals(replacementMethod)) {
+ if (!AnalyzedMethodUtil.canAccess(typeProto, replacementMethod, true, true, true)) {
+ continue;
+ }
+
+ replacementMethod = resolvedMethod;
+ }
+ }
+
+ if (replacementMethod.equals(method)) {
+ return true;
+ }
+
+ Instruction deodexedInstruction;
+ if (isRange) {
+ Instruction3rc instruction = (Instruction3rc)analyzedInstruction.instruction;
+ deodexedInstruction = new ImmutableInstruction3rc(instruction.getOpcode(), instruction.getStartRegister(),
+ instruction.getRegisterCount(), replacementMethod);
+ } else {
+ Instruction35c instruction = (Instruction35c)analyzedInstruction.instruction;
+ deodexedInstruction = new ImmutableInstruction35c(instruction.getOpcode(), instruction.getRegisterCount(),
+ instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(),
+ instruction.getRegisterF(), instruction.getRegisterG(), replacementMethod);
+ }
+
+ analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
+ return true;
+ }
+
private boolean analyzeInvokeVirtualQuick(@Nonnull AnalyzedInstruction analyzedInstruction, boolean isSuper,
boolean isRange) {
int methodIndex;
@@ -1616,7 +1785,7 @@ public class MethodAnalyzer {
}
resolvedMethod = superType.getMethodByVtableIndex(methodIndex);
- } else{
+ } else {
resolvedMethod = objectRegisterTypeProto.getMethodByVtableIndex(methodIndex);
}
@@ -1628,12 +1797,13 @@ public class MethodAnalyzer {
// no need to check class access for invoke-super. A class can obviously access its superclass.
ClassDef thisClass = classPath.getClassDef(method.getDefiningClass());
- if (!isSuper && !canAccessClass(thisClass, classPath.getClassDef(resolvedMethod.getDefiningClass()))) {
+ if (!isSuper && !TypeUtils.canAccessClass(
+ thisClass.getType(), classPath.getClassDef(resolvedMethod.getDefiningClass()))) {
// the class is not accessible. So we start looking at objectRegisterTypeProto (which may be different
// than resolvedMethod.getDefiningClass()), and walk up the class hierarchy.
ClassDef methodClass = classPath.getClassDef(objectRegisterTypeProto.getType());
- while (!canAccessClass(thisClass, methodClass)) {
+ while (!TypeUtils.canAccessClass(thisClass.getType(), methodClass)) {
String superclass = methodClass.getSuperclass();
if (superclass == null) {
throw new ExceptionWithContext("Couldn't find accessible class while resolving method %s",
@@ -1689,24 +1859,6 @@ public class MethodAnalyzer {
return true;
}
- private boolean canAccessClass(@Nonnull ClassDef accessorClassDef, @Nonnull ClassDef accesseeClassDef) {
- if (AccessFlags.PUBLIC.isSet(accesseeClassDef.getAccessFlags())) {
- return true;
- }
-
- // Classes can only be public or package private. Any private or protected inner classes are actually
- // package private.
- return getPackage(accesseeClassDef.getType()).equals(getPackage(accessorClassDef.getType()));
- }
-
- private static String getPackage(String className) {
- int lastSlash = className.lastIndexOf('/');
- if (lastSlash < 0) {
- return "";
- }
- return className.substring(1, lastSlash);
- }
-
private boolean analyzePutGetVolatile(@Nonnull AnalyzedInstruction analyzedInstruction) {
return analyzePutGetVolatile(analyzedInstruction, true);
}
@@ -1717,12 +1869,12 @@ public class MethodAnalyzer {
Opcode originalOpcode = analyzedInstruction.instruction.getOpcode();
- Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType,
- originalOpcode);
+ Opcode opcode = classPath.getFieldInstructionMapper().getAndCheckDeodexedOpcode(
+ fieldType, originalOpcode);
Instruction deodexedInstruction;
- if (originalOpcode.isOdexedStaticVolatile()) {
+ if (originalOpcode.isStaticFieldAccessor()) {
OneRegisterInstruction instruction = (OneRegisterInstruction)analyzedInstruction.instruction;
deodexedInstruction = new ImmutableInstruction21c(opcode, instruction.getRegisterA(), field);
} else {
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/OdexedFieldInstructionMapper.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/OdexedFieldInstructionMapper.java
index 49136c35..0ed1fef1 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/OdexedFieldInstructionMapper.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/OdexedFieldInstructionMapper.java
@@ -34,155 +34,147 @@ package org.jf.dexlib2.analysis;
import org.jf.dexlib2.Opcode;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.HashMap;
+import java.util.Map;
public class OdexedFieldInstructionMapper {
- private static Opcode[][][][] opcodeMap = new Opcode[][][][] {
- //get opcodes
- new Opcode[][][] {
- //iget quick
- new Opcode[][] {
- //odexed
- new Opcode[] {
- /*Z*/ Opcode.IGET_QUICK,
- /*B*/ Opcode.IGET_QUICK,
- /*S*/ Opcode.IGET_QUICK,
- /*C*/ Opcode.IGET_QUICK,
- /*I,F*/ Opcode.IGET_QUICK,
- /*J,D*/ Opcode.IGET_WIDE_QUICK,
- /*L,[*/ Opcode.IGET_OBJECT_QUICK
- },
- //deodexed
- new Opcode[] {
- /*Z*/ Opcode.IGET_BOOLEAN,
- /*B*/ Opcode.IGET_BYTE,
- /*S*/ Opcode.IGET_SHORT,
- /*C*/ Opcode.IGET_CHAR,
- /*I,F*/ Opcode.IGET,
- /*J,D*/ Opcode.IGET_WIDE,
- /*L,[*/ Opcode.IGET_OBJECT
- }
- },
- //iget volatile
- new Opcode[][] {
- //odexed
- new Opcode[] {
- /*Z*/ Opcode.IGET_VOLATILE,
- /*B*/ Opcode.IGET_VOLATILE,
- /*S*/ Opcode.IGET_VOLATILE,
- /*C*/ Opcode.IGET_VOLATILE,
- /*I,F*/ Opcode.IGET_VOLATILE,
- /*J,D*/ Opcode.IGET_WIDE_VOLATILE,
- /*L,[*/ Opcode.IGET_OBJECT_VOLATILE
- },
- //deodexed
- new Opcode[] {
- /*Z*/ Opcode.IGET_BOOLEAN,
- /*B*/ Opcode.IGET_BYTE,
- /*S*/ Opcode.IGET_SHORT,
- /*C*/ Opcode.IGET_CHAR,
- /*I,F*/ Opcode.IGET,
- /*J,D*/ Opcode.IGET_WIDE,
- /*L,[*/ Opcode.IGET_OBJECT
- }
- },
- //sget volatile
- new Opcode[][] {
- //odexed
- new Opcode[] {
- /*Z*/ Opcode.SGET_VOLATILE,
- /*B*/ Opcode.SGET_VOLATILE,
- /*S*/ Opcode.SGET_VOLATILE,
- /*C*/ Opcode.SGET_VOLATILE,
- /*I,F*/ Opcode.SGET_VOLATILE,
- /*J,D*/ Opcode.SGET_WIDE_VOLATILE,
- /*L,[*/ Opcode.SGET_OBJECT_VOLATILE
- },
- //deodexed
- new Opcode[] {
- /*Z*/ Opcode.SGET_BOOLEAN,
- /*B*/ Opcode.SGET_BYTE,
- /*S*/ Opcode.SGET_SHORT,
- /*C*/ Opcode.SGET_CHAR,
- /*I,F*/ Opcode.SGET,
- /*J,D*/ Opcode.SGET_WIDE,
- /*L,[*/ Opcode.SGET_OBJECT
- }
- }
- },
- //put opcodes
- new Opcode[][][] {
- //iput quick
- new Opcode[][] {
- //odexed
- new Opcode[] {
- /*Z*/ Opcode.IPUT_QUICK,
- /*B*/ Opcode.IPUT_QUICK,
- /*S*/ Opcode.IPUT_QUICK,
- /*C*/ Opcode.IPUT_QUICK,
- /*I,F*/ Opcode.IPUT_QUICK,
- /*J,D*/ Opcode.IPUT_WIDE_QUICK,
- /*L,[*/ Opcode.IPUT_OBJECT_QUICK
- },
- //deodexed
- new Opcode[] {
- /*Z*/ Opcode.IPUT_BOOLEAN,
- /*B*/ Opcode.IPUT_BYTE,
- /*S*/ Opcode.IPUT_SHORT,
- /*C*/ Opcode.IPUT_CHAR,
- /*I,F*/ Opcode.IPUT,
- /*J,D*/ Opcode.IPUT_WIDE,
- /*L,[*/ Opcode.IPUT_OBJECT
- }
- },
- //iput volatile
- new Opcode[][] {
- //odexed
- new Opcode[] {
- /*Z*/ Opcode.IPUT_VOLATILE,
- /*B*/ Opcode.IPUT_VOLATILE,
- /*S*/ Opcode.IPUT_VOLATILE,
- /*C*/ Opcode.IPUT_VOLATILE,
- /*I,F*/ Opcode.IPUT_VOLATILE,
- /*J,D*/ Opcode.IPUT_WIDE_VOLATILE,
- /*L,[*/ Opcode.IPUT_OBJECT_VOLATILE
- },
- //deodexed
- new Opcode[] {
- /*Z*/ Opcode.IPUT_BOOLEAN,
- /*B*/ Opcode.IPUT_BYTE,
- /*S*/ Opcode.IPUT_SHORT,
- /*C*/ Opcode.IPUT_CHAR,
- /*I,F*/ Opcode.IPUT,
- /*J,D*/ Opcode.IPUT_WIDE,
- /*L,[*/ Opcode.IPUT_OBJECT
- }
- },
- //sput volatile
- new Opcode[][] {
- //odexed
- new Opcode[] {
- /*Z*/ Opcode.SPUT_VOLATILE,
- /*B*/ Opcode.SPUT_VOLATILE,
- /*S*/ Opcode.SPUT_VOLATILE,
- /*C*/ Opcode.SPUT_VOLATILE,
- /*I,F*/ Opcode.SPUT_VOLATILE,
- /*J,D*/ Opcode.SPUT_WIDE_VOLATILE,
- /*L,[*/ Opcode.SPUT_OBJECT_VOLATILE
- },
- //deodexed
- new Opcode[] {
- /*Z*/ Opcode.SPUT_BOOLEAN,
- /*B*/ Opcode.SPUT_BYTE,
- /*S*/ Opcode.SPUT_SHORT,
- /*C*/ Opcode.SPUT_CHAR,
- /*I,F*/ Opcode.SPUT,
- /*J,D*/ Opcode.SPUT_WIDE,
- /*L,[*/ Opcode.SPUT_OBJECT
- }
- }
- }
+
+ private static final int GET = 0;
+ private static final int PUT = 1;
+
+ private static final int INSTANCE = 0;
+ private static final int STATIC = 1;
+
+ private static final int PRIMITIVE = 0;
+ private static final int WIDE = 1;
+ private static final int REFERENCE = 2;
+
+ private static class FieldOpcode {
+ public final char type;
+ public final boolean isStatic;
+ @Nonnull public final Opcode normalOpcode;
+ @Nullable public final Opcode quickOpcode;
+ @Nullable public final Opcode volatileOpcode;
+
+ public FieldOpcode(char type, @Nonnull Opcode normalOpcode, @Nullable Opcode quickOpcode,
+ @Nullable Opcode volatileOpcode) {
+ this.type = type;
+ this.isStatic = false;
+ this.normalOpcode = normalOpcode;
+ this.quickOpcode = quickOpcode;
+ this.volatileOpcode = volatileOpcode;
+ }
+
+ public FieldOpcode(char type, boolean isStatic, @Nonnull Opcode normalOpcode, @Nullable Opcode volatileOpcode) {
+ this.type = type;
+ this.isStatic = isStatic;
+ this.normalOpcode = normalOpcode;
+ this.quickOpcode = null;
+ this.volatileOpcode = volatileOpcode;
+ }
+
+ public FieldOpcode(char type, @Nonnull Opcode normalOpcode, @Nullable Opcode quickOpcode) {
+ this.type = type;
+ this.isStatic = false;
+ this.normalOpcode = normalOpcode;
+ this.quickOpcode = quickOpcode;
+ this.volatileOpcode = null;
+ }
+ }
+
+ private static final FieldOpcode[] dalvikFieldOpcodes = new FieldOpcode[] {
+ new FieldOpcode('Z', Opcode.IGET_BOOLEAN, Opcode.IGET_QUICK, Opcode.IGET_VOLATILE),
+ new FieldOpcode('B', Opcode.IGET_BYTE, Opcode.IGET_QUICK, Opcode.IGET_VOLATILE),
+ new FieldOpcode('S', Opcode.IGET_SHORT, Opcode.IGET_QUICK, Opcode.IGET_VOLATILE),
+ new FieldOpcode('C', Opcode.IGET_CHAR, Opcode.IGET_QUICK, Opcode.IGET_VOLATILE),
+ new FieldOpcode('I', Opcode.IGET, Opcode.IGET_QUICK, Opcode.IGET_VOLATILE),
+ new FieldOpcode('F', Opcode.IGET, Opcode.IGET_QUICK, Opcode.IGET_VOLATILE),
+ new FieldOpcode('J', Opcode.IGET_WIDE, Opcode.IGET_WIDE_QUICK, Opcode.IGET_WIDE_VOLATILE),
+ new FieldOpcode('D', Opcode.IGET_WIDE, Opcode.IGET_WIDE_QUICK, Opcode.IGET_WIDE_VOLATILE),
+ new FieldOpcode('L', Opcode.IGET_OBJECT, Opcode.IGET_OBJECT_QUICK, Opcode.IGET_OBJECT_VOLATILE),
+ new FieldOpcode('[', Opcode.IGET_OBJECT, Opcode.IGET_OBJECT_QUICK, Opcode.IGET_OBJECT_VOLATILE),
+
+ new FieldOpcode('Z', Opcode.IPUT_BOOLEAN, Opcode.IPUT_QUICK, Opcode.IPUT_VOLATILE),
+ new FieldOpcode('B', Opcode.IPUT_BYTE, Opcode.IPUT_QUICK, Opcode.IPUT_VOLATILE),
+ new FieldOpcode('S', Opcode.IPUT_SHORT, Opcode.IPUT_QUICK, Opcode.IPUT_VOLATILE),
+ new FieldOpcode('C', Opcode.IPUT_CHAR, Opcode.IPUT_QUICK, Opcode.IPUT_VOLATILE),
+ new FieldOpcode('I', Opcode.IPUT, Opcode.IPUT_QUICK, Opcode.IPUT_VOLATILE),
+ new FieldOpcode('F', Opcode.IPUT, Opcode.IPUT_QUICK, Opcode.IPUT_VOLATILE),
+ new FieldOpcode('J', Opcode.IPUT_WIDE, Opcode.IPUT_WIDE_QUICK, Opcode.IPUT_WIDE_VOLATILE),
+ new FieldOpcode('D', Opcode.IPUT_WIDE, Opcode.IPUT_WIDE_QUICK, Opcode.IPUT_WIDE_VOLATILE),
+ new FieldOpcode('L', Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT_QUICK, Opcode.IPUT_OBJECT_VOLATILE),
+ new FieldOpcode('[', Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT_QUICK, Opcode.IPUT_OBJECT_VOLATILE),
+
+ new FieldOpcode('Z', true, Opcode.SPUT_BOOLEAN, Opcode.SPUT_VOLATILE),
+ new FieldOpcode('B', true, Opcode.SPUT_BYTE, Opcode.SPUT_VOLATILE),
+ new FieldOpcode('S', true, Opcode.SPUT_SHORT, Opcode.SPUT_VOLATILE),
+ new FieldOpcode('C', true, Opcode.SPUT_CHAR, Opcode.SPUT_VOLATILE),
+ new FieldOpcode('I', true, Opcode.SPUT, Opcode.SPUT_VOLATILE),
+ new FieldOpcode('F', true, Opcode.SPUT, Opcode.SPUT_VOLATILE),
+ new FieldOpcode('J', true, Opcode.SPUT_WIDE, Opcode.SPUT_WIDE_VOLATILE),
+ new FieldOpcode('D', true, Opcode.SPUT_WIDE, Opcode.SPUT_WIDE_VOLATILE),
+ new FieldOpcode('L', true, Opcode.SPUT_OBJECT, Opcode.SPUT_OBJECT_VOLATILE),
+ new FieldOpcode('[', true, Opcode.SPUT_OBJECT, Opcode.SPUT_OBJECT_VOLATILE),
+
+ new FieldOpcode('Z', true, Opcode.SGET_BOOLEAN, Opcode.SGET_VOLATILE),
+ new FieldOpcode('B', true, Opcode.SGET_BYTE, Opcode.SGET_VOLATILE),
+ new FieldOpcode('S', true, Opcode.SGET_SHORT, Opcode.SGET_VOLATILE),
+ new FieldOpcode('C', true, Opcode.SGET_CHAR, Opcode.SGET_VOLATILE),
+ new FieldOpcode('I', true, Opcode.SGET, Opcode.SGET_VOLATILE),
+ new FieldOpcode('F', true, Opcode.SGET, Opcode.SGET_VOLATILE),
+ new FieldOpcode('J', true, Opcode.SGET_WIDE, Opcode.SGET_WIDE_VOLATILE),
+ new FieldOpcode('D', true, Opcode.SGET_WIDE, Opcode.SGET_WIDE_VOLATILE),
+ new FieldOpcode('L', true, Opcode.SGET_OBJECT, Opcode.SGET_OBJECT_VOLATILE),
+ new FieldOpcode('[', true, Opcode.SGET_OBJECT, Opcode.SGET_OBJECT_VOLATILE),
};
+ private static final FieldOpcode[] artFieldOpcodes = new FieldOpcode[] {
+ new FieldOpcode('Z', Opcode.IGET_BOOLEAN, Opcode.IGET_BOOLEAN_QUICK),
+ new FieldOpcode('B', Opcode.IGET_BYTE, Opcode.IGET_BYTE_QUICK),
+ new FieldOpcode('S', Opcode.IGET_SHORT, Opcode.IGET_SHORT_QUICK),
+ new FieldOpcode('C', Opcode.IGET_CHAR, Opcode.IGET_CHAR_QUICK),
+ new FieldOpcode('I', Opcode.IGET, Opcode.IGET_QUICK),
+ new FieldOpcode('F', Opcode.IGET, Opcode.IGET_QUICK),
+ new FieldOpcode('J', Opcode.IGET_WIDE, Opcode.IGET_WIDE_QUICK),
+ new FieldOpcode('D', Opcode.IGET_WIDE, Opcode.IGET_WIDE_QUICK),
+ new FieldOpcode('L', Opcode.IGET_OBJECT, Opcode.IGET_OBJECT_QUICK),
+ new FieldOpcode('[', Opcode.IGET_OBJECT, Opcode.IGET_OBJECT_QUICK),
+
+ new FieldOpcode('Z', Opcode.IPUT_BOOLEAN, Opcode.IPUT_BOOLEAN_QUICK),
+ new FieldOpcode('B', Opcode.IPUT_BYTE, Opcode.IPUT_BYTE_QUICK),
+ new FieldOpcode('S', Opcode.IPUT_SHORT, Opcode.IPUT_SHORT_QUICK),
+ new FieldOpcode('C', Opcode.IPUT_CHAR, Opcode.IPUT_CHAR_QUICK),
+ new FieldOpcode('I', Opcode.IPUT, Opcode.IPUT_QUICK),
+ new FieldOpcode('F', Opcode.IPUT, Opcode.IPUT_QUICK),
+ new FieldOpcode('J', Opcode.IPUT_WIDE, Opcode.IPUT_WIDE_QUICK),
+ new FieldOpcode('D', Opcode.IPUT_WIDE, Opcode.IPUT_WIDE_QUICK),
+ new FieldOpcode('L', Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT_QUICK),
+ new FieldOpcode('[', Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT_QUICK)
+ };
+
+ private final FieldOpcode[][][] opcodeMap = new FieldOpcode[2][2][10];
+ private final Map<Opcode, Integer> opcodeValueTypeMap = new HashMap<Opcode, Integer>(30);
+
+ private static int getValueType(char type) {
+ switch (type) {
+ case 'Z':
+ case 'B':
+ case 'S':
+ case 'C':
+ case 'I':
+ case 'F':
+ return PRIMITIVE;
+ case 'J':
+ case 'D':
+ return WIDE;
+ case 'L':
+ case '[':
+ return REFERENCE;
+ }
+ throw new RuntimeException(String.format("Unknown type %s: ", type));
+ }
+
private static int getTypeIndex(char type) {
switch (type) {
case 'Z':
@@ -194,47 +186,71 @@ public class OdexedFieldInstructionMapper {
case 'C':
return 3;
case 'I':
- case 'F':
return 4;
+ case 'F':
+ return 5;
case 'J':
+ return 6;
case 'D':
- return 5;
+ return 7;
case 'L':
+ return 8;
case '[':
- return 6;
- default:
+ return 9;
}
throw new RuntimeException(String.format("Unknown type %s: ", type));
}
- private static int getOpcodeSubtype(@Nonnull Opcode opcode) {
- if (opcode.isOdexedInstanceQuick()) {
- return 0;
- } else if (opcode.isOdexedInstanceVolatile()) {
- return 1;
- } else if (opcode.isOdexedStaticVolatile()) {
- return 2;
- }
- throw new RuntimeException(String.format("Not an odexed field access opcode: %s", opcode.name));
+ private static boolean isGet(@Nonnull Opcode opcode) {
+ return (opcode.flags & Opcode.SETS_REGISTER) != 0;
}
- @Nonnull
- static Opcode getAndCheckDeodexedOpcodeForOdexedOpcode(@Nonnull String fieldType, @Nonnull Opcode odexedOpcode) {
- int opcodeType = odexedOpcode.setsRegister()?0:1;
- int opcodeSubType = getOpcodeSubtype(odexedOpcode);
- int typeIndex = getTypeIndex(fieldType.charAt(0));
+ private static boolean isStatic(@Nonnull Opcode opcode) {
+ return (opcode.flags & Opcode.STATIC_FIELD_ACCESSOR) != 0;
+ }
- Opcode correctOdexedOpcode, deodexedOpcode;
+ public OdexedFieldInstructionMapper(boolean isArt) {
+ FieldOpcode[] opcodes;
+ if (isArt) {
+ opcodes = artFieldOpcodes;
+ } else {
+ opcodes = dalvikFieldOpcodes;
+ }
- correctOdexedOpcode = opcodeMap[opcodeType][opcodeSubType][0][typeIndex];
- deodexedOpcode = opcodeMap[opcodeType][opcodeSubType][1][typeIndex];
+ for (FieldOpcode fieldOpcode: opcodes) {
+ opcodeMap[isGet(fieldOpcode.normalOpcode)?GET:PUT]
+ [isStatic(fieldOpcode.normalOpcode)?STATIC:INSTANCE]
+ [getTypeIndex(fieldOpcode.type)] = fieldOpcode;
- if (correctOdexedOpcode != odexedOpcode) {
+ if (fieldOpcode.quickOpcode != null) {
+ opcodeValueTypeMap.put(fieldOpcode.quickOpcode, getValueType(fieldOpcode.type));
+ }
+ if (fieldOpcode.volatileOpcode != null) {
+ opcodeValueTypeMap.put(fieldOpcode.volatileOpcode, getValueType(fieldOpcode.type));
+ }
+ }
+ }
+
+ @Nonnull
+ public Opcode getAndCheckDeodexedOpcode(@Nonnull String fieldType, @Nonnull Opcode odexedOpcode) {
+ FieldOpcode fieldOpcode = opcodeMap[isGet(odexedOpcode)?GET:PUT]
+ [isStatic(odexedOpcode)?STATIC:INSTANCE]
+ [getTypeIndex(fieldType.charAt(0))];
+
+ if (!isCompatible(odexedOpcode, fieldOpcode.type)) {
throw new AnalysisException(String.format("Incorrect field type \"%s\" for %s", fieldType,
odexedOpcode.name));
}
- return deodexedOpcode;
+ return fieldOpcode.normalOpcode;
+ }
+
+ private boolean isCompatible(Opcode opcode, char type) {
+ Integer valueType = opcodeValueTypeMap.get(opcode);
+ if (valueType == null) {
+ throw new RuntimeException("Unexpected opcode: " + opcode.name);
+ }
+ return valueType == getValueType(type);
}
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/PrimitiveProto.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/PrimitiveProto.java
index 06ab8e17..2c283932 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/PrimitiveProto.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/PrimitiveProto.java
@@ -31,6 +31,7 @@
package org.jf.dexlib2.analysis;
+import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.util.ExceptionWithContext;
@@ -65,7 +66,11 @@ public class PrimitiveProto implements TypeProto {
@Override
@Nullable
- public MethodReference getMethodByVtableIndex(int vtableIndex) {
+ public Method getMethodByVtableIndex(int vtableIndex) {
return null;
}
+
+ @Override public int findMethodIndexInVtable(@Nonnull MethodReference method) {
+ return -1;
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/TypeProto.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/TypeProto.java
index f6db2399..776363b8 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/TypeProto.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/TypeProto.java
@@ -31,6 +31,7 @@
package org.jf.dexlib2.analysis;
+import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
@@ -45,5 +46,6 @@ public interface TypeProto {
@Nullable String getSuperclass();
@Nonnull TypeProto getCommonSuperclass(@Nonnull TypeProto other);
@Nullable FieldReference getFieldByOffset(int fieldOffset);
- @Nullable MethodReference getMethodByVtableIndex(int vtableIndex);
+ @Nullable Method getMethodByVtableIndex(int vtableIndex);
+ int findMethodIndexInVtable(@Nonnull MethodReference method);
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/UnknownClassProto.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/UnknownClassProto.java
index 38256fbe..32873456 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/UnknownClassProto.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/UnknownClassProto.java
@@ -31,6 +31,7 @@
package org.jf.dexlib2.analysis;
+import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
@@ -75,7 +76,11 @@ public class UnknownClassProto implements TypeProto {
@Override
@Nullable
- public MethodReference getMethodByVtableIndex(int vtableIndex) {
+ public Method getMethodByVtableIndex(int vtableIndex) {
return classPath.getClass("Ljava/lang/Object;").getMethodByVtableIndex(vtableIndex);
}
+
+ @Override public int findMethodIndexInVtable(@Nonnull MethodReference method) {
+ return classPath.getClass("Ljava/lang/Object;").findMethodIndexInVtable(method);
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/util/TypeProtoUtils.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/util/TypeProtoUtils.java
index 0313c7c3..e2adf1c4 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/util/TypeProtoUtils.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/util/TypeProtoUtils.java
@@ -94,4 +94,16 @@ public class TypeProtoUtils {
return type.getClassPath().getUnknownClass();
}
}
+
+ public static boolean extendsFrom(@Nonnull TypeProto candidate, @Nonnull String possibleSuper) {
+ if (candidate.getType().equals(possibleSuper)) {
+ return true;
+ }
+ for (TypeProto superProto: getSuperclassChain(candidate)) {
+ if (superProto.getType().equals(possibleSuper)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java b/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java
index 84981221..b1e5dbbf 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/builder/MutableMethodImplementation.java
@@ -482,6 +482,49 @@ public class MutableMethodImplementation implements MethodImplementation {
} while (true);
}
+ private int mapCodeAddressToIndex(int codeAddress) {
+ float avgCodeUnitsPerInstruction = 1.9f;
+
+ int index = (int)(codeAddress/avgCodeUnitsPerInstruction);
+ if (index >= instructionList.size()) {
+ index = instructionList.size() - 1;
+ }
+
+ MethodLocation guessedLocation = instructionList.get(index);
+
+ if (guessedLocation.codeAddress == codeAddress) {
+ return index;
+ } else if (guessedLocation.codeAddress > codeAddress) {
+ do {
+ index--;
+ } while (instructionList.get(index).codeAddress > codeAddress);
+ return index;
+ } else {
+ do {
+ index++;
+ } while (index < instructionList.size() && instructionList.get(index).codeAddress <= codeAddress);
+ return index-1;
+ }
+ }
+
+ @Nonnull
+ public Label newLabelForAddress(int codeAddress) {
+ if (codeAddress < 0 || codeAddress > instructionList.get(instructionList.size()-1).codeAddress) {
+ throw new IndexOutOfBoundsException(String.format("codeAddress %d out of bounds", codeAddress));
+ }
+ MethodLocation referent = instructionList.get(mapCodeAddressToIndex(codeAddress));
+ return referent.addNewLabel();
+ }
+
+ @Nonnull
+ public Label newLabelForIndex(int instructionIndex) {
+ if (instructionIndex < 0 || instructionIndex >= instructionList.size()) {
+ throw new IndexOutOfBoundsException(String.format("instruction index %d out of bounds", instructionIndex));
+ }
+ MethodLocation referent = instructionList.get(instructionIndex);
+ return referent.addNewLabel();
+ }
+
@Nonnull
private Label newLabel(@Nonnull int[] codeAddressToIndex, int codeAddress) {
MethodLocation referent = instructionList.get(mapCodeAddressToIndex(codeAddressToIndex, codeAddress));
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java
index 7d06bff7..eeb28227 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java
@@ -37,13 +37,19 @@ import javax.annotation.Nonnull;
public class BaseDexBuffer {
@Nonnull /* package private */ final byte[] buf;
+ /* package private */ final int baseOffset;
public BaseDexBuffer(@Nonnull byte[] buf) {
+ this(buf, 0);
+ }
+ public BaseDexBuffer(@Nonnull byte[] buf, int offset) {
this.buf = buf;
+ this.baseOffset = offset;
}
public int readSmallUint(int offset) {
byte[] buf = this.buf;
+ offset += baseOffset;
int result = (buf[offset] & 0xff) |
((buf[offset+1] & 0xff) << 8) |
((buf[offset+2] & 0xff) << 16) |
@@ -56,6 +62,7 @@ public class BaseDexBuffer {
public int readOptionalUint(int offset) {
byte[] buf = this.buf;
+ offset += baseOffset;
int result = (buf[offset] & 0xff) |
((buf[offset+1] & 0xff) << 8) |
((buf[offset+2] & 0xff) << 16) |
@@ -68,16 +75,18 @@ public class BaseDexBuffer {
public int readUshort(int offset) {
byte[] buf = this.buf;
+ offset += baseOffset;
return (buf[offset] & 0xff) |
((buf[offset+1] & 0xff) << 8);
}
public int readUbyte(int offset) {
- return buf[offset] & 0xff;
+ return buf[offset + baseOffset] & 0xff;
}
public long readLong(int offset) {
byte[] buf = this.buf;
+ offset += baseOffset;
return (buf[offset] & 0xff) |
((buf[offset+1] & 0xff) << 8) |
((buf[offset+2] & 0xff) << 16) |
@@ -88,8 +97,26 @@ public class BaseDexBuffer {
(((long)buf[offset+7]) << 56);
}
+ public int readLongAsSmallUint(int offset) {
+ byte[] buf = this.buf;
+ offset += baseOffset;
+ long result = (buf[offset] & 0xff) |
+ ((buf[offset+1] & 0xff) << 8) |
+ ((buf[offset+2] & 0xff) << 16) |
+ ((buf[offset+3] & 0xffL) << 24) |
+ ((buf[offset+4] & 0xffL) << 32) |
+ ((buf[offset+5] & 0xffL) << 40) |
+ ((buf[offset+6] & 0xffL) << 48) |
+ (((long)buf[offset+7]) << 56);
+ if (result < 0 || result > Integer.MAX_VALUE) {
+ throw new ExceptionWithContext("Encountered out-of-range ulong at offset 0x%x", offset);
+ }
+ return (int)result;
+ }
+
public int readInt(int offset) {
byte[] buf = this.buf;
+ offset += baseOffset;
return (buf[offset] & 0xff) |
((buf[offset+1] & 0xff) << 8) |
((buf[offset+2] & 0xff) << 16) |
@@ -98,12 +125,13 @@ public class BaseDexBuffer {
public int readShort(int offset) {
byte[] buf = this.buf;
+ offset += baseOffset;
return (buf[offset] & 0xff) |
(buf[offset+1] << 8);
}
public int readByte(int offset) {
- return buf[offset];
+ return buf[baseOffset + offset];
}
@Nonnull
@@ -115,4 +143,8 @@ public class BaseDexBuffer {
protected byte[] getBuf() {
return buf;
}
+
+ protected int getBaseOffset() {
+ return baseOffset;
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java
index 96645b8c..13c0a7b0 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java
@@ -49,7 +49,7 @@ public class BaseDexReader<T extends BaseDexBuffer> {
public void setOffset(int offset) { this.offset = offset; }
public int readSleb128() {
- int end = offset;
+ int end = dexBuf.baseOffset + offset;
int currentByteValue;
int result;
byte[] buf = dexBuf.buf;
@@ -84,7 +84,7 @@ public class BaseDexReader<T extends BaseDexBuffer> {
}
}
- offset = end;
+ offset = end - dexBuf.baseOffset;
return result;
}
@@ -93,7 +93,7 @@ public class BaseDexReader<T extends BaseDexBuffer> {
}
private int readUleb128(boolean allowLarge) {
- int end = offset;
+ int end = dexBuf.baseOffset + offset;
int currentByteValue;
int result;
byte[] buf = dexBuf.buf;
@@ -129,7 +129,7 @@ public class BaseDexReader<T extends BaseDexBuffer> {
}
}
- offset = end;
+ offset = end - dexBuf.baseOffset;
return result;
}
@@ -150,7 +150,7 @@ public class BaseDexReader<T extends BaseDexBuffer> {
* @return The unsigned value, reinterpreted as a signed int
*/
public int readBigUleb128() {
- int end = offset;
+ int end = dexBuf.baseOffset + offset;
int currentByteValue;
int result;
byte[] buf = dexBuf.buf;
@@ -179,12 +179,12 @@ public class BaseDexReader<T extends BaseDexBuffer> {
}
}
- offset = end;
+ offset = end - dexBuf.baseOffset;
return result;
}
public void skipUleb128() {
- int end = offset;
+ int end = dexBuf.baseOffset + offset;
byte currentByteValue;
byte[] buf = dexBuf.buf;
@@ -206,7 +206,7 @@ public class BaseDexReader<T extends BaseDexBuffer> {
}
}
- offset = end;
+ offset = end - dexBuf.baseOffset;
}
public int readSmallUint() {
@@ -285,7 +285,7 @@ public class BaseDexReader<T extends BaseDexBuffer> {
public int readByte(int offset) { return dexBuf.readByte(offset); }
public int readSizedInt(int bytes) {
- int o = offset;
+ int o = dexBuf.baseOffset + offset;
byte[] buf = dexBuf.buf;
int result;
@@ -311,12 +311,12 @@ public class BaseDexReader<T extends BaseDexBuffer> {
default:
throw new ExceptionWithContext("Invalid size %d for sized int at offset 0x%x", bytes, offset);
}
- offset = o + bytes;
+ offset = o + bytes - dexBuf.baseOffset;
return result;
}
public int readSizedSmallUint(int bytes) {
- int o = offset;
+ int o = dexBuf.baseOffset + offset;
byte[] buf = dexBuf.buf;
int result = 0;
@@ -341,12 +341,12 @@ public class BaseDexReader<T extends BaseDexBuffer> {
default:
throw new ExceptionWithContext("Invalid size %d for sized uint at offset 0x%x", bytes, offset);
}
- offset = o + bytes;
+ offset = o + bytes - dexBuf.baseOffset;
return result;
}
public int readSizedRightExtendedInt(int bytes) {
- int o = offset;
+ int o = dexBuf.baseOffset + offset;
byte[] buf = dexBuf.buf;
int result;
@@ -373,12 +373,12 @@ public class BaseDexReader<T extends BaseDexBuffer> {
throw new ExceptionWithContext(
"Invalid size %d for sized, right extended int at offset 0x%x", bytes, offset);
}
- offset = o + bytes;
+ offset = o + bytes - dexBuf.baseOffset;
return result;
}
public long readSizedRightExtendedLong(int bytes) {
- int o = offset;
+ int o = dexBuf.baseOffset + offset;
byte[] buf = dexBuf.buf;
long result;
@@ -439,12 +439,12 @@ public class BaseDexReader<T extends BaseDexBuffer> {
throw new ExceptionWithContext(
"Invalid size %d for sized, right extended long at offset 0x%x", bytes, offset);
}
- offset = o + bytes;
+ offset = o + bytes - dexBuf.baseOffset;
return result;
}
public long readSizedLong(int bytes) {
- int o = offset;
+ int o = dexBuf.baseOffset + offset;
byte[] buf = dexBuf.buf;
long result;
@@ -505,13 +505,14 @@ public class BaseDexReader<T extends BaseDexBuffer> {
throw new ExceptionWithContext("Invalid size %d for sized long at offset 0x%x", bytes, offset);
}
- offset = o + bytes;
+ offset = o + bytes - dexBuf.baseOffset;
return result;
}
public String readString(int utf16Length) {
int[] ret = new int[1];
- String value = Utf8Utils.utf8BytesWithUtf16LengthToString(dexBuf.buf, offset, utf16Length, ret);
+ String value = Utf8Utils.utf8BytesWithUtf16LengthToString(
+ dexBuf.buf, dexBuf.baseOffset + offset, utf16Length, ret);
offset += ret[0];
return value;
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java
index 1774096e..32505eec 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java
@@ -46,7 +46,7 @@ import java.io.InputStream;
import java.util.Set;
public class DexBackedDexFile extends BaseDexBuffer implements DexFile {
- private final Opcodes opcodes;
+ @Nonnull private final Opcodes opcodes;
private final int stringCount;
private final int stringStartOffset;
@@ -61,8 +61,8 @@ public class DexBackedDexFile extends BaseDexBuffer implements DexFile {
private final int classCount;
private final int classStartOffset;
- private DexBackedDexFile(Opcodes opcodes, @Nonnull byte[] buf, int offset, boolean verifyMagic) {
- super(buf);
+ private DexBackedDexFile(@Nonnull Opcodes opcodes, @Nonnull byte[] buf, int offset, boolean verifyMagic) {
+ super(buf, offset);
this.opcodes = opcodes;
@@ -117,14 +117,20 @@ public class DexBackedDexFile extends BaseDexBuffer implements DexFile {
return new DexBackedDexFile(opcodes, buf, 0, false);
}
- public Opcodes getOpcodes() {
+ @Override @Nonnull public Opcodes getOpcodes() {
return opcodes;
}
+ // Will only be true for a dalvik-style odex file
public boolean isOdexFile() {
return false;
}
+ // Will be true for both a dalvik-style odex file, and an art-style odex file embedded in an oat file
+ public boolean hasOdexOpcodes() {
+ return false;
+ }
+
@Nonnull
@Override
public Set<? extends DexBackedClassDef> getClasses() {
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedOdexFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedOdexFile.java
index 1aa9c1eb..12f19db0 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedOdexFile.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedOdexFile.java
@@ -33,7 +33,6 @@ package org.jf.dexlib2.dexbacked;
import com.google.common.io.ByteStreams;
import org.jf.dexlib2.Opcodes;
-import org.jf.dexlib2.dexbacked.raw.HeaderItem;
import org.jf.dexlib2.dexbacked.raw.OdexHeaderItem;
import org.jf.dexlib2.dexbacked.util.VariableSizeList;
@@ -61,6 +60,10 @@ public class DexBackedOdexFile extends DexBackedDexFile {
return true;
}
+ @Override public boolean hasOdexOpcodes() {
+ return true;
+ }
+
public List<String> getDependencies() {
final int dexOffset = OdexHeaderItem.getDexOffset(odexBuf);
final int dependencyOffset = OdexHeaderItem.getDependenciesOffset(odexBuf) - dexOffset;
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/OatFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/OatFile.java
new file mode 100644
index 00000000..dbeb67ce
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/OatFile.java
@@ -0,0 +1,496 @@
+/*
+ * Copyright 2014, 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.dexlib2.dexbacked;
+
+import com.google.common.io.ByteStreams;
+import org.jf.dexlib2.Opcodes;
+import org.jf.dexlib2.dexbacked.OatFile.SymbolTable.Symbol;
+import org.jf.dexlib2.dexbacked.raw.HeaderItem;
+import org.jf.util.AbstractForwardSequentialList;
+
+import javax.annotation.Nonnull;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.util.AbstractList;
+import java.util.Iterator;
+import java.util.List;
+
+public class OatFile extends BaseDexBuffer {
+ private static final byte[] ELF_MAGIC = new byte[] { 0x7f, 'E', 'L', 'F' };
+ private static final byte[] OAT_MAGIC = new byte[] { 'o', 'a', 't', '\n' };
+ private static final int MIN_ELF_HEADER_SIZE = 52;
+
+ // These are the "known working" versions that I have manually inspected the source for.
+ // Later version may or may not work, depending on what changed.
+ private static final int MIN_OAT_VERSION = 56;
+ private static final int MAX_OAT_VERSION = 71;
+
+ public static final int UNSUPPORTED = 0;
+ public static final int SUPPORTED = 1;
+ public static final int UNKNOWN = 2;
+
+ private final boolean is64bit;
+ @Nonnull private final OatHeader oatHeader;
+ @Nonnull private final Opcodes opcodes;
+
+ public OatFile(@Nonnull byte[] buf) {
+ super(buf);
+
+ if (buf.length < MIN_ELF_HEADER_SIZE) {
+ throw new NotAnOatFileException();
+ }
+
+ verifyMagic(buf);
+
+ if (buf[4] == 1) {
+ is64bit = false;
+ } else if (buf[4] == 2) {
+ is64bit = true;
+ } else {
+ throw new InvalidOatFileException(String.format("Invalid word-size value: %x", buf[5]));
+ }
+
+ OatHeader oatHeader = null;
+ SymbolTable symbolTable = getSymbolTable();
+ for (Symbol symbol: symbolTable.getSymbols()) {
+ if (symbol.getName().equals("oatdata")) {
+ oatHeader = new OatHeader(symbol.getFileOffset());
+ break;
+ }
+ }
+
+ if (oatHeader == null) {
+ throw new InvalidOatFileException("Oat file has no oatdata symbol");
+ }
+ this.oatHeader = oatHeader;
+
+ if (!oatHeader.isValid()) {
+ throw new InvalidOatFileException("Invalid oat magic value");
+ }
+
+ this.opcodes = Opcodes.forArtVersion(oatHeader.getVersion());
+ }
+
+ private static void verifyMagic(byte[] buf) {
+ for (int i = 0; i < ELF_MAGIC.length; i++) {
+ if (buf[i] != ELF_MAGIC[i]) {
+ throw new NotAnOatFileException();
+ }
+ }
+ }
+
+ public static OatFile fromInputStream(@Nonnull InputStream is)
+ throws IOException {
+ if (!is.markSupported()) {
+ throw new IllegalArgumentException("InputStream must support mark");
+ }
+ is.mark(4);
+ byte[] partialHeader = new byte[4];
+ try {
+ ByteStreams.readFully(is, partialHeader);
+ } catch (EOFException ex) {
+ throw new NotAnOatFileException();
+ } finally {
+ is.reset();
+ }
+
+ verifyMagic(partialHeader);
+
+ is.reset();
+
+ byte[] buf = ByteStreams.toByteArray(is);
+ return new OatFile(buf);
+ }
+
+ public int getOatVersion() {
+ return oatHeader.getVersion();
+ }
+
+ public int isSupportedVersion() {
+ int version = getOatVersion();
+ if (version < MIN_OAT_VERSION) {
+ return UNSUPPORTED;
+ }
+ if (version <= MAX_OAT_VERSION) {
+ return SUPPORTED;
+ }
+ return UNKNOWN;
+ }
+
+ @Nonnull
+ public List<OatDexFile> getDexFiles() {
+ return new AbstractForwardSequentialList<OatDexFile>() {
+ @Override public int size() {
+ return oatHeader.getDexFileCount();
+ }
+
+ @Nonnull @Override public Iterator<OatDexFile> iterator() {
+ return new Iterator<OatDexFile>() {
+ int index = 0;
+ int offset = oatHeader.getDexListStart();
+
+ @Override public boolean hasNext() {
+ return index < size();
+ }
+
+ @Override public OatDexFile next() {
+ int filenameLength = readSmallUint(offset);
+ offset += 4;
+
+ // TODO: what is the correct character encoding?
+ String filename = new String(buf, offset, filenameLength, Charset.forName("US-ASCII"));
+ offset += filenameLength;
+
+ offset += 4; // checksum
+
+ int dexOffset = readSmallUint(offset) + oatHeader.offset;
+ offset += 4;
+
+ int classCount = readSmallUint(dexOffset + HeaderItem.CLASS_COUNT_OFFSET);
+ offset += 4 * classCount;
+
+ index++;
+
+ return new OatDexFile(dexOffset, filename);
+ }
+
+ @Override public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ };
+ }
+
+ public class OatDexFile extends DexBackedDexFile {
+ @Nonnull public final String filename;
+
+ public OatDexFile(int offset, @Nonnull String filename) {
+ super(opcodes, OatFile.this.buf, offset);
+ this.filename = filename;
+ }
+
+ public int getOatVersion() {
+ return OatFile.this.getOatVersion();
+ }
+
+ @Override public boolean hasOdexOpcodes() {
+ return true;
+ }
+ }
+
+ private class OatHeader {
+ private final int offset;
+
+ public OatHeader(int offset) {
+ this.offset = offset;
+ }
+
+ public boolean isValid() {
+ for (int i=0; i<OAT_MAGIC.length; i++) {
+ if (buf[offset + i] != OAT_MAGIC[i]) {
+ return false;
+ }
+ }
+
+ for (int i=4; i<7; i++) {
+ if (buf[offset + i] < '0' || buf[offset + i] > '9') {
+ return false;
+ }
+ }
+
+ return buf[offset + 7] == 0;
+ }
+
+ public int getVersion() {
+ return Integer.valueOf(new String(buf, offset + 4, 3));
+ }
+
+ public int getDexFileCount() {
+ return readSmallUint(offset + 20);
+ }
+
+ public int getKeyValueStoreSize() {
+ int version = getVersion();
+ if (version < 56) {
+ throw new IllegalStateException("Unsupported oat version");
+ }
+ int fieldOffset = 17 * 4;
+ return readSmallUint(offset + fieldOffset);
+ }
+
+ public int getHeaderSize() {
+ int version = getVersion();
+ if (version >= 56) {
+ return 18*4 + getKeyValueStoreSize();
+ } else {
+ throw new IllegalStateException("Unsupported oat version");
+ }
+
+ }
+
+ public int getDexListStart() {
+ return offset + getHeaderSize();
+ }
+ }
+
+ @Nonnull
+ private List<SectionHeader> getSections() {
+ final int offset;
+ final int entrySize;
+ final int entryCount;
+ if (is64bit) {
+ offset = readLongAsSmallUint(40);
+ entrySize = readUshort(58);
+ entryCount = readUshort(60);
+ } else {
+ offset = readSmallUint(32);
+ entrySize = readUshort(46);
+ entryCount = readUshort(48);
+ }
+
+ if (offset + (entrySize * entryCount) > buf.length) {
+ throw new InvalidOatFileException("The ELF section headers extend past the end of the file");
+ }
+
+ return new AbstractList<SectionHeader>() {
+ @Override public SectionHeader get(int index) {
+ if (index < 0 || index >= entryCount) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (is64bit) {
+ return new SectionHeader64Bit(offset + (index * entrySize));
+ } else {
+ return new SectionHeader32Bit(offset + (index * entrySize));
+ }
+ }
+
+ @Override public int size() {
+ return entryCount;
+ }
+ };
+ }
+
+ @Nonnull
+ private SymbolTable getSymbolTable() {
+ for (SectionHeader header: getSections()) {
+ if (header.getType() == SectionHeader.TYPE_DYNAMIC_SYMBOL_TABLE) {
+ return new SymbolTable(header);
+ }
+ }
+ throw new InvalidOatFileException("Oat file has no symbol table");
+ }
+
+ @Nonnull
+ private StringTable getSectionNameStringTable() {
+ int index = readUshort(50);
+ if (index == 0) {
+ throw new InvalidOatFileException("There is no section name string table");
+ }
+
+ try {
+ return new StringTable(getSections().get(index));
+ } catch (IndexOutOfBoundsException ex) {
+ throw new InvalidOatFileException("The section index for the section name string table is invalid");
+ }
+ }
+
+ private abstract class SectionHeader {
+ protected final int offset;
+ public static final int TYPE_DYNAMIC_SYMBOL_TABLE = 11;
+ public SectionHeader(int offset) { this.offset = offset; }
+ @Nonnull public String getName() { return getSectionNameStringTable().getString(readSmallUint(offset)); }
+ public int getType() { return readInt(offset + 4); }
+ public abstract long getAddress();
+ public abstract int getOffset();
+ public abstract int getSize();
+ public abstract int getLink();
+ public abstract int getEntrySize();
+ }
+
+ private class SectionHeader32Bit extends SectionHeader {
+ public SectionHeader32Bit(int offset) { super(offset); }
+ @Override public long getAddress() { return readInt(offset + 12) & 0xFFFFFFFFL; }
+ @Override public int getOffset() { return readSmallUint(offset + 16); }
+ @Override public int getSize() { return readSmallUint(offset + 20); }
+ @Override public int getLink() { return readSmallUint(offset + 24); }
+ @Override public int getEntrySize() { return readSmallUint(offset + 36); }
+ }
+
+ private class SectionHeader64Bit extends SectionHeader {
+ public SectionHeader64Bit(int offset) { super(offset); }
+ @Override public long getAddress() { return readLong(offset + 16); }
+ @Override public int getOffset() { return readLongAsSmallUint(offset + 24); }
+ @Override public int getSize() { return readLongAsSmallUint(offset + 32); }
+ @Override public int getLink() { return readSmallUint(offset + 40); }
+ @Override public int getEntrySize() { return readLongAsSmallUint(offset + 56); }
+ }
+
+ class SymbolTable {
+ @Nonnull private final StringTable stringTable;
+ private final int offset;
+ private final int entryCount;
+ private final int entrySize;
+
+ public SymbolTable(@Nonnull SectionHeader header) {
+ try {
+ this.stringTable = new StringTable(getSections().get(header.getLink()));
+ } catch (IndexOutOfBoundsException ex) {
+ throw new InvalidOatFileException("String table section index is invalid");
+ }
+ this.offset = header.getOffset();
+ this.entrySize = header.getEntrySize();
+ this.entryCount = header.getSize() / entrySize;
+
+ if (offset + entryCount * entrySize > buf.length) {
+ throw new InvalidOatFileException("Symbol table extends past end of file");
+ }
+ }
+
+ @Nonnull
+ public List<Symbol> getSymbols() {
+ return new AbstractList<Symbol>() {
+ @Override public Symbol get(int index) {
+ if (index < 0 || index >= entryCount) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (is64bit) {
+ return new Symbol64(offset + index * entrySize);
+ } else {
+ return new Symbol32(offset + index * entrySize);
+ }
+ }
+
+ @Override public int size() {
+ return entryCount;
+ }
+ };
+ }
+
+ public abstract class Symbol {
+ protected final int offset;
+ public Symbol(int offset) { this.offset = offset; }
+ @Nonnull public abstract String getName();
+ public abstract long getValue();
+ public abstract int getSize();
+ public abstract int getSectionIndex();
+
+ public int getFileOffset() {
+ SectionHeader sectionHeader;
+ try {
+ sectionHeader = getSections().get(getSectionIndex());
+ } catch (IndexOutOfBoundsException ex) {
+ throw new InvalidOatFileException("Section index for symbol is out of bounds");
+ }
+
+ long sectionAddress = sectionHeader.getAddress();
+ int sectionOffset = sectionHeader.getOffset();
+ int sectionSize = sectionHeader.getSize();
+
+ long symbolAddress = getValue();
+
+ if (symbolAddress < sectionAddress || symbolAddress >= sectionAddress + sectionSize) {
+ throw new InvalidOatFileException("symbol address lies outside it's associated section");
+ }
+
+ long fileOffset = (sectionOffset + (getValue() - sectionAddress));
+ assert fileOffset <= Integer.MAX_VALUE;
+ return (int)fileOffset;
+ }
+ }
+
+ public class Symbol32 extends Symbol {
+ public Symbol32(int offset) { super(offset); }
+
+ @Nonnull
+ public String getName() { return stringTable.getString(readSmallUint(offset)); }
+ public long getValue() { return readSmallUint(offset + 4); }
+ public int getSize() { return readSmallUint(offset + 8); }
+ public int getSectionIndex() { return readUshort(offset + 14); }
+ }
+
+ public class Symbol64 extends Symbol {
+ public Symbol64(int offset) { super(offset); }
+
+ @Nonnull
+ public String getName() { return stringTable.getString(readSmallUint(offset)); }
+ public long getValue() { return readLong(offset + 8); }
+ public int getSize() { return readLongAsSmallUint(offset + 16); }
+ public int getSectionIndex() { return readUshort(offset + 6); }
+ }
+ }
+
+ private class StringTable {
+ private final int offset;
+ private final int size;
+
+ public StringTable(@Nonnull SectionHeader header) {
+ this.offset = header.getOffset();
+ this.size = header.getSize();
+
+ if (offset + size > buf.length) {
+ throw new InvalidOatFileException("String table extends past end of file");
+ }
+ }
+
+ @Nonnull
+ public String getString(int index) {
+ if (index >= size) {
+ throw new InvalidOatFileException("String index is out of bounds");
+ }
+
+ int start = offset + index;
+ int end = start;
+ while (buf[end] != 0) {
+ end++;
+ if (end >= offset + size) {
+ throw new InvalidOatFileException("String extends past end of string table");
+ }
+ }
+
+ return new String(buf, start, end-start, Charset.forName("US-ASCII"));
+ }
+
+ }
+
+ public static class InvalidOatFileException extends RuntimeException {
+ public InvalidOatFileException(String message) {
+ super(message);
+ }
+ }
+
+ public static class NotAnOatFileException extends RuntimeException {
+ public NotAnOatFileException() {}
+ }
+} \ No newline at end of file
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/HeaderItem.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/HeaderItem.java
index 3499eadc..531ff461 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/HeaderItem.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/HeaderItem.java
@@ -42,9 +42,14 @@ import javax.annotation.Nullable;
public class HeaderItem {
public static final int ITEM_SIZE = 0x70;
+ /**
+ * The magic numbers for dex files.
+ *
+ * They are: "dex\n035\0" and "dex\n037\0".
+ */
public static final byte[][] MAGIC_VALUES= new byte[][] {
new byte[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00},
- new byte[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x36, 0x00}};
+ new byte[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x37, 0x00}};
public static final int LITTLE_ENDIAN_TAG = 0x12345678;
public static final int BIG_ENDIAN_TAG = 0x78563412;
@@ -225,6 +230,21 @@ public class HeaderItem {
return "Invalid";
}
+
+ /**
+ * Get the higest magic number supported by Android for this api level.
+ * @return The dex file magic number
+ */
+ public static byte[] getMagicForApi(int api) {
+ if (api < 24) {
+ // Prior to Android N we only support dex version 035.
+ return HeaderItem.MAGIC_VALUES[0];
+ } else {
+ // On android N and later we support dex version 037.
+ return HeaderItem.MAGIC_VALUES[1];
+ }
+ }
+
private static int getVersion(byte[] buf, int offset) {
if (buf.length - offset < 8) {
return 0;
@@ -241,7 +261,7 @@ public class HeaderItem {
}
}
if (matches) {
- return i==0?35:36;
+ return i==0?35:37;
}
}
return 0;
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/RawDexFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/RawDexFile.java
index 1fac80bb..204a29d8 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/RawDexFile.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/RawDexFile.java
@@ -59,7 +59,7 @@ public class RawDexFile extends DexBackedDexFile {
@Nonnull
public byte[] readByteRange(int start, int length) {
- return Arrays.copyOfRange(getBuf(), start, start+length);
+ return Arrays.copyOfRange(getBuf(), getBaseOffset() + start, getBaseOffset() + start + length);
}
public int getMapOffset() {
@@ -94,6 +94,7 @@ public class RawDexFile extends DexBackedDexFile {
}
public void writeAnnotations(@Nonnull Writer out, @Nonnull AnnotatedBytes annotatedBytes) throws IOException {
+ // TODO: need to pass in the offset
annotatedBytes.writeAnnotations(out, getBuf());
}
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/DexFile.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/DexFile.java
index 45707f03..474bfb13 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/iface/DexFile.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/DexFile.java
@@ -31,6 +31,8 @@
package org.jf.dexlib2.iface;
+import org.jf.dexlib2.Opcodes;
+
import javax.annotation.Nonnull;
import java.util.Set;
@@ -46,4 +48,11 @@ public interface DexFile {
* @return A set of the classes defined in this dex file
*/
@Nonnull Set<? extends ClassDef> getClasses();
+
+ /**
+ * Get the Opcodes associated with this dex file
+ *
+ * @return The Opcodes instance representing the possible opcodes that can be encountered in this dex file
+ */
+ @Nonnull Opcodes getOpcodes();
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableDexFile.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableDexFile.java
index e911eb38..2112bd07 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableDexFile.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableDexFile.java
@@ -32,6 +32,7 @@
package org.jf.dexlib2.immutable;
import com.google.common.collect.ImmutableSet;
+import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.DexFile;
import org.jf.util.ImmutableUtils;
@@ -42,21 +43,37 @@ import java.util.Collection;
public class ImmutableDexFile implements DexFile {
@Nonnull protected final ImmutableSet<? extends ImmutableClassDef> classes;
+ @Nonnull private final Opcodes opcodes;
+ @Deprecated
public ImmutableDexFile(@Nullable Collection<? extends ClassDef> classes) {
this.classes = ImmutableClassDef.immutableSetOf(classes);
+ this.opcodes = Opcodes.forApi(19);
}
+ @Deprecated
public ImmutableDexFile(@Nullable ImmutableSet<? extends ImmutableClassDef> classes) {
this.classes = ImmutableUtils.nullToEmptySet(classes);
+ this.opcodes = Opcodes.forApi(19);
+ }
+
+ public ImmutableDexFile(@Nonnull Opcodes opcodes, @Nullable Collection<? extends ClassDef> classes) {
+ this.classes = ImmutableClassDef.immutableSetOf(classes);
+ this.opcodes = opcodes;
+ }
+
+ public ImmutableDexFile(@Nonnull Opcodes opcodes, @Nullable ImmutableSet<? extends ImmutableClassDef> classes) {
+ this.classes = ImmutableUtils.nullToEmptySet(classes);
+ this.opcodes = opcodes;
}
public static ImmutableDexFile of(DexFile dexFile) {
if (dexFile instanceof ImmutableDexFile) {
return (ImmutableDexFile)dexFile;
}
- return new ImmutableDexFile(dexFile.getClasses());
+ return new ImmutableDexFile(dexFile.getOpcodes(), dexFile.getClasses());
}
@Nonnull @Override public ImmutableSet<? extends ImmutableClassDef> getClasses() { return classes; }
+ @Nonnull @Override public Opcodes getOpcodes() { return opcodes; }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/DexRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/DexRewriter.java
index e482cd04..839ac096 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/DexRewriter.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/DexRewriter.java
@@ -31,6 +31,7 @@
package org.jf.dexlib2.rewriter;
+import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.iface.*;
import org.jf.dexlib2.iface.debug.DebugItem;
import org.jf.dexlib2.iface.instruction.Instruction;
@@ -116,6 +117,10 @@ public class DexRewriter implements Rewriters {
@Override @Nonnull public Set<? extends ClassDef> getClasses() {
return RewriterUtils.rewriteSet(getClassDefRewriter(), dexFile.getClasses());
}
+
+ @Nonnull @Override public Opcodes getOpcodes() {
+ return dexFile.getOpcodes();
+ }
}
@Nonnull @Override public Rewriter<ClassDef> getClassDefRewriter() { return classDefRewriter; }
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java b/dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java
index 631b8928..dc978daf 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java
@@ -35,6 +35,7 @@ import com.google.common.base.Predicate;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.MethodReference;
+import org.jf.util.CharSequenceUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -68,6 +69,12 @@ public final class MethodUtil {
return methodReference.getName().equals("<init>");
}
+ public static boolean isPackagePrivate(@Nonnull Method method) {
+ return (method.getAccessFlags() & (AccessFlags.PRIVATE.getValue() |
+ AccessFlags.PROTECTED.getValue() |
+ AccessFlags.PUBLIC.getValue())) == 0;
+ }
+
public static int getParameterRegisterCount(@Nonnull Method method) {
return getParameterRegisterCount(method, MethodUtil.isStatic(method));
}
@@ -109,5 +116,11 @@ public final class MethodUtil {
return sb.toString();
}
+ public static boolean methodSignaturesMatch(@Nonnull MethodReference a, @Nonnull MethodReference b) {
+ return (a.getName().equals(b.getName()) &&
+ a.getReturnType().equals(b.getReturnType()) &&
+ CharSequenceUtils.listEquals(a.getParameterTypes(), b.getParameterTypes()));
+ }
+
private MethodUtil() {}
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java b/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java
index aa428b05..674d5180 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java
@@ -33,17 +33,19 @@
package org.jf.dexlib2.util;
+import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction;
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction;
+import javax.annotation.Nonnull;
import java.util.List;
public class SyntheticAccessorFSM {
-// line 42 "SyntheticAccessorFSM.rl"
+// line 43 "SyntheticAccessorFSM.rl"
-// line 47 "/home/jesusfreke/projects/smali/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java"
+// line 48 "/home/jesusfreke/projects/smali/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java"
private static byte[] init__SyntheticAccessorFSM_actions_0()
{
return new byte [] {
@@ -187,7 +189,7 @@ static final int SyntheticAccessorFSM_error = 0;
static final int SyntheticAccessorFSM_en_main = 1;
-// line 43 "SyntheticAccessorFSM.rl"
+// line 44 "SyntheticAccessorFSM.rl"
// math type constants
public static final int ADD = SyntheticAccessorResolver.ADD_ASSIGNMENT;
@@ -211,7 +213,13 @@ static final int SyntheticAccessorFSM_en_main = 1;
public static final int NEGATIVE_ONE = -1;
public static final int OTHER = 0;
- public static int test(List<? extends Instruction> instructions) {
+ @Nonnull private final Opcodes opcodes;
+
+ public SyntheticAccessorFSM(@Nonnull Opcodes opcodes) {
+ this.opcodes = opcodes;
+ }
+
+ public int test(List<? extends Instruction> instructions) {
int accessorType = -1;
int cs, p = 0;
int pe = instructions.size();
@@ -231,12 +239,12 @@ static final int SyntheticAccessorFSM_en_main = 1;
int returnRegister = -1;
-// line 235 "/home/jesusfreke/projects/smali/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java"
+// line 242 "/home/jesusfreke/projects/smali/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java"
{
cs = SyntheticAccessorFSM_start;
}
-// line 240 "/home/jesusfreke/projects/smali/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java"
+// line 247 "/home/jesusfreke/projects/smali/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java"
{
int _klen;
int _trans = 0;
@@ -270,9 +278,9 @@ case 1:
break;
_mid = _lower + ((_upper-_lower) >> 1);
- if ( ( instructions.get(p).getOpcode().value) < _SyntheticAccessorFSM_trans_keys[_mid] )
+ if ( ( opcodes.getOpcodeValue(instructions.get(p).getOpcode())) < _SyntheticAccessorFSM_trans_keys[_mid] )
_upper = _mid - 1;
- else if ( ( instructions.get(p).getOpcode().value) > _SyntheticAccessorFSM_trans_keys[_mid] )
+ else if ( ( opcodes.getOpcodeValue(instructions.get(p).getOpcode())) > _SyntheticAccessorFSM_trans_keys[_mid] )
_lower = _mid + 1;
else {
_trans += (_mid - _keys);
@@ -293,9 +301,9 @@ case 1:
break;
_mid = _lower + (((_upper-_lower) >> 1) & ~1);
- if ( ( instructions.get(p).getOpcode().value) < _SyntheticAccessorFSM_trans_keys[_mid] )
+ if ( ( opcodes.getOpcodeValue(instructions.get(p).getOpcode())) < _SyntheticAccessorFSM_trans_keys[_mid] )
_upper = _mid - 2;
- else if ( ( instructions.get(p).getOpcode().value) > _SyntheticAccessorFSM_trans_keys[_mid+1] )
+ else if ( ( opcodes.getOpcodeValue(instructions.get(p).getOpcode())) > _SyntheticAccessorFSM_trans_keys[_mid+1] )
_lower = _mid + 2;
else {
_trans += ((_mid - _keys)>>1);
@@ -317,19 +325,19 @@ case 1:
switch ( _SyntheticAccessorFSM_actions[_acts++] )
{
case 0:
-// line 93 "SyntheticAccessorFSM.rl"
+// line 100 "SyntheticAccessorFSM.rl"
{
putRegister = ((OneRegisterInstruction)instructions.get(p)).getRegisterA();
}
break;
case 1:
-// line 100 "SyntheticAccessorFSM.rl"
+// line 107 "SyntheticAccessorFSM.rl"
{
constantValue = ((WideLiteralInstruction)instructions.get(p)).getWideLiteral();
}
break;
case 2:
-// line 104 "SyntheticAccessorFSM.rl"
+// line 111 "SyntheticAccessorFSM.rl"
{
mathType = INT;
mathOp = ADD;
@@ -337,146 +345,146 @@ case 1:
}
break;
case 3:
-// line 110 "SyntheticAccessorFSM.rl"
+// line 117 "SyntheticAccessorFSM.rl"
{ mathType = INT; }
break;
case 4:
-// line 111 "SyntheticAccessorFSM.rl"
+// line 118 "SyntheticAccessorFSM.rl"
{ mathType = LONG; }
break;
case 5:
-// line 112 "SyntheticAccessorFSM.rl"
+// line 119 "SyntheticAccessorFSM.rl"
{ mathType = FLOAT; }
break;
case 6:
-// line 113 "SyntheticAccessorFSM.rl"
+// line 120 "SyntheticAccessorFSM.rl"
{mathType = DOUBLE; }
break;
case 7:
-// line 113 "SyntheticAccessorFSM.rl"
+// line 120 "SyntheticAccessorFSM.rl"
{
mathOp = ADD;
}
break;
case 8:
-// line 116 "SyntheticAccessorFSM.rl"
+// line 123 "SyntheticAccessorFSM.rl"
{ mathType = INT; }
break;
case 9:
-// line 117 "SyntheticAccessorFSM.rl"
+// line 124 "SyntheticAccessorFSM.rl"
{ mathType = LONG; }
break;
case 10:
-// line 118 "SyntheticAccessorFSM.rl"
+// line 125 "SyntheticAccessorFSM.rl"
{ mathType = FLOAT; }
break;
case 11:
-// line 119 "SyntheticAccessorFSM.rl"
+// line 126 "SyntheticAccessorFSM.rl"
{mathType = DOUBLE; }
break;
case 12:
-// line 119 "SyntheticAccessorFSM.rl"
+// line 126 "SyntheticAccessorFSM.rl"
{
mathOp = SUB;
}
break;
case 13:
-// line 123 "SyntheticAccessorFSM.rl"
+// line 130 "SyntheticAccessorFSM.rl"
{
mathOp = MUL;
}
break;
case 14:
-// line 127 "SyntheticAccessorFSM.rl"
+// line 134 "SyntheticAccessorFSM.rl"
{
mathOp = DIV;
}
break;
case 15:
-// line 131 "SyntheticAccessorFSM.rl"
+// line 138 "SyntheticAccessorFSM.rl"
{
mathOp = REM;
}
break;
case 16:
-// line 134 "SyntheticAccessorFSM.rl"
+// line 141 "SyntheticAccessorFSM.rl"
{
mathOp = AND;
}
break;
case 17:
-// line 137 "SyntheticAccessorFSM.rl"
+// line 144 "SyntheticAccessorFSM.rl"
{
mathOp = OR;
}
break;
case 18:
-// line 140 "SyntheticAccessorFSM.rl"
+// line 147 "SyntheticAccessorFSM.rl"
{
mathOp = XOR;
}
break;
case 19:
-// line 143 "SyntheticAccessorFSM.rl"
+// line 150 "SyntheticAccessorFSM.rl"
{
mathOp = SHL;
}
break;
case 20:
-// line 146 "SyntheticAccessorFSM.rl"
+// line 153 "SyntheticAccessorFSM.rl"
{
mathOp = SHR;
}
break;
case 21:
-// line 149 "SyntheticAccessorFSM.rl"
+// line 156 "SyntheticAccessorFSM.rl"
{
mathOp = USHR;
}
break;
case 22:
-// line 155 "SyntheticAccessorFSM.rl"
+// line 162 "SyntheticAccessorFSM.rl"
{
returnRegister = ((OneRegisterInstruction)instructions.get(p)).getRegisterA();
}
break;
case 23:
-// line 161 "SyntheticAccessorFSM.rl"
+// line 168 "SyntheticAccessorFSM.rl"
{
accessorType = SyntheticAccessorResolver.GETTER; { p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
case 24:
-// line 165 "SyntheticAccessorFSM.rl"
+// line 172 "SyntheticAccessorFSM.rl"
{
accessorType = SyntheticAccessorResolver.SETTER; { p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
case 25:
-// line 169 "SyntheticAccessorFSM.rl"
+// line 176 "SyntheticAccessorFSM.rl"
{
accessorType = SyntheticAccessorResolver.METHOD; { p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
case 26:
-// line 173 "SyntheticAccessorFSM.rl"
+// line 180 "SyntheticAccessorFSM.rl"
{
accessorType = getIncrementType(mathOp, mathType, constantValue, putRegister, returnRegister);
}
break;
case 27:
-// line 177 "SyntheticAccessorFSM.rl"
+// line 184 "SyntheticAccessorFSM.rl"
{
accessorType = getIncrementType(mathOp, mathType, constantValue, putRegister, returnRegister);
}
break;
case 28:
-// line 185 "SyntheticAccessorFSM.rl"
+// line 192 "SyntheticAccessorFSM.rl"
{
accessorType = mathOp; { p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 480 "/home/jesusfreke/projects/smali/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java"
+// line 487 "/home/jesusfreke/projects/smali/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorFSM.java"
}
}
}
@@ -496,7 +504,7 @@ case 5:
break; }
}
-// line 198 "SyntheticAccessorFSM.rl"
+// line 205 "SyntheticAccessorFSM.rl"
return accessorType;
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorResolver.java b/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorResolver.java
index a46a18f0..7808f84d 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorResolver.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/util/SyntheticAccessorResolver.java
@@ -35,6 +35,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import org.jf.dexlib2.AccessFlags;
+import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodImplementation;
@@ -68,10 +69,12 @@ public class SyntheticAccessorResolver {
public static final int SHR_ASSIGNMENT = 16;
public static final int USHR_ASSIGNMENT = 17;
+ private final SyntheticAccessorFSM syntheticAccessorFSM;
private final Map<String, ClassDef> classDefMap;
private final Map<String, AccessedMember> resolvedAccessors = Maps.newConcurrentMap();
- public SyntheticAccessorResolver(Iterable<? extends ClassDef> classDefs) {
+ public SyntheticAccessorResolver(@Nonnull Opcodes opcodes, @Nonnull Iterable<? extends ClassDef> classDefs) {
+ this.syntheticAccessorFSM = new SyntheticAccessorFSM(opcodes);
ImmutableMap.Builder<String, ClassDef> builder = ImmutableMap.builder();
for (ClassDef classDef: classDefs) {
@@ -124,7 +127,8 @@ public class SyntheticAccessorResolver {
List<Instruction> instructions = ImmutableList.copyOf(matchedMethodImpl.getInstructions());
- int accessType = SyntheticAccessorFSM.test(instructions);
+
+ int accessType = syntheticAccessorFSM.test(instructions);
if (accessType >= 0) {
AccessedMember member =
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java b/dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java
index 02890b87..6be21af0 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java
@@ -31,6 +31,8 @@
package org.jf.dexlib2.util;
+import org.jf.dexlib2.AccessFlags;
+import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.reference.TypeReference;
import javax.annotation.Nonnull;
@@ -49,5 +51,24 @@ public final class TypeUtils {
return type.length() == 1;
}
+ @Nonnull
+ public static String getPackage(@Nonnull String type) {
+ int lastSlash = type.lastIndexOf('/');
+ if (lastSlash < 0) {
+ return "";
+ }
+ return type.substring(1, lastSlash);
+ }
+
+ public static boolean canAccessClass(@Nonnull String accessorType, @Nonnull ClassDef accesseeClassDef) {
+ if (AccessFlags.PUBLIC.isSet(accesseeClassDef.getAccessFlags())) {
+ return true;
+ }
+
+ // Classes can only be public or package private. Any private or protected inner classes are actually
+ // package private.
+ return getPackage(accesseeClassDef.getType()).equals(getPackage(accessorType));
+ }
+
private TypeUtils() {}
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java
index be23978e..4e81f7fa 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/DexWriter.java
@@ -37,6 +37,7 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.Opcode;
+import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.base.BaseAnnotation;
import org.jf.dexlib2.base.BaseAnnotationElement;
@@ -94,7 +95,7 @@ public abstract class DexWriter<
public static final int NO_INDEX = -1;
public static final int NO_OFFSET = 0;
- protected final int api;
+ protected final Opcodes opcodes;
protected int stringIndexSectionOffset = NO_OFFSET;
protected int typeSectionOffset = NO_OFFSET;
@@ -134,7 +135,7 @@ public abstract class DexWriter<
protected final AnnotationSection<StringKey, TypeKey, AnnotationKey, AnnotationElement, EncodedValue> annotationSection;
protected final AnnotationSetSection<AnnotationKey, AnnotationSetKey> annotationSetSection;
- protected DexWriter(int api,
+ protected DexWriter(Opcodes opcodes,
StringSection<StringKey, StringRef> stringSection,
TypeSection<StringKey, TypeKey, TypeRef> typeSection,
ProtoSection<StringKey, TypeKey, ProtoKey, TypeListKey> protoSection,
@@ -146,7 +147,8 @@ public abstract class DexWriter<
AnnotationSection<StringKey, TypeKey, AnnotationKey, AnnotationElement,
EncodedValue> annotationSection,
AnnotationSetSection<AnnotationKey, AnnotationSetKey> annotationSetSection) {
- this.api = api;
+ this.opcodes = opcodes;
+
this.stringSection = stringSection;
this.typeSection = typeSection;
this.protoSection = protoSection;
@@ -943,7 +945,7 @@ public abstract class DexWriter<
writer.writeInt(debugItemOffset);
InstructionWriter instructionWriter =
- InstructionWriter.makeInstructionWriter(writer, stringSection, typeSection, fieldSection,
+ InstructionWriter.makeInstructionWriter(opcodes, writer, stringSection, typeSection, fieldSection,
methodSection);
writer.writeInt(codeUnitCount);
@@ -1219,8 +1221,8 @@ public abstract class DexWriter<
}
private void writeHeader(@Nonnull DexDataWriter writer, int dataOffset, int fileSize) throws IOException {
- // always write the 035 version, there's no reason to use the 036 version for now
- writer.write(HeaderItem.MAGIC_VALUES[0]);
+ // Write the appropriate header.
+ writer.write(HeaderItem.getMagicForApi(opcodes.api));
// checksum placeholder
writer.writeInt(0);
@@ -1266,6 +1268,6 @@ public abstract class DexWriter<
// Workaround for a crash in Dalvik VM before Jelly Bean MR1 (4.2)
// which is triggered by NO_OFFSET in parameter annotation list.
// (https://code.google.com/p/android/issues/detail?id=35304)
- return (api < 17);
+ return (opcodes.api < 17);
}
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java
index c9aa73a1..f16256c5 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/InstructionWriter.java
@@ -33,6 +33,8 @@ package org.jf.dexlib2.writer;
import com.google.common.collect.Ordering;
import com.google.common.primitives.Ints;
+import org.jf.dexlib2.Opcode;
+import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.instruction.SwitchElement;
@@ -50,6 +52,7 @@ import java.util.List;
public class InstructionWriter<StringRef extends StringReference, TypeRef extends TypeReference,
FieldRefKey extends FieldReference, MethodRefKey extends MethodReference> {
+ @Nonnull private final Opcodes opcodes;
@Nonnull private final DexDataWriter writer;
@Nonnull private final StringSection<?, StringRef> stringSection;
@Nonnull private final TypeSection<?, ?, TypeRef> typeSection;
@@ -59,20 +62,23 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
@Nonnull static <StringRef extends StringReference, TypeRef extends TypeReference, FieldRefKey extends FieldReference, MethodRefKey extends MethodReference>
InstructionWriter<StringRef, TypeRef, FieldRefKey, MethodRefKey>
makeInstructionWriter(
+ @Nonnull Opcodes opcodes,
@Nonnull DexDataWriter writer,
@Nonnull StringSection<?, StringRef> stringSection,
@Nonnull TypeSection<?, ?, TypeRef> typeSection,
@Nonnull FieldSection<?, ?, FieldRefKey, ?> fieldSection,
@Nonnull MethodSection<?, ?, ?, MethodRefKey, ?> methodSection) {
return new InstructionWriter<StringRef, TypeRef, FieldRefKey, MethodRefKey>(
- writer, stringSection, typeSection, fieldSection, methodSection);
+ opcodes, writer, stringSection, typeSection, fieldSection, methodSection);
}
- InstructionWriter(@Nonnull DexDataWriter writer,
+ InstructionWriter(@Nonnull Opcodes opcodes,
+ @Nonnull DexDataWriter writer,
@Nonnull StringSection<?, StringRef> stringSection,
@Nonnull TypeSection<?, ?, TypeRef> typeSection,
@Nonnull FieldSection<?, ?, FieldRefKey, ?> fieldSection,
@Nonnull MethodSection<?, ?, ?, MethodRefKey, ?> methodSection) {
+ this.opcodes = opcodes;
this.writer = writer;
this.stringSection = stringSection;
this.typeSection = typeSection;
@@ -80,9 +86,17 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
this.methodSection = methodSection;
}
+ private short getOpcodeValue(Opcode opcode) {
+ Short value = opcodes.getOpcodeValue(opcode);
+ if (value == null) {
+ throw new ExceptionWithContext("Instruction %s is invalid for api %d", opcode.name, opcodes.api);
+ }
+ return value;
+ }
+
public void write(@Nonnull Instruction10t instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getCodeOffset());
} catch (IOException ex) {
throw new RuntimeException(ex);
@@ -91,7 +105,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction10x instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(0);
} catch (IOException ex) {
throw new RuntimeException(ex);
@@ -100,7 +114,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction11n instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(packNibbles(instruction.getRegisterA(), instruction.getNarrowLiteral()));
} catch (IOException ex) {
throw new RuntimeException(ex);
@@ -109,7 +123,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction11x instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getRegisterA());
} catch (IOException ex) {
throw new RuntimeException(ex);
@@ -118,7 +132,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction12x instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
} catch (IOException ex) {
throw new RuntimeException(ex);
@@ -127,7 +141,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction20bc instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getVerificationError());
writer.writeUshort(getReferenceIndex(instruction));
} catch (IOException ex) {
@@ -137,7 +151,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction20t instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(0);
writer.writeShort(instruction.getCodeOffset());
} catch (IOException ex) {
@@ -147,7 +161,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction21c instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getRegisterA());
writer.writeUshort(getReferenceIndex(instruction));
} catch (IOException ex) {
@@ -157,7 +171,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction21ih instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getHatLiteral());
} catch (IOException ex) {
@@ -167,7 +181,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction21lh instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getHatLiteral());
} catch (IOException ex) {
@@ -177,7 +191,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction21s instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getNarrowLiteral());
} catch (IOException ex) {
@@ -187,7 +201,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction21t instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getCodeOffset());
} catch (IOException ex) {
@@ -197,7 +211,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction22b instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getRegisterA());
writer.write(instruction.getRegisterB());
writer.write(instruction.getNarrowLiteral());
@@ -208,7 +222,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction22c instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
writer.writeUshort(getReferenceIndex(instruction));
} catch (IOException ex) {
@@ -218,7 +232,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction22s instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
writer.writeShort(instruction.getNarrowLiteral());
} catch (IOException ex) {
@@ -228,7 +242,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction22t instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
writer.writeShort(instruction.getCodeOffset());
} catch (IOException ex) {
@@ -238,7 +252,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction22x instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getRegisterA());
writer.writeUshort(instruction.getRegisterB());
} catch (IOException ex) {
@@ -248,7 +262,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction23x instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getRegisterA());
writer.write(instruction.getRegisterB());
writer.write(instruction.getRegisterC());
@@ -259,7 +273,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction30t instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(0);
writer.writeInt(instruction.getCodeOffset());
} catch (IOException ex) {
@@ -269,7 +283,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction31c instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getRegisterA());
writer.writeInt(getReferenceIndex(instruction));
} catch (IOException ex) {
@@ -279,7 +293,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction31i instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getRegisterA());
writer.writeInt(instruction.getNarrowLiteral());
} catch (IOException ex) {
@@ -289,7 +303,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction31t instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getRegisterA());
writer.writeInt(instruction.getCodeOffset());
} catch (IOException ex) {
@@ -299,7 +313,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction32x instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(0);
writer.writeUshort(instruction.getRegisterA());
writer.writeUshort(instruction.getRegisterB());
@@ -310,7 +324,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction35c instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(packNibbles(instruction.getRegisterG(), instruction.getRegisterCount()));
writer.writeUshort(getReferenceIndex(instruction));
writer.write(packNibbles(instruction.getRegisterC(), instruction.getRegisterD()));
@@ -322,7 +336,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction25x instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(packNibbles(
instruction.getRegisterParameterG(), instruction.getParameterRegisterCount()));
writer.write(packNibbles(
@@ -335,7 +349,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
}
public void write(@Nonnull Instruction3rc instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getRegisterCount());
writer.writeUshort(getReferenceIndex(instruction));
writer.writeUshort(instruction.getStartRegister());
@@ -346,7 +360,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull Instruction51l instruction) {
try {
- writer.write(instruction.getOpcode().value);
+ writer.write(getOpcodeValue(instruction.getOpcode()));
writer.write(instruction.getRegisterA());
writer.writeLong(instruction.getWideLiteral());
} catch (IOException ex) {
@@ -356,7 +370,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull ArrayPayload instruction) {
try {
- writer.writeUshort(instruction.getOpcode().value);
+ writer.writeUshort(getOpcodeValue(instruction.getOpcode()));
writer.writeUshort(instruction.getElementWidth());
List<Number> elements = instruction.getArrayElements();
writer.writeInt(elements.size());
@@ -393,7 +407,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull SparseSwitchPayload instruction) {
try {
writer.writeUbyte(0);
- writer.writeUbyte(instruction.getOpcode().value >> 8);
+ writer.writeUbyte(getOpcodeValue(instruction.getOpcode()) >> 8);
List<? extends SwitchElement> elements = Ordering.from(switchElementComparator).immutableSortedCopy(
instruction.getSwitchElements());
writer.writeUshort(elements.size());
@@ -417,7 +431,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
public void write(@Nonnull PackedSwitchPayload instruction) {
try {
writer.writeUbyte(0);
- writer.writeUbyte(instruction.getOpcode().value >> 8);
+ writer.writeUbyte(getOpcodeValue(instruction.getOpcode()) >> 8);
List<? extends SwitchElement> elements = instruction.getSwitchElements();
writer.writeUshort(elements.size());
if (elements.size() == 0) {
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java
index 9a727b27..d1190249 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java
@@ -34,8 +34,8 @@ package org.jf.dexlib2.writer.builder;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;
-import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.ValueType;
import org.jf.dexlib2.iface.Annotation;
import org.jf.dexlib2.iface.MethodImplementation;
@@ -49,7 +49,6 @@ import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
-import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -59,20 +58,27 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
BuilderClassDef, BuilderAnnotation, BuilderAnnotationSet, BuilderTypeList, BuilderField, BuilderMethod,
BuilderEncodedValue, BuilderAnnotationElement> {
- private final BuilderContext context;
+ @Nonnull private final BuilderContext context;
- public static DexBuilder makeDexBuilder() {
+ @Nonnull public static DexBuilder makeDexBuilder() {
BuilderContext context = new BuilderContext();
- return new DexBuilder(15, context);
+ return new DexBuilder(Opcodes.forApi(20), context);
}
+ @Deprecated
+ @Nonnull
public static DexBuilder makeDexBuilder(int api) {
BuilderContext context = new BuilderContext();
- return new DexBuilder(api, context);
+ return new DexBuilder(Opcodes.forApi(api), context);
}
- private DexBuilder(int api, @Nonnull BuilderContext context) {
- super(api, context.stringPool, context.typePool, context.protoPool,
+ @Nonnull public static DexBuilder makeDexBuilder(@Nonnull Opcodes opcodes) {
+ BuilderContext context = new BuilderContext();
+ return new DexBuilder(opcodes, context);
+ }
+
+ private DexBuilder(@Nonnull Opcodes opcodes, @Nonnull BuilderContext context) {
+ super(opcodes, context.stringPool, context.typePool, context.protoPool,
context.fieldPool, context.methodPool, context.classPool, context.typeListPool, context.annotationPool,
context.annotationSetPool);
this.context = context;
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java
index d7f63922..27d8044e 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java
@@ -31,6 +31,7 @@
package org.jf.dexlib2.writer.pool;
+import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.ValueType;
import org.jf.dexlib2.iface.Annotation;
import org.jf.dexlib2.iface.AnnotationElement;
@@ -56,11 +57,19 @@ public class DexPool extends DexWriter<CharSequence, StringReference, CharSequen
TypeListPool.Key<? extends Collection<? extends CharSequence>>, Field, PoolMethod,
EncodedValue, AnnotationElement> {
+ @Nonnull
public static DexPool makeDexPool() {
- return makeDexPool(15);
+ return makeDexPool(Opcodes.forApi(20));
}
+ @Deprecated
+ @Nonnull
public static DexPool makeDexPool(int api) {
+ return makeDexPool(Opcodes.forApi(api));
+ }
+
+ @Nonnull
+ public static DexPool makeDexPool(@Nonnull Opcodes opcodes) {
StringPool stringPool = new StringPool();
TypePool typePool = new TypePool(stringPool);
FieldPool fieldPool = new FieldPool(stringPool, typePool);
@@ -72,14 +81,14 @@ public class DexPool extends DexWriter<CharSequence, StringReference, CharSequen
ClassPool classPool = new ClassPool(stringPool, typePool, fieldPool, methodPool, annotationSetPool,
typeListPool);
- return new DexPool(api, stringPool, typePool, protoPool, fieldPool, methodPool, classPool, typeListPool,
+ return new DexPool(opcodes, stringPool, typePool, protoPool, fieldPool, methodPool, classPool, typeListPool,
annotationPool, annotationSetPool);
}
- private DexPool(int api, StringPool stringPool, TypePool typePool, ProtoPool protoPool, FieldPool fieldPool,
+ private DexPool(Opcodes opcodes, StringPool stringPool, TypePool typePool, ProtoPool protoPool, FieldPool fieldPool,
MethodPool methodPool, ClassPool classPool, TypeListPool typeListPool,
AnnotationPool annotationPool, AnnotationSetPool annotationSetPool) {
- super(api, stringPool, typePool, protoPool, fieldPool, methodPool,
+ super(opcodes, stringPool, typePool, protoPool, fieldPool, methodPool,
classPool, typeListPool, annotationPool, annotationSetPool);
}
diff --git a/dexlib2/src/main/ragel/SyntheticAccessorFSM.rl b/dexlib2/src/main/ragel/SyntheticAccessorFSM.rl
index c46f9bac..96ac5367 100644
--- a/dexlib2/src/main/ragel/SyntheticAccessorFSM.rl
+++ b/dexlib2/src/main/ragel/SyntheticAccessorFSM.rl
@@ -34,6 +34,7 @@ package org.jf.dexlib2.util;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction;
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction;
+import org.jf.dexlib2.Opcodes;
import java.util.List;
@@ -63,7 +64,13 @@ public class SyntheticAccessorFSM {
public static final int NEGATIVE_ONE = -1;
public static final int OTHER = 0;
- public static int test(List<? extends Instruction> instructions) {
+ @Nonnull private final Opcodes opcodes;
+
+ public SyntheticAccessorFSM(@Nonnull Opcodes opcodes) {
+ this.opcodes = opcodes;
+ }
+
+ public int test(List<? extends Instruction> instructions) {
int accessorType = -1;
int cs, p = 0;
int pe = instructions.size();
@@ -85,7 +92,7 @@ public class SyntheticAccessorFSM {
%%{
import "Opcodes.rl";
alphtype short;
- getkey instructions.get(p).getOpcode().value;
+ getkey opcodes.getOpcodeValue(instructions.get(p).getOpcode());
get = (0x52 .. 0x58) | (0x60 .. 0x66); # all igets/sgets
diff --git a/dexlib2/src/test/java/org/jf/dexlib2/AccessorTest.java b/dexlib2/src/test/java/org/jf/dexlib2/AccessorTest.java
index 924d3fd3..4c8f85bf 100644
--- a/dexlib2/src/test/java/org/jf/dexlib2/AccessorTest.java
+++ b/dexlib2/src/test/java/org/jf/dexlib2/AccessorTest.java
@@ -81,7 +81,7 @@ public class AccessorTest {
Assert.assertNotNull(url);
DexFile f = DexFileFactory.loadDexFile(url.getFile(), 15, false);
- SyntheticAccessorResolver sar = new SyntheticAccessorResolver(f.getClasses());
+ SyntheticAccessorResolver sar = new SyntheticAccessorResolver(f.getOpcodes(), f.getClasses());
ClassDef accessorTypesClass = null;
ClassDef accessorsClass = null;
diff --git a/dexlib2/src/test/java/org/jf/dexlib2/analysis/CommonSuperclassTest.java b/dexlib2/src/test/java/org/jf/dexlib2/analysis/CommonSuperclassTest.java
index f3b1094e..3f1ee56d 100644
--- a/dexlib2/src/test/java/org/jf/dexlib2/analysis/CommonSuperclassTest.java
+++ b/dexlib2/src/test/java/org/jf/dexlib2/analysis/CommonSuperclassTest.java
@@ -33,6 +33,7 @@ package org.jf.dexlib2.analysis;
import com.google.common.collect.ImmutableSet;
import junit.framework.Assert;
+import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.immutable.ImmutableDexFile;
import org.junit.Test;
@@ -53,39 +54,42 @@ public class CommonSuperclassTest {
private final ClassPath classPath;
public CommonSuperclassTest() throws IOException {
- classPath = new ClassPath(new ImmutableDexFile(ImmutableSet.of(
- TestUtils.makeClassDef("Ljava/lang/Object;", null),
- TestUtils.makeClassDef("Ltest/one;", "Ljava/lang/Object;"),
- TestUtils.makeClassDef("Ltest/two;", "Ljava/lang/Object;"),
- TestUtils.makeClassDef("Ltest/onetwo;", "Ltest/one;"),
- TestUtils.makeClassDef("Ltest/onetwothree;", "Ltest/onetwo;"),
- TestUtils.makeClassDef("Ltest/onethree;", "Ltest/one;"),
- TestUtils.makeClassDef("Ltest/fivetwo;", "Ltest/five;"),
- TestUtils.makeClassDef("Ltest/fivetwothree;", "Ltest/fivetwo;"),
- TestUtils.makeClassDef("Ltest/fivethree;", "Ltest/five;"),
- TestUtils.makeInterfaceDef("Ljava/lang/Cloneable;"),
- TestUtils.makeInterfaceDef("Ljava/io/Serializable;"),
-
- // basic class and interface
- TestUtils.makeClassDef("Liface/classiface1;", "Ljava/lang/Object;", "Liface/iface1;"),
- TestUtils.makeInterfaceDef("Liface/iface1;"),
-
- // a more complex interface tree
- TestUtils.makeInterfaceDef("Liface/base1;"),
- // implements undefined interface
- TestUtils.makeInterfaceDef("Liface/sub1;", "Liface/base1;", "Liface/base2;"),
- // this implements sub1, so that its interfaces can't be fully resolved either
- TestUtils.makeInterfaceDef("Liface/sub2;", "Liface/base1;", "Liface/sub1;"),
- TestUtils.makeInterfaceDef("Liface/sub3;", "Liface/base1;"),
- TestUtils.makeInterfaceDef("Liface/sub4;", "Liface/base1;", "Liface/sub3;"),
- TestUtils.makeClassDef("Liface/classsub1;", "Ljava/lang/Object;", "Liface/sub1;"),
- TestUtils.makeClassDef("Liface/classsub2;", "Ljava/lang/Object;", "Liface/sub2;"),
- TestUtils.makeClassDef("Liface/classsub3;", "Ljava/lang/Object;", "Liface/sub3;", "Liface/base;"),
- TestUtils.makeClassDef("Liface/classsub4;", "Ljava/lang/Object;", "Liface/sub3;", "Liface/sub4;"),
- TestUtils.makeClassDef("Liface/classsubsub4;", "Liface/classsub4;"),
- TestUtils.makeClassDef("Liface/classsub1234;", "Ljava/lang/Object;", "Liface/sub1;", "Liface/sub2;",
- "Liface/sub3;", "Liface/sub4;")
- )));
+ classPath = new ClassPath(new DexClassProvider(new ImmutableDexFile(Opcodes.forApi(19),
+ ImmutableSet.of(
+ TestUtils.makeClassDef("Ljava/lang/Object;", null),
+ TestUtils.makeClassDef("Ltest/one;", "Ljava/lang/Object;"),
+ TestUtils.makeClassDef("Ltest/two;", "Ljava/lang/Object;"),
+ TestUtils.makeClassDef("Ltest/onetwo;", "Ltest/one;"),
+ TestUtils.makeClassDef("Ltest/onetwothree;", "Ltest/onetwo;"),
+ TestUtils.makeClassDef("Ltest/onethree;", "Ltest/one;"),
+ TestUtils.makeClassDef("Ltest/fivetwo;", "Ltest/five;"),
+ TestUtils.makeClassDef("Ltest/fivetwothree;", "Ltest/fivetwo;"),
+ TestUtils.makeClassDef("Ltest/fivethree;", "Ltest/five;"),
+ TestUtils.makeInterfaceDef("Ljava/lang/Cloneable;"),
+ TestUtils.makeInterfaceDef("Ljava/io/Serializable;"),
+
+ // basic class and interface
+ TestUtils.makeClassDef("Liface/classiface1;", "Ljava/lang/Object;", "Liface/iface1;"),
+ TestUtils.makeInterfaceDef("Liface/iface1;"),
+
+ // a more complex interface tree
+ TestUtils.makeInterfaceDef("Liface/base1;"),
+ // implements undefined interface
+ TestUtils.makeInterfaceDef("Liface/sub1;", "Liface/base1;", "Liface/base2;"),
+ // this implements sub1, so that its interfaces can't be fully resolved either
+ TestUtils.makeInterfaceDef("Liface/sub2;", "Liface/base1;", "Liface/sub1;"),
+ TestUtils.makeInterfaceDef("Liface/sub3;", "Liface/base1;"),
+ TestUtils.makeInterfaceDef("Liface/sub4;", "Liface/base1;", "Liface/sub3;"),
+ TestUtils.makeClassDef("Liface/classsub1;", "Ljava/lang/Object;", "Liface/sub1;"),
+ TestUtils.makeClassDef("Liface/classsub2;", "Ljava/lang/Object;", "Liface/sub2;"),
+ TestUtils.makeClassDef("Liface/classsub3;", "Ljava/lang/Object;", "Liface/sub3;",
+ "Liface/base;"),
+ TestUtils.makeClassDef("Liface/classsub4;", "Ljava/lang/Object;", "Liface/sub3;",
+ "Liface/sub4;"),
+ TestUtils.makeClassDef("Liface/classsubsub4;", "Liface/classsub4;"),
+ TestUtils.makeClassDef("Liface/classsub1234;", "Ljava/lang/Object;", "Liface/sub1;",
+ "Liface/sub2;", "Liface/sub3;", "Liface/sub4;")
+ ))));
}
public void superclassTest(String commonSuperclass,
diff --git a/dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java b/dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java
index 65a82f05..90a63590 100644
--- a/dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java
+++ b/dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java
@@ -35,6 +35,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.Opcode;
+import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.DexFile;
import org.jf.dexlib2.iface.instruction.Instruction;
@@ -66,12 +67,12 @@ public class CustomMethodInlineTableTest {
ClassDef classDef = new ImmutableClassDef("Lblah;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null,
null, null, null, null, null, ImmutableList.of(method));
- DexFile dexFile = new ImmutableDexFile(ImmutableList.of(classDef));
+ DexFile dexFile = new ImmutableDexFile(Opcodes.forApi(19), ImmutableList.of(classDef));
ClassPath classPath = ClassPath.fromClassPath(ImmutableList.<String>of(), ImmutableList.<String>of(), dexFile,
15, false);
InlineMethodResolver inlineMethodResolver = new CustomInlineMethodResolver(classPath, "Lblah;->blah()V");
- MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver);
+ MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver, false);
Instruction deodexedInstruction = methodAnalyzer.getInstructions().get(0);
Assert.assertEquals(Opcode.INVOKE_VIRTUAL, deodexedInstruction.getOpcode());
@@ -93,12 +94,12 @@ public class CustomMethodInlineTableTest {
ClassDef classDef = new ImmutableClassDef("Lblah;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null,
null, null, null, null, ImmutableList.of(method), null);
- DexFile dexFile = new ImmutableDexFile(ImmutableList.of(classDef));
+ DexFile dexFile = new ImmutableDexFile(Opcodes.forApi(19), ImmutableList.of(classDef));
ClassPath classPath = ClassPath.fromClassPath(ImmutableList.<String>of(), ImmutableList.<String>of(), dexFile,
15, false);
InlineMethodResolver inlineMethodResolver = new CustomInlineMethodResolver(classPath, "Lblah;->blah()V");
- MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver);
+ MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver, false);
Instruction deodexedInstruction = methodAnalyzer.getInstructions().get(0);
Assert.assertEquals(Opcode.INVOKE_STATIC, deodexedInstruction.getOpcode());
@@ -120,12 +121,12 @@ public class CustomMethodInlineTableTest {
ClassDef classDef = new ImmutableClassDef("Lblah;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null,
null, null, null, null, ImmutableList.of(method), null);
- DexFile dexFile = new ImmutableDexFile(ImmutableList.of(classDef));
+ DexFile dexFile = new ImmutableDexFile(Opcodes.forApi(19), ImmutableList.of(classDef));
ClassPath classPath = ClassPath.fromClassPath(ImmutableList.<String>of(), ImmutableList.<String>of(), dexFile,
15, false);
InlineMethodResolver inlineMethodResolver = new CustomInlineMethodResolver(classPath, "Lblah;->blah()V");
- MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver);
+ MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver, false);
Instruction deodexedInstruction = methodAnalyzer.getInstructions().get(0);
Assert.assertEquals(Opcode.INVOKE_DIRECT, deodexedInstruction.getOpcode());
diff --git a/dexlib2/src/test/java/org/jf/dexlib2/analysis/util/SuperclassChainTest.java b/dexlib2/src/test/java/org/jf/dexlib2/analysis/util/SuperclassChainTest.java
index 59b0d276..84cd284b 100644
--- a/dexlib2/src/test/java/org/jf/dexlib2/analysis/util/SuperclassChainTest.java
+++ b/dexlib2/src/test/java/org/jf/dexlib2/analysis/util/SuperclassChainTest.java
@@ -34,7 +34,9 @@ package org.jf.dexlib2.analysis.util;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import junit.framework.Assert;
+import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.analysis.ClassPath;
+import org.jf.dexlib2.analysis.DexClassProvider;
import org.jf.dexlib2.analysis.TestUtils;
import org.jf.dexlib2.analysis.TypeProto;
import org.jf.dexlib2.iface.ClassDef;
@@ -45,7 +47,6 @@ import java.io.IOException;
public class SuperclassChainTest {
-
@Test
public void testGetSuperclassChain() throws IOException {
ClassDef objectClassDef = TestUtils.makeClassDef("Ljava/lang/Object;", null);
@@ -56,7 +57,7 @@ public class SuperclassChainTest {
ImmutableSet<ClassDef> classes = ImmutableSet.<ClassDef>of(
objectClassDef, oneClassDef, twoClassDef, threeClassDef);
- ClassPath classPath = new ClassPath(new ImmutableDexFile(classes));
+ ClassPath classPath = new ClassPath(new DexClassProvider(new ImmutableDexFile(Opcodes.forApi(19), classes)));
TypeProto objectClassProto = classPath.getClass("Ljava/lang/Object;");
TypeProto oneClassProto = classPath.getClass("Ltest/one;");
@@ -87,7 +88,7 @@ public class SuperclassChainTest {
ClassDef twoClassDef = TestUtils.makeClassDef("Ltest/two;", "Ltest/one;");
ClassDef threeClassDef = TestUtils.makeClassDef("Ltest/three;", "Ltest/two;");
ImmutableSet<ClassDef> classes = ImmutableSet.<ClassDef>of(twoClassDef, threeClassDef);
- ClassPath classPath = new ClassPath(new ImmutableDexFile(classes));
+ ClassPath classPath = new ClassPath(new DexClassProvider(new ImmutableDexFile(Opcodes.forApi(19), classes)));
TypeProto unknownClassProto = classPath.getUnknownClass();
TypeProto oneClassProto = classPath.getClass("Ltest/one;");
diff --git a/dexlib2/src/test/java/org/jf/dexlib2/builder/MutableMethodImplementationTest.java b/dexlib2/src/test/java/org/jf/dexlib2/builder/MutableMethodImplementationTest.java
new file mode 100644
index 00000000..0df5ab3d
--- /dev/null
+++ b/dexlib2/src/test/java/org/jf/dexlib2/builder/MutableMethodImplementationTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2015, 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.dexlib2.builder;
+
+import org.jf.dexlib2.Opcode;
+import org.jf.dexlib2.builder.instruction.BuilderInstruction10x;
+import org.jf.dexlib2.builder.instruction.BuilderInstruction32x;
+import org.jf.dexlib2.iface.MethodImplementation;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class MutableMethodImplementationTest {
+
+ @Test
+ public void testTryEndAtEndOfMethod() {
+ MethodImplementationBuilder builder = new MethodImplementationBuilder(10);
+
+ Label startLabel = builder.addLabel("start");
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction32x(Opcode.MOVE_16, 0, 0));
+ Label endLabel = builder.addLabel("end");
+
+ builder.addCatch(startLabel, endLabel, startLabel);
+
+ MethodImplementation methodImplementation = builder.getMethodImplementation();
+
+ Assert.assertEquals(0, methodImplementation.getTryBlocks().get(0).getStartCodeAddress());
+ Assert.assertEquals(8, methodImplementation.getTryBlocks().get(0).getCodeUnitCount());
+
+ methodImplementation = new MutableMethodImplementation(methodImplementation);
+
+ Assert.assertEquals(0, methodImplementation.getTryBlocks().get(0).getStartCodeAddress());
+ Assert.assertEquals(8, methodImplementation.getTryBlocks().get(0).getCodeUnitCount());
+ }
+
+ @Test
+ public void testNewLabelByAddress() {
+ MethodImplementationBuilder builder = new MethodImplementationBuilder(10);
+
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction32x(Opcode.MOVE_16, 0, 0));
+
+ MutableMethodImplementation mutableMethodImplementation =
+ new MutableMethodImplementation(builder.getMethodImplementation());
+
+ mutableMethodImplementation.addCatch(
+ mutableMethodImplementation.newLabelForAddress(0),
+ mutableMethodImplementation.newLabelForAddress(8),
+ mutableMethodImplementation.newLabelForAddress(1));
+
+ Assert.assertEquals(0, mutableMethodImplementation.getTryBlocks().get(0).getStartCodeAddress());
+ Assert.assertEquals(8, mutableMethodImplementation.getTryBlocks().get(0).getCodeUnitCount());
+ Assert.assertEquals(1, mutableMethodImplementation.getTryBlocks().get(0).getExceptionHandlers().get(0)
+ .getHandlerCodeAddress());
+ }
+
+ @Test
+ public void testNewLabelByIndex() {
+ MethodImplementationBuilder builder = new MethodImplementationBuilder(10);
+
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction10x(Opcode.NOP));
+ builder.addInstruction(new BuilderInstruction32x(Opcode.MOVE_16, 0, 0));
+
+ MutableMethodImplementation mutableMethodImplementation =
+ new MutableMethodImplementation(builder.getMethodImplementation());
+
+ mutableMethodImplementation.addCatch(
+ mutableMethodImplementation.newLabelForIndex(0),
+ mutableMethodImplementation.newLabelForIndex(6),
+ mutableMethodImplementation.newLabelForIndex(1));
+
+ Assert.assertEquals(0, mutableMethodImplementation.getTryBlocks().get(0).getStartCodeAddress());
+ Assert.assertEquals(8, mutableMethodImplementation.getTryBlocks().get(0).getCodeUnitCount());
+ Assert.assertEquals(1, mutableMethodImplementation.getTryBlocks().get(0).getExceptionHandlers().get(0)
+ .getHandlerCodeAddress());
+ }
+}
diff --git a/dexlib2/src/test/java/org/jf/dexlib2/writer/DexWriterTest.java b/dexlib2/src/test/java/org/jf/dexlib2/writer/DexWriterTest.java
index 8ba975a1..1a0a2892 100644
--- a/dexlib2/src/test/java/org/jf/dexlib2/writer/DexWriterTest.java
+++ b/dexlib2/src/test/java/org/jf/dexlib2/writer/DexWriterTest.java
@@ -72,12 +72,12 @@ public class DexWriterTest {
MemoryDataStore dataStore = new MemoryDataStore();
try {
- DexPool.writeTo(dataStore, new ImmutableDexFile(ImmutableSet.of(classDef)));
+ DexPool.writeTo(dataStore, new ImmutableDexFile(Opcodes.forApi(19), ImmutableSet.of(classDef)));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
- DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15, false), dataStore.getData());
+ DexBackedDexFile dexFile = new DexBackedDexFile(Opcodes.forApi(15), dataStore.getData());
ClassDef dbClassDef = Iterables.getFirst(dexFile.getClasses(), null);
Assert.assertNotNull(dbClassDef);
Annotation dbAnnotation = Iterables.getFirst(dbClassDef.getAnnotations(), null);
@@ -112,12 +112,12 @@ public class DexWriterTest {
MemoryDataStore dataStore = new MemoryDataStore();
try {
- DexPool.writeTo(dataStore, new ImmutableDexFile(ImmutableSet.of(classDef)));
+ DexPool.writeTo(dataStore, new ImmutableDexFile(Opcodes.forApi(19), ImmutableSet.of(classDef)));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
- DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15, false), dataStore.getData());
+ DexBackedDexFile dexFile = new DexBackedDexFile(Opcodes.forApi(15), dataStore.getData());
ClassDef dbClassDef = Iterables.getFirst(dexFile.getClasses(), null);
Assert.assertNotNull(dbClassDef);
Annotation dbAnnotation = Iterables.getFirst(dbClassDef.getAnnotations(), null);
diff --git a/dexlib2/src/test/java/org/jf/dexlib2/writer/JumboStringConversionTest.java b/dexlib2/src/test/java/org/jf/dexlib2/writer/JumboStringConversionTest.java
index 7e504a17..c246e0ec 100644
--- a/dexlib2/src/test/java/org/jf/dexlib2/writer/JumboStringConversionTest.java
+++ b/dexlib2/src/test/java/org/jf/dexlib2/writer/JumboStringConversionTest.java
@@ -62,7 +62,7 @@ import java.util.List;
public class JumboStringConversionTest {
@Test
public void testJumboStringConversion() throws IOException {
- DexBuilder dexBuilder = DexBuilder.makeDexBuilder(15);
+ DexBuilder dexBuilder = DexBuilder.makeDexBuilder(Opcodes.forApi(15));
MethodImplementationBuilder methodBuilder = new MethodImplementationBuilder(1);
for (int i=0; i<66000; i++) {
@@ -92,7 +92,7 @@ public class JumboStringConversionTest {
MemoryDataStore dexStore = new MemoryDataStore();
dexBuilder.writeTo(dexStore);
- DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15, false), dexStore.getData());
+ DexBackedDexFile dexFile = new DexBackedDexFile(Opcodes.forApi(15), dexStore.getData());
ClassDef classDef = Iterables.getFirst(dexFile.getClasses(), null);
Assert.assertNotNull(classDef);
@@ -122,7 +122,7 @@ public class JumboStringConversionTest {
@Test
public void testJumboStringConversion_NonMethodBuilder() throws IOException {
- DexBuilder dexBuilder = DexBuilder.makeDexBuilder(15);
+ DexBuilder dexBuilder = DexBuilder.makeDexBuilder(Opcodes.forApi(15));
final List<Instruction> instructions = Lists.newArrayList();
for (int i=0; i<66000; i++) {
@@ -189,7 +189,7 @@ public class JumboStringConversionTest {
MemoryDataStore dexStore = new MemoryDataStore();
dexBuilder.writeTo(dexStore);
- DexBackedDexFile dexFile = new DexBackedDexFile(new Opcodes(15, false), dexStore.getData());
+ DexBackedDexFile dexFile = new DexBackedDexFile(Opcodes.forApi(15), dexStore.getData());
ClassDef classDef = Iterables.getFirst(dexFile.getClasses(), null);
Assert.assertNotNull(classDef);
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 7e793277..692d204c 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sun Mar 01 19:20:47 PST 2015
+#Sun Feb 14 12:35:03 PST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.11-bin.zip
diff --git a/settings.gradle b/settings.gradle
index 6c4f08cf..f7a6cf75 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1,5 @@
-include 'util', 'dexlib2', 'baksmali', 'smali', 'dexlib2:accessorTestGenerator' \ No newline at end of file
+include 'util', 'dexlib2', 'baksmali', 'smali', 'dexlib2:accessorTestGenerator'
+
+if (System.getProperty("user.dir").startsWith(file("smalidea").absolutePath)) {
+ include 'smalidea'
+} \ No newline at end of file
diff --git a/smali/build.gradle b/smali/build.gradle
index 0e5cbf2d..75001d73 100644
--- a/smali/build.gradle
+++ b/smali/build.gradle
@@ -52,6 +52,15 @@ configurations {
compile.exclude group: 'de.jflex', module: 'jflex'
}
+sourceSets {
+ main {
+ resources {
+ // This adds the generated .tokens files to the jar
+ srcDir 'build/generated-src/antlr/main'
+ }
+ }
+}
+
idea {
module {
excludeDirs -= buildDir
@@ -83,16 +92,13 @@ dependencies {
processResources.inputs.property('version', version)
processResources.expand('version': version)
-// This is the jar that gets uploaded to maven
-jar {
- baseName = 'maven'
-}
-
// Build a separate jar that contains all dependencies
task fatJar(type: Jar, dependsOn: jar) {
from sourceSets.main.output
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
+ classifier = 'fat'
+
manifest {
attributes('Main-Class': 'org.jf.smali.main')
}
diff --git a/smali/src/main/antlr/smaliParser.g b/smali/src/main/antlr/smaliParser.g
index 6d07452c..fcccbe80 100644
--- a/smali/src/main/antlr/smaliParser.g
+++ b/smali/src/main/antlr/smaliParser.g
@@ -39,7 +39,7 @@ tokens {
ANNOTATION_DIRECTIVE;
ANNOTATION_VISIBILITY;
ARRAY_DATA_DIRECTIVE;
- ARRAY_DESCRIPTOR;
+ ARRAY_TYPE_PREFIX;
ARROW;
BOOL_LITERAL;
BYTE_LITERAL;
@@ -133,10 +133,7 @@ tokens {
OPEN_BRACE;
OPEN_PAREN;
PACKED_SWITCH_DIRECTIVE;
- PARAM_LIST_END;
- PARAM_LIST_START;
- PARAM_LIST_OR_ID_END;
- PARAM_LIST_OR_ID_START;
+ PARAM_LIST_OR_ID_PRIMITIVE_TYPE;
PARAMETER_DIRECTIVE;
POSITIVE_INTEGER_LITERAL;
PRIMITIVE_TYPE;
@@ -260,7 +257,7 @@ import org.jf.dexlib2.Opcodes;
private boolean verboseErrors = false;
private boolean allowOdex = false;
private int apiLevel = 15;
- private Opcodes opcodes = new Opcodes(apiLevel, false);
+ private Opcodes opcodes = Opcodes.forApi(apiLevel);
public void setVerboseErrors(boolean verboseErrors) {
this.verboseErrors = verboseErrors;
@@ -377,16 +374,12 @@ import org.jf.dexlib2.Opcodes;
case '[':
{
int i = typeStartIndex;
- while (str.charAt(++i) == '[');
+ while (str.charAt(++i) == '[');
- if (str.charAt(i++) == 'L') {
- while (str.charAt(i++) != ';');
- }
-
- token.setType(ARRAY_DESCRIPTOR);
- token.setText(str.substring(typeStartIndex, i));
- token.setStopIndex(baseToken.getStartIndex() + i - 1);
- break;
+ token.setType(ARRAY_TYPE_PREFIX);
+ token.setText(str.substring(typeStartIndex, i));
+ token.setStopIndex(baseToken.getStartIndex() + i - 1);
+ break;
}
default:
throw new RuntimeException(String.format("Invalid character '\%c' in param list \"\%s\" at position \%d", str.charAt(typeStartIndex), str, typeStartIndex));
@@ -541,7 +534,7 @@ registers_directive
};
param_list_or_id
- : PARAM_LIST_OR_ID_START PRIMITIVE_TYPE+ PARAM_LIST_OR_ID_END;
+ : PARAM_LIST_OR_ID_PRIMITIVE_TYPE+;
/*identifiers are much more general than most languages. Any of the below can either be
the indicated type OR an identifier, depending on the context*/
@@ -598,25 +591,30 @@ method_prototype
: OPEN_PAREN param_list CLOSE_PAREN type_descriptor
-> ^(I_METHOD_PROTOTYPE[$start, "I_METHOD_PROTOTYPE"] ^(I_METHOD_RETURN_TYPE type_descriptor) param_list?);
+param_list_or_id_primitive_type
+ : PARAM_LIST_OR_ID_PRIMITIVE_TYPE -> PRIMITIVE_TYPE[$PARAM_LIST_OR_ID_PRIMITIVE_TYPE];
+
param_list
- : PARAM_LIST_START nonvoid_type_descriptor* PARAM_LIST_END -> nonvoid_type_descriptor*
- | PARAM_LIST_OR_ID_START PRIMITIVE_TYPE* PARAM_LIST_OR_ID_END -> PRIMITIVE_TYPE*
+ : param_list_or_id_primitive_type+
| nonvoid_type_descriptor*;
+array_descriptor
+ : ARRAY_TYPE_PREFIX (PRIMITIVE_TYPE | CLASS_DESCRIPTOR);
+
type_descriptor
: VOID_TYPE
| PRIMITIVE_TYPE
| CLASS_DESCRIPTOR
- | ARRAY_DESCRIPTOR;
+ | array_descriptor;
nonvoid_type_descriptor
: PRIMITIVE_TYPE
| CLASS_DESCRIPTOR
- | ARRAY_DESCRIPTOR;
+ | array_descriptor;
reference_type_descriptor
: CLASS_DESCRIPTOR
- | ARRAY_DESCRIPTOR;
+ | array_descriptor;
integer_literal
: POSITIVE_INTEGER_LITERAL -> INTEGER_LITERAL[$POSITIVE_INTEGER_LITERAL]
@@ -692,9 +690,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
diff --git a/smali/src/main/antlr/smaliTreeWalker.g b/smali/src/main/antlr/smaliTreeWalker.g
index 8eed2b20..c3a50994 100644
--- a/smali/src/main/antlr/smaliTreeWalker.g
+++ b/smali/src/main/antlr/smaliTreeWalker.g
@@ -77,7 +77,7 @@ import java.util.*;
public String classType;
private boolean verboseErrors = false;
private int apiLevel = 15;
- private Opcodes opcodes = new Opcodes(apiLevel, false);
+ private Opcodes opcodes = Opcodes.forApi(apiLevel);
private DexBuilder dexBuilder;
public void setDexBuilder(DexBuilder dexBuilder) {
@@ -1219,20 +1219,20 @@ insn_sparse_switch_directive
$method::methodBuilder.addInstruction(new BuilderSparseSwitchPayload($sparse_switch_elements.elements));
};
+array_descriptor returns [String type]
+ : ARRAY_TYPE_PREFIX ( PRIMITIVE_TYPE { $type = $ARRAY_TYPE_PREFIX.text + $PRIMITIVE_TYPE.text; }
+ | CLASS_DESCRIPTOR { $type = $ARRAY_TYPE_PREFIX.text + $CLASS_DESCRIPTOR.text; });
+
nonvoid_type_descriptor returns [String type]
- : (PRIMITIVE_TYPE
- | CLASS_DESCRIPTOR
- | ARRAY_DESCRIPTOR)
- {
- $type = $start.getText();
- };
+ : (PRIMITIVE_TYPE { $type = $text; }
+ | CLASS_DESCRIPTOR { $type = $text; }
+ | array_descriptor { $type = $array_descriptor.type; })
+ ;
reference_type_descriptor returns [String type]
- : (CLASS_DESCRIPTOR
- | ARRAY_DESCRIPTOR)
- {
- $type = $start.getText();
- };
+ : (CLASS_DESCRIPTOR { $type = $text; }
+ | array_descriptor { $type = $array_descriptor.type; })
+ ;
type_descriptor returns [String type]
: VOID_TYPE {$type = "V";}
diff --git a/smali/src/main/java/org/jf/smali/SmaliOptions.java b/smali/src/main/java/org/jf/smali/SmaliOptions.java
new file mode 100644
index 00000000..165c3a89
--- /dev/null
+++ b/smali/src/main/java/org/jf/smali/SmaliOptions.java
@@ -0,0 +1,52 @@
+/*
+ * 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.smali;
+
+public class SmaliOptions {
+ public int apiLevel = 15;
+ public String outputDexFile = "out.dex";
+
+ public int jobs = Runtime.getRuntime().availableProcessors();
+ public boolean allowOdex = false;
+ public boolean verboseErrors = false;
+ public boolean printTokens = false;
+ public boolean experimental = false;
+
+ public boolean listMethods = false;
+ public String methodListFilename = null;
+
+ public boolean listFields = false;
+ public String fieldListFilename = null;
+
+ public boolean listTypes = false;
+ public String typeListFilename = null;
+}
diff --git a/smali/src/main/java/org/jf/smali/SmaliTestUtils.java b/smali/src/main/java/org/jf/smali/SmaliTestUtils.java
index 26de0089..bef07414 100644
--- a/smali/src/main/java/org/jf/smali/SmaliTestUtils.java
+++ b/smali/src/main/java/org/jf/smali/SmaliTestUtils.java
@@ -57,7 +57,7 @@ public class SmaliTestUtils {
throws RecognitionException, IOException {
CommonTokenStream tokens;
LexerErrorInterface lexer;
- DexBuilder dexBuilder = DexBuilder.makeDexBuilder(apiLevel);
+ DexBuilder dexBuilder = DexBuilder.makeDexBuilder(Opcodes.forApi(apiLevel, experimental));
Reader reader = new StringReader(smaliText);
@@ -94,8 +94,7 @@ public class SmaliTestUtils {
dexBuilder.writeTo(dataStore);
- DexBackedDexFile dexFile = new DexBackedDexFile(
- new Opcodes(apiLevel, experimental), dataStore.getData());
+ DexBackedDexFile dexFile = new DexBackedDexFile(Opcodes.forApi(apiLevel, experimental), dataStore.getData());
return Iterables.getFirst(dexFile.getClasses(), null);
}
diff --git a/smali/src/main/java/org/jf/smali/main.java b/smali/src/main/java/org/jf/smali/main.java
index 98fb7a1f..e5562808 100644
--- a/smali/src/main/java/org/jf/smali/main.java
+++ b/smali/src/main/java/org/jf/smali/main.java
@@ -36,8 +36,8 @@ import org.antlr.runtime.Token;
import org.antlr.runtime.TokenSource;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.CommonTreeNodeStream;
-import org.antlr.runtime.tree.TreeNodeStream;
import org.apache.commons.cli.*;
+import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.writer.builder.DexBuilder;
import org.jf.dexlib2.writer.io.FileDataStore;
import org.jf.util.ConsoleUtil;
@@ -46,10 +46,7 @@ import org.jf.util.SmaliHelpFormatter;
import javax.annotation.Nonnull;
import java.io.*;
import java.util.*;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
+import java.util.concurrent.*;
/**
* Main class for smali. It recognizes enough options to be able to dispatch
@@ -93,6 +90,95 @@ public class main {
}
/**
+ * A more programmatic-friendly entry point for smali
+ *
+ * @param options a SmaliOptions object with the options to run smali with
+ * @param input The files/directories to process
+ * @return true if assembly completed with no errors, or false if errors were encountered
+ */
+ public static boolean run(final SmaliOptions options, String... input) throws IOException {
+ LinkedHashSet<File> filesToProcessSet = new LinkedHashSet<File>();
+
+ for (String fileToProcess: input) {
+ File argFile = new File(fileToProcess);
+
+ if (!argFile.exists()) {
+ throw new IllegalArgumentException("Cannot find file or directory \"" + fileToProcess + "\"");
+ }
+
+ if (argFile.isDirectory()) {
+ getSmaliFilesInDir(argFile, filesToProcessSet);
+ } else if (argFile.isFile()) {
+ filesToProcessSet.add(argFile);
+ }
+ }
+
+ boolean errors = false;
+
+ final DexBuilder dexBuilder = DexBuilder.makeDexBuilder(
+ Opcodes.forApi(options.apiLevel, options.experimental));
+
+ ExecutorService executor = Executors.newFixedThreadPool(options.jobs);
+ List<Future<Boolean>> tasks = Lists.newArrayList();
+
+ for (final File file: filesToProcessSet) {
+ tasks.add(executor.submit(new Callable<Boolean>() {
+ @Override public Boolean call() throws Exception {
+ return assembleSmaliFile(file, dexBuilder, options);
+ }
+ }));
+ }
+
+ for (Future<Boolean> task: tasks) {
+ while(true) {
+ try {
+ try {
+ if (!task.get()) {
+ errors = true;
+ }
+ } catch (ExecutionException ex) {
+ throw new RuntimeException(ex);
+ }
+ } catch (InterruptedException ex) {
+ continue;
+ }
+ break;
+ }
+ }
+
+ executor.shutdown();
+
+ if (errors) {
+ return false;
+ }
+
+ if (options.listMethods) {
+ if (Strings.isNullOrEmpty(options.methodListFilename)) {
+ options.methodListFilename = options.outputDexFile + ".methods";
+ }
+ writeReferences(dexBuilder.getMethodReferences(), options.methodListFilename);
+ }
+
+ if (options.listFields) {
+ if (Strings.isNullOrEmpty(options.fieldListFilename)) {
+ options.fieldListFilename = options.outputDexFile + ".fields";
+ }
+ writeReferences(dexBuilder.getFieldReferences(), options.fieldListFilename);
+ }
+
+ if (options.listTypes) {
+ if (Strings.isNullOrEmpty(options.typeListFilename)) {
+ options.typeListFilename = options.outputDexFile + ".types";
+ }
+ writeReferences(dexBuilder.getTypeReferences(), options.typeListFilename);
+ }
+
+ dexBuilder.writeTo(new FileDataStore(new File(options.outputDexFile)));
+
+ return true;
+ }
+
+ /**
* Run!
*/
public static void main(String[] args) {
@@ -109,24 +195,7 @@ public class main {
return;
}
- int jobs = -1;
- boolean allowOdex = false;
- boolean verboseErrors = false;
- boolean printTokens = false;
- boolean experimental = false;
-
- boolean listMethods = false;
- String methodListFilename = null;
-
- boolean listFields = false;
- String fieldListFilename = null;
-
- boolean listTypes = false;
- String typeListFilename = null;
-
- int apiLevel = 15;
-
- String outputDexFile = "out.dex";
+ SmaliOptions smaliOptions = new SmaliOptions();
String[] remainingArgs = commandLine.getArgs();
@@ -150,37 +219,37 @@ public class main {
usage(false);
return;
case 'o':
- outputDexFile = commandLine.getOptionValue("o");
+ smaliOptions.outputDexFile = commandLine.getOptionValue("o");
break;
case 'x':
- allowOdex = true;
+ smaliOptions.allowOdex = true;
break;
case 'X':
- experimental = true;
+ smaliOptions.experimental = true;
break;
case 'a':
- apiLevel = Integer.parseInt(commandLine.getOptionValue("a"));
+ smaliOptions.apiLevel = Integer.parseInt(commandLine.getOptionValue("a"));
break;
case 'j':
- jobs = Integer.parseInt(commandLine.getOptionValue("j"));
+ smaliOptions.jobs = Integer.parseInt(commandLine.getOptionValue("j"));
break;
case 'm':
- listMethods = true;
- methodListFilename = commandLine.getOptionValue("m");
+ smaliOptions.listMethods = true;
+ smaliOptions.methodListFilename = commandLine.getOptionValue("m");
break;
case 'f':
- listFields = true;
- fieldListFilename = commandLine.getOptionValue("f");
+ smaliOptions.listFields = true;
+ smaliOptions.fieldListFilename = commandLine.getOptionValue("f");
break;
case 't':
- listTypes = true;
- typeListFilename = commandLine.getOptionValue("t");
+ smaliOptions.listTypes = true;
+ smaliOptions.typeListFilename = commandLine.getOptionValue("t");
break;
case 'V':
- verboseErrors = true;
+ smaliOptions.verboseErrors = true;
break;
case 'T':
- printTokens = true;
+ smaliOptions.printTokens = true;
break;
default:
assert false;
@@ -193,90 +262,9 @@ public class main {
}
try {
- LinkedHashSet<File> filesToProcess = new LinkedHashSet<File>();
-
- for (String arg: remainingArgs) {
- File argFile = new File(arg);
-
- if (!argFile.exists()) {
- throw new RuntimeException("Cannot find file or directory \"" + arg + "\"");
- }
-
- if (argFile.isDirectory()) {
- getSmaliFilesInDir(argFile, filesToProcess);
- } else if (argFile.isFile()) {
- filesToProcess.add(argFile);
- }
- }
-
- if (jobs <= 0) {
- jobs = Runtime.getRuntime().availableProcessors();
- if (jobs > 6) {
- jobs = 6;
- }
- }
-
- boolean errors = false;
-
- final DexBuilder dexBuilder = DexBuilder.makeDexBuilder(apiLevel);
- ExecutorService executor = Executors.newFixedThreadPool(jobs);
- List<Future<Boolean>> tasks = Lists.newArrayList();
-
- final boolean finalVerboseErrors = verboseErrors;
- final boolean finalPrintTokens = printTokens;
- final boolean finalAllowOdex = allowOdex;
- final int finalApiLevel = apiLevel;
- final boolean finalExperimental = experimental;
- for (final File file: filesToProcess) {
- tasks.add(executor.submit(new Callable<Boolean>() {
- @Override public Boolean call() throws Exception {
- return assembleSmaliFile(file, dexBuilder, finalVerboseErrors, finalPrintTokens,
- finalAllowOdex, finalApiLevel, finalExperimental);
- }
- }));
- }
-
- for (Future<Boolean> task: tasks) {
- while(true) {
- try {
- if (!task.get()) {
- errors = true;
- }
- } catch (InterruptedException ex) {
- continue;
- }
- break;
- }
- }
-
- executor.shutdown();
-
- if (errors) {
+ if (!run(smaliOptions, remainingArgs)) {
System.exit(1);
}
-
- if (listMethods) {
- if (Strings.isNullOrEmpty(methodListFilename)) {
- methodListFilename = outputDexFile + ".methods";
- }
- writeReferences(dexBuilder.getMethodReferences(), methodListFilename);
- }
-
- if (listFields) {
- if (Strings.isNullOrEmpty(fieldListFilename)) {
- fieldListFilename = outputDexFile + ".fields";
- }
- writeReferences(dexBuilder.getFieldReferences(), fieldListFilename);
- }
-
- if (listTypes) {
- if (Strings.isNullOrEmpty(typeListFilename)) {
- typeListFilename = outputDexFile + ".types";
- }
- writeReferences(dexBuilder.getTypeReferences(), typeListFilename);
- }
-
- dexBuilder.writeTo(new FileDataStore(new File(outputDexFile)));
} catch (RuntimeException ex) {
System.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:");
ex.printStackTrace();
@@ -318,22 +306,20 @@ public class main {
}
}
- private static boolean assembleSmaliFile(File smaliFile, DexBuilder dexBuilder, boolean verboseErrors,
- boolean printTokens, boolean allowOdex, int apiLevel,
- boolean experimental)
+ private static boolean assembleSmaliFile(File smaliFile, DexBuilder dexBuilder, SmaliOptions options)
throws Exception {
CommonTokenStream tokens;
LexerErrorInterface lexer;
- FileInputStream fis = new FileInputStream(smaliFile.getAbsolutePath());
+ FileInputStream fis = new FileInputStream(smaliFile);
InputStreamReader reader = new InputStreamReader(fis, "UTF-8");
lexer = new smaliFlexLexer(reader);
((smaliFlexLexer)lexer).setSourceFile(smaliFile);
tokens = new CommonTokenStream((TokenSource)lexer);
- if (printTokens) {
+ if (options.printTokens) {
tokens.getTokens();
for (int i=0; i<tokens.size(); i++) {
@@ -349,9 +335,9 @@ public class main {
}
smaliParser parser = new smaliParser(tokens);
- parser.setVerboseErrors(verboseErrors);
- parser.setAllowOdex(allowOdex);
- parser.setApiLevel(apiLevel, experimental);
+ parser.setVerboseErrors(options.verboseErrors);
+ parser.setAllowOdex(options.allowOdex);
+ parser.setApiLevel(options.apiLevel, options.experimental);
smaliParser.smali_file_return result = parser.smali_file();
@@ -364,14 +350,14 @@ public class main {
CommonTreeNodeStream treeStream = new CommonTreeNodeStream(t);
treeStream.setTokenStream(tokens);
- if (printTokens) {
+ if (options.printTokens) {
System.out.println(t.toStringTree());
}
smaliTreeWalker dexGen = new smaliTreeWalker(treeStream);
- dexGen.setApiLevel(apiLevel, experimental);
+ dexGen.setApiLevel(options.apiLevel, options.experimental);
- dexGen.setVerboseErrors(verboseErrors);
+ dexGen.setVerboseErrors(options.verboseErrors);
dexGen.setDexBuilder(dexBuilder);
dexGen.smali_file();
diff --git a/smali/src/main/jflex/smaliLexer.jflex b/smali/src/main/jflex/smaliLexer.jflex
index bc17362f..2f57a438 100644
--- a/smali/src/main/jflex/smaliLexer.jflex
+++ b/smali/src/main/jflex/smaliLexer.jflex
@@ -172,6 +172,20 @@ import static org.jf.smali.smaliParser.*;
public String getErrorHeader(InvalidToken token) {
return getSourceName()+"["+ token.getLine()+","+token.getCharPositionInLine()+"]";
}
+
+ public void reset(CharSequence charSequence, int start, int end, int initialState) {
+ zzReader = BlankReader.INSTANCE;
+ zzBuffer = new char[charSequence.length()];
+ for (int i=0; i<charSequence.length(); i++) {
+ zzBuffer[i] = charSequence.charAt(i);
+ }
+
+ yychar = zzCurrentPos = zzMarkedPos = zzStartRead = start;
+ zzEndRead = end;
+ zzAtBOL = true;
+ zzAtEOF = false;
+ yybegin(initialState);
+ }
%}
HexPrefix = 0 [xX]
@@ -217,13 +231,14 @@ PrimitiveType = [ZBSCIJFD]
ClassDescriptor = L ({SimpleName} "/")* {SimpleName} ;
-ArrayDescriptor = "[" + ({PrimitiveType} | {ClassDescriptor})
+ArrayPrefix = "["+
-Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
+Type = {PrimitiveType} | {ClassDescriptor} | {ArrayPrefix} ({ClassDescriptor} | {PrimitiveType})
%state PARAM_LIST_OR_ID
%state PARAM_LIST
+%state ARRAY_DESCRIPTOR
%state STRING
%state CHAR
@@ -292,17 +307,17 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
}
<PARAM_LIST_OR_ID> {
- {PrimitiveType} { return newToken(PRIMITIVE_TYPE); }
- [^] { yypushback(1); yybegin(YYINITIAL); return newToken(PARAM_LIST_OR_ID_END); }
- <<EOF>> { yybegin(YYINITIAL); return newToken(PARAM_LIST_OR_ID_END); }
+ {PrimitiveType} { return newToken(PARAM_LIST_OR_ID_PRIMITIVE_TYPE); }
+ [^] { yypushback(1); yybegin(YYINITIAL); }
+ <<EOF>> { yybegin(YYINITIAL); }
}
<PARAM_LIST> {
{PrimitiveType} { return newToken(PRIMITIVE_TYPE); }
{ClassDescriptor} { return newToken(CLASS_DESCRIPTOR); }
- {ArrayDescriptor} { return newToken(ARRAY_DESCRIPTOR); }
- [^] { yypushback(1); yybegin(YYINITIAL); return newToken(PARAM_LIST_END); }
- <<EOF>> { yybegin(YYINITIAL); return newToken(PARAM_LIST_END); }
+ {ArrayPrefix} { return newToken(ARRAY_TYPE_PREFIX); }
+ [^] { yypushback(1); yybegin(YYINITIAL);}
+ <<EOF>> { yybegin(YYINITIAL);}
}
<STRING> {
@@ -406,7 +421,7 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
return newToken(INSTRUCTION_FORMAT10x);
}
- "return-void-barrier" {
+ "return-void-barrier" | "return-void-no-barrier" {
return newToken(INSTRUCTION_FORMAT10x_ODEX);
}
@@ -507,7 +522,9 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
"liberate-variable" {
return newToken(INSTRUCTION_FORMAT22c_STRING);
}
- "iget-quick" | "iget-wide-quick" | "iget-object-quick" | "iput-quick" | "iput-wide-quick" | "iput-object-quick" {
+
+ "iget-quick" | "iget-wide-quick" | "iget-object-quick" | "iput-quick" | "iput-wide-quick" | "iput-object-quick" |
+ "iput-boolean-quick" | "iput-byte-quick" | "iput-char-quick" | "iput-short-quick" {
return newToken(INSTRUCTION_FORMAT22cs_FIELD);
}
@@ -612,23 +629,36 @@ Type = {PrimitiveType} | {ClassDescriptor} | {ArrayDescriptor}
}
}
+<ARRAY_DESCRIPTOR> {
+ {PrimitiveType} { yybegin(YYINITIAL); return newToken(PRIMITIVE_TYPE); }
+ {ClassDescriptor} { yybegin(YYINITIAL); return newToken(CLASS_DESCRIPTOR); }
+ [^] { yypushback(1); yybegin(YYINITIAL); }
+ <<EOF>> { yybegin(YYINITIAL); }
+}
+
/*Types*/
<YYINITIAL> {
{PrimitiveType} { return newToken(PRIMITIVE_TYPE); }
V { return newToken(VOID_TYPE); }
{ClassDescriptor} { return newToken(CLASS_DESCRIPTOR); }
- {ArrayDescriptor} { return newToken(ARRAY_DESCRIPTOR); }
+
+ // we have to drop into a separate state so that we don't parse something like
+ // "[I->" as "[" followed by "I-" as a SIMPLE_NAME
+ {ArrayPrefix} {
+ yybegin(ARRAY_DESCRIPTOR);
+ return newToken(ARRAY_TYPE_PREFIX);
+ }
{PrimitiveType} {PrimitiveType}+ {
+ // go back and re-lex it as a PARAM_LIST_OR_ID
yypushback(yylength());
yybegin(PARAM_LIST_OR_ID);
- return newToken(PARAM_LIST_OR_ID_START);
}
{Type} {Type}+ {
+ // go back and re-lex it as a PARAM_LIST
yypushback(yylength());
yybegin(PARAM_LIST);
- return newToken(PARAM_LIST_START);
}
{SimpleName} { return newToken(SIMPLE_NAME); }
diff --git a/smali/src/test/resources/LexerTest/InstructionTest.smali b/smali/src/test/resources/LexerTest/InstructionTest.smali
index f6dcbb1e..174cff8c 100644
--- a/smali/src/test/resources/LexerTest/InstructionTest.smali
+++ b/smali/src/test/resources/LexerTest/InstructionTest.smali
@@ -2,6 +2,7 @@ goto
return-void
nop
return-void-barrier
+return-void-no-barrier
const/4
move-result
move-result-wide
@@ -132,6 +133,10 @@ iget-object-quick
iput-quick
iput-wide-quick
iput-object-quick
+iput-boolean-quick
+iput-byte-quick
+iput-char-quick
+iput-short-quick
rsub-int
add-int/lit16
mul-int/lit16
diff --git a/smali/src/test/resources/LexerTest/InstructionTest.tokens b/smali/src/test/resources/LexerTest/InstructionTest.tokens
index fb5503b5..fa959bad 100644
--- a/smali/src/test/resources/LexerTest/InstructionTest.tokens
+++ b/smali/src/test/resources/LexerTest/InstructionTest.tokens
@@ -2,6 +2,7 @@ INSTRUCTION_FORMAT10t("goto")
INSTRUCTION_FORMAT10x("return-void")
INSTRUCTION_FORMAT10x("nop")
INSTRUCTION_FORMAT10x_ODEX("return-void-barrier")
+INSTRUCTION_FORMAT10x_ODEX("return-void-no-barrier")
INSTRUCTION_FORMAT11n("const/4")
INSTRUCTION_FORMAT11x("move-result")
INSTRUCTION_FORMAT11x("move-result-wide")
@@ -132,6 +133,10 @@ INSTRUCTION_FORMAT22cs_FIELD("iget-object-quick")
INSTRUCTION_FORMAT22cs_FIELD("iput-quick")
INSTRUCTION_FORMAT22cs_FIELD("iput-wide-quick")
INSTRUCTION_FORMAT22cs_FIELD("iput-object-quick")
+INSTRUCTION_FORMAT22cs_FIELD("iput-boolean-quick")
+INSTRUCTION_FORMAT22cs_FIELD("iput-byte-quick")
+INSTRUCTION_FORMAT22cs_FIELD("iput-char-quick")
+INSTRUCTION_FORMAT22cs_FIELD("iput-short-quick")
INSTRUCTION_FORMAT22s_OR_ID("rsub-int")
INSTRUCTION_FORMAT22s("add-int/lit16")
INSTRUCTION_FORMAT22s("mul-int/lit16")
diff --git a/smali/src/test/resources/LexerTest/RealSmaliFileTest.tokens b/smali/src/test/resources/LexerTest/RealSmaliFileTest.tokens
index ba40c2f2..f9b096fb 100644
--- a/smali/src/test/resources/LexerTest/RealSmaliFileTest.tokens
+++ b/smali/src/test/resources/LexerTest/RealSmaliFileTest.tokens
@@ -184,7 +184,8 @@ REGISTER("v0")
COMMA(",")
REGISTER("v0")
COMMA(",")
-ARRAY_DESCRIPTOR("[I")
+ARRAY_TYPE_PREFIX("[")
+PRIMITIVE_TYPE("I")
INSTRUCTION_FORMAT31t("fill-array-data")
REGISTER("v0")
COMMA(",")
@@ -197,7 +198,8 @@ CLASS_DESCRIPTOR("Lcom/android/internal/os/BatteryStatsImpl;")
ARROW("->")
SIMPLE_NAME("PROC_WAKELOCKS_FORMAT")
COLON(":")
-ARRAY_DESCRIPTOR("[I")
+ARRAY_TYPE_PREFIX("[")
+PRIMITIVE_TYPE("I")
LINE_DIRECTIVE(".line")
POSITIVE_INTEGER_LITERAL("3495")
INSTRUCTION_FORMAT21c_TYPE("new-instance")
@@ -552,13 +554,11 @@ METHOD_DIRECTIVE(".method")
ACCESS_SPEC("public")
SIMPLE_NAME("setCallForwardingOption")
OPEN_PAREN("(")
-PARAM_LIST_START("")
PRIMITIVE_TYPE("I")
PRIMITIVE_TYPE("I")
CLASS_DESCRIPTOR("Ljava/lang/String;")
PRIMITIVE_TYPE("I")
CLASS_DESCRIPTOR("Landroid/os/Message;")
-PARAM_LIST_END("")
CLOSE_PAREN(")")
VOID_TYPE("V")
REGISTERS_DIRECTIVE(".registers")
@@ -703,12 +703,10 @@ CLASS_DESCRIPTOR("Lcom/android/internal/telephony/gsm/GSMPhone$MyHandler;")
ARROW("->")
SIMPLE_NAME("obtainMessage")
OPEN_PAREN("(")
-PARAM_LIST_START("")
PRIMITIVE_TYPE("I")
PRIMITIVE_TYPE("I")
PRIMITIVE_TYPE("I")
CLASS_DESCRIPTOR("Ljava/lang/Object;")
-PARAM_LIST_END("")
CLOSE_PAREN(")")
CLASS_DESCRIPTOR("Landroid/os/Message;")
INSTRUCTION_FORMAT11x("move-result-object")
@@ -760,14 +758,12 @@ CLASS_DESCRIPTOR("Lcom/android/internal/telephony/CommandsInterface;")
ARROW("->")
SIMPLE_NAME("setCallForward")
OPEN_PAREN("(")
-PARAM_LIST_START("")
PRIMITIVE_TYPE("I")
PRIMITIVE_TYPE("I")
PRIMITIVE_TYPE("I")
CLASS_DESCRIPTOR("Ljava/lang/String;")
PRIMITIVE_TYPE("I")
CLASS_DESCRIPTOR("Landroid/os/Message;")
-PARAM_LIST_END("")
CLOSE_PAREN(")")
VOID_TYPE("V")
LINE_DIRECTIVE(".line")
diff --git a/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.smali b/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.smali
index 2120d33f..9becb916 100644
--- a/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.smali
+++ b/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.smali
@@ -23,6 +23,8 @@ LI/I/I;
[D
[Ljava/lang/String;
[LI/I/I;
+[[LI/I/I;
+[[I
IIIII
ZBSCIJFD
@@ -49,4 +51,6 @@ L[Ljava/lang/String;
<linit>
-III \ No newline at end of file
+III
+
+[I->clone()Ljava/lang/Object; \ No newline at end of file
diff --git a/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.tokens b/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.tokens
index d99d2c29..b0b66dbd 100644
--- a/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.tokens
+++ b/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.tokens
@@ -13,63 +13,72 @@ CLASS_DESCRIPTOR("LI;")
CLASS_DESCRIPTOR("LV;")
CLASS_DESCRIPTOR("LI/I/I;")
-ARRAY_DESCRIPTOR("[Z")
-ARRAY_DESCRIPTOR("[B")
-ARRAY_DESCRIPTOR("[S")
-ARRAY_DESCRIPTOR("[C")
-ARRAY_DESCRIPTOR("[I")
-ARRAY_DESCRIPTOR("[J")
-ARRAY_DESCRIPTOR("[F")
-ARRAY_DESCRIPTOR("[D")
-ARRAY_DESCRIPTOR("[Ljava/lang/String;")
-ARRAY_DESCRIPTOR("[LI/I/I;")
-
-PARAM_LIST_OR_ID_START("")
-PRIMITIVE_TYPE("I")
-PRIMITIVE_TYPE("I")
-PRIMITIVE_TYPE("I")
-PRIMITIVE_TYPE("I")
-PRIMITIVE_TYPE("I")
-PARAM_LIST_OR_ID_END("")
-
-PARAM_LIST_OR_ID_START("")
+ARRAY_TYPE_PREFIX("[")
PRIMITIVE_TYPE("Z")
+ARRAY_TYPE_PREFIX("[")
PRIMITIVE_TYPE("B")
+ARRAY_TYPE_PREFIX("[")
PRIMITIVE_TYPE("S")
+ARRAY_TYPE_PREFIX("[")
PRIMITIVE_TYPE("C")
+ARRAY_TYPE_PREFIX("[")
PRIMITIVE_TYPE("I")
+ARRAY_TYPE_PREFIX("[")
PRIMITIVE_TYPE("J")
+ARRAY_TYPE_PREFIX("[")
PRIMITIVE_TYPE("F")
+ARRAY_TYPE_PREFIX("[")
PRIMITIVE_TYPE("D")
-PARAM_LIST_OR_ID_END("")
+ARRAY_TYPE_PREFIX("[")
+CLASS_DESCRIPTOR("Ljava/lang/String;")
+ARRAY_TYPE_PREFIX("[")
+CLASS_DESCRIPTOR("LI/I/I;")
+ARRAY_TYPE_PREFIX("[[")
+CLASS_DESCRIPTOR("LI/I/I;")
+ARRAY_TYPE_PREFIX("[[")
+PRIMITIVE_TYPE("I")
+
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("I")
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("I")
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("I")
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("I")
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("I")
+
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("Z")
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("B")
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("S")
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("C")
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("I")
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("J")
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("F")
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("D")
-PARAM_LIST_START("")
PRIMITIVE_TYPE("I")
CLASS_DESCRIPTOR("La;")
-ARRAY_DESCRIPTOR("[La;")
-ARRAY_DESCRIPTOR("[I")
-PARAM_LIST_END("")
+ARRAY_TYPE_PREFIX("[")
+CLASS_DESCRIPTOR("La;")
+ARRAY_TYPE_PREFIX("[")
+PRIMITIVE_TYPE("I")
-PARAM_LIST_START("")
CLASS_DESCRIPTOR("Ljava/lang/String;")
CLASS_DESCRIPTOR("Ljava/lang/String;")
-PARAM_LIST_END("")
-PARAM_LIST_START("")
-ARRAY_DESCRIPTOR("[I")
-ARRAY_DESCRIPTOR("[I")
-ARRAY_DESCRIPTOR("[I")
-PARAM_LIST_END("")
+ARRAY_TYPE_PREFIX("[")
+PRIMITIVE_TYPE("I")
+ARRAY_TYPE_PREFIX("[")
+PRIMITIVE_TYPE("I")
+ARRAY_TYPE_PREFIX("[")
+PRIMITIVE_TYPE("I")
-PARAM_LIST_START("")
-ARRAY_DESCRIPTOR("[I")
-ARRAY_DESCRIPTOR("[Z")
-PARAM_LIST_END("")
+ARRAY_TYPE_PREFIX("[")
+PRIMITIVE_TYPE("I")
+ARRAY_TYPE_PREFIX("[")
+PRIMITIVE_TYPE("Z")
-PARAM_LIST_START("")
-ARRAY_DESCRIPTOR("[I")
-ARRAY_DESCRIPTOR("[Ljava/lang/String;")
-PARAM_LIST_END("")
+ARRAY_TYPE_PREFIX("[")
+PRIMITIVE_TYPE("I")
+ARRAY_TYPE_PREFIX("[")
+CLASS_DESCRIPTOR("Ljava/lang/String;")
MEMBER_NAME("<init>")
MEMBER_NAME("<clinit>")
@@ -79,17 +88,23 @@ MEMBER_NAME("<init->")
SIMPLE_NAME("Ljava") INVALID_TOKEN("/") SIMPLE_NAME("lang") INVALID_TOKEN("/") SIMPLE_NAME("String")
SIMPLE_NAME("L") INVALID_TOKEN(";")
SIMPLE_NAME("LI")
-SIMPLE_NAME("L") ARRAY_DESCRIPTOR("[Ljava/lang/String;")
+SIMPLE_NAME("L") ARRAY_TYPE_PREFIX("[") CLASS_DESCRIPTOR("Ljava/lang/String;")
-INVALID_TOKEN("[")
-INVALID_TOKEN("[") VOID_TYPE("V")
-INVALID_TOKEN("[") SIMPLE_NAME("java") INVALID_TOKEN("/") SIMPLE_NAME("lang") INVALID_TOKEN("/") SIMPLE_NAME("String") INVALID_TOKEN(";")
-INVALID_TOKEN("[") INVALID_TOKEN(";")
+ARRAY_TYPE_PREFIX("[")
+ARRAY_TYPE_PREFIX("[") VOID_TYPE("V")
+ARRAY_TYPE_PREFIX("[") SIMPLE_NAME("java") INVALID_TOKEN("/") SIMPLE_NAME("lang") INVALID_TOKEN("/") SIMPLE_NAME("String") INVALID_TOKEN(";")
+ARRAY_TYPE_PREFIX("[") INVALID_TOKEN(";")
MEMBER_NAME("<linit>")
-PARAM_LIST_OR_ID_START("")
-PRIMITIVE_TYPE("I")
-PRIMITIVE_TYPE("I")
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("I")
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("I")
+PARAM_LIST_OR_ID_PRIMITIVE_TYPE("I")
+
+ARRAY_TYPE_PREFIX("[")
PRIMITIVE_TYPE("I")
-PARAM_LIST_OR_ID_END("") \ No newline at end of file
+ARROW("->")
+SIMPLE_NAME("clone")
+OPEN_PAREN("(")
+CLOSE_PAREN(")")
+CLASS_DESCRIPTOR("Ljava/lang/Object;") \ No newline at end of file
diff --git a/smalidea/.gitignore b/smalidea/.gitignore
new file mode 100644
index 00000000..f8be3996
--- /dev/null
+++ b/smalidea/.gitignore
@@ -0,0 +1,3 @@
+build
+test-config
+test-system
diff --git a/smalidea/build.gradle b/smalidea/build.gradle
new file mode 100644
index 00000000..6b855d7b
--- /dev/null
+++ b/smalidea/build.gradle
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2013, 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.
+ */
+
+buildscript {
+ repositories {
+ maven {
+ url "https://plugins.gradle.org/m2/"
+ }
+ }
+ dependencies {
+ classpath 'gradle.plugin.org.jetbrains:gradle-intellij-plugin:0.0.40'
+ }
+}
+
+apply plugin: 'java'
+apply plugin: 'idea'
+apply plugin: 'antlr'
+
+version = '0.03'
+
+if (!('release' in gradle.startParameter.taskNames)) {
+ def versionSuffix
+ try {
+ def git = org.eclipse.jgit.api.Git.open(file('..'))
+ def head = git.getRepository().getRef('HEAD')
+ versionSuffix = head.getObjectId().abbreviate(8).name()
+
+ if (!git.status().call().clean) {
+ versionSuffix += '-dirty'
+ }
+ } catch (Exception ex) {
+ // In case we can't get the commit for some reason,
+ // just use -dev
+ versionSuffix = 'dev'
+ }
+
+ def baseVersion = version
+ version = baseVersion + '-' + versionSuffix
+} else {
+ if (System.env.JDK7_HOME == null && !JavaVersion.current().isJava7()) {
+ throw new InvalidUserDataException("bzzzzzzzt. Release builds must be performed with java 7. " +
+ "Either run gradle with java 7, or define the JDK7_HOME environment variable.")
+ }
+}
+
+if (System.env.JDK7_HOME != null) {
+ sourceCompatibility = 1.7
+ targetCompatibility = 1.7
+
+ tasks.withType(JavaCompile) {
+ doFirst {
+ options.fork = true
+ options.bootClasspath = "$System.env.JDK7_HOME/jre/lib/rt.jar"
+ options.bootClasspath += "$File.pathSeparator$System.env.JDK7_HOME/jre/lib/jsse.jar"
+ }
+ }
+}
+
+def sandboxDir = "${buildDir}/sandbox"
+
+// We don't want to use the org.jetbrains.intellij plugin when generating the idea project files,
+// so that idea classes aren't included as project dependencies, since they will already exist
+// in the plugin sdk defined for the project
+if (!('idea' in gradle.startParameter.taskNames)) {
+ apply plugin: 'org.jetbrains.intellij'
+
+ intellij {
+ version 'IC-14.1.4'
+ pluginName 'smalidea'
+
+ updateSinceUntilBuild false
+
+ sandboxDirectory sandboxDir
+ }
+
+ // This prints out the directories that can be used to configure a plugin sdk in IDEA, using
+ // the copy of IDEA downloaded by the org.jetbrains.intellij plugin
+ task ideaDirs() {
+ project.afterEvaluate {
+ if (intellij != null) {
+ println "IDEA Plugin jdk: ${intellij.ideaDirectory}"
+ println "sources: ${project.configurations['intellij-sources'].files[0]}"
+ }
+ }
+ }
+
+ dependencies {
+ compile files("${System.properties['java.home']}/../lib/tools.jar")
+ }
+} else {
+ // If we're running the idea task, let's make sure nothing else is being run, since
+ // we have to use a special configuration for the idea task
+ if (gradle.startParameter.taskNames.size() > 1) {
+ throw new InvalidUserDataException("The idea task must be run by itself.")
+ }
+
+ project(':') {
+ idea {
+ project {
+ ipr {
+ withXml {
+ def node = it.asNode()
+
+ /*node.find { it.@name == 'ProjectRootManager' }
+ .@'project-jdk-type' = 'IDEA JDK'*/
+
+ def componentNode = node.find { it.@name == 'ProjectRunConfigurationManager' }
+ if (componentNode == null) {
+ componentNode = it.node.appendNode 'component', [name: 'ProjectRunConfigurationManager']
+ }
+
+ if (componentNode.find { it.@name == 'All smalidea tests' } == null) {
+ componentNode.append(new XmlParser().parseText("""
+ <configuration default="false" name="All smalidea tests" type="JUnit" factoryName="JUnit">
+ <extension name="coverage" enabled="false" merge="false" runner="idea" />
+ <module name="smalidea" />
+ <option name="TEST_OBJECT" value="directory" />
+ <option name="VM_PARAMETERS" value="-Didea.system.path=${sandboxDir}/config -Didea.system.path=${sandboxDir}/system-test -Didea.load.plugins.id=org.jf.smalidea" />
+ <option name="WORKING_DIRECTORY" value="file://\$PROJECT_DIR\$/smalidea" />
+ <option name="PASS_PARENT_ENVS" value="true" />
+ <option name="TEST_SEARCH_SCOPE">
+ <value defaultName="moduleWithDependencies" />
+ </option>
+ <dir value="\$PROJECT_DIR\$/smalidea/src/test/java" />
+ </configuration>"""))
+ }
+ }
+ }
+ }
+ }
+ }
+
+ idea {
+ module {
+ jdkName = 'IDEA Plugin jdk'
+
+ excludeDirs -= buildDir
+ if (buildDir.exists()) {
+ excludeDirs.addAll(buildDir.listFiles())
+ }
+
+ for (sourceDir in (sourceDirs + testSourceDirs)) {
+ excludeDirs.remove(sourceDir);
+ while ((sourceDir = sourceDir.getParentFile()) != null) {
+ excludeDirs.remove(sourceDir);
+ }
+ }
+
+ iml {
+ withXml {
+ def node = it.node
+
+ node.@type = 'PLUGIN_MODULE'
+
+ def pluginUrl = 'file://$MODULE_DIR$/src/main/resources/META-INF/plugin.xml'
+
+ def pluginNode = node.find { it.@name == 'DevKit.ModuleBuildProperties' }
+ if (pluginNode == null) {
+ node.appendNode 'component', [name: 'DevKit.ModuleBuildProperties',
+ url : pluginUrl]
+ } else {
+ pluginNode.@url = pluginUrl
+ }
+ }
+ }
+ }
+ }
+}
+
+repositories {
+ mavenLocal()
+ mavenCentral()
+}
+
+dependencies {
+ compile project(':smali')
+ compile depends.antlr_runtime
+ compile depends.gson
+
+ antlr depends.antlr
+}
+
+task extractTokens(type: org.gradle.api.tasks.Copy, dependsOn: ':smali:build') {
+ def allArtifacts = configurations.default.resolvedConfiguration.resolvedArtifacts
+ def smaliArtifact = allArtifacts.find { it.moduleVersion.id.name.equals('smali') }
+
+ from(zipTree(smaliArtifact.file)) {
+ include '**/*.tokens'
+ }
+ into "${buildDir}/tokens"
+}
+
+generateGrammarSource {
+ def tokensDir = file("${buildDir}/tokens/org/jf/smali")
+ inputs.file new File(tokensDir, 'smaliParser.tokens')
+ setArguments(['-lib', tokensDir.path])
+ outputDirectory(file("${buildDir}/generated-src/antlr/main/org/jf/smalidea"))
+}
+generateGrammarSource.dependsOn(extractTokens)
+
+ideaModule.dependsOn(generateGrammarSource)
+
+task release(dependsOn: 'buildPlugin') {
+}
+
+tasks.getByPath('idea').dependsOn(project(':').getTasksByName('idea', true).findAll({
+ it.project.name != 'smalidea'
+})) \ No newline at end of file
diff --git a/smalidea/src/main/antlr/smalideaParser.g b/smalidea/src/main/antlr/smalideaParser.g
new file mode 100644
index 00000000..0da263f2
--- /dev/null
+++ b/smalidea/src/main/antlr/smalideaParser.g
@@ -0,0 +1,1363 @@
+/*
+ * [The "BSD licence"]
+ * Copyright (c) 2010 Ben Gruver
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+parser grammar smalideaParser;
+
+options {
+ tokenVocab=smaliParser;
+}
+
+@header {
+package org.jf.smalidea;
+
+import com.intellij.lang.PsiBuilder;
+import com.intellij.lang.PsiBuilder.Marker;
+import com.intellij.psi.tree.IElementType;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+}
+
+
+@members {
+ private PsiBuilder psiBuilder;
+
+ public void setPsiBuilder(PsiBuilder psiBuilder) {
+ this.psiBuilder = psiBuilder;
+ }
+
+ public Marker mark() {
+ return psiBuilder.mark();
+ }
+
+ protected void syncToFollows(boolean acceptEof) {
+ BitSet follow = computeErrorRecoverySet();
+ int mark = input.mark();
+ Marker marker = null;
+ try {
+ int token = input.LA(1);
+ while (!follow.member(token)) {
+ if (token == Token.EOF) {
+ if (acceptEof) {
+ break;
+ }
+ input.rewind(mark);
+ mark = -1;
+ marker = null;
+ return;
+ }
+ if (marker == null) {
+ marker = mark();
+ }
+ input.consume();
+ token = input.LA(1);
+ }
+ } finally {
+ if (mark != -1) {
+ input.release(mark);
+ }
+ if (marker != null) {
+ marker.error("Unexpected tokens");
+ }
+ }
+ }
+
+ @Override
+ public void recover(IntStream input, RecognitionException re) {
+ BitSet followSet = computeErrorRecoverySet();
+ beginResync();
+ consumeUntil(input, followSet);
+ endResync();
+ }
+
+ @Override
+ protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow)
+ throws RecognitionException
+ {
+ RecognitionException e = null;
+ // if next token is what we are looking for then "delete" this token
+ if ( mismatchIsUnwantedToken(input, ttype) ) {
+ e = new UnwantedTokenException(ttype, input);
+ beginResync();
+ Marker mark = mark();
+ input.consume(); // simply delete extra token
+ mark.error(getErrorMessage(e, tokenNames));
+ endResync();
+ reportError(null, e, true); // report after consuming so AW sees the token in the exception
+ // we want to return the token we're actually matching
+ Object matchedSymbol = getCurrentInputSymbol(input);
+ input.consume(); // move past ttype token as if all were ok
+ return matchedSymbol;
+ }
+ // can't recover with single token deletion, try insertion
+ if ( mismatchIsMissingToken(input, follow) ) {
+ Object inserted = getMissingSymbol(input, e, ttype, follow);
+ Marker mark = mark();
+ e = new MissingTokenException(ttype, input, inserted);
+ mark.error(getErrorMessage(e, tokenNames));
+ reportError(null, e, true); // report after inserting so AW sees the token in the exception
+ return inserted;
+ }
+
+ // even that didn't work; must throw the exception
+ e = new MismatchedTokenException(ttype, input);
+ throw e;
+ }
+
+ @Override
+ public void reportError(RecognitionException e) {
+ reportError(mark(), e, false);
+ }
+
+ public void reportError(@Nullable Marker marker, RecognitionException e, boolean alreadyReported) {
+ // if we've already reported an error and have not matched a token
+ // yet successfully, don't report any errors.
+ if ( state.errorRecovery ) {
+ if (marker != null) {
+ marker.drop();
+ }
+ return;
+ }
+ state.syntaxErrors++; // don't count spurious
+ state.errorRecovery = true;
+
+ if (marker != null) {
+ if (!alreadyReported) {
+ displayRecognitionError(marker, this.getTokenNames(), e);
+ } else {
+ marker.drop();
+ }
+ }
+ }
+
+ public void finishToken(Marker marker, IElementType elementType) {
+ if (state.errorRecovery) {
+ marker.drop();
+ } else {
+ marker.done(elementType);
+ }
+ }
+
+ @Override
+ public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
+ displayRecognitionError(mark(), tokenNames, e);
+ }
+
+ public void displayRecognitionError(@Nonnull Marker marker, String[] tokenNames, RecognitionException e) {
+ marker.error(getErrorMessage(e, tokenNames));
+ }
+}
+
+sync[boolean toEof]
+ @init { syncToFollows($toEof); }
+ : /*epsilon*/;
+
+smali_file
+ @init {
+ mark().done(SmaliElementTypes.EXTENDS_LIST);
+ mark().done(SmaliElementTypes.IMPLEMENTS_LIST);
+ }
+ :
+ (
+ ( class_spec
+ | super_spec
+ | implements_spec
+ | source_spec
+ | method
+ | field
+ | annotation
+ )
+ sync[true]
+ )+
+ EOF;
+
+class_spec
+ @init { Marker marker = mark(); }
+ : CLASS_DIRECTIVE class_access_list class_descriptor
+ { marker.done(SmaliElementTypes.CLASS_STATEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+super_spec
+ @init { Marker marker = mark(); }
+ : SUPER_DIRECTIVE class_descriptor
+ { marker.done(SmaliElementTypes.SUPER_STATEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+implements_spec
+ @init { Marker marker = mark(); }
+ : IMPLEMENTS_DIRECTIVE class_descriptor
+ { marker.done(SmaliElementTypes.IMPLEMENTS_STATEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+source_spec
+ @init { Marker marker = mark(); }
+ : SOURCE_DIRECTIVE string_literal
+ { marker.done(SmaliElementTypes.SOURCE_STATEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+// class_access_list should be separate from access_list, because
+// it exists in a slightly different context, and can consume
+// ACCESS_SPECs greedily, without having to look ahead.
+class_access_list
+ @init { Marker marker = mark(); }
+ : ACCESS_SPEC*
+ { marker.done(SmaliElementTypes.MODIFIER_LIST); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+access_list
+ @init { Marker marker = mark(); }
+ : ACCESS_SPEC*
+ { marker.done(SmaliElementTypes.MODIFIER_LIST); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+/*When there are annotations immediately after a field definition, we don't know whether they are field annotations
+or class annotations until we determine if there is an .end field directive. In either case, we still "consume" and parse
+the annotations. If it turns out that they are field annotations, we include them in the I_FIELD AST. Otherwise, we
+add them to the $smali_file::classAnnotations list*/
+field
+ @init {
+ Marker marker = mark();
+ Marker annotationsMarker = null;
+ boolean gotEndField = false;
+ }
+ : FIELD_DIRECTIVE
+ access_list
+ member_name colon nonvoid_type_descriptor
+ field_initializer?
+ (
+ (ANNOTATION_DIRECTIVE)=> (
+ { annotationsMarker = mark(); }
+ ((ANNOTATION_DIRECTIVE)=> annotation)+
+ )
+ )?
+ ( end_field_directive { gotEndField = true; } )?
+ {
+ if (annotationsMarker != null) {
+ if (gotEndField) {
+ annotationsMarker.drop();
+ marker.done(SmaliElementTypes.FIELD);
+ } else {
+ marker.doneBefore(SmaliElementTypes.FIELD, annotationsMarker);
+ annotationsMarker.drop();
+ }
+ } else {
+ marker.done(SmaliElementTypes.FIELD);
+ }
+ };
+ catch [RecognitionException re] {
+ if (annotationsMarker != null) {
+ annotationsMarker.drop();
+ }
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+end_field_directive
+ : END_FIELD_DIRECTIVE;
+
+field_initializer
+ @init { Marker marker = mark(); }
+ : EQUAL literal
+ { marker.done(SmaliElementTypes.FIELD_INITIALIZER); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+method
+ @init {
+ Marker marker = mark();
+ mark().done(SmaliElementTypes.THROWS_LIST);
+ }
+ : METHOD_DIRECTIVE access_list member_name method_prototype statements_and_directives
+ end_method_directive
+ { marker.done(SmaliElementTypes.METHOD); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+end_method_directive
+ : END_METHOD_DIRECTIVE;
+catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+statements_and_directives
+ : (
+ ( ordered_method_item
+ | registers_directive
+ | catch_directive
+ | catchall_directive
+ | parameter_directive
+ | annotation
+ )
+ sync[false]
+ )*;
+
+/* Method items whose order/location is important */
+ordered_method_item
+ : label
+ | instruction
+ | debug_directive;
+
+registers_directive
+ @init { Marker marker = mark(); }
+ : (
+ REGISTERS_DIRECTIVE integral_literal
+ | LOCALS_DIRECTIVE integral_literal
+ )
+ { marker.done(SmaliElementTypes.REGISTERS_STATEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+param_list_or_id
+ : PARAM_LIST_OR_ID_PRIMITIVE_TYPE+;
+
+/*identifiers are much more general than most languages. Any of the below can either be
+the indicated type OR an identifier, depending on the context*/
+simple_name
+ : SIMPLE_NAME
+ | ACCESS_SPEC
+ | VERIFICATION_ERROR_TYPE
+ | POSITIVE_INTEGER_LITERAL
+ | NEGATIVE_INTEGER_LITERAL
+ | FLOAT_LITERAL_OR_ID
+ | DOUBLE_LITERAL_OR_ID
+ | BOOL_LITERAL
+ | NULL_LITERAL
+ | register
+ | param_list_or_id
+ | PRIMITIVE_TYPE
+ | VOID_TYPE
+ | ANNOTATION_VISIBILITY
+ | INSTRUCTION_FORMAT10t
+ | INSTRUCTION_FORMAT10x
+ | INSTRUCTION_FORMAT10x_ODEX
+ | INSTRUCTION_FORMAT11x
+ | INSTRUCTION_FORMAT12x_OR_ID
+ | INSTRUCTION_FORMAT21c_FIELD
+ | INSTRUCTION_FORMAT21c_FIELD_ODEX
+ | INSTRUCTION_FORMAT21c_STRING
+ | INSTRUCTION_FORMAT21c_TYPE
+ | INSTRUCTION_FORMAT21t
+ | INSTRUCTION_FORMAT22c_FIELD
+ | INSTRUCTION_FORMAT22c_FIELD_ODEX
+ | INSTRUCTION_FORMAT22c_TYPE
+ | INSTRUCTION_FORMAT22cs_FIELD
+ | INSTRUCTION_FORMAT22s_OR_ID
+ | INSTRUCTION_FORMAT22t
+ | INSTRUCTION_FORMAT23x
+ | INSTRUCTION_FORMAT31i_OR_ID
+ | INSTRUCTION_FORMAT31t
+ | INSTRUCTION_FORMAT35c_METHOD
+ | INSTRUCTION_FORMAT35c_METHOD_ODEX
+ | INSTRUCTION_FORMAT35c_TYPE
+ | INSTRUCTION_FORMAT35mi_METHOD
+ | INSTRUCTION_FORMAT35ms_METHOD
+ | INSTRUCTION_FORMAT51l;
+
+member_name
+ @init { Marker marker = mark(); }
+ : member_name_inner
+ { marker.done(SmaliElementTypes.MEMBER_NAME); };
+
+member_name_inner
+ : (simple_name
+ | MEMBER_NAME);
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+method_prototype
+ @init { Marker marker = mark(); }
+ : open_paren param_list close_paren type_descriptor
+ { marker.done(SmaliElementTypes.METHOD_PROTOTYPE); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+open_paren
+ : OPEN_PAREN;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+close_paren
+ : CLOSE_PAREN;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+open_brace
+ : OPEN_BRACE;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+close_brace
+ : CLOSE_BRACE;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+comma
+ : COMMA;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+colon
+ : COLON;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+dotdot
+ : DOTDOT;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+param_list_inner
+ : param+;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+param_list
+ @init { Marker marker = mark(); }
+ : param_list_inner?
+ { marker.done(SmaliElementTypes.METHOD_PARAM_LIST); };
+
+param
+ @init {
+ Marker marker = mark();
+ mark().done(SmaliElementTypes.MODIFIER_LIST);
+ }
+ : nonvoid_type_descriptor
+ { marker.done(SmaliElementTypes.METHOD_PARAMETER); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+method_prototype_reference
+ : open_paren param_list_reference close_paren type_descriptor;
+
+param_list_reference
+ @init {
+ Marker marker = mark();
+ }
+ : nonvoid_type_descriptor*
+ { marker.done(SmaliElementTypes.METHOD_REFERENCE_PARAM_LIST); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+primitive_type
+ @init { Marker marker = mark(); }
+ : (PRIMITIVE_TYPE | PARAM_LIST_OR_ID_PRIMITIVE_TYPE)
+ { finishToken(marker, SmaliElementTypes.PRIMITIVE_TYPE); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+class_descriptor
+ @init { Marker marker = mark(); }
+ : CLASS_DESCRIPTOR
+ { finishToken(marker, SmaliElementTypes.CLASS_TYPE); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+array_descriptor
+ @init { Marker marker = mark(); }
+ : ARRAY_TYPE_PREFIX (primitive_type | class_descriptor)
+ { finishToken(marker, SmaliElementTypes.ARRAY_TYPE); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+void_type
+ @init { Marker marker = mark(); }
+ : VOID_TYPE
+ { finishToken(marker, SmaliElementTypes.VOID_TYPE); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+type_descriptor
+ : void_type
+ | primitive_type
+ | class_descriptor
+ | array_descriptor;
+ catch [RecognitionException re] {
+ Marker marker = mark();
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+nonvoid_type_descriptor
+ : primitive_type
+ | class_descriptor
+ | array_descriptor;
+ catch [RecognitionException re] {
+ Marker marker = mark();
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+reference_type_descriptor
+ : class_descriptor
+ | array_descriptor;
+ catch [RecognitionException re] {
+ Marker marker = mark();
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+null_literal
+ @init { Marker marker = mark(); }
+ : NULL_LITERAL
+ { finishToken(marker, SmaliElementTypes.LITERAL); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+bool_literal
+ @init { Marker marker = mark(); }
+ : BOOL_LITERAL
+ { finishToken(marker, SmaliElementTypes.LITERAL); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+byte_literal
+ @init { Marker marker = mark(); }
+ : BYTE_LITERAL
+ { finishToken(marker, SmaliElementTypes.LITERAL); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+char_literal
+ @init { Marker marker = mark(); }
+ : CHAR_LITERAL
+ { finishToken(marker, SmaliElementTypes.LITERAL); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+short_literal
+ @init { Marker marker = mark(); }
+ : SHORT_LITERAL
+ { finishToken(marker, SmaliElementTypes.LITERAL); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+integer_literal
+ @init { Marker marker = mark(); }
+ : ( POSITIVE_INTEGER_LITERAL
+ | NEGATIVE_INTEGER_LITERAL)
+ { finishToken(marker, SmaliElementTypes.LITERAL); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+long_literal
+ @init { Marker marker = mark(); }
+ : LONG_LITERAL
+ { finishToken(marker, SmaliElementTypes.LITERAL); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+float_literal
+ @init { Marker marker = mark(); }
+ : ( FLOAT_LITERAL_OR_ID
+ | FLOAT_LITERAL )
+ { finishToken(marker, SmaliElementTypes.LITERAL); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+double_literal
+ @init { Marker marker = mark(); }
+ : ( DOUBLE_LITERAL_OR_ID
+ | DOUBLE_LITERAL)
+ { finishToken(marker, SmaliElementTypes.LITERAL); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+string_literal
+ @init { Marker marker = mark(); }
+ : STRING_LITERAL
+ { finishToken(marker, SmaliElementTypes.LITERAL); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+array_literal
+ @init { Marker marker = mark(); }
+ : open_brace (literal (comma literal)* | ) close_brace
+ { marker.done(SmaliElementTypes.LITERAL); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+enum_literal
+ @init { Marker marker = mark(); }
+ : ENUM_DIRECTIVE fully_qualified_field
+ { marker.done(SmaliElementTypes.LITERAL); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+type_field_method_literal
+ @init { Marker marker = mark(); }
+ : ( type_descriptor
+ | fully_qualified_field
+ | fully_qualified_method)
+ { marker.done(SmaliElementTypes.LITERAL); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+subannotation
+ @init {
+ Marker marker = mark();
+ Marker paramListMarker = null;
+ }
+ : SUBANNOTATION_DIRECTIVE class_descriptor
+ { paramListMarker = mark(); }
+ annotation_element*
+ { paramListMarker.done(SmaliElementTypes.ANNOTATION_PARAMETER_LIST); }
+ end_subannotation_directive
+ { marker.done(SmaliElementTypes.ANNOTATION); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+end_subannotation_directive
+ : END_SUBANNOTATION_DIRECTIVE;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+literal
+ : long_literal
+ | integer_literal
+ | short_literal
+ | byte_literal
+ | float_literal
+ | double_literal
+ | char_literal
+ | string_literal
+ | bool_literal
+ | null_literal
+ | array_literal
+ | subannotation
+ | type_field_method_literal
+ | enum_literal;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+string_or_null_literal
+ : string_literal
+ | null_literal;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+integral_literal
+ : long_literal
+ | integer_literal
+ | short_literal
+ | char_literal
+ | byte_literal;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+fixed_32bit_literal
+ : long_literal
+ | integer_literal
+ | short_literal
+ | byte_literal
+ | float_literal
+ | char_literal
+ | bool_literal;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+fixed_literal
+ : integer_literal
+ | long_literal
+ | short_literal
+ | byte_literal
+ | float_literal
+ | double_literal
+ | char_literal
+ | bool_literal;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+annotation_element
+ @init {
+ Marker marker = mark();
+ Marker nameMarker = null;
+ }
+ : { nameMarker = mark(); } simple_name { nameMarker.done(SmaliElementTypes.ANNOTATION_ELEMENT_NAME); }
+ equal literal
+ { marker.done(SmaliElementTypes.ANNOTATION_ELEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+equal
+ : EQUAL;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+annotation
+ @init {
+ Marker marker = mark();
+ Marker paramListMarker = null;
+ }
+ : ANNOTATION_DIRECTIVE annotation_visibility class_descriptor
+ { paramListMarker = mark(); }
+ annotation_element*
+ { paramListMarker.done(SmaliElementTypes.ANNOTATION_PARAMETER_LIST); }
+ end_annotation_directive
+ { marker.done(SmaliElementTypes.ANNOTATION); };
+
+annotation_visibility
+ : ANNOTATION_VISIBILITY;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+end_annotation_directive
+ : END_ANNOTATION_DIRECTIVE;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+arrow
+ : ARROW;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+fully_qualified_method
+ @init { Marker marker = mark(); }
+ : reference_type_descriptor arrow member_name method_prototype_reference
+ { marker.done(SmaliElementTypes.METHOD_REFERENCE); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+fully_qualified_field
+ @init { Marker marker = mark(); }
+ : reference_type_descriptor arrow member_name colon nonvoid_type_descriptor
+ { marker.done(SmaliElementTypes.FIELD_REFERENCE); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+label
+ @init { Marker marker = mark(); }
+ : colon simple_name
+ { marker.done(SmaliElementTypes.LABEL); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+label_ref
+ @init { Marker marker = mark(); }
+ : colon simple_name
+ { marker.done(SmaliElementTypes.LABEL_REFERENCE); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+register_list
+ : open_brace (register (comma register)*)? close_brace;
+
+register_range
+ : open_brace (register (dotdot register)?)? close_brace;
+
+verification_error_reference
+ : class_descriptor | fully_qualified_field | fully_qualified_method;
+
+catch_directive
+ @init { Marker marker = mark(); }
+ : CATCH_DIRECTIVE nonvoid_type_descriptor open_brace label_ref dotdot label_ref close_brace label_ref
+ { marker.done(SmaliElementTypes.CATCH_STATEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+catchall_directive
+ @init { Marker marker = mark(); }
+ : CATCHALL_DIRECTIVE open_brace label_ref dotdot label_ref close_brace label_ref
+ { marker.done(SmaliElementTypes.CATCH_ALL_STATEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+/*When there are annotations immediately after a parameter definition, we don't know whether they are parameter annotations
+or method annotations until we determine if there is an .end parameter directive. In either case, we still "consume" and parse
+the annotations. If it turns out that they are parameter annotations, we include them in the I_PARAMETER AST. Otherwise, we
+add them to the $statements_and_directives::methodAnnotations list*/
+parameter_directive
+ @init {
+ Marker marker = mark();
+ Marker annotationsMarker = null;
+ boolean gotEndParam = false;
+ }
+ : PARAMETER_DIRECTIVE register
+ (comma local_name)?
+ { annotationsMarker = mark(); } parameter_annotations
+ ( end_parameter_directive { gotEndParam = true; } )?
+ {
+ if (gotEndParam) {
+ annotationsMarker.drop();
+ marker.done(SmaliElementTypes.PARAMETER_STATEMENT);
+ } else {
+ marker.doneBefore(SmaliElementTypes.PARAMETER_STATEMENT, annotationsMarker);
+ annotationsMarker.drop();
+ }
+ };
+ catch [RecognitionException re] {
+ if (annotationsMarker != null) {
+ annotationsMarker.drop();
+ }
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+parameter_annotations
+ : ((ANNOTATION_DIRECTIVE)=> annotation)*;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+end_parameter_directive
+ : END_PARAMETER_DIRECTIVE;
+
+local_name
+ @init {
+ Marker localNameMarker = mark();
+ Marker stringMarker = mark();
+ }
+ : STRING_LITERAL
+ {
+ finishToken(stringMarker, SmaliElementTypes.LITERAL);
+ finishToken(localNameMarker, SmaliElementTypes.LOCAL_NAME);
+ };
+ catch [RecognitionException re] {
+ stringMarker.drop();
+ recover(input, re);
+ reportError(localNameMarker, re, false);
+ }
+
+register
+ @init { Marker marker = mark(); }
+ : REGISTER
+ { finishToken(marker, SmaliElementTypes.REGISTER_REFERENCE); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+debug_directive
+ : line_directive
+ | local_directive
+ | end_local_directive
+ | restart_local_directive
+ | prologue_directive
+ | epilogue_directive
+ | source_directive;
+
+line_directive
+ @init { Marker marker = mark(); }
+ : LINE_DIRECTIVE integral_literal
+ { marker.done(SmaliElementTypes.LINE_DEBUG_STATEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+local_directive
+ @init { Marker marker = mark(); }
+ : LOCAL_DIRECTIVE register (comma string_or_null_literal colon type_descriptor
+ (comma string_literal)? )?
+ { marker.done(SmaliElementTypes.LOCAL_DEBUG_STATEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+end_local_directive
+ @init { Marker marker = mark(); }
+ : END_LOCAL_DIRECTIVE register
+ { marker.done(SmaliElementTypes.END_LOCAL_DEBUG_STATEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+restart_local_directive
+ @init { Marker marker = mark(); }
+ : RESTART_LOCAL_DIRECTIVE register
+ { marker.done(SmaliElementTypes.RESTART_LOCAL_DEBUG_STATEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+prologue_directive
+ @init { Marker marker = mark(); }
+ : PROLOGUE_DIRECTIVE
+ { marker.done(SmaliElementTypes.PROLOGUE_DEBUG_STATEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+epilogue_directive
+ @init { Marker marker = mark(); }
+ : EPILOGUE_DIRECTIVE
+ { marker.done(SmaliElementTypes.EPILOGUE_DEBUG_STATEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+source_directive
+ @init { Marker marker = mark(); }
+ : SOURCE_DIRECTIVE string_literal?
+ { marker.done(SmaliElementTypes.SOURCE_DEBUG_STATEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+instruction_format12x
+ : INSTRUCTION_FORMAT12x
+ | INSTRUCTION_FORMAT12x_OR_ID;
+
+instruction_format22s
+ : INSTRUCTION_FORMAT22s
+ | INSTRUCTION_FORMAT22s_OR_ID;
+
+instruction_format31i
+ : INSTRUCTION_FORMAT31i
+ | INSTRUCTION_FORMAT31i_OR_ID;
+
+instruction
+ @init { Marker marker = mark(); }
+ : ( insn_format10t
+ | insn_format10x
+ | insn_format10x_odex
+ | insn_format11n
+ | insn_format11x
+ | insn_format12x
+ | insn_format20bc
+ | insn_format20t
+ | insn_format21c_field
+ | insn_format21c_field_odex
+ | insn_format21c_string
+ | insn_format21c_type
+ | insn_format21ih
+ | insn_format21lh
+ | insn_format21s
+ | insn_format21t
+ | insn_format22b
+ | insn_format22c_field
+ | insn_format22c_field_odex
+ | insn_format22c_type
+ | insn_format22cs_field
+ | insn_format22s
+ | insn_format22t
+ | insn_format22x
+ | insn_format23x
+ | insn_format30t
+ | insn_format31c
+ | insn_format31i
+ | insn_format31t
+ | insn_format32x
+ | insn_format35c_method
+ | insn_format35c_type
+ | insn_format35c_method_odex
+ | insn_format35mi_method
+ | insn_format35ms_method
+ | insn_format3rc_method
+ | insn_format3rc_method_odex
+ | insn_format3rc_type
+ | insn_format3rmi_method
+ | insn_format3rms_method
+ | insn_format51l
+ | insn_array_data_directive
+ | insn_packed_switch_directive
+ | insn_sparse_switch_directive )
+ { marker.done(SmaliElementTypes.INSTRUCTION); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+insn_format10t
+ : //e.g. goto endloop:
+ //e.g. goto +3
+ INSTRUCTION_FORMAT10t label_ref;
+
+insn_format10x
+ : //e.g. return-void
+ INSTRUCTION_FORMAT10x;
+
+insn_format10x_odex
+ : //e.g. return-void-barrier
+ INSTRUCTION_FORMAT10x_ODEX;
+
+insn_format11n
+ : //e.g. const/4 v0, 5
+ INSTRUCTION_FORMAT11n register comma integral_literal;
+
+insn_format11x
+ : //e.g. move-result-object v1
+ INSTRUCTION_FORMAT11x register;
+
+insn_format12x
+ : //e.g. move v1 v2
+ instruction_format12x register comma register;
+
+insn_format20bc
+ : //e.g. throw-verification-error generic-error, Lsome/class;
+ INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE comma verification_error_reference;
+
+insn_format20t
+ : //e.g. goto/16 endloop:
+ INSTRUCTION_FORMAT20t label_ref;
+
+insn_format21c_field
+ : //e.g. sget-object v0, java/lang/System/out LJava/io/PrintStream;
+ INSTRUCTION_FORMAT21c_FIELD register comma fully_qualified_field;
+
+insn_format21c_field_odex
+ : //e.g. sget-object-volatile v0, java/lang/System/out LJava/io/PrintStream;
+ INSTRUCTION_FORMAT21c_FIELD_ODEX register comma fully_qualified_field;
+
+insn_format21c_string
+ : //e.g. const-string v1, "Hello World!"
+ INSTRUCTION_FORMAT21c_STRING register comma string_literal;
+
+insn_format21c_type
+ : //e.g. const-class v2, Lorg/jf/HelloWorld2/HelloWorld2;
+ INSTRUCTION_FORMAT21c_TYPE register comma nonvoid_type_descriptor;
+
+insn_format21ih
+ : //e.g. const/high16 v1, 1234
+ INSTRUCTION_FORMAT21ih register comma fixed_32bit_literal;
+
+insn_format21lh
+ : //e.g. const-wide/high16 v1, 1234
+ INSTRUCTION_FORMAT21lh register comma fixed_32bit_literal;
+
+insn_format21s
+ : //e.g. const/16 v1, 1234
+ INSTRUCTION_FORMAT21s register comma integral_literal;
+
+insn_format21t
+ : //e.g. if-eqz v0, endloop:
+ INSTRUCTION_FORMAT21t register comma label_ref;
+
+insn_format22b
+ : //e.g. add-int v0, v1, 123
+ INSTRUCTION_FORMAT22b register comma register comma integral_literal;
+
+insn_format22c_field
+ : //e.g. iput-object v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
+ INSTRUCTION_FORMAT22c_FIELD register comma register comma fully_qualified_field;
+
+insn_format22c_field_odex
+ : //e.g. iput-object-volatile v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
+ INSTRUCTION_FORMAT22c_FIELD_ODEX register comma register comma fully_qualified_field;
+
+insn_format22c_type
+ : //e.g. instance-of v0, v1, Ljava/lang/String;
+ INSTRUCTION_FORMAT22c_TYPE register comma register comma nonvoid_type_descriptor;
+
+insn_format22cs_field
+ : //e.g. iget-quick v0, v1, field@0xc
+ INSTRUCTION_FORMAT22cs_FIELD register comma register comma FIELD_OFFSET;
+
+insn_format22s
+ : //e.g. add-int/lit16 v0, v1, 12345
+ instruction_format22s register comma register comma integral_literal;
+
+insn_format22t
+ : //e.g. if-eq v0, v1, endloop:
+ INSTRUCTION_FORMAT22t register comma register comma label_ref;
+
+insn_format22x
+ : //e.g. move/from16 v1, v1234
+ INSTRUCTION_FORMAT22x register comma register;
+
+insn_format23x
+ : //e.g. add-int v1, v2, v3
+ INSTRUCTION_FORMAT23x register comma register comma register;
+
+insn_format30t
+ : //e.g. goto/32 endloop:
+ INSTRUCTION_FORMAT30t label_ref;
+
+insn_format31c
+ : //e.g. const-string/jumbo v1 "Hello World!"
+ INSTRUCTION_FORMAT31c register comma string_literal;
+
+insn_format31i
+ : //e.g. const v0, 123456
+ instruction_format31i register comma fixed_32bit_literal;
+
+insn_format31t
+ : //e.g. fill-array-data v0, ArrayData:
+ INSTRUCTION_FORMAT31t register comma label_ref;
+
+insn_format32x
+ : //e.g. move/16 v4567, v1234
+ INSTRUCTION_FORMAT32x register comma register;
+
+insn_format35c_method
+ : //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V
+ INSTRUCTION_FORMAT35c_METHOD register_list comma fully_qualified_method;
+
+insn_format35c_type
+ : //e.g. filled-new-array {v0,v1}, I
+ INSTRUCTION_FORMAT35c_TYPE register_list comma nonvoid_type_descriptor;
+
+insn_format35c_method_odex
+ : //e.g. invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+ INSTRUCTION_FORMAT35c_METHOD_ODEX register_list comma fully_qualified_method;
+
+insn_format35mi_method
+ : //e.g. execute-inline {v0, v1}, inline@0x4
+ INSTRUCTION_FORMAT35mi_METHOD register_list comma INLINE_INDEX;
+
+insn_format35ms_method
+ : //e.g. invoke-virtual-quick {v0, v1}, vtable@0x4
+ INSTRUCTION_FORMAT35ms_METHOD register_list comma VTABLE_INDEX;
+
+insn_format3rc_method
+ : //e.g. invoke-virtual/range {v25..v26}, java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ INSTRUCTION_FORMAT3rc_METHOD register_range comma fully_qualified_method;
+
+insn_format3rc_method_odex
+ : //e.g. invoke-object-init/range {p0}, Ljava/lang/Object;-><init>()V
+ INSTRUCTION_FORMAT3rc_METHOD_ODEX register_list comma fully_qualified_method;
+
+insn_format3rc_type
+ : //e.g. filled-new-array/range {v0..v6}, I
+ INSTRUCTION_FORMAT3rc_TYPE register_range comma nonvoid_type_descriptor;
+
+insn_format3rmi_method
+ : //e.g. execute-inline/range {v0 .. v10}, inline@0x14
+ INSTRUCTION_FORMAT3rmi_METHOD register_range comma INLINE_INDEX;
+
+insn_format3rms_method
+ : //e.g. invoke-virtual-quick/range {v0 .. v10}, vtable@0x14
+ INSTRUCTION_FORMAT3rms_METHOD register_range comma VTABLE_INDEX;
+
+insn_format51l
+ : //e.g. const-wide v0, 5000000000L
+ INSTRUCTION_FORMAT51l register comma fixed_literal;
+
+insn_array_data_directive
+ : ARRAY_DATA_DIRECTIVE
+ integer_literal
+ array_data_element* end_array_data_directive;
+
+end_array_data_directive
+ : END_ARRAY_DATA_DIRECTIVE;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+array_data_element
+ @init { Marker marker = mark(); }
+ : fixed_literal
+ { marker.done(SmaliElementTypes.ARRAY_DATA_ELEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+insn_packed_switch_directive
+ : PACKED_SWITCH_DIRECTIVE
+ fixed_32bit_literal
+ packed_switch_element*
+ end_packed_switch_directive;
+
+end_packed_switch_directive
+ : END_PACKED_SWITCH_DIRECTIVE;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+packed_switch_element
+ @init { Marker marker = mark(); }
+ : label_ref
+ { marker.done(SmaliElementTypes.PACKED_SWITCH_ELEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
+
+insn_sparse_switch_directive
+ : SPARSE_SWITCH_DIRECTIVE
+ sparse_switch_element*
+ end_sparse_switch_directive;
+
+end_sparse_switch_directive
+ : END_SPARSE_SWITCH_DIRECTIVE;
+ catch [RecognitionException re] {
+ Marker errorMarker = mark();
+ recover(input, re);
+ reportError(errorMarker, re, false);
+ }
+
+sparse_switch_element
+ @init { Marker marker = mark(); }
+ : fixed_32bit_literal arrow label_ref
+ { marker.done(SmaliElementTypes.SPARSE_SWITCH_ELEMENT); };
+ catch [RecognitionException re] {
+ recover(input, re);
+ reportError(marker, re, false);
+ }
diff --git a/smalidea/src/main/java/org/jf/smalidea/PsiBuilderTokenStream.java b/smalidea/src/main/java/org/jf/smalidea/PsiBuilderTokenStream.java
new file mode 100644
index 00000000..00004001
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/PsiBuilderTokenStream.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2012, 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;
+
+import com.intellij.lang.PsiBuilder;
+import com.intellij.lang.PsiBuilder.Marker;
+import com.intellij.psi.TokenType;
+import com.intellij.psi.tree.IElementType;
+import org.antlr.runtime.CommonToken;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenSource;
+import org.antlr.runtime.TokenStream;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smali.InvalidToken;
+import org.jf.smali.smaliParser;
+
+import javax.annotation.Nonnull;
+import java.util.ArrayList;
+
+public class PsiBuilderTokenStream implements TokenStream {
+ @Nonnull private PsiBuilder psiBuilder;
+ @Nullable private CommonToken currentToken = null;
+ @Nonnull private ArrayList<Marker> markers = new ArrayList<PsiBuilder.Marker>();
+
+ public PsiBuilderTokenStream(@Nonnull PsiBuilder psiBuilder) {
+ this.psiBuilder = psiBuilder;
+ }
+
+ @Override public Token LT(int k) {
+ if (k == 1) {
+ if (currentToken == null) {
+ buildCurrentToken();
+ }
+ return currentToken;
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public int range() {
+ return currentToken==null?0:1;
+ }
+
+ @Override public Token get(int i) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public TokenSource getTokenSource() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public String toString(int start, int stop) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public String toString(Token start, Token stop) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public void consume() {
+ psiBuilder.advanceLexer();
+ buildCurrentToken();
+ }
+
+ private void buildCurrentToken() {
+ IElementType element = psiBuilder.getTokenType();
+ if (element != null) {
+ if (element instanceof SmaliLexicalElementType) {
+ SmaliLexicalElementType elementType = (SmaliLexicalElementType)element;
+ currentToken = new CommonToken(elementType.tokenId, psiBuilder.getTokenText());
+ } else if (element == TokenType.BAD_CHARACTER) {
+ currentToken = new InvalidToken("", psiBuilder.getTokenText());
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ } else {
+ currentToken = new CommonToken(Token.EOF);
+ }
+ }
+
+ @Override public int LA(int i) {
+ IElementType elementType = psiBuilder.lookAhead(i-1);
+ if (elementType == null) {
+ return -1;
+ } else if (elementType instanceof SmaliLexicalElementType) {
+ return ((SmaliLexicalElementType)elementType).tokenId;
+ } else if (elementType == TokenType.BAD_CHARACTER) {
+ return smaliParser.INVALID_TOKEN;
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public int mark() {
+ int ret = markers.size();
+ markers.add(psiBuilder.mark());
+ return ret;
+ }
+
+ @Override public int index() {
+ return psiBuilder.getCurrentOffset();
+ }
+
+ @Override public void rewind(int markerIndex) {
+ PsiBuilder.Marker marker = markers.get(markerIndex);
+ marker.rollbackTo();
+ while (markerIndex < markers.size()) {
+ markers.remove(markerIndex);
+ }
+ }
+
+ @Override public void rewind() {
+ rewind(markers.size()-1);
+ mark();
+ }
+
+ @Override public void release(int markerIndex) {
+ while (markerIndex < markers.size()) {
+ markers.remove(markerIndex).drop();
+ }
+ }
+
+ @Override public void seek(int index) {
+ if (index < psiBuilder.getCurrentOffset()) {
+ throw new UnsupportedOperationException();
+ }
+ while (index > psiBuilder.getCurrentOffset()) {
+ consume();
+ }
+ }
+
+ @Override public int size() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public String getSourceName() {
+ return null;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/SmaliASTFactory.java b/smalidea/src/main/java/org/jf/smalidea/SmaliASTFactory.java
new file mode 100644
index 00000000..4e0208c2
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/SmaliASTFactory.java
@@ -0,0 +1,19 @@
+package org.jf.smalidea;
+
+import com.intellij.lang.ASTFactory;
+import com.intellij.psi.impl.source.tree.LeafElement;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.leaf.SmaliClassDescriptor;
+
+public class SmaliASTFactory extends ASTFactory {
+
+ @Nullable
+ @Override
+ public LeafElement createLeaf(IElementType type, CharSequence text) {
+ if (type == SmaliTokens.CLASS_DESCRIPTOR) {
+ return new SmaliClassDescriptor(text);
+ }
+ return super.createLeaf(type, text);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/SmaliColorsPage.java b/smalidea/src/main/java/org/jf/smalidea/SmaliColorsPage.java
new file mode 100644
index 00000000..b0ed5c04
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/SmaliColorsPage.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.fileTypes.SyntaxHighlighter;
+import com.intellij.openapi.options.colors.AttributesDescriptor;
+import com.intellij.openapi.options.colors.ColorDescriptor;
+import com.intellij.openapi.options.colors.ColorSettingsPage;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.List;
+import java.util.Map;
+
+public class SmaliColorsPage implements ColorSettingsPage {
+ private static final AttributesDescriptor[] ATTRS;
+
+ static {
+ List<TextAttributesKey> keys = SmaliHighlightingColors.getAllKeys();
+
+ ATTRS = new AttributesDescriptor[keys.size()];
+ for (int i=0; i<keys.size(); i++) {
+ TextAttributesKey key = keys.get(i);
+
+ ATTRS[i] = new AttributesDescriptor(key.getExternalName(), key);
+ }
+ }
+
+ @Nullable @Override public Icon getIcon() {
+ return SmaliIcons.SmaliIcon;
+ }
+
+ @NotNull @Override public SyntaxHighlighter getHighlighter() {
+ return new SmaliHighlighter();
+ }
+
+ @NotNull @Override public String getDemoText() {
+ return ".class public Lorg/jf/smalidea/ColorExample;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".source \"ColorExample.smali\"\n" +
+ "\n" +
+ ".field public exampleField:I = 1234\n" +
+ "\n" +
+ ".field public boolField:Z = true\n" +
+ "\n" +
+ "# This is an example comment\n" +
+ "\n" +
+ ".method public constructor <init>()V\n" +
+ " .registers 1\n" +
+ " invoke-direct {p0}, Ljava/lang/Object;-><init>()V\n" +
+ " return-void\n" +
+ ".end method\n" +
+ "\n" +
+ ".method public exampleMethod()V\n" +
+ " .registers 10\n" +
+ "\n" +
+ " const v0, 1234\n" +
+ " const-string v1, \"An Example String\"\n" +
+ "\n" +
+ " invoke-virtual {p0, v0, v1}, Lorg/jf/smalidea/ColorExample;->anotherMethod(ILjava/lang/String;)V\n" +
+ "\n" +
+ " move v2, v1\n" +
+ " move v1, v0\n" +
+ " move v0, p0\n" +
+ "\n" +
+ " invoke-virtual/range {v0 .. v2}, Lorg/jf/smalidea/ColorExample;->anotherMethod(ILjava/lang/String;)V\n" +
+ "\n" +
+ " return-void\n" +
+ ".end method\n" +
+ "\n" +
+ ".method public anotherMethod(ILjava/Lang/String;)V\n" +
+ " .registers 10\n" +
+ "\n" +
+ " # This is another example comment\n" +
+ "\n" +
+ " return-void\n" +
+ ".end method\n" +
+ "\n" +
+ ".method public odexInstructions()V\n" +
+ " .registers 10\n" +
+ " invoke-virtual {p0}, vtable@0x1b\n" +
+ "\n" +
+ " iget-quick p0, field@0x1\n" +
+ "\n" +
+ " execute-inline {p0}, inline@0xa\n" +
+ "\n" +
+ " throw-verification-error illegal-method-access, Lblah;->Blort()V\n" +
+ ".end method";
+ }
+
+ @NotNull @Override public AttributesDescriptor[] getAttributeDescriptors() {
+ return ATTRS;
+ }
+
+ @Nullable @Override public Map<String, TextAttributesKey> getAdditionalHighlightingTagToDescriptorMap() {
+ return null;
+ }
+
+ @NotNull @Override public ColorDescriptor[] getColorDescriptors() {
+ return ColorDescriptor.EMPTY_ARRAY;
+ }
+
+ @NotNull @Override public String getDisplayName() {
+ return "smali";
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/SmaliFileType.java b/smalidea/src/main/java/org/jf/smalidea/SmaliFileType.java
new file mode 100644
index 00000000..e840bb8d
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/SmaliFileType.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2012, 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;
+
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+public class SmaliFileType extends LanguageFileType {
+ public static final SmaliFileType INSTANCE = new SmaliFileType();
+ public static final String DEFAULT_EXTENSION = "smali";
+
+ private SmaliFileType() {
+ super(SmaliLanguage.INSTANCE);
+ }
+
+ @NotNull @Override public String getName() {
+ return "smali";
+ }
+
+ @NotNull @Override public String getDescription() {
+ return "smali Files";
+ }
+
+ @NotNull @Override public String getDefaultExtension() {
+ return DEFAULT_EXTENSION;
+ }
+
+ @Override public Icon getIcon() {
+ return SmaliIcons.SmaliIcon;
+ }
+
+ @Override public boolean isJVMDebuggingSupported() {
+ return true;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/SmaliFileTypeFactory.java b/smalidea/src/main/java/org/jf/smalidea/SmaliFileTypeFactory.java
new file mode 100644
index 00000000..b5834c18
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/SmaliFileTypeFactory.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012, 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;
+
+import com.intellij.openapi.fileTypes.FileTypeConsumer;
+import com.intellij.openapi.fileTypes.FileTypeFactory;
+import org.jetbrains.annotations.NotNull;
+
+public class SmaliFileTypeFactory extends FileTypeFactory {
+ @Override
+ public void createFileTypes(@NotNull FileTypeConsumer consumer) {
+ consumer.consume(SmaliFileType.INSTANCE, SmaliFileType.DEFAULT_EXTENSION);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/SmaliHighlighter.java b/smalidea/src/main/java/org/jf/smalidea/SmaliHighlighter.java
new file mode 100644
index 00000000..71e206a0
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/SmaliHighlighter.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.fileTypes.SyntaxHighlighterBase;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.NotNull;
+
+
+public class SmaliHighlighter extends SyntaxHighlighterBase {
+ @NotNull @Override public Lexer getHighlightingLexer() {
+ return new SmaliLexer();
+ }
+
+ @NotNull @Override public TextAttributesKey[] getTokenHighlights(IElementType tokenType) {
+ if (tokenType instanceof SmaliLexicalElementType) {
+ return ((SmaliLexicalElementType) tokenType).textAttributesKeys;
+ }
+ return new TextAttributesKey[] {};
+ }
+
+ // TODO: implement context sensitive highlighting. i.e. instance fields vs static fields, labels, etc. See: HighlightVisitorImpl
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/SmaliHighlightingColors.java b/smalidea/src/main/java/org/jf/smalidea/SmaliHighlightingColors.java
new file mode 100644
index 00000000..eba5fd33
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/SmaliHighlightingColors.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2014, 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;
+
+import com.google.common.collect.Lists;
+import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+
+import java.util.Collections;
+import java.util.List;
+
+public class SmaliHighlightingColors {
+ private static final List<TextAttributesKey> allKeys = Lists.newArrayList();
+
+ public static final TextAttributesKey ACCESS = createTextAttributesKey(
+ "ACCESS", DefaultLanguageHighlighterColors.KEYWORD);
+ public static final TextAttributesKey ARROW = createTextAttributesKey(
+ "ARROW", DefaultLanguageHighlighterColors.PREDEFINED_SYMBOL);
+ public static final TextAttributesKey BRACES = createTextAttributesKey(
+ "BRACES", DefaultLanguageHighlighterColors.BRACES);
+ public static final TextAttributesKey COLON = createTextAttributesKey(
+ "COLON", DefaultLanguageHighlighterColors.PREDEFINED_SYMBOL);
+ public static final TextAttributesKey COMMA = createTextAttributesKey(
+ "COMMA", DefaultLanguageHighlighterColors.COMMA);
+ public static final TextAttributesKey COMMENT = createTextAttributesKey(
+ "COMMENT", DefaultLanguageHighlighterColors.LINE_COMMENT);
+ public static final TextAttributesKey DIRECTIVE = createTextAttributesKey(
+ "DIRECTIVE", DefaultLanguageHighlighterColors.KEYWORD);
+ public static final TextAttributesKey DOTDOT = createTextAttributesKey(
+ "DOTDOT", DefaultLanguageHighlighterColors.PREDEFINED_SYMBOL);
+ public static final TextAttributesKey EQUAL = createTextAttributesKey(
+ "EQUAL", DefaultLanguageHighlighterColors.PREDEFINED_SYMBOL);
+ public static final TextAttributesKey IDENTIFIER = createTextAttributesKey(
+ "IDENTIFIER", DefaultLanguageHighlighterColors.INSTANCE_METHOD);
+ public static final TextAttributesKey INSTRUCTION = createTextAttributesKey(
+ "INSTRUCTION", DefaultLanguageHighlighterColors.KEYWORD);
+ public static final TextAttributesKey LITERAL = createTextAttributesKey(
+ "LITERAL", DefaultLanguageHighlighterColors.NUMBER);
+ public static final TextAttributesKey NUMBER = createTextAttributesKey(
+ "NUMBER", DefaultLanguageHighlighterColors.NUMBER);
+ public static final TextAttributesKey ODEX_REFERENCE = createTextAttributesKey(
+ "ODEX_REFERENCE", DefaultLanguageHighlighterColors.INSTANCE_METHOD);
+ public static final TextAttributesKey PARENS = createTextAttributesKey(
+ "PARENS", DefaultLanguageHighlighterColors.PARENTHESES);
+ public static final TextAttributesKey REGISTER = createTextAttributesKey(
+ "REGISTER", DefaultLanguageHighlighterColors.LOCAL_VARIABLE);
+ public static final TextAttributesKey STRING = createTextAttributesKey(
+ "STRING", DefaultLanguageHighlighterColors.STRING);
+ public static final TextAttributesKey TYPE = createTextAttributesKey(
+ "TYPE", DefaultLanguageHighlighterColors.CLASS_REFERENCE);
+ public static final TextAttributesKey VERIFICATION_ERROR_TYPE = createTextAttributesKey(
+ "VERIFICATION_ERROR_TYPE", DefaultLanguageHighlighterColors.KEYWORD);
+
+ private static TextAttributesKey createTextAttributesKey(String name, TextAttributesKey defaultColor) {
+ TextAttributesKey key = TextAttributesKey.createTextAttributesKey(name, defaultColor);
+ allKeys.add(key);
+ return key;
+ }
+
+ public static List<TextAttributesKey> getAllKeys() {
+ return Collections.unmodifiableList(allKeys);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/SmaliIcons.java b/smalidea/src/main/java/org/jf/smalidea/SmaliIcons.java
new file mode 100644
index 00000000..449e71b5
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/SmaliIcons.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012, 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;
+
+import com.intellij.openapi.util.IconLoader;
+
+import javax.swing.*;
+
+public class SmaliIcons {
+ public static final Icon SmaliIcon = IconLoader.getIcon("/icons/smali.png");
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/SmaliLanguage.java b/smalidea/src/main/java/org/jf/smalidea/SmaliLanguage.java
new file mode 100644
index 00000000..f437ec27
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/SmaliLanguage.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012, 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;
+
+import com.intellij.lang.Language;
+
+public class SmaliLanguage extends Language {
+ public static final SmaliLanguage INSTANCE = new SmaliLanguage();
+
+ private SmaliLanguage() {
+ super("smali", "text/smali");
+ }
+
+ @Override public boolean isCaseSensitive() {
+ return true;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/SmaliLexer.java b/smalidea/src/main/java/org/jf/smalidea/SmaliLexer.java
new file mode 100644
index 00000000..67e5945f
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/SmaliLexer.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.lexer.LexerBase;
+import com.intellij.psi.TokenType;
+import com.intellij.psi.tree.IElementType;
+import org.antlr.runtime.CommonToken;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smali.smaliFlexLexer;
+import org.jf.smali.smaliParser;
+import org.jf.util.BlankReader;
+
+public class SmaliLexer extends LexerBase {
+ private final smaliFlexLexer lexer = new smaliFlexLexer(BlankReader.INSTANCE);
+ private CommonToken token = null;
+ private int state = 0;
+ private int endOffset;
+ private CharSequence text;
+
+ public SmaliLexer() {
+ super();
+ lexer.setSuppressErrors(true);
+ }
+
+ @Override public void start(@NotNull CharSequence buffer, int startOffset, int endOffset, int initialState) {
+ text = buffer;
+ lexer.reset(buffer, startOffset, endOffset, initialState);
+ this.endOffset = endOffset;
+ this.token = null;
+ this.state = 0;
+ }
+
+ @NotNull @Override public CharSequence getTokenSequence() {
+ return getTokenText();
+ }
+
+ @NotNull @Override public String getTokenText() {
+ ensureToken();
+ return token.getText();
+ }
+
+ @Override
+ public int getState() {
+ ensureToken();
+ return state;
+ }
+
+ @Override
+ public IElementType getTokenType() {
+ ensureToken();
+ return mapTokenTypeToElementType(token.getType());
+ }
+
+ private IElementType mapTokenTypeToElementType(int tokenType) {
+ if (tokenType == smaliParser.WHITE_SPACE) {
+ return TokenType.WHITE_SPACE;
+ }
+ if (tokenType == smaliParser.INVALID_TOKEN) {
+ return TokenType.BAD_CHARACTER;
+ }
+ if (tokenType == smaliParser.EOF) {
+ return null;
+ }
+ return SmaliTokens.getElementType(tokenType);
+ }
+
+ @Override
+ public int getTokenStart() {
+ ensureToken();
+ return token.getStartIndex();
+ }
+
+ @Override
+ public int getTokenEnd() {
+ ensureToken();
+ return token.getStopIndex()+1;
+ }
+
+ @Override
+ public void advance() {
+ token = null;
+ state = 0;
+ }
+
+ @NotNull @Override public CharSequence getBufferSequence() {
+ return text;
+ }
+
+ @Override
+ public int getBufferEnd() {
+ return endOffset;
+ }
+
+ private void ensureToken() {
+ if (token == null) {
+ token = (CommonToken)lexer.nextToken();
+ state = lexer.yystate();
+ }
+ assert token != null;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/SmaliLexicalElementType.java b/smalidea/src/main/java/org/jf/smalidea/SmaliLexicalElementType.java
new file mode 100644
index 00000000..5103dd9e
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/SmaliLexicalElementType.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.psi.tree.IElementType;
+
+public class SmaliLexicalElementType extends IElementType {
+ public final int tokenId;
+ public final TextAttributesKey[] textAttributesKeys;
+
+ protected SmaliLexicalElementType(int tokenId, String tokenName, TextAttributesKey textAttributesKey) {
+ super(tokenName, SmaliLanguage.INSTANCE);
+ this.tokenId = tokenId;
+ this.textAttributesKeys = new TextAttributesKey[] {textAttributesKey};
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/SmaliParser.java b/smalidea/src/main/java/org/jf/smalidea/SmaliParser.java
new file mode 100644
index 00000000..ed0fb19a
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/SmaliParser.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2014, 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;
+
+
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.PsiBuilder;
+import com.intellij.lang.PsiParser;
+import com.intellij.psi.tree.IElementType;
+import org.antlr.runtime.RecognitionException;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliParser implements PsiParser {
+ @NotNull @Override public ASTNode parse(IElementType root, PsiBuilder builder) {
+ builder.setDebugMode(true);
+
+ PsiBuilder.Marker rootMarker = builder.mark();
+ PsiBuilder.Marker classMarker = builder.mark();
+
+ PsiBuilderTokenStream tokenStream = new PsiBuilderTokenStream(builder);
+ smalideaParser parser = new smalideaParser(tokenStream);
+ parser.setPsiBuilder(builder);
+ try {
+ parser.smali_file();
+ } catch (RecognitionException ex) {
+ // TODO: how to handle this?
+ ex.printStackTrace();
+ }
+
+ classMarker.done(SmaliElementTypes.CLASS);
+ rootMarker.done(root);
+ return builder.getTreeBuilt();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/SmaliParserDefinition.java b/smalidea/src/main/java/org/jf/smalidea/SmaliParserDefinition.java
new file mode 100644
index 00000000..77f1623a
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/SmaliParserDefinition.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.LanguageUtil;
+import com.intellij.lang.ParserDefinition;
+import com.intellij.lang.PsiParser;
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.FileViewProvider;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.TokenType;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.IFileElementType;
+import com.intellij.psi.tree.TokenSet;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.jf.smalidea.psi.stub.element.SmaliStubElementType;
+
+public class SmaliParserDefinition implements ParserDefinition {
+ @NotNull @Override public Lexer createLexer(Project project) {
+ return new SmaliLexer();
+ }
+
+ @Override public PsiParser createParser(Project project) {
+ return new SmaliParser();
+ }
+
+ @Override public IFileElementType getFileNodeType() {
+ return SmaliElementTypes.FILE;
+ }
+
+ private static final TokenSet WHITESPACE = TokenSet.create(TokenType.WHITE_SPACE);
+ @NotNull @Override public TokenSet getWhitespaceTokens() {
+ return WHITESPACE;
+ }
+
+ private static final TokenSet COMMENT = TokenSet.create(SmaliTokens.LINE_COMMENT);
+ @NotNull @Override public TokenSet getCommentTokens() {
+ return COMMENT;
+ }
+
+ private static final TokenSet STRING_LITERAL = TokenSet.create(SmaliTokens.STRING_LITERAL);
+ @NotNull @Override public TokenSet getStringLiteralElements() {
+ return STRING_LITERAL;
+ }
+
+ @NotNull @Override public PsiElement createElement(ASTNode node) {
+ IElementType elementType = node.getElementType();
+ if (elementType instanceof SmaliStubElementType) {
+ return ((SmaliStubElementType)elementType).createPsi(node);
+ }
+ throw new RuntimeException("Unexpected element type");
+ }
+
+ @Override public PsiFile createFile(FileViewProvider viewProvider) {
+ return new SmaliFile(viewProvider);
+ }
+
+ @Override public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) {
+ return LanguageUtil.canStickTokensTogetherByLexer(left, right, new SmaliLexer());
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/SmaliTokens.java b/smalidea/src/main/java/org/jf/smalidea/SmaliTokens.java
new file mode 100644
index 00000000..83327649
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/SmaliTokens.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright 2014, 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;
+
+import com.google.common.collect.Maps;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.TokenSet;
+import org.jf.smali.smaliParser;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+public class SmaliTokens {
+ private static final IElementType[] ELEMENT_TYPES;
+
+ public static IElementType getElementType(int tokenType) {
+ return ELEMENT_TYPES[tokenType];
+ }
+
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType ACCESS_SPEC;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType ANNOTATION_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType ANNOTATION_VISIBILITY;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType ARRAY_DATA_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType ARRAY_TYPE_PREFIX;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType ARROW;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType BOOL_LITERAL;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType BYTE_LITERAL;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType CATCH_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType CATCHALL_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType CHAR_LITERAL;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType CLASS_DESCRIPTOR;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType CLASS_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType CLOSE_BRACE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType CLOSE_PAREN;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType COLON;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType COMMA;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType DOTDOT;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType DOUBLE_LITERAL;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType DOUBLE_LITERAL_OR_ID;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType END_ANNOTATION_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType END_ARRAY_DATA_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType END_FIELD_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType END_LOCAL_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType END_METHOD_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType END_PACKED_SWITCH_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType END_PARAMETER_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType END_SPARSE_SWITCH_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType END_SUBANNOTATION_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType ENUM_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType EPILOGUE_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType EQUAL;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType FIELD_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType FIELD_OFFSET;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType FLOAT_LITERAL;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType FLOAT_LITERAL_OR_ID;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType IMPLEMENTS_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INLINE_INDEX;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT10t;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT10x;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT10x_ODEX;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT11n;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT11x;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT12x;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT12x_OR_ID;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT20bc;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT20t;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT21c_FIELD;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT21c_FIELD_ODEX;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT21c_STRING;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT21c_TYPE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT21ih;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT21lh;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT21s;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT21t;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT22b;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT22c_FIELD;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT22c_FIELD_ODEX;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT22c_TYPE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT22cs_FIELD;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT22s;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT22s_OR_ID;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT22t;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT22x;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT23x;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT30t;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT31c;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT31i;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT31i_OR_ID;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT31t;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT32x;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT35c_METHOD;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT35c_METHOD_ODEX;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT35c_TYPE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT35mi_METHOD;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT35ms_METHOD;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT3rc_METHOD;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT3rc_METHOD_ODEX;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT3rc_TYPE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT3rmi_METHOD;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT3rms_METHOD;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType INSTRUCTION_FORMAT51l;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType LINE_COMMENT;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType LINE_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType LOCAL_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType LOCALS_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType LONG_LITERAL;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType METHOD_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType MEMBER_NAME;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType NEGATIVE_INTEGER_LITERAL;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType NULL_LITERAL;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType OPEN_BRACE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType OPEN_PAREN;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType PACKED_SWITCH_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType PARAM_LIST_OR_ID_PRIMITIVE_TYPE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType PARAMETER_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType POSITIVE_INTEGER_LITERAL;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType PRIMITIVE_TYPE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType PROLOGUE_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType REGISTER;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType REGISTERS_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType RESTART_LOCAL_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType SHORT_LITERAL;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType SIMPLE_NAME;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType SOURCE_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType SPARSE_SWITCH_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType STRING_LITERAL;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType SUBANNOTATION_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType SUPER_DIRECTIVE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType VERIFICATION_ERROR_TYPE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType VOID_TYPE;
+ @SuppressWarnings({"UnusedDeclaration"}) public static IElementType VTABLE_INDEX;
+
+ public static final TokenSet INSTRUCTION_TOKENS;
+
+ static {
+ Map<String, TextAttributesKey> tokenColors = Maps.newHashMap();
+
+ tokenColors.put("ACCESS_SPEC", SmaliHighlightingColors.ACCESS);
+ tokenColors.put("ANNOTATION_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("ANNOTATION_VISIBILITY", SmaliHighlightingColors.ACCESS);
+ tokenColors.put("ARRAY_DATA_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("ARRAY_TYPE_PREFIX", SmaliHighlightingColors.TYPE);
+ tokenColors.put("ARROW", SmaliHighlightingColors.ARROW);
+ tokenColors.put("BOOL_LITERAL", SmaliHighlightingColors.LITERAL);
+ tokenColors.put("BYTE_LITERAL", SmaliHighlightingColors.NUMBER);
+ tokenColors.put("CATCH_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("CATCHALL_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("CHAR_LITERAL", SmaliHighlightingColors.STRING);
+ tokenColors.put("CLASS_DESCRIPTOR", SmaliHighlightingColors.TYPE);
+ tokenColors.put("CLASS_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("CLOSE_BRACE", SmaliHighlightingColors.BRACES);
+ tokenColors.put("CLOSE_PAREN", SmaliHighlightingColors.PARENS);
+ tokenColors.put("COLON", SmaliHighlightingColors.COLON);
+ tokenColors.put("COMMA", SmaliHighlightingColors.COMMA);
+ tokenColors.put("DOTDOT", SmaliHighlightingColors.DOTDOT);
+ tokenColors.put("DOUBLE_LITERAL", SmaliHighlightingColors.NUMBER);
+ tokenColors.put("DOUBLE_LITERAL_OR_ID", SmaliHighlightingColors.NUMBER);
+ tokenColors.put("END_ANNOTATION_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("END_ARRAY_DATA_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("END_FIELD_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("END_LOCAL_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("END_METHOD_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("END_PACKED_SWITCH_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("END_PARAMETER_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("END_SPARSE_SWITCH_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("END_SUBANNOTATION_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("ENUM_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("EPILOGUE_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("EQUAL", SmaliHighlightingColors.EQUAL);
+ tokenColors.put("FIELD_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("FIELD_OFFSET", SmaliHighlightingColors.ODEX_REFERENCE);
+ tokenColors.put("FLOAT_LITERAL", SmaliHighlightingColors.NUMBER);
+ tokenColors.put("FLOAT_LITERAL_OR_ID", SmaliHighlightingColors.NUMBER);
+ tokenColors.put("IMPLEMENTS_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("INLINE_INDEX", SmaliHighlightingColors.ODEX_REFERENCE);
+ tokenColors.put("INSTRUCTION_FORMAT10t", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT10x", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT10x_ODEX", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT11n", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT11x", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT12x", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT12x_OR_ID", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT20bc", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT20t", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT21c_FIELD", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT21c_FIELD_ODEX", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT21c_STRING", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT21c_TYPE", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT21ih", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT21lh", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT21s", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT21t", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT22b", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT22c_FIELD", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT22c_FIELD_ODEX", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT22c_TYPE", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT22cs_FIELD", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT22s", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT22s_OR_ID", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT22t", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT22x", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT23x", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT30t", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT31c", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT31i", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT31i_OR_ID", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT31t", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT32x", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT35c_METHOD", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT35c_METHOD_ODEX", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT35c_TYPE", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT35mi_METHOD", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT35ms_METHOD", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT3rc_METHOD", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT3rc_METHOD_ODEX", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT3rc_TYPE", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT3rmi_METHOD", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT3rms_METHOD", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("INSTRUCTION_FORMAT51l", SmaliHighlightingColors.INSTRUCTION);
+ tokenColors.put("LINE_COMMENT", SmaliHighlightingColors.COMMENT);
+ tokenColors.put("LINE_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("LOCAL_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("LOCALS_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("LONG_LITERAL", SmaliHighlightingColors.NUMBER);
+ tokenColors.put("MEMBER_NAME", SmaliHighlightingColors.IDENTIFIER);
+ tokenColors.put("METHOD_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("NEGATIVE_INTEGER_LITERAL", SmaliHighlightingColors.NUMBER);
+ tokenColors.put("NULL_LITERAL", SmaliHighlightingColors.LITERAL);
+ tokenColors.put("OPEN_BRACE", SmaliHighlightingColors.BRACES);
+ tokenColors.put("OPEN_PAREN", SmaliHighlightingColors.PARENS);
+ tokenColors.put("PACKED_SWITCH_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("PARAM_LIST_OR_ID_PRIMITIVE_TYPE", SmaliHighlightingColors.TYPE);
+ tokenColors.put("PARAMETER_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("POSITIVE_INTEGER_LITERAL", SmaliHighlightingColors.NUMBER);
+ tokenColors.put("PRIMITIVE_TYPE", SmaliHighlightingColors.TYPE);
+ tokenColors.put("PROLOGUE_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("REGISTER", SmaliHighlightingColors.REGISTER);
+ tokenColors.put("REGISTERS_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("RESTART_LOCAL_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("SHORT_LITERAL", SmaliHighlightingColors.NUMBER);
+ tokenColors.put("SIMPLE_NAME", SmaliHighlightingColors.IDENTIFIER);
+ tokenColors.put("SOURCE_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("SPARSE_SWITCH_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("STRING_LITERAL", SmaliHighlightingColors.STRING);
+ tokenColors.put("SUBANNOTATION_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("SUPER_DIRECTIVE", SmaliHighlightingColors.DIRECTIVE);
+ tokenColors.put("VERIFICATION_ERROR_TYPE", SmaliHighlightingColors.VERIFICATION_ERROR_TYPE);
+ tokenColors.put("VOID_TYPE", SmaliHighlightingColors.TYPE);
+ tokenColors.put("VTABLE_INDEX", SmaliHighlightingColors.ODEX_REFERENCE);
+
+ int tokenCount = smaliParser.tokenNames.length;
+ ELEMENT_TYPES = new IElementType[tokenCount];
+
+ for (int tokenId=0; tokenId<tokenCount; tokenId++) {
+ String tokenName = smaliParser.tokenNames[tokenId];
+ Field field;
+
+ try {
+ field = SmaliTokens.class.getField(tokenName);
+ } catch (NoSuchFieldException ex) {
+ continue;
+ }
+
+ TextAttributesKey textAttributesKey = tokenColors.get(tokenName);
+
+ if (textAttributesKey == null) {
+ throw new RuntimeException("No color attribute for token " + tokenName);
+ }
+
+ SmaliLexicalElementType elementType = new SmaliLexicalElementType(tokenId, tokenName, textAttributesKey);
+ ELEMENT_TYPES[tokenId] = elementType;
+
+ try {
+ field.set(null, elementType);
+ } catch (IllegalAccessException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ INSTRUCTION_TOKENS = TokenSet.create(
+ INSTRUCTION_FORMAT10t,
+ INSTRUCTION_FORMAT10x,
+ INSTRUCTION_FORMAT10x_ODEX,
+ INSTRUCTION_FORMAT11n,
+ INSTRUCTION_FORMAT11x,
+ INSTRUCTION_FORMAT12x_OR_ID,
+ INSTRUCTION_FORMAT12x,
+ INSTRUCTION_FORMAT20bc,
+ INSTRUCTION_FORMAT20t,
+ INSTRUCTION_FORMAT21c_FIELD,
+ INSTRUCTION_FORMAT21c_FIELD_ODEX,
+ INSTRUCTION_FORMAT21c_STRING,
+ INSTRUCTION_FORMAT21c_TYPE,
+ INSTRUCTION_FORMAT21ih,
+ INSTRUCTION_FORMAT21lh,
+ INSTRUCTION_FORMAT21s,
+ INSTRUCTION_FORMAT21t,
+ INSTRUCTION_FORMAT22b,
+ INSTRUCTION_FORMAT22c_FIELD,
+ INSTRUCTION_FORMAT22c_FIELD_ODEX,
+ INSTRUCTION_FORMAT22c_TYPE,
+ INSTRUCTION_FORMAT22cs_FIELD,
+ INSTRUCTION_FORMAT22s_OR_ID,
+ INSTRUCTION_FORMAT22s,
+ INSTRUCTION_FORMAT22t,
+ INSTRUCTION_FORMAT22x,
+ INSTRUCTION_FORMAT23x,
+ INSTRUCTION_FORMAT30t,
+ INSTRUCTION_FORMAT31c,
+ INSTRUCTION_FORMAT31i_OR_ID,
+ INSTRUCTION_FORMAT31i,
+ INSTRUCTION_FORMAT31t,
+ INSTRUCTION_FORMAT32x,
+ INSTRUCTION_FORMAT35c_METHOD,
+ INSTRUCTION_FORMAT35c_METHOD_ODEX,
+ INSTRUCTION_FORMAT35c_TYPE,
+ INSTRUCTION_FORMAT35mi_METHOD,
+ INSTRUCTION_FORMAT35ms_METHOD,
+ INSTRUCTION_FORMAT3rc_METHOD,
+ INSTRUCTION_FORMAT3rc_METHOD_ODEX,
+ INSTRUCTION_FORMAT3rc_TYPE,
+ INSTRUCTION_FORMAT3rmi_METHOD,
+ INSTRUCTION_FORMAT3rms_METHOD,
+ INSTRUCTION_FORMAT51l,
+ ARRAY_DATA_DIRECTIVE,
+ PACKED_SWITCH_DIRECTIVE,
+ SPARSE_SWITCH_DIRECTIVE
+ );
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliCodeFragmentFactory.java b/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliCodeFragmentFactory.java
new file mode 100644
index 00000000..5e2dd0c9
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliCodeFragmentFactory.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright 2014, 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.debugging;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.evaluation.*;
+import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilder;
+import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
+import com.intellij.debugger.engine.jdi.StackFrameProxy;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.Key;
+import com.intellij.psi.JavaCodeFragment;
+import com.intellij.psi.JavaRecursiveElementVisitor;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiLocalVariable;
+import com.intellij.psi.util.PsiMatchers;
+import com.sun.jdi.*;
+import com.sun.tools.jdi.LocalVariableImpl;
+import com.sun.tools.jdi.LocationImpl;
+import org.jf.dexlib2.analysis.AnalyzedInstruction;
+import org.jf.dexlib2.analysis.RegisterType;
+import org.jf.smalidea.SmaliFileType;
+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;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.Map;
+
+public class SmaliCodeFragmentFactory extends DefaultCodeFragmentFactory {
+ static final Key<List<LazyValue>> SMALI_LAZY_VALUES_KEY = Key.create("_smali_register_value_key_");
+
+ @Override
+ public JavaCodeFragment createCodeFragment(TextWithImports item, PsiElement context, Project project) {
+ context = wrapContext(project, context);
+ JavaCodeFragment fragment = super.createCodeFragment(item, context, project);
+ List<LazyValue> lazyValues = context.getUserData(SMALI_LAZY_VALUES_KEY);
+ if (lazyValues != null) {
+ fragment.putUserData(SMALI_LAZY_VALUES_KEY, lazyValues);
+ }
+ return fragment;
+ }
+
+ @Override
+ public boolean isContextAccepted(PsiElement contextElement) {
+ if (contextElement == null) {
+ return false;
+ }
+ return contextElement.getLanguage() == SmaliLanguage.INSTANCE;
+ }
+
+ @Override
+ public JavaCodeFragment createPresentationCodeFragment(TextWithImports item, PsiElement context, Project project) {
+ context = wrapContext(project, context);
+ JavaCodeFragment fragment = super.createPresentationCodeFragment(item, context, project);
+ List<LazyValue> lazyValues = context.getUserData(SMALI_LAZY_VALUES_KEY);
+ if (lazyValues != null) {
+ fragment.putUserData(SMALI_LAZY_VALUES_KEY, lazyValues);
+ }
+ return fragment;
+ }
+
+ @Override public LanguageFileType getFileType() {
+ return SmaliFileType.INSTANCE;
+ }
+
+ @Override public EvaluatorBuilder getEvaluatorBuilder() {
+ final EvaluatorBuilder builder = super.getEvaluatorBuilder();
+ return new EvaluatorBuilder() {
+
+ @Override
+ public ExpressionEvaluator build(PsiElement codeFragment, SourcePosition position)
+ throws EvaluateException {
+ return new SmaliExpressionEvaluator(codeFragment, builder.build(codeFragment, position));
+ }
+ };
+ }
+
+ private PsiElement wrapContext(final Project project, final PsiElement originalContext) {
+ if (project.isDefault()) return originalContext;
+
+ final List<LazyValue> lazyValues = Lists.newArrayList();
+
+ SmaliInstruction currentInstruction = (SmaliInstruction)PsiUtil.searchBackward(originalContext,
+ PsiMatchers.hasClass(SmaliInstruction.class),
+ PsiMatchers.hasClass(SmaliMethod.class));
+
+ if (currentInstruction == null) {
+ currentInstruction = (SmaliInstruction)PsiUtil.searchForward(originalContext,
+ PsiMatchers.hasClass(SmaliInstruction.class),
+ PsiMatchers.hasClass(SmaliMethod.class));
+ if (currentInstruction == null) {
+ return originalContext;
+ }
+ }
+
+ final SmaliMethod containingMethod = currentInstruction.getParentMethod();
+ AnalyzedInstruction analyzedInstruction = currentInstruction.getAnalyzedInstruction();
+ if (analyzedInstruction == null) {
+ return originalContext;
+ }
+
+ final int firstParameterRegister = containingMethod.getRegisterCount() -
+ containingMethod.getParameterRegisterCount();
+
+ final Map<String, String> registerMap = Maps.newHashMap();
+ StringBuilder variablesText = new StringBuilder();
+ for (int i=0; i<containingMethod.getRegisterCount(); i++) {
+ int parameterRegisterNumber = i - firstParameterRegister;
+
+ RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(i);
+ switch (registerType.category) {
+ case RegisterType.UNKNOWN:
+ case RegisterType.UNINIT:
+ case RegisterType.CONFLICTED:
+ case RegisterType.LONG_HI:
+ case RegisterType.DOUBLE_HI:
+ continue;
+ case RegisterType.NULL:
+ case RegisterType.ONE:
+ case RegisterType.INTEGER:
+ variablesText.append("int v").append(i).append(";\n");
+ registerMap.put("v" + i, "I");
+ if (parameterRegisterNumber >= 0) {
+ variablesText.append("int p").append(parameterRegisterNumber).append(";\n");
+ registerMap.put("p" + parameterRegisterNumber, "I");
+ }
+ break;
+ case RegisterType.BOOLEAN:
+ variablesText.append("boolean v").append(i).append(";\n");
+ registerMap.put("v" + i, "Z");
+ if (parameterRegisterNumber >= 0) {
+ variablesText.append("boolean p").append(parameterRegisterNumber).append(";\n");
+ registerMap.put("p" + parameterRegisterNumber, "Z");
+ }
+ break;
+ case RegisterType.BYTE:
+ case RegisterType.POS_BYTE:
+ variablesText.append("byte v").append(i).append(";\n");
+ registerMap.put("v" + i, "B");
+ if (parameterRegisterNumber >= 0) {
+ variablesText.append("byte p").append(parameterRegisterNumber).append(";\n");
+ registerMap.put("p" + parameterRegisterNumber, "B");
+ }
+ break;
+ case RegisterType.SHORT:
+ case RegisterType.POS_SHORT:
+ variablesText.append("short v").append(i).append(";\n");
+ registerMap.put("v" + i, "S");
+ if (parameterRegisterNumber >= 0) {
+ variablesText.append("short p").append(parameterRegisterNumber).append(";\n");
+ registerMap.put("p" + parameterRegisterNumber, "S");
+ }
+ break;
+ case RegisterType.CHAR:
+ variablesText.append("char v").append(i).append(";\n");
+ registerMap.put("v" + i, "C");
+ if (parameterRegisterNumber >= 0) {
+ variablesText.append("char p").append(parameterRegisterNumber).append(";\n");
+ registerMap.put("p" + parameterRegisterNumber, "C");
+ }
+ break;
+ case RegisterType.FLOAT:
+ variablesText.append("float v").append(i).append(";\n");
+ registerMap.put("v" + i, "F");
+ if (parameterRegisterNumber >= 0) {
+ variablesText.append("float p").append(parameterRegisterNumber).append(";\n");
+ registerMap.put("p" + parameterRegisterNumber, "F");
+ }
+ break;
+ case RegisterType.LONG_LO:
+ variablesText.append("long v").append(i).append(";\n");
+ registerMap.put("v" + i, "J");
+ if (parameterRegisterNumber >= 0) {
+ variablesText.append("long p").append(parameterRegisterNumber).append(";\n");
+ registerMap.put("p" + parameterRegisterNumber, "J");
+ }
+ break;
+ case RegisterType.DOUBLE_LO:
+ variablesText.append("double v").append(i).append(";\n");
+ registerMap.put("v" + i, "D");
+ if (parameterRegisterNumber >= 0) {
+ variablesText.append("double p").append(parameterRegisterNumber).append(";\n");
+ registerMap.put("p" + parameterRegisterNumber, "D");
+ }
+ break;
+ case RegisterType.UNINIT_REF:
+ case RegisterType.UNINIT_THIS:
+ case RegisterType.REFERENCE:
+ 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(javaType).append(" p").append(parameterRegisterNumber).append(";\n");
+ registerMap.put("p" + parameterRegisterNumber, "Ljava/lang/Object;");
+ }
+ break;
+ }
+ }
+ final TextWithImportsImpl textWithImports = new TextWithImportsImpl(CodeFragmentKind.CODE_BLOCK,
+ variablesText.toString(), "", getFileType());
+
+ final JavaCodeFragment codeFragment = super.createCodeFragment(textWithImports, originalContext, project);
+
+ codeFragment.accept(new JavaRecursiveElementVisitor() {
+ @Override
+ public void visitLocalVariable(final PsiLocalVariable variable) {
+ final String name = variable.getName();
+ if (name != null && registerMap.containsKey(name)) {
+ int registerNumber = Integer.parseInt(name.substring(1));
+ if (name.charAt(0) == 'p') {
+ registerNumber += ApplicationManager.getApplication().runReadAction(new Computable<Integer>() {
+ @Override public Integer compute() {
+ return containingMethod.getRegisterCount() -
+ containingMethod.getParameterRegisterCount();
+ }
+ });
+ }
+ LazyValue lazyValue = LazyValue.create(containingMethod, project, registerNumber,
+ registerMap.get(name));
+ variable.putUserData(CodeFragmentFactoryContextWrapper.LABEL_VARIABLE_VALUE_KEY, lazyValue);
+ lazyValues.add(lazyValue);
+ }
+ }
+ });
+
+ int offset = variablesText.length() - 1;
+
+ final PsiElement newContext = codeFragment.findElementAt(offset);
+ if (newContext != null) {
+ newContext.putUserData(SMALI_LAZY_VALUES_KEY, lazyValues);
+ return newContext;
+ }
+ return originalContext;
+ }
+
+ public static Value evaluateRegister(EvaluationContext context, final SmaliMethod smaliMethod,
+ final int registerNum, final String type) throws EvaluateException {
+
+ final StackFrameProxy frameProxy = context.getSuspendContext().getFrameProxy();
+ if (frameProxy == null) {
+ return null;
+ }
+
+ VirtualMachine vm = frameProxy.getStackFrame().virtualMachine();
+ Location currentLocation = frameProxy.location();
+ if (currentLocation == null) {
+ return null;
+ }
+
+ Method method = currentLocation.method();
+
+ try {
+ final Constructor<LocalVariableImpl> localVariableConstructor = LocalVariableImpl.class.getDeclaredConstructor(
+ VirtualMachine.class, Method.class, Integer.TYPE, Location.class, Location.class, String.class,
+ String.class, String.class);
+ localVariableConstructor.setAccessible(true);
+
+ Constructor<LocationImpl> locationConstructor = LocationImpl.class.getDeclaredConstructor(
+ VirtualMachine.class, Method.class, Long.TYPE);
+ locationConstructor.setAccessible(true);
+
+ int methodSize = 0;
+ for (SmaliInstruction instruction: smaliMethod.getInstructions()) {
+ methodSize += instruction.getInstructionSize();
+ }
+ Location endLocation = method.locationOfCodeIndex((methodSize/2) - 1);
+
+ LocalVariable localVariable = localVariableConstructor.newInstance(vm,
+ method,
+ mapRegister(frameProxy.getStackFrame().virtualMachine(), smaliMethod, registerNum),
+ method.locationOfCodeIndex(0),
+ endLocation,
+ String.format("v%d", registerNum), type, null);
+
+ return frameProxy.getStackFrame().getValue(localVariable);
+ } catch (NoSuchMethodException e) {
+ return null;
+ } catch (InstantiationException e) {
+ return null;
+ } catch (IllegalAccessException e) {
+ return null;
+ } catch (InvocationTargetException e) {
+ return null;
+ }
+ }
+
+ private static int mapRegister(final VirtualMachine vm, final SmaliMethod smaliMethod, final int register) {
+ if (vm.version().equals("1.5.0")) {
+ return mapRegisterForDalvik(smaliMethod, register);
+ } else {
+ return mapRegisterForArt(smaliMethod, register);
+ }
+ }
+
+ private static int mapRegisterForArt(final SmaliMethod smaliMethod, final int register) {
+ return ApplicationManager.getApplication().runReadAction(new Computable<Integer>() {
+ @Override public Integer compute() {
+
+ int totalRegisters = smaliMethod.getRegisterCount();
+ int parameterRegisters = smaliMethod.getParameterRegisterCount();
+
+ if (smaliMethod.getModifierList().hasModifierProperty("static")) {
+ return register;
+ }
+
+ // For ART, the parameter registers are rotated to the front
+ if (register >= (totalRegisters - parameterRegisters)) {
+ return register - (totalRegisters - parameterRegisters);
+ }
+ return register + parameterRegisters;
+ }
+ });
+ }
+
+ private static int mapRegisterForDalvik(final SmaliMethod smaliMethod, final int register) {
+ return ApplicationManager.getApplication().runReadAction(new Computable<Integer>() {
+ @Override public Integer compute() {
+ if (smaliMethod.getModifierList().hasModifierProperty("static")) {
+ return register;
+ }
+
+ int totalRegisters = smaliMethod.getRegisterCount();
+ int parameterRegisters = smaliMethod.getParameterRegisterCount();
+
+ // For dalvik, p0 is mapped to register 1, and register 0 is mapped to register 1000
+ if (register == (totalRegisters - parameterRegisters)) {
+ return 0;
+ }
+ if (register == 0) {
+ return 1000;
+ }
+ return register;
+ }
+ });
+ }
+}
+
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliDebuggerSupport.java b/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliDebuggerSupport.java
new file mode 100644
index 00000000..f822fd1f
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliDebuggerSupport.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2014, 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.debugging;
+
+import com.intellij.debugger.actions.StepOverActionHandler;
+import com.intellij.debugger.impl.DebuggerSession;
+import com.intellij.debugger.ui.JavaDebuggerSupport;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import com.intellij.xdebugger.impl.actions.DebuggerActionHandler;
+import com.sun.jdi.request.StepRequest;
+import org.jetbrains.annotations.NotNull;
+
+public class SmaliDebuggerSupport extends JavaDebuggerSupport {
+ private static boolean useModifiedMethod;
+
+ static {
+ try {
+ DebuggerSession.class.getMethod("stepOver", boolean.class, int.class);
+ useModifiedMethod = true;
+ } catch (NoSuchMethodException ex) {
+ useModifiedMethod = false;
+ }
+ }
+
+ private final StepOverActionHandler myStepOverActionHandler = new StepOverActionHandler() {
+ @Override
+ public void perform(@NotNull final Project project, AnActionEvent e) {
+ final DebuggerSession session = getSession(project);
+
+ if (session != null) {
+ if (useModifiedMethod) {
+ session.stepOver(false, StepRequest.STEP_MIN);
+ } else {
+ session.stepOver(false);
+ }
+ }
+ }
+
+ @Override public boolean isEnabled(@NotNull Project project, AnActionEvent event) {
+ // TODO: check if we're currently in a smali file?
+ return super.isEnabled(project, event);
+ }
+ };
+
+ @NotNull
+ @Override
+ public DebuggerActionHandler getStepOverHandler() {
+ return myStepOverActionHandler;
+ }
+
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliExpressionEvaluator.java b/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliExpressionEvaluator.java
new file mode 100644
index 00000000..89bba297
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliExpressionEvaluator.java
@@ -0,0 +1,70 @@
+/*
+ * 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.debugging;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
+import com.intellij.debugger.engine.evaluation.expression.Modifier;
+import com.intellij.psi.PsiElement;
+import com.sun.jdi.Value;
+import org.jf.smalidea.debugging.value.LazyValue;
+
+import java.util.List;
+
+public class SmaliExpressionEvaluator implements ExpressionEvaluator {
+ private final PsiElement fragment;
+ private final ExpressionEvaluator evaluator;
+
+ public SmaliExpressionEvaluator(PsiElement fragment, ExpressionEvaluator evaluator) {
+ this.fragment = fragment;
+ this.evaluator = evaluator;
+ }
+
+ @Override public Value evaluate(EvaluationContext context) throws EvaluateException {
+ List<LazyValue> lazyValues = fragment.getUserData(SmaliCodeFragmentFactory.SMALI_LAZY_VALUES_KEY);
+ if (lazyValues != null) {
+ for (LazyValue lazyValue: lazyValues) {
+ lazyValue.setEvaluationContext(context);
+ }
+ }
+ return evaluator.evaluate(context);
+ }
+
+ @Override public Value getValue() {
+ return evaluator.getValue();
+ }
+
+ @Override public Modifier getModifier() {
+ return evaluator.getModifier();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliPositionManager.java b/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliPositionManager.java
new file mode 100644
index 00000000..781a8569
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliPositionManager.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2014, 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.debugging;
+
+import com.intellij.debugger.NoDataException;
+import com.intellij.debugger.PositionManager;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.requests.ClassPrepareRequestor;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.sun.jdi.Location;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.request.ClassPrepareRequest;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.impl.SmaliClass;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+import org.jf.smalidea.psi.index.SmaliClassNameIndex;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class SmaliPositionManager implements PositionManager {
+ private final DebugProcess debugProcess;
+
+ public SmaliPositionManager(DebugProcess debugProcess) {
+ this.debugProcess = debugProcess;
+ }
+
+ public SourcePosition getSourcePosition(String declaringType, String methodName, String methodSignature,
+ int codeIndex) throws NoDataException {
+ Collection<SmaliClass> classes = SmaliClassNameIndex.INSTANCE.get(declaringType,
+ debugProcess.getProject(), GlobalSearchScope.projectScope(debugProcess.getProject()));
+
+ if (classes.size() > 0) {
+ SmaliClass smaliClass = classes.iterator().next();
+
+ // TODO: make an index for this?
+ for (SmaliMethod smaliMethod: smaliClass.getMethods()) {
+ if (smaliMethod.getName().equals(methodName) &&
+ smaliMethod.getMethodPrototype().getText().equals(methodSignature)) {
+ return smaliMethod.getSourcePositionForCodeOffset(codeIndex * 2);
+ }
+ }
+ }
+
+ throw NoDataException.INSTANCE;
+ }
+
+ @Override
+ public SourcePosition getSourcePosition(@Nullable Location location) throws NoDataException {
+ if (location == null) {
+ throw NoDataException.INSTANCE;
+ }
+
+ return getSourcePosition(location.declaringType().name(), location.method().name(),
+ location.method().signature(), (int)location.codeIndex());
+ }
+
+ @Override @NotNull
+ public List<ReferenceType> getAllClasses(@NotNull SourcePosition classPosition) throws NoDataException {
+ if (!(classPosition.getElementAt().getContainingFile() instanceof SmaliFile)) {
+ throw NoDataException.INSTANCE;
+ }
+
+ String className = getClassFromPosition(classPosition);
+ return debugProcess.getVirtualMachineProxy().classesByName(className);
+ }
+
+ @NotNull
+ private String getClassFromPosition(@NotNull final SourcePosition position) {
+ return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+ @Override public String compute() {
+ SmaliClass smaliClass = ((SmaliFile)position.getElementAt().getContainingFile()).getPsiClass();
+ if (smaliClass == null) {
+ return "";
+ }
+ return smaliClass.getQualifiedName();
+ }
+ });
+ }
+
+ @Override @NotNull
+ public List<Location> locationsOfLine(@NotNull final ReferenceType type,
+ @NotNull final SourcePosition position) throws NoDataException {
+ if (!(position.getElementAt().getContainingFile() instanceof SmaliFile)) {
+ throw NoDataException.INSTANCE;
+ }
+
+ final ArrayList<Location> locations = new ArrayList<Location>(1);
+
+ ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ String typeName = type.name();
+ Collection<SmaliClass> classes = SmaliClassNameIndex.INSTANCE.get(typeName, debugProcess.getProject(),
+ GlobalSearchScope.projectScope(debugProcess.getProject()));
+
+ if (classes.size() > 0) {
+ final SmaliClass smaliClass = classes.iterator().next();
+
+ Location location = smaliClass.getLocationForSourcePosition(type, position);
+
+ if (location != null) {
+ locations.add(location);
+ }
+ }
+ }
+ });
+ return locations;
+ }
+
+ @Override
+ public ClassPrepareRequest createPrepareRequest(@NotNull final ClassPrepareRequestor requestor,
+ @NotNull final SourcePosition position) throws NoDataException {
+ Computable<Boolean> isSmaliFile = new Computable<Boolean>() {
+ @Override
+ public Boolean compute() {
+ return position.getFile() instanceof SmaliFile;
+ }
+ };
+
+ ApplicationManager.getApplication().runReadAction(isSmaliFile);
+
+ if (!isSmaliFile.compute()) {
+ throw NoDataException.INSTANCE;
+ }
+
+ String className = getClassFromPosition(position);
+ return debugProcess.getRequestsManager().createClassPrepareRequest(new ClassPrepareRequestor() {
+ @Override
+ public void processClassPrepare(DebugProcess debuggerProcess, ReferenceType referenceType) {
+ requestor.processClassPrepare(debuggerProcess, referenceType);
+ }
+ }, className);
+ }
+} \ No newline at end of file
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliPositionManagerFactory.java b/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliPositionManagerFactory.java
new file mode 100644
index 00000000..d78b57c8
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/SmaliPositionManagerFactory.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012, 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.debugging;
+
+import com.intellij.debugger.PositionManager;
+import com.intellij.debugger.PositionManagerFactory;
+import com.intellij.debugger.engine.DebugProcess;
+import org.jetbrains.annotations.NotNull;
+
+public class SmaliPositionManagerFactory extends PositionManagerFactory {
+ @Override
+ public PositionManager createPositionManager(@NotNull DebugProcess process) {
+ return new SmaliPositionManager(process);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyArrayReference.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyArrayReference.java
new file mode 100644
index 00000000..ad55a9f0
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyArrayReference.java
@@ -0,0 +1,75 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.ArrayReference;
+import com.sun.jdi.ClassNotLoadedException;
+import com.sun.jdi.InvalidTypeException;
+import com.sun.jdi.Value;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+import java.util.List;
+
+public class LazyArrayReference extends LazyObjectReference<ArrayReference> implements ArrayReference {
+ public LazyArrayReference(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ public Value getValue(int index) {
+ return getValue().getValue(index);
+ }
+
+ public List<Value> getValues() {
+ return getValue().getValues();
+ }
+
+ public List<Value> getValues(int index, int length) {
+ return getValue().getValues(index, length);
+ }
+
+ public int length() {
+ return getValue().length();
+ }
+
+ public void setValue(int index, Value value) throws InvalidTypeException, ClassNotLoadedException {
+ getValue().setValue(index, value);
+ }
+
+ public void setValues(int index, List<? extends Value> values, int srcIndex, int length) throws InvalidTypeException, ClassNotLoadedException {
+ getValue().setValues(index, values, srcIndex, length);
+ }
+
+ public void setValues(List<? extends Value> values) throws InvalidTypeException, ClassNotLoadedException {
+ getValue().setValues(values);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyBooleanValue.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyBooleanValue.java
new file mode 100644
index 00000000..e42da259
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyBooleanValue.java
@@ -0,0 +1,46 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.BooleanValue;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+public class LazyBooleanValue extends LazyPrimitiveValue<BooleanValue> implements BooleanValue {
+ public LazyBooleanValue(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ @Override public boolean value() {
+ return getValue().value();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyByteValue.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyByteValue.java
new file mode 100644
index 00000000..bc0e6a38
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyByteValue.java
@@ -0,0 +1,46 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.ByteValue;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+public class LazyByteValue extends LazyComparablePrimitiveValue<ByteValue> implements ByteValue {
+ public LazyByteValue(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ @Override public byte value() {
+ return getValue().value();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyCharValue.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyCharValue.java
new file mode 100644
index 00000000..0c536dd9
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyCharValue.java
@@ -0,0 +1,46 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.CharValue;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+public class LazyCharValue extends LazyComparablePrimitiveValue<CharValue> implements CharValue {
+ public LazyCharValue(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ @Override public char value() {
+ return getValue().value();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyClassLoaderReference.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyClassLoaderReference.java
new file mode 100644
index 00000000..dc41bbb5
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyClassLoaderReference.java
@@ -0,0 +1,54 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.ClassLoaderReference;
+import com.sun.jdi.ReferenceType;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+import java.util.List;
+
+public class LazyClassLoaderReference extends LazyObjectReference<ClassLoaderReference>
+ implements ClassLoaderReference {
+ public LazyClassLoaderReference(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ public List<ReferenceType> definedClasses() {
+ return getValue().definedClasses();
+ }
+
+ public List<ReferenceType> visibleClasses() {
+ return getValue().visibleClasses();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyClassObjectReference.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyClassObjectReference.java
new file mode 100644
index 00000000..62ac4203
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyClassObjectReference.java
@@ -0,0 +1,48 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.ClassObjectReference;
+import com.sun.jdi.ReferenceType;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+public class LazyClassObjectReference extends LazyObjectReference<ClassObjectReference>
+ implements ClassObjectReference {
+ public LazyClassObjectReference(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ public ReferenceType reflectedType() {
+ return getValue().reflectedType();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyComparablePrimitiveValue.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyComparablePrimitiveValue.java
new file mode 100644
index 00000000..e4a0b332
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyComparablePrimitiveValue.java
@@ -0,0 +1,47 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.PrimitiveValue;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+public class LazyComparablePrimitiveValue<T extends PrimitiveValue & Comparable<T>> extends LazyPrimitiveValue<T>
+ implements Comparable<T> {
+ public LazyComparablePrimitiveValue(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ public int compareTo(T o) {
+ return getValue().compareTo(o);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyDoubleValue.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyDoubleValue.java
new file mode 100644
index 00000000..ae9e17a8
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyDoubleValue.java
@@ -0,0 +1,46 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.DoubleValue;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+public class LazyDoubleValue extends LazyComparablePrimitiveValue<DoubleValue> implements DoubleValue {
+ public LazyDoubleValue(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ @Override public double value() {
+ return getValue().value();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyFloatValue.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyFloatValue.java
new file mode 100644
index 00000000..54041cd6
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyFloatValue.java
@@ -0,0 +1,46 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.FloatValue;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+public class LazyFloatValue extends LazyComparablePrimitiveValue<FloatValue> implements FloatValue {
+ public LazyFloatValue(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ @Override public float value() {
+ return getValue().value();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyIntegerValue.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyIntegerValue.java
new file mode 100644
index 00000000..87b13caf
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyIntegerValue.java
@@ -0,0 +1,46 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.IntegerValue;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+public class LazyIntegerValue extends LazyComparablePrimitiveValue<IntegerValue> implements IntegerValue {
+ public LazyIntegerValue(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ @Override public int value() {
+ return getValue().value();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyLongValue.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyLongValue.java
new file mode 100644
index 00000000..e1c1aafc
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyLongValue.java
@@ -0,0 +1,46 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.LongValue;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+public class LazyLongValue extends LazyComparablePrimitiveValue<LongValue> implements LongValue {
+ public LazyLongValue(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ @Override public long value() {
+ return getValue().value();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyObjectReference.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyObjectReference.java
new file mode 100644
index 00000000..9f50bf3f
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyObjectReference.java
@@ -0,0 +1,101 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.*;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+import java.util.List;
+import java.util.Map;
+
+public class LazyObjectReference<T extends ObjectReference> extends LazyValue<T> implements ObjectReference {
+
+ public LazyObjectReference(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ @Override public void disableCollection() {
+ getValue().disableCollection();
+ }
+
+ @Override public ReferenceType referenceType() {
+ return getValue().referenceType();
+ }
+
+ @Override public Value getValue(Field sig) {
+ return getValue().getValue(sig);
+ }
+
+ @Override public Map<Field, Value> getValues(List<? extends Field> fields) {
+ return getValue().getValues(fields);
+ }
+
+ @Override public void setValue(Field field, Value value) throws InvalidTypeException, ClassNotLoadedException {
+ getValue().setValue(field, value);
+ }
+
+ @Override
+ public Value invokeMethod(ThreadReference thread, Method method, List<? extends Value> arguments, int options)
+ throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException,
+ InvocationException {
+ return getValue().invokeMethod(thread, method, arguments, options);
+ }
+
+ @Override public void enableCollection() {
+ getValue().enableCollection();
+ }
+
+ @Override public boolean isCollected() {
+ return getValue().isCollected();
+ }
+
+ @Override public long uniqueID() {
+ return getValue().uniqueID();
+ }
+
+ @Override public List<ThreadReference> waitingThreads() throws IncompatibleThreadStateException {
+ return getValue().waitingThreads();
+ }
+
+ @Override public ThreadReference owningThread() throws IncompatibleThreadStateException {
+ return getValue().owningThread();
+ }
+
+ @Override public int entryCount() throws IncompatibleThreadStateException {
+ return getValue().entryCount();
+ }
+
+ @Override public List<ObjectReference> referringObjects(long maxReferrers) {
+ return getValue().referringObjects(maxReferrers);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyPrimitiveValue.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyPrimitiveValue.java
new file mode 100644
index 00000000..65d36357
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyPrimitiveValue.java
@@ -0,0 +1,78 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.PrimitiveValue;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+public class LazyPrimitiveValue<T extends PrimitiveValue> extends LazyValue<T> implements PrimitiveValue {
+ public LazyPrimitiveValue(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ @Override public boolean booleanValue() {
+ return getValue().booleanValue();
+ }
+
+ @Override public byte byteValue() {
+ return getValue().byteValue();
+ }
+
+ @Override public char charValue() {
+ return getValue().charValue();
+ }
+
+ @Override public double doubleValue() {
+ return getValue().doubleValue();
+ }
+
+ @Override public float floatValue() {
+ return getValue().floatValue();
+ }
+
+ @Override public int intValue() {
+ return getValue().intValue();
+ }
+
+ @Override public long longValue() {
+ return getValue().longValue();
+ }
+
+ @Override public short shortValue() {
+ return getValue().shortValue();
+ }
+
+ @Override public String toString() {
+ return getValue().toString();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyShortValue.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyShortValue.java
new file mode 100644
index 00000000..10a5fa32
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyShortValue.java
@@ -0,0 +1,46 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.ShortValue;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+public class LazyShortValue extends LazyComparablePrimitiveValue<ShortValue> implements ShortValue {
+ public LazyShortValue(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ @Override public short value() {
+ return getValue().value();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyStringReference.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyStringReference.java
new file mode 100644
index 00000000..88fd0070
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyStringReference.java
@@ -0,0 +1,46 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.StringReference;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+public class LazyStringReference extends LazyObjectReference<StringReference> implements StringReference {
+ public LazyStringReference(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ public String value() {
+ return getValue().value();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyThreadGroupReference.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyThreadGroupReference.java
new file mode 100644
index 00000000..05f05d63
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyThreadGroupReference.java
@@ -0,0 +1,71 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.ThreadGroupReference;
+import com.sun.jdi.ThreadReference;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+import java.util.List;
+
+public class LazyThreadGroupReference extends LazyObjectReference<ThreadGroupReference>
+ implements ThreadGroupReference {
+
+ public LazyThreadGroupReference(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ @Override public String name() {
+ return getValue().name();
+ }
+
+ @Override public ThreadGroupReference parent() {
+ return getValue().parent();
+ }
+
+ @Override public void resume() {
+ getValue().resume();
+ }
+
+ @Override public void suspend() {
+ getValue().suspend();
+ }
+
+ @Override public List<ThreadGroupReference> threadGroups() {
+ return getValue().threadGroups();
+ }
+
+ @Override public List<ThreadReference> threads() {
+ return getValue().threads();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyThreadReference.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyThreadReference.java
new file mode 100644
index 00000000..61a13f88
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyThreadReference.java
@@ -0,0 +1,120 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.*;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+import java.util.List;
+
+public class LazyThreadReference extends LazyObjectReference<ThreadReference> implements ThreadReference {
+ public LazyThreadReference(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+
+ public ObjectReference currentContendedMonitor() throws IncompatibleThreadStateException {
+ return getValue().currentContendedMonitor();
+ }
+
+ public void forceEarlyReturn(Value value) throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException {
+ getValue().forceEarlyReturn(value);
+ }
+
+ public StackFrame frame(int index) throws IncompatibleThreadStateException {
+ return getValue().frame(index);
+ }
+
+ public int frameCount() throws IncompatibleThreadStateException {
+ return getValue().frameCount();
+ }
+
+ public List<StackFrame> frames() throws IncompatibleThreadStateException {
+ return getValue().frames();
+ }
+
+ public List<StackFrame> frames(int start, int length) throws IncompatibleThreadStateException {
+ return getValue().frames(start, length);
+ }
+
+ public void interrupt() {
+ getValue().interrupt();
+ }
+
+ public boolean isAtBreakpoint() {
+ return getValue().isAtBreakpoint();
+ }
+
+ public boolean isSuspended() {
+ return getValue().isSuspended();
+ }
+
+ public String name() {
+ return getValue().name();
+ }
+
+ public List<ObjectReference> ownedMonitors() throws IncompatibleThreadStateException {
+ return getValue().ownedMonitors();
+ }
+
+ public List<MonitorInfo> ownedMonitorsAndFrames() throws IncompatibleThreadStateException {
+ return getValue().ownedMonitorsAndFrames();
+ }
+
+ public void popFrames(StackFrame frame) throws IncompatibleThreadStateException {
+ getValue().popFrames(frame);
+ }
+
+ public void resume() {
+ getValue().resume();
+ }
+
+ public int status() {
+ return getValue().status();
+ }
+
+ public void stop(ObjectReference throwable) throws InvalidTypeException {
+ getValue().stop(throwable);
+ }
+
+ public void suspend() {
+ getValue().suspend();
+ }
+
+ public int suspendCount() {
+ return getValue().suspendCount();
+ }
+
+ public ThreadGroupReference threadGroup() {
+ return getValue().threadGroup();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyValue.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyValue.java
new file mode 100644
index 00000000..746a629b
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyValue.java
@@ -0,0 +1,179 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.impl.DebuggerContextImpl;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.Type;
+import com.sun.jdi.Value;
+import com.sun.jdi.VirtualMachine;
+import org.jf.smalidea.debugging.SmaliCodeFragmentFactory;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public class LazyValue<T extends Value> implements Value {
+ private final int registerNumber;
+ private final Project project;
+ private final SmaliMethod method;
+ private final String type;
+
+ private EvaluationContext evaluationContext;
+ private Value value;
+
+ public LazyValue(SmaliMethod method, Project project, int registerNumber, String type) {
+ this.method = method;
+ this.project = project;
+ this.registerNumber = registerNumber;
+ this.type = type;
+ }
+
+ public static LazyValue create(@Nonnull SmaliMethod method, @Nonnull Project project, int registerNumber,
+ @Nonnull String type) {
+ if (type.equals("B")) {
+ return new LazyByteValue(method, project, registerNumber, type);
+ } else if (type.equals("S")) {
+ return new LazyShortValue(method, project, registerNumber, type);
+ } else if (type.equals("J")) {
+ return new LazyLongValue(method, project, registerNumber, type);
+ } else if (type.equals("I")) {
+ return new LazyIntegerValue(method, project, registerNumber, type);
+ } else if (type.equals("F")) {
+ return new LazyFloatValue(method, project, registerNumber, type);
+ } else if (type.equals("D")) {
+ return new LazyDoubleValue(method, project, registerNumber, type);
+ } else if (type.equals("Z")) {
+ return new LazyBooleanValue(method, project, registerNumber, type);
+ } else if (type.equals("C")) {
+ return new LazyCharValue(method, project, registerNumber, type);
+ } else if (type.equals("V")) {
+ return new LazyVoidValue(method, project, registerNumber, type);
+ } else if (type.startsWith("[")) {
+ return new LazyArrayReference(method, project, registerNumber, type);
+ } else if (type.equals("Ljava/lang/String;")) {
+ return new LazyStringReference(method, project, registerNumber, type);
+ } else if (type.equals("Ljava/lang/Class;")) {
+ return new LazyClassObjectReference(method, project, registerNumber, type);
+ } else if (type.equals("Ljava/lang/ThreadGroup;")) {
+ return new LazyThreadGroupReference(method, project, registerNumber, type);
+ } else if (type.equals("Ljava/lang/Thread;")) {
+ return new LazyThreadReference(method, project, registerNumber, type);
+ } else if (type.equals("Ljava/lang/ClassLoader;")) {
+ return new LazyClassLoaderReference(method, project, registerNumber, type);
+ } else if (type.startsWith("L")) {
+ return new LazyObjectReference(method, project, registerNumber, type);
+ }
+ return new LazyValue(method, project, registerNumber, type);
+ }
+
+ @Nullable
+ private T getNullableValue() {
+ if (value == null) {
+ try {
+ if (evaluationContext == null) {
+ final DebuggerContextImpl debuggerContext = DebuggerManagerEx.getInstanceEx(project).getContext();
+ evaluationContext = debuggerContext.createEvaluationContext();
+ if (evaluationContext == null) {
+ return null;
+ }
+ }
+
+ value = SmaliCodeFragmentFactory.evaluateRegister(evaluationContext, method, registerNumber, type);
+ evaluationContext = null;
+ } catch (EvaluateException ex) {
+ return null;
+ }
+ }
+ return (T)value;
+ }
+
+ @Nonnull
+ protected T getValue() {
+ T value = getNullableValue();
+ assert value != null;
+ return value;
+ }
+
+ @Override
+ public Type type() {
+ return getValue().type();
+ }
+
+ @Override
+ public VirtualMachine virtualMachine() {
+ if (evaluationContext != null) {
+ return ((VirtualMachineProxyImpl)evaluationContext.getDebugProcess().getVirtualMachineProxy())
+ .getVirtualMachine();
+ } else {
+ final DebuggerContextImpl debuggerContext = DebuggerManagerEx.getInstanceEx(project).getContext();
+ final DebugProcessImpl process = debuggerContext.getDebugProcess();
+ if (process != null) {
+ return process.getVirtualMachineProxy().getVirtualMachine();
+ }
+ }
+ return null;
+ }
+
+ public void setEvaluationContext(@Nonnull EvaluationContext evaluationContext) {
+ this.evaluationContext = evaluationContext;
+ }
+
+ @Override public boolean equals(Object obj) {
+ Value value = getNullableValue();
+ if (value != null) {
+ return value.equals(obj);
+ }
+ return super.equals(obj);
+ }
+
+ @Override public int hashCode() {
+ Value value = getNullableValue();
+ if (value != null) {
+ return value.hashCode();
+ }
+ return super.hashCode();
+ }
+
+ @Override public String toString() {
+ Value value = getNullableValue();
+ if (value != null) {
+ return value.toString();
+ }
+ return super.toString();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyVoidValue.java b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyVoidValue.java
new file mode 100644
index 00000000..a7f6bdc5
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/debugging/value/LazyVoidValue.java
@@ -0,0 +1,42 @@
+/*
+ * 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.debugging.value;
+
+import com.intellij.openapi.project.Project;
+import com.sun.jdi.VoidValue;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+public class LazyVoidValue extends LazyValue<VoidValue> implements VoidValue {
+ public LazyVoidValue(SmaliMethod method, Project project, int registerNumber, String type) {
+ super(method, project, registerNumber, type);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaClassDef.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaClassDef.java
new file mode 100644
index 00000000..c954702a
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaClassDef.java
@@ -0,0 +1,214 @@
+/*
+ * 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() {
+ return NameUtils.javaToSmaliType(psiClass);
+ }
+
+ @Nullable @Override public String getSuperclass() {
+ PsiClass superClass = psiClass.getSuperClass();
+ if (superClass == null) {
+ return null;
+ }
+ return NameUtils.javaToSmaliType(superClass);
+ }
+
+ @Nonnull @Override public List<String> getInterfaces() {
+ List<String> interfaceList = Lists.newArrayList();
+ PsiClass[] interfaces = psiClass.getInterfaces();
+ if (interfaces == null) {
+ return interfaceList;
+ }
+
+ for (PsiClass psiClass: interfaces) {
+ interfaceList.add(NameUtils.javaToSmaliType(psiClass));
+ }
+
+ 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());
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaExceptionHandler.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaExceptionHandler.java
new file mode 100644
index 00000000..72909b63
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaExceptionHandler.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015, 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 org.jf.dexlib2.base.BaseExceptionHandler;
+import org.jf.smalidea.psi.impl.SmaliCatchStatement;
+import org.jf.smalidea.psi.impl.SmaliClassTypeElement;
+import org.jf.smalidea.psi.impl.SmaliLabel;
+import org.jf.smalidea.psi.impl.SmaliLabelReference;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public class SmalideaExceptionHandler extends BaseExceptionHandler {
+ @Nonnull private final SmaliCatchStatement catchStatement;
+
+ public SmalideaExceptionHandler(@Nonnull SmaliCatchStatement catchStatement) {
+ this.catchStatement = catchStatement;
+ }
+
+ @Nullable @Override public String getExceptionType() {
+ SmaliClassTypeElement exceptionType = catchStatement.getExceptionType();
+ if (exceptionType == null) {
+ return null;
+ }
+ return exceptionType.getText();
+ }
+
+ @Override public int getHandlerCodeAddress() {
+ SmaliLabelReference handlerLabel = catchStatement.getHandlerLabel();
+ // TODO: how to handle a reference to a non-existent label..
+ SmaliLabel smaliLabel = handlerLabel.resolve();
+ return smaliLabel.getOffset() / 2;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaField.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaField.java
new file mode 100644
index 00000000..7b98174a
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaField.java
@@ -0,0 +1,116 @@
+/*
+ * 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?");
+ }
+ return NameUtils.javaToSmaliType(containingClass);
+ }
+
+ @Nonnull @Override public String getName() {
+ return psiField.getNameIdentifier().getText();
+ }
+
+ @Nonnull @Override public String getType() {
+ return NameUtils.javaToSmaliType(psiField.getType());
+ }
+
+ @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();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaMethod.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaMethod.java
new file mode 100644
index 00000000..abc4dda8
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaMethod.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2014, 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.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;
+import org.jf.dexlib2.iface.instruction.Instruction;
+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.util.NameUtils;
+
+import javax.annotation.Nonnull;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+public class SmalideaMethod extends BaseMethodReference implements Method {
+ private final PsiMethod psiMethod;
+
+ public SmalideaMethod(@NotNull PsiMethod psiMethod) {
+ this.psiMethod = psiMethod;
+ }
+
+ @Nonnull @Override public String getDefiningClass() {
+ PsiClass cls = psiMethod.getContainingClass();
+ assert cls != null;
+ return NameUtils.javaToSmaliType(cls);
+ }
+
+ @Nonnull @Override public List<? extends MethodParameter> getParameters() {
+ PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
+
+ return Lists.transform(Arrays.asList(parameters), new Function<PsiParameter, MethodParameter>() {
+ @Nullable @Override
+ public MethodParameter apply(@Nullable PsiParameter psiParameter) {
+ if (psiParameter == null) {
+ return null;
+ }
+ return new SmalideaMethodParameter(psiParameter);
+ }
+ });
+ }
+
+ @Override public int 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() {
+ // TODO: implement this
+ return ImmutableSet.of();
+ }
+
+ @Nullable @Override public MethodImplementation getImplementation() {
+ 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();
+ }
+ };
+ }
+ return null;
+ }
+
+ @Nonnull @Override public String getName() {
+ return psiMethod.getName();
+ }
+
+ @Nonnull @Override public List<? extends CharSequence> getParameterTypes() {
+ PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
+
+ return Lists.transform(Arrays.asList(parameters), new Function<PsiParameter, CharSequence>() {
+ @Nullable @Override
+ public CharSequence apply(@Nullable PsiParameter psiParameter) {
+ if (psiParameter == null) {
+ return null;
+ }
+ return psiParameter.getText();
+ }
+ });
+ }
+
+ @Nonnull @Override public String getReturnType() {
+ return psiMethod.getReturnTypeElement().getText();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaMethodParameter.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaMethodParameter.java
new file mode 100644
index 00000000..49d75c83
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaMethodParameter.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2014, 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.PsiParameter;
+import org.jetbrains.annotations.Nullable;
+import org.jf.dexlib2.base.BaseMethodParameter;
+import org.jf.dexlib2.iface.Annotation;
+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 PsiParameter psiParameter;
+
+ public SmalideaMethodParameter(PsiParameter psiParameter) {
+ this.psiParameter = psiParameter;
+ }
+
+ @Nonnull @Override public Set<? extends Annotation> getAnnotations() {
+ // TODO: implement this
+ return ImmutableSet.of();
+ }
+
+ @Nullable @Override public String getName() {
+ return StringUtils.parseQuotedString(psiParameter.getName());
+ }
+
+ @Nonnull @Override public String getType() {
+ return NameUtils.javaToSmaliType(psiParameter.getType());
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaTryBlock.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaTryBlock.java
new file mode 100644
index 00000000..6fbab593
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/SmalideaTryBlock.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015, 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 org.jf.dexlib2.base.BaseTryBlock;
+import org.jf.smalidea.psi.impl.SmaliCatchStatement;
+
+import javax.annotation.Nonnull;
+import java.util.Arrays;
+import java.util.List;
+
+public class SmalideaTryBlock extends BaseTryBlock<SmalideaExceptionHandler> {
+ @Nonnull private final SmaliCatchStatement catchStatement;
+
+ public SmalideaTryBlock(@Nonnull SmaliCatchStatement catchStatement) {
+ this.catchStatement = catchStatement;
+ }
+
+ @Override public int getCodeUnitCount() {
+ int endOffset = catchStatement.getEndLabel().resolve().getOffset() / 2;
+ return endOffset - getStartCodeAddress();
+ }
+
+ @Override public int getStartCodeAddress() {
+ // TODO: how to handle references to non-existent labels?
+ return catchStatement.getStartLabel().resolve().getOffset() / 2;
+ }
+
+ @Nonnull @Override public List<? extends SmalideaExceptionHandler> getExceptionHandlers() {
+ return Arrays.asList(new SmalideaExceptionHandler(catchStatement));
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/analysis/SmalideaClassProvider.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/analysis/SmalideaClassProvider.java
new file mode 100644
index 00000000..9d2a14ac
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/analysis/SmalideaClassProvider.java
@@ -0,0 +1,32 @@
+package org.jf.smalidea.dexlib.analysis;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+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);
+ PsiClass psiClass = NameUtils.resolveSmaliType(project, manager.getDefaultResolveScope(file), type);
+ if (psiClass != null) {
+ return new SmalideaClassDef(psiClass);
+ }
+ return null;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaArrayPayload.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaArrayPayload.java
new file mode 100644
index 00000000..26f2daf7
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaArrayPayload.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import org.jf.dexlib2.iface.instruction.formats.ArrayPayload;
+import org.jf.smalidea.psi.impl.SmaliArrayDataElement;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.List;
+
+public class SmalideaArrayPayload extends SmalideaInstruction implements ArrayPayload {
+ public SmalideaArrayPayload(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+
+ @Override public int getElementWidth() {
+ return (int)psiInstruction.getArrayDataWidth().getIntegralValue();
+ }
+
+ @Nonnull @Override public List<Number> getArrayElements() {
+ return Lists.transform(psiInstruction.getArrayDataElements(), new Function<SmaliArrayDataElement, Number>() {
+ @Nullable @Override public Number apply(SmaliArrayDataElement smaliArrayDataElement) {
+ return smaliArrayDataElement.getValue().getIntegralValue();
+ }
+ });
+ }
+
+ @Override public int getCodeUnits() {
+ return psiInstruction.getInstructionSize()/2;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction.java
new file mode 100644
index 00000000..b5b259a2
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import com.intellij.psi.PsiType;
+import org.jf.dexlib2.Opcode;
+import org.jf.dexlib2.ReferenceType;
+import org.jf.dexlib2.iface.instruction.Instruction;
+import org.jf.dexlib2.iface.reference.Reference;
+import org.jf.dexlib2.immutable.reference.ImmutableFieldReference;
+import org.jf.dexlib2.immutable.reference.ImmutableMethodReference;
+import org.jf.dexlib2.immutable.reference.ImmutableStringReference;
+import org.jf.dexlib2.immutable.reference.ImmutableTypeReference;
+import org.jf.smalidea.psi.impl.*;
+import org.jf.smalidea.util.NameUtils;
+import org.jf.smalidea.util.StringUtils;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.List;
+
+public abstract class SmalideaInstruction implements Instruction {
+ @Nonnull protected final SmaliInstruction psiInstruction;
+
+ protected SmalideaInstruction(@Nonnull SmaliInstruction instruction) {
+ this.psiInstruction = instruction;
+ }
+
+ @Nonnull
+ public static SmalideaInstruction of(SmaliInstruction instruction) {
+ switch (instruction.getOpcode().format) {
+ case Format10t:
+ return new SmalideaInstruction10t(instruction);
+ case Format10x:
+ return new SmalideaInstruction10x(instruction);
+ case Format11n:
+ return new SmalideaInstruction11n(instruction);
+ case Format11x:
+ return new SmalideaInstruction11x(instruction);
+ case Format12x:
+ return new SmalideaInstruction12x(instruction);
+ case Format20t:
+ return new SmalideaInstruction20t(instruction);
+ case Format21c:
+ return new SmalideaInstruction21c(instruction);
+ case Format21ih:
+ return new SmalideaInstruction21ih(instruction);
+ case Format21lh:
+ return new SmalideaInstruction21lh(instruction);
+ case Format21s:
+ return new SmalideaInstruction21s(instruction);
+ case Format21t:
+ return new SmalideaInstruction21t(instruction);
+ case Format22b:
+ return new SmalideaInstruction22b(instruction);
+ case Format22c:
+ return new SmalideaInstruction22c(instruction);
+ case Format22s:
+ return new SmalideaInstruction22s(instruction);
+ case Format22t:
+ return new SmalideaInstruction22t(instruction);
+ case Format22x:
+ return new SmalideaInstruction22x(instruction);
+ case Format23x:
+ return new SmalideaInstruction23x(instruction);
+ case Format30t:
+ return new SmalideaInstruction30t(instruction);
+ case Format31c:
+ return new SmalideaInstruction31c(instruction);
+ case Format31i:
+ return new SmalideaInstruction31i(instruction);
+ case Format31t:
+ return new SmalideaInstruction31t(instruction);
+ case Format32x:
+ return new SmalideaInstruction32x(instruction);
+ case Format35c:
+ return new SmalideaInstruction35c(instruction);
+ case Format3rc:
+ return new SmalideaInstruction3rc(instruction);
+ case Format51l:
+ return new SmalideaInstruction51l(instruction);
+ case PackedSwitchPayload:
+ return new SmalideaPackedSwitchPayload(instruction);
+ case SparseSwitchPayload:
+ return new SmalideaSparseSwitchPayload(instruction);
+ case ArrayPayload:
+ return new SmalideaArrayPayload(instruction);
+ default:
+ throw new RuntimeException("Unexpected instruction type");
+ }
+ }
+
+ @Nonnull public Opcode getOpcode() {
+ return psiInstruction.getOpcode();
+ }
+
+ public int getCodeUnits() {
+ return getOpcode().format.size / 2;
+ }
+
+ public int getCodeOffset() {
+ SmaliLabelReference labelReference = psiInstruction.getTarget();
+ if (labelReference == null) {
+ return -1;
+ }
+
+ SmaliLabel label = labelReference.resolve();
+ if (label == null) {
+ return -1;
+ }
+ return (label.getOffset() - psiInstruction.getOffset())/2;
+ }
+
+ public int getRegisterCount() {
+ return psiInstruction.getRegisterCount();
+ }
+
+ public int getRegisterA() {
+ return psiInstruction.getRegister(0);
+ }
+
+ public int getRegisterB() {
+ return psiInstruction.getRegister(1);
+ }
+
+ public int getRegisterC() {
+ return psiInstruction.getRegister(2);
+ }
+
+ public int getNarrowLiteral() {
+ SmaliLiteral literal = psiInstruction.getLiteral();
+ if (literal == null) {
+ return 0;
+ }
+ return (int)literal.getIntegralValue();
+ }
+
+ public long getWideLiteral() {
+ SmaliLiteral literal = psiInstruction.getLiteral();
+ if (literal == null) {
+ return 0;
+ }
+ return literal.getIntegralValue();
+ }
+
+ @Nonnull public Reference getReference() {
+ switch (getReferenceType()) {
+ case ReferenceType.STRING:
+ return new ImmutableStringReference(StringUtils.parseQuotedString(
+ psiInstruction.getLiteral().getText()));
+ case ReferenceType.TYPE:
+ SmaliTypeElement typeReference = psiInstruction.getTypeReference();
+ assert typeReference != null;
+ return new ImmutableTypeReference(typeReference.getText());
+ case ReferenceType.METHOD:
+ SmaliMethodReference methodReference = psiInstruction.getMethodReference();
+ assert methodReference != null;
+ String containingClass = methodReference.getContainingType().getText();
+ List<String> paramTypes =
+ Lists.transform(methodReference.getParameterTypes(), new Function<PsiType, String>() {
+ @Nullable @Override public String apply(@Nullable PsiType psiType) {
+ if (psiType == null) {
+ return null;
+ }
+ return NameUtils.javaToSmaliType(psiType);
+ }
+ });
+
+ return new ImmutableMethodReference(containingClass,
+ methodReference.getName(),
+ paramTypes,
+ methodReference.getReturnType().getText());
+ case ReferenceType.FIELD:
+ SmaliFieldReference fieldReference = psiInstruction.getFieldReference();
+ assert fieldReference != null;
+ containingClass = fieldReference.getContainingType().getText();
+ return new ImmutableFieldReference(containingClass,
+ fieldReference.getName(),
+ fieldReference.getFieldType().getText());
+ }
+ assert false;
+ return null;
+ }
+
+ public int getReferenceType() {
+ return psiInstruction.getOpcode().referenceType;
+ }
+
+} \ No newline at end of file
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction10t.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction10t.java
new file mode 100644
index 00000000..80a4ba66
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction10t.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction10t;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction10t extends SmalideaInstruction implements Instruction10t {
+ public SmalideaInstruction10t(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction10x.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction10x.java
new file mode 100644
index 00000000..04804514
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction10x.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction10x;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction10x extends SmalideaInstruction implements Instruction10x {
+ public SmalideaInstruction10x(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction11n.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction11n.java
new file mode 100644
index 00000000..1b185dd8
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction11n.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction11n;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction11n extends SmalideaInstruction implements Instruction11n {
+ public SmalideaInstruction11n(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction11x.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction11x.java
new file mode 100644
index 00000000..7e8fbf4d
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction11x.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction11x;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction11x extends SmalideaInstruction implements Instruction11x {
+ public SmalideaInstruction11x(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction12x.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction12x.java
new file mode 100644
index 00000000..c6cba0a7
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction12x.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction12x;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction12x extends SmalideaInstruction implements Instruction12x {
+ public SmalideaInstruction12x(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction20t.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction20t.java
new file mode 100644
index 00000000..1c0a9216
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction20t.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction20t;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction20t extends SmalideaInstruction implements Instruction20t {
+ public SmalideaInstruction20t(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21c.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21c.java
new file mode 100644
index 00000000..f2ac6f1a
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21c.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction21c extends SmalideaInstruction implements Instruction21c {
+ public SmalideaInstruction21c(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21ih.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21ih.java
new file mode 100644
index 00000000..ce5f598f
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21ih.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction21ih;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction21ih extends SmalideaInstruction implements Instruction21ih {
+ public SmalideaInstruction21ih(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+
+ @Override public short getHatLiteral() {
+ return (short)(getNarrowLiteral() >>> 16);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21lh.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21lh.java
new file mode 100644
index 00000000..3ef08505
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21lh.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction21lh;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction21lh extends SmalideaInstruction implements Instruction21lh {
+ public SmalideaInstruction21lh(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+
+ @Override public short getHatLiteral() {
+ return (short)(getWideLiteral() >>> 48);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21s.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21s.java
new file mode 100644
index 00000000..5ae75060
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21s.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction21s;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction21s extends SmalideaInstruction implements Instruction21s {
+ public SmalideaInstruction21s(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21t.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21t.java
new file mode 100644
index 00000000..11e17564
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction21t.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction21t;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction21t extends SmalideaInstruction implements Instruction21t {
+ public SmalideaInstruction21t(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22b.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22b.java
new file mode 100644
index 00000000..f1360467
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22b.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction22b;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction22b extends SmalideaInstruction implements Instruction22b {
+ public SmalideaInstruction22b(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22c.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22c.java
new file mode 100644
index 00000000..4d7dacbe
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22c.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction22c;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction22c extends SmalideaInstruction implements Instruction22c {
+ public SmalideaInstruction22c(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22s.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22s.java
new file mode 100644
index 00000000..81897688
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22s.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction22s;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction22s extends SmalideaInstruction implements Instruction22s {
+ public SmalideaInstruction22s(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22t.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22t.java
new file mode 100644
index 00000000..8f4811d9
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22t.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction22t;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction22t extends SmalideaInstruction implements Instruction22t {
+ public SmalideaInstruction22t(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22x.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22x.java
new file mode 100644
index 00000000..5cc8b004
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction22x.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction22x;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction22x extends SmalideaInstruction implements Instruction22x {
+ public SmalideaInstruction22x(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction23x.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction23x.java
new file mode 100644
index 00000000..3cc60d89
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction23x.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction23x;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction23x extends SmalideaInstruction implements Instruction23x {
+ public SmalideaInstruction23x(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction30t.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction30t.java
new file mode 100644
index 00000000..324fc773
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction30t.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction30t;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction30t extends SmalideaInstruction implements Instruction30t {
+ public SmalideaInstruction30t(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction31c.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction31c.java
new file mode 100644
index 00000000..ffea2175
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction31c.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction31c;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction31c extends SmalideaInstruction implements Instruction31c {
+ public SmalideaInstruction31c(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction31i.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction31i.java
new file mode 100644
index 00000000..0fef6674
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction31i.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction31i;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction31i extends SmalideaInstruction implements Instruction31i {
+ public SmalideaInstruction31i(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction31t.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction31t.java
new file mode 100644
index 00000000..142fd446
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction31t.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction31t;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction31t extends SmalideaInstruction implements Instruction31t {
+ public SmalideaInstruction31t(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction32x.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction32x.java
new file mode 100644
index 00000000..1ac27deb
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction32x.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction32x;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction32x extends SmalideaInstruction implements Instruction32x {
+ public SmalideaInstruction32x(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction35c.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction35c.java
new file mode 100644
index 00000000..a3ddcce0
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction35c.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction35c;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction35c extends SmalideaInstruction implements Instruction35c {
+ public SmalideaInstruction35c(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+
+ @Override public int getRegisterC() {
+ return psiInstruction.getRegister(0);
+ }
+
+ @Override public int getRegisterD() {
+ return psiInstruction.getRegister(1);
+ }
+
+ @Override public int getRegisterE() {
+ return psiInstruction.getRegister(2);
+ }
+
+ @Override public int getRegisterF() {
+ return psiInstruction.getRegister(3);
+ }
+
+ @Override public int getRegisterG() {
+ return psiInstruction.getRegister(4);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction3rc.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction3rc.java
new file mode 100644
index 00000000..509e6b75
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction3rc.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction3rc;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction3rc extends SmalideaInstruction implements Instruction3rc {
+ public SmalideaInstruction3rc(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+
+ @Override public int getStartRegister() {
+ return psiInstruction.getRegister(0);
+ }
+
+ @Override public int getRegisterCount() {
+ return psiInstruction.getRegister(1) - getStartRegister() + 1;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction51l.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction51l.java
new file mode 100644
index 00000000..3b58628b
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaInstruction51l.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import org.jf.dexlib2.iface.instruction.formats.Instruction51l;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+
+import javax.annotation.Nonnull;
+
+public class SmalideaInstruction51l extends SmalideaInstruction implements Instruction51l {
+ public SmalideaInstruction51l(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaPackedSwitchPayload.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaPackedSwitchPayload.java
new file mode 100644
index 00000000..9d2a0fc3
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaPackedSwitchPayload.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import com.google.common.collect.Lists;
+import org.jf.dexlib2.Opcode;
+import org.jf.dexlib2.iface.instruction.SwitchElement;
+import org.jf.dexlib2.iface.instruction.formats.PackedSwitchPayload;
+import org.jf.smalidea.psi.impl.*;
+import org.jf.smalidea.util.InstructionUtils;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+
+public class SmalideaPackedSwitchPayload extends SmalideaInstruction implements PackedSwitchPayload {
+ public SmalideaPackedSwitchPayload(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+
+ @Nonnull @Override public List<? extends SwitchElement> getSwitchElements() {
+ final SmaliLiteral startKey = psiInstruction.getPackedSwitchStartKey();
+ assert startKey != null;
+ List<SmaliPackedSwitchElement> elements = psiInstruction.getPackedSwitchElements();
+
+ SmaliMethod smaliMethod = psiInstruction.getParentMethod();
+ SmaliInstruction packedSwitchInstruction = InstructionUtils.findFirstInstructionWithTarget(
+ smaliMethod, Opcode.PACKED_SWITCH, psiInstruction.getOffset());
+ final int baseOffset;
+
+ if (packedSwitchInstruction == null) {
+ baseOffset = 0;
+ } else {
+ baseOffset = packedSwitchInstruction.getOffset();
+ }
+
+ List<SwitchElement> newElements = Lists.newArrayList();
+ // TODO: check for integer wraparound (how does art/dalvik handle that?)
+ int initialKey = (int)startKey.getIntegralValue();
+ for (int i=0; i<elements.size(); i++) {
+ final SmaliPackedSwitchElement element = elements.get(i);
+
+ final int key = initialKey + i;
+
+ newElements.add(new SwitchElement() {
+ @Override public int getKey() {
+ return key;
+ }
+
+ @Override public int getOffset() {
+ SmaliLabelReference labelReference = element.getTarget();
+ if (labelReference == null) {
+ return 0;
+ }
+
+ SmaliLabel label = labelReference.resolve();
+ if (label == null) {
+ return 0;
+ }
+
+ return label.getOffset() - baseOffset;
+ }
+ });
+ }
+
+ return newElements;
+ }
+
+ @Override public int getCodeUnits() {
+ return psiInstruction.getInstructionSize()/2;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaSparseSwitchPayload.java b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaSparseSwitchPayload.java
new file mode 100644
index 00000000..15eaea2d
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/dexlib/instruction/SmalideaSparseSwitchPayload.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2014, 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.instruction;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import org.jf.dexlib2.Opcode;
+import org.jf.dexlib2.iface.instruction.SwitchElement;
+import org.jf.dexlib2.iface.instruction.formats.SparseSwitchPayload;
+import org.jf.smalidea.psi.impl.*;
+import org.jf.smalidea.util.InstructionUtils;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+
+public class SmalideaSparseSwitchPayload extends SmalideaInstruction implements SparseSwitchPayload {
+ public SmalideaSparseSwitchPayload(@Nonnull SmaliInstruction instruction) {
+ super(instruction);
+ }
+
+ @Nonnull @Override public List<? extends SwitchElement> getSwitchElements() {
+ List<SmaliSparseSwitchElement> elements = psiInstruction.getSparseSwitchElements();
+
+ SmaliMethod smaliMethod = psiInstruction.getParentMethod();
+ SmaliInstruction sparseSwitchInstruction = InstructionUtils.findFirstInstructionWithTarget(
+ smaliMethod, Opcode.SPARSE_SWITCH, psiInstruction.getOffset());
+ final int baseOffset;
+
+ if (sparseSwitchInstruction == null) {
+ baseOffset = 0;
+ } else {
+ baseOffset = sparseSwitchInstruction.getOffset();
+ }
+
+ return Lists.transform(elements, new Function<SmaliSparseSwitchElement, SwitchElement>() {
+ @Override public SwitchElement apply(final SmaliSparseSwitchElement element) {
+ return new SwitchElement() {
+ @Override public int getKey() {
+ return (int)element.getKey().getIntegralValue();
+ }
+
+ @Override public int getOffset() {
+ SmaliLabelReference labelReference = element.getTarget();
+ if (labelReference == null) {
+ return 0;
+ }
+
+ SmaliLabel label = labelReference.resolve();
+ if (label == null) {
+ return 0;
+ }
+
+ return label.getOffset() - baseOffset;
+ }
+ };
+ }
+ });
+ }
+
+ @Override public int getCodeUnits() {
+ return psiInstruction.getInstructionSize()/2;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/errorReporting/ErrorReporter.java b/smalidea/src/main/java/org/jf/smalidea/errorReporting/ErrorReporter.java
new file mode 100644
index 00000000..92aef72b
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/errorReporting/ErrorReporter.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jf.smalidea.errorReporting;
+
+import com.intellij.diagnostic.IdeErrorsDialog;
+import com.intellij.diagnostic.LogMessageEx;
+import com.intellij.diagnostic.ReportMessages;
+import com.intellij.errorreport.bean.ErrorBean;
+import com.intellij.ide.DataManager;
+import com.intellij.ide.plugins.IdeaPluginDescriptor;
+import com.intellij.ide.plugins.PluginManager;
+import com.intellij.idea.IdeaLogger;
+import com.intellij.notification.NotificationListener;
+import com.intellij.notification.NotificationType;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.diagnostic.ErrorReportSubmitter;
+import com.intellij.openapi.diagnostic.IdeaLoggingEvent;
+import com.intellij.openapi.diagnostic.SubmittedReportInfo;
+import com.intellij.openapi.extensions.PluginId;
+import com.intellij.openapi.progress.EmptyProgressIndicator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.util.Consumer;
+
+import java.awt.*;
+import java.util.Map;
+
+/**
+ * Sends crash reports to Github.
+ *
+ * Based on the go-lang plugin's error reporter
+ * (https://github.com/dlsniper/google-go-lang-idea-plugin/commit/c451006cc9fc926ca347189951baa94f4032c5c4)
+ */
+public class ErrorReporter extends ErrorReportSubmitter {
+
+ @Override
+ public String getReportActionText() {
+ return "Report as issue on smali's github repo";
+ }
+
+ @Override
+ public boolean submit(IdeaLoggingEvent[] events, String additionalInfo, Component parentComponent,
+ final Consumer<SubmittedReportInfo> consumer) {
+ IdeaLoggingEvent event = events[0];
+ ErrorBean bean = new ErrorBean(event.getThrowable(), IdeaLogger.ourLastActionId);
+
+ final DataContext dataContext = DataManager.getInstance().getDataContext(parentComponent);
+
+ bean.setDescription(additionalInfo);
+ bean.setMessage(event.getMessage());
+
+ Throwable throwable = event.getThrowable();
+ if (throwable != null) {
+ final PluginId pluginId = IdeErrorsDialog.findPluginId(throwable);
+ if (pluginId != null) {
+ final IdeaPluginDescriptor ideaPluginDescriptor = PluginManager.getPlugin(pluginId);
+ if (ideaPluginDescriptor != null && !ideaPluginDescriptor.isBundled()) {
+ bean.setPluginName(ideaPluginDescriptor.getName());
+ bean.setPluginVersion(ideaPluginDescriptor.getVersion());
+ }
+ }
+ }
+
+ Object data = event.getData();
+
+ if (data instanceof LogMessageEx) {
+ bean.setAttachments(((LogMessageEx)data).getAttachments());
+ }
+
+ Map<String, String> reportValues = ITNProxy.createParameters(bean);
+
+ final Project project = CommonDataKeys.PROJECT.getData(dataContext);
+
+ Consumer<String> successCallback = new Consumer<String>() {
+ @Override
+ public void consume(String token) {
+ final SubmittedReportInfo reportInfo = new SubmittedReportInfo(
+ null, "Issue " + token, SubmittedReportInfo.SubmissionStatus.NEW_ISSUE);
+ consumer.consume(reportInfo);
+
+ ReportMessages.GROUP.createNotification(ReportMessages.ERROR_REPORT,
+ "Submitted",
+ NotificationType.INFORMATION,
+ null).setImportant(false).notify(project);
+ }
+ };
+
+ Consumer<Exception> errorCallback = new Consumer<Exception>() {
+ @Override
+ public void consume(Exception e) {
+ String message = String.format("<html>There was an error while creating a GitHub issue: %s<br>" +
+ "Please consider manually creating an issue on the " +
+ "<a href=\"https://github.com/JesusFreke/smali/issues\">Smali Issue Tracker</a></html>",
+ e.getMessage());
+ ReportMessages.GROUP.createNotification(ReportMessages.ERROR_REPORT,
+ message,
+ NotificationType.ERROR,
+ NotificationListener.URL_OPENING_LISTENER).setImportant(false).notify(project);
+ }
+ };
+
+ GithubFeedbackTask task = new GithubFeedbackTask(project, "Submitting error report", true, reportValues,
+ successCallback, errorCallback);
+
+ if (project == null) {
+ task.run(new EmptyProgressIndicator());
+ } else {
+ ProgressManager.getInstance().run(task);
+ }
+ return true;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/errorReporting/GithubFeedbackTask.java b/smalidea/src/main/java/org/jf/smalidea/errorReporting/GithubFeedbackTask.java
new file mode 100644
index 00000000..ab54dc6b
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/errorReporting/GithubFeedbackTask.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jf.smalidea.errorReporting;
+
+import com.google.common.io.CharStreams;
+import com.google.gson.Gson;
+import com.intellij.ide.plugins.IdeaPluginDescriptorImpl;
+import com.intellij.ide.plugins.PluginManager;
+import com.intellij.openapi.extensions.PluginId;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.project.Project;
+import com.intellij.util.Consumer;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class GithubFeedbackTask extends Task.Backgroundable {
+ private final Consumer<String> myCallback;
+ private final Consumer<Exception> myErrorCallback;
+ private final Map<String, String> myParams;
+
+ public GithubFeedbackTask(@Nullable Project project,
+ @NotNull String title,
+ boolean canBeCancelled,
+ Map<String, String> params,
+ final Consumer<String> callback,
+ final Consumer<Exception> errorCallback) {
+ super(project, title, canBeCancelled);
+
+ myParams = params;
+ myCallback = callback;
+ myErrorCallback = errorCallback;
+ }
+
+ @Override
+ public void run(@NotNull ProgressIndicator indicator) {
+ indicator.setIndeterminate(true);
+ try {
+ String token = sendFeedback(myParams);
+ myCallback.consume(token);
+ }
+ catch (Exception e) {
+ myErrorCallback.consume(e);
+ }
+ }
+
+ private static String getToken() {
+ InputStream stream = GithubFeedbackTask.class.getClassLoader().getResourceAsStream("token");
+ if (stream == null) {
+ return null;
+ }
+ try {
+ return CharStreams.toString(new InputStreamReader(stream, "UTF-8"));
+ } catch (IOException ex) {
+ return null;
+ }
+ }
+
+ public static String sendFeedback(Map<String, String> environmentDetails) throws IOException {
+ String url = "https://api.github.com/repos/JesusFreke/smalidea-issues/issues";
+ String userAgent = "smalidea plugin";
+
+ IdeaPluginDescriptorImpl pluginDescriptor =
+ (IdeaPluginDescriptorImpl) PluginManager.getPlugin(PluginId.getId("org.jf.smalidea"));
+
+ if (pluginDescriptor != null) {
+ String name = pluginDescriptor.getName();
+ String version = pluginDescriptor.getVersion();
+ userAgent = name + " (" + version + ")";
+ }
+
+ HttpURLConnection httpURLConnection = connect(url);
+ httpURLConnection.setDoOutput(true);
+ httpURLConnection.setRequestMethod("POST");
+ httpURLConnection.setRequestProperty("User-Agent", userAgent);
+ httpURLConnection.setRequestProperty("Content-Type", "application/json");
+
+ String token = getToken();
+ if (token != null) {
+ httpURLConnection.setRequestProperty("Authorization", "token " + token);
+ }
+ OutputStream outputStream = httpURLConnection.getOutputStream();
+
+ try {
+ outputStream.write(convertToGithubIssueFormat(environmentDetails));
+ } finally {
+ outputStream.close();
+ }
+
+ int responseCode = httpURLConnection.getResponseCode();
+ if (responseCode != 201) {
+ throw new RuntimeException("Expected HTTP_CREATED (201), obtained " + responseCode);
+ }
+
+ return Long.toString(System.currentTimeMillis());
+ }
+
+ private static byte[] convertToGithubIssueFormat(Map<String, String> environmentDetails) {
+ LinkedHashMap<String, String> result = new LinkedHashMap<String, String>(5);
+ result.put("title", "[auto-generated] Crash in plugin");
+ result.put("body", generateGithubIssueBody(environmentDetails));
+
+ return ((new Gson()).toJson(result)).getBytes(Charset.forName("UTF-8"));
+ }
+
+ private static String generateGithubIssueBody(Map<String, String> body) {
+ String errorDescription = body.get("error.description");
+ if (errorDescription == null) {
+ errorDescription = "";
+ }
+ body.remove("error.description");
+
+ String errorMessage = body.get("error.message");
+ if (errorMessage == null || errorMessage.isEmpty()) {
+ errorMessage = "invalid error";
+ }
+ body.remove("error.message");
+
+ String stackTrace = body.get("error.stacktrace");
+ if (stackTrace == null || stackTrace.isEmpty()) {
+ stackTrace = "invalid stacktrace";
+ }
+ body.remove("error.stacktrace");
+
+ String result = "";
+
+ if (!errorDescription.isEmpty()) {
+ result += errorDescription + "\n\n";
+ }
+
+ for (Map.Entry<String, String> entry : body.entrySet()) {
+ result += entry.getKey() + ": " + entry.getValue() + "\n";
+ }
+
+ result += "\n```\n" + stackTrace + "\n```\n";
+
+ result += "\n```\n" + errorMessage + "\n```";
+
+ return result;
+ }
+
+ private static HttpURLConnection connect(String url) throws IOException {
+ HttpURLConnection connection = (HttpURLConnection) ((new URL(url)).openConnection());
+ connection.setConnectTimeout(5000);
+ connection.setReadTimeout(5000);
+ return connection;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/errorReporting/ITNProxy.java b/smalidea/src/main/java/org/jf/smalidea/errorReporting/ITNProxy.java
new file mode 100644
index 00000000..5bf93e32
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/errorReporting/ITNProxy.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jf.smalidea.errorReporting;
+
+import com.intellij.errorreport.bean.ErrorBean;
+import com.intellij.idea.IdeaLogger;
+import com.intellij.openapi.application.Application;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ApplicationNamesInfo;
+import com.intellij.openapi.application.ex.ApplicationInfoEx;
+import com.intellij.openapi.diagnostic.Attachment;
+import com.intellij.openapi.updateSettings.impl.UpdateSettings;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.SystemProperties;
+import com.intellij.util.containers.ContainerUtil;
+
+import java.util.Calendar;
+import java.util.Map;
+
+/**
+ * @author stathik
+ * @since Aug 4, 2003
+ */
+public class ITNProxy {
+
+ public static Map<String, String> createParameters(ErrorBean error) {
+ Map<String, String> params = ContainerUtil.newLinkedHashMap(40);
+
+ params.put("protocol.version", "1");
+
+ params.put("os.name", SystemProperties.getOsName());
+ params.put("java.version", SystemProperties.getJavaVersion());
+ params.put("java.vm.vendor", SystemProperties.getJavaVmVendor());
+
+ ApplicationInfoEx appInfo = ApplicationInfoEx.getInstanceEx();
+ ApplicationNamesInfo namesInfo = ApplicationNamesInfo.getInstance();
+ Application application = ApplicationManager.getApplication();
+ params.put("app.name", namesInfo.getProductName());
+ params.put("app.name.full", namesInfo.getFullProductName());
+ params.put("app.name.version", appInfo.getVersionName());
+ params.put("app.eap", Boolean.toString(appInfo.isEAP()));
+ params.put("app.internal", Boolean.toString(application.isInternal()));
+ params.put("app.build", appInfo.getBuild().asString());
+ params.put("app.version.major", appInfo.getMajorVersion());
+ params.put("app.version.minor", appInfo.getMinorVersion());
+ params.put("app.build.date", format(appInfo.getBuildDate()));
+ params.put("app.build.date.release", format(appInfo.getMajorReleaseBuildDate()));
+ params.put("app.compilation.timestamp", IdeaLogger.getOurCompilationTimestamp());
+
+ UpdateSettings updateSettings = UpdateSettings.getInstance();
+ params.put("update.channel.status", updateSettings.getSelectedChannelStatus().getCode());
+ params.put("update.ignored.builds", StringUtil.join(updateSettings.getIgnoredBuildNumbers(), ","));
+
+ params.put("plugin.name", error.getPluginName());
+ params.put("plugin.version", error.getPluginVersion());
+
+ params.put("last.action", error.getLastAction());
+ params.put("previous.exception", error.getPreviousException() == null ? null : Integer.toString(error.getPreviousException()));
+
+ params.put("error.message", error.getMessage());
+ params.put("error.stacktrace", error.getStackTrace());
+ params.put("error.description", error.getDescription());
+
+ params.put("assignee.id", error.getAssigneeId() == null ? null : Integer.toString(error.getAssigneeId()));
+
+ for (Attachment attachment : error.getAttachments()) {
+ params.put("attachment.name", attachment.getName());
+ params.put("attachment.value", attachment.getEncodedBytes());
+ }
+
+ return params;
+ }
+
+ private static String format(Calendar calendar) {
+ return calendar == null ? null : Long.toString(calendar.getTime().getTime());
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliClassReferenceSearcher.java b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliClassReferenceSearcher.java
new file mode 100644
index 00000000..63e4d6fe
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliClassReferenceSearcher.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2015, 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.findUsages;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.QueryExecutorBase;
+import com.intellij.openapi.progress.EmptyProgressIndicator;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.impl.search.LowLevelSearchUtil;
+import com.intellij.psi.search.*;
+import com.intellij.psi.search.searches.ReferencesSearch;
+import com.intellij.psi.search.searches.ReferencesSearch.SearchParameters;
+import com.intellij.util.Processor;
+import com.intellij.util.text.StringSearcher;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.util.NameUtils;
+
+public class SmaliClassReferenceSearcher extends QueryExecutorBase<PsiReference, ReferencesSearch.SearchParameters> {
+ @Override public void processQuery(final SearchParameters queryParameters, final Processor<PsiReference> consumer) {
+ final PsiElement element = queryParameters.getElementToSearch();
+ if (!(element instanceof PsiClass)) {
+ return;
+ }
+
+ String smaliType = ApplicationManager.getApplication().runReadAction(
+ new Computable<String>() {
+ @Override public String compute() {
+ String qualifiedName = ((PsiClass)element).getQualifiedName();
+ if (qualifiedName != null) {
+ return NameUtils.javaToSmaliType((PsiClass)element);
+ }
+ return null;
+ }
+ });
+ if (smaliType == null) {
+ return;
+ }
+
+ final StringSearcher stringSearcher = new StringSearcher(smaliType, true, true, false, false);
+
+ final SingleTargetRequestResultProcessor processor = new SingleTargetRequestResultProcessor(element);
+
+ SearchScope querySearchScope = ApplicationManager.getApplication().runReadAction(
+ new Computable<SearchScope>() {
+ @Override public SearchScope compute() {
+ return queryParameters.getEffectiveSearchScope();
+ }
+ });
+
+ if (querySearchScope instanceof LocalSearchScope) {
+ for (final PsiElement scopeElement : ((LocalSearchScope)querySearchScope).getScope()) {
+ ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ LowLevelSearchUtil.processElementsContainingWordInElement(
+ new TextOccurenceProcessor() {
+ @Override public boolean execute(
+ @NotNull PsiElement element, int offsetInElement) {
+ return processor.processTextOccurrence(element, offsetInElement, consumer);
+ }
+ },
+ scopeElement, stringSearcher, true, new EmptyProgressIndicator());
+ }
+ });
+ }
+ } else if (querySearchScope instanceof GlobalSearchScope) {
+ PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(element.getProject());
+ // TODO: limit search scope to only smali files. See, e.g. AnnotatedPackagesSearcher.PackageInfoFilesOnly
+ helper.processAllFilesWithWord(smaliType, (GlobalSearchScope)querySearchScope,
+ new Processor<PsiFile>() {
+ @Override
+ public boolean process(PsiFile file) {
+ LowLevelSearchUtil.processElementsContainingWordInElement(
+ new TextOccurenceProcessor() {
+ @Override public boolean execute(
+ @NotNull PsiElement element, int offsetInElement) {
+ return processor.processTextOccurrence(element, offsetInElement, consumer);
+ }
+ },
+ file, stringSearcher, true, new EmptyProgressIndicator());
+ return true;
+ }
+ }, true);
+ } else {
+ assert false;
+ return;
+ }
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliFindUsagesProvider.java b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliFindUsagesProvider.java
new file mode 100644
index 00000000..335bce27
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliFindUsagesProvider.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2015, 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.findUsages;
+
+import com.intellij.lang.cacheBuilder.WordsScanner;
+import com.intellij.lang.java.JavaFindUsagesProvider;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class SmaliFindUsagesProvider extends JavaFindUsagesProvider {
+ @Override public boolean canFindUsagesFor(@NotNull PsiElement element) {
+ return element instanceof PsiClass;
+ }
+
+ @Nullable @Override public WordsScanner getWordsScanner() {
+ return new SmaliWordScanner();
+ }
+
+
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliUsageTargetProvider.java b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliUsageTargetProvider.java
new file mode 100644
index 00000000..e87782b6
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliUsageTargetProvider.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015, 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.findUsages;
+
+import com.intellij.codeInsight.TargetElementUtilBase;
+import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.usages.UsageTarget;
+import com.intellij.usages.UsageTargetProvider;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.SmaliTokens;
+import org.jf.smalidea.psi.impl.SmaliMemberName;
+
+/**
+ * A usage target provider for smali member names consisting of primitive types.
+ *
+ * For member names like IIII, the default logic to find the usage target doesn't work, due to the member
+ * name being split up into multiple leaf tokens.
+ */
+public class SmaliUsageTargetProvider implements UsageTargetProvider {
+ @Nullable @Override public UsageTarget[] getTargets(Editor editor, PsiFile file) {
+ PsiElement element = file.findElementAt(
+ TargetElementUtilBase.adjustOffset(file, editor.getDocument(), editor.getCaretModel().getOffset()));
+ if (element == null) {
+ return null;
+ }
+ return getTargets(element);
+ }
+
+ @Nullable @Override public UsageTarget[] getTargets(PsiElement element) {
+ ASTNode node = element.getNode();
+ if (node == null) {
+ return null;
+ }
+
+ if (node.getElementType() == SmaliTokens.PARAM_LIST_OR_ID_PRIMITIVE_TYPE) {
+ PsiElement parent = element.getParent();
+ if (parent instanceof SmaliMemberName) {
+ return new UsageTarget[] { new PsiElement2UsageTargetAdapter(parent.getParent()) };
+ }
+ }
+ return null;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliUsageTypeProvider.java b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliUsageTypeProvider.java
new file mode 100644
index 00000000..ad869421
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliUsageTypeProvider.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2015, 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.findUsages;
+
+import com.intellij.psi.*;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.usages.impl.rules.UsageType;
+import com.intellij.usages.impl.rules.UsageTypeProvider;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.dexlib2.Opcode;
+import org.jf.smalidea.SmaliTokens;
+import org.jf.smalidea.psi.impl.*;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+public class SmaliUsageTypeProvider implements UsageTypeProvider {
+
+ static final UsageType CLASS_DECLARATION = new UsageType("Class declaration");
+ static final UsageType VERIFICATION_ERROR = new UsageType("Usage in verification error");
+ static final UsageType FIELD_TYPE_REFERENCE = new UsageType("Usage as field type in a field reference");
+ static final UsageType FIELD_DECLARING_TYPE_REFERENCE = new UsageType("Usage as a declaring type in a field reference");
+ static final UsageType METHOD_RETURN_TYPE_REFERENCE = new UsageType("Usage as return type in a method reference");
+ static final UsageType METHOD_PARAM_REFERENCE = new UsageType("Usage as parameter in a method reference");
+ static final UsageType METHOD_DECLARING_TYPE_REFERENCE = new UsageType("Usage as a declaring type in a method reference");
+ static final UsageType LITERAL = new UsageType("Usage as a literal");
+
+ @Nullable @Override public UsageType getUsageType(PsiElement element) {
+ if (element instanceof PsiReference) {
+ PsiElement referenced = ((PsiReference) element).resolve();
+ if (referenced != null) {
+ if (referenced instanceof PsiClass) {
+ return findClassUsageType(element);
+ } else if (referenced instanceof PsiField) {
+ return findFieldUsageType(element);
+ } else if (referenced instanceof PsiMethod) {
+ return findMethodUsageType(element);
+ }
+ }
+ }
+ return UsageType.UNCLASSIFIED;
+ }
+
+ 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;
+
+ while (element != null) {
+ if (element instanceof SmaliFieldReference) {
+ PsiElement prev = originalElement.getPrevSibling();
+ while (prev != null) {
+ // if the element is to the right of a colon, then it is the field type, otherwise it is
+ // the declaring class
+ if (prev.getNode().getElementType() == SmaliTokens.COLON) {
+ return FIELD_TYPE_REFERENCE;
+ }
+ prev = prev.getPrevSibling();
+ }
+ return FIELD_DECLARING_TYPE_REFERENCE;
+ } else if (element instanceof SmaliMethodReferenceParamList) {
+ return METHOD_PARAM_REFERENCE;
+ } else if (element instanceof SmaliMethodReference) {
+ PsiElement prev = originalElement.getPrevSibling();
+ while (prev != null) {
+ IElementType elementType = prev.getNode().getElementType();
+ // if the element is to the right of a close paren, then it is the return type,
+ // otherwise it is the declaring class. Any parameter type will be taken care of by the previous
+ // "if" for SmaliMethodReferenceParamList
+ if (elementType == SmaliTokens.CLOSE_PAREN) {
+ return METHOD_RETURN_TYPE_REFERENCE;
+ }
+ prev = prev.getPrevSibling();
+ }
+ return METHOD_DECLARING_TYPE_REFERENCE;
+ } else if (element instanceof SmaliInstruction) {
+ Opcode opcode = ((SmaliInstruction) element).getOpcode();
+ if (opcode == Opcode.INSTANCE_OF) {
+ return UsageType.CLASS_INSTANCE_OF;
+ } else if (opcode == Opcode.CHECK_CAST) {
+ return UsageType.CLASS_CAST_TO;
+ } else if (newArrayInstructions.contains(opcode)) {
+ return UsageType.CLASS_NEW_ARRAY;
+ } else if (opcode == Opcode.NEW_INSTANCE) {
+ return UsageType.CLASS_NEW_OPERATOR;
+ } else if (opcode == Opcode.CONST_CLASS) {
+ return UsageType.CLASS_CLASS_OBJECT_ACCESS;
+ } else if (opcode == Opcode.THROW_VERIFICATION_ERROR) {
+ return VERIFICATION_ERROR;
+ }
+ } else if (element instanceof SmaliSuperStatement || element instanceof SmaliImplementsStatement) {
+ return UsageType.CLASS_EXTENDS_IMPLEMENTS_LIST;
+ } else if (element instanceof SmaliClassStatement) {
+ return CLASS_DECLARATION;
+ } else if (element instanceof SmaliMethodParamList) {
+ return UsageType.CLASS_METHOD_PARAMETER_DECLARATION;
+ } else if (element instanceof SmaliMethodPrototype) {
+ return UsageType.CLASS_METHOD_RETURN_TYPE;
+ } else if (element instanceof SmaliField) {
+ return UsageType.CLASS_FIELD_DECLARATION;
+ } else if (element instanceof SmaliCatchStatement) {
+ return UsageType.CLASS_CATCH_CLAUSE_PARAMETER_DECLARATION;
+ } else if (element instanceof SmaliLocalDebugStatement) {
+ return UsageType.CLASS_LOCAL_VAR_DECLARATION;
+ } else if (element instanceof SmaliAnnotation) {
+ return UsageType.ANNOTATION;
+ } else if (element instanceof SmaliLiteral) {
+ return LITERAL;
+ }
+ element = element.getParent();
+ }
+ 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;
+ }
+
+ @Nullable
+ private UsageType findMethodUsageType(@NotNull PsiElement element) {
+ PsiElement originalElement = element;
+
+ while (element != null) {
+ element = element.getParent();
+
+ if (element instanceof SmaliInstruction) {
+ Opcode opcode = ((SmaliInstruction) element).getOpcode();
+ if (opcode == Opcode.THROW_VERIFICATION_ERROR) {
+ return VERIFICATION_ERROR;
+ }
+ } if (element instanceof SmaliLiteral) {
+ return LITERAL;
+ }
+ }
+ return UsageType.UNCLASSIFIED;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliWordScanner.java b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliWordScanner.java
new file mode 100644
index 00000000..56bbdafb
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliWordScanner.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2015, 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.findUsages;
+
+import com.intellij.lang.cacheBuilder.WordOccurrence;
+import com.intellij.lang.cacheBuilder.WordOccurrence.Kind;
+import com.intellij.lang.cacheBuilder.WordsScanner;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.TokenSet;
+import com.intellij.util.Processor;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.SmaliLexer;
+import org.jf.smalidea.SmaliTokens;
+
+public class SmaliWordScanner implements WordsScanner {
+
+ private static final TokenSet MEMBER_NAME_TOKENS = TokenSet.create(
+ SmaliTokens.MEMBER_NAME,
+ SmaliTokens.SIMPLE_NAME,
+ SmaliTokens.ACCESS_SPEC,
+ SmaliTokens.VERIFICATION_ERROR_TYPE,
+ SmaliTokens.POSITIVE_INTEGER_LITERAL,
+ SmaliTokens.NEGATIVE_INTEGER_LITERAL,
+ SmaliTokens.FLOAT_LITERAL_OR_ID,
+ SmaliTokens.DOUBLE_LITERAL_OR_ID,
+ SmaliTokens.BOOL_LITERAL,
+ SmaliTokens.NULL_LITERAL,
+ SmaliTokens.REGISTER,
+ SmaliTokens.PRIMITIVE_TYPE,
+ SmaliTokens.VOID_TYPE,
+ SmaliTokens.ANNOTATION_VISIBILITY,
+ SmaliTokens.INSTRUCTION_FORMAT10t,
+ SmaliTokens.INSTRUCTION_FORMAT10x,
+ SmaliTokens.INSTRUCTION_FORMAT10x_ODEX,
+ SmaliTokens.INSTRUCTION_FORMAT11x,
+ SmaliTokens.INSTRUCTION_FORMAT12x_OR_ID,
+ SmaliTokens.INSTRUCTION_FORMAT21c_FIELD,
+ SmaliTokens.INSTRUCTION_FORMAT21c_FIELD_ODEX,
+ SmaliTokens.INSTRUCTION_FORMAT21c_STRING,
+ SmaliTokens.INSTRUCTION_FORMAT21c_TYPE,
+ SmaliTokens.INSTRUCTION_FORMAT21t,
+ SmaliTokens.INSTRUCTION_FORMAT22c_FIELD,
+ SmaliTokens.INSTRUCTION_FORMAT22c_FIELD_ODEX,
+ SmaliTokens.INSTRUCTION_FORMAT22c_TYPE,
+ SmaliTokens.INSTRUCTION_FORMAT22cs_FIELD,
+ SmaliTokens.INSTRUCTION_FORMAT22s_OR_ID,
+ SmaliTokens.INSTRUCTION_FORMAT22t,
+ SmaliTokens.INSTRUCTION_FORMAT23x,
+ SmaliTokens.INSTRUCTION_FORMAT31i_OR_ID,
+ SmaliTokens.INSTRUCTION_FORMAT31t,
+ SmaliTokens.INSTRUCTION_FORMAT35c_METHOD,
+ SmaliTokens.INSTRUCTION_FORMAT35c_METHOD_ODEX,
+ SmaliTokens.INSTRUCTION_FORMAT35c_TYPE,
+ SmaliTokens.INSTRUCTION_FORMAT35mi_METHOD,
+ SmaliTokens.INSTRUCTION_FORMAT35ms_METHOD,
+ SmaliTokens.INSTRUCTION_FORMAT51l);
+
+ @Override public void processWords(CharSequence fileText, Processor<WordOccurrence> processor) {
+ SmaliLexer lexer = new SmaliLexer();
+ lexer.start(fileText);
+
+ IElementType type = lexer.getTokenType();
+ while (type != null) {
+ if (type == SmaliTokens.CLASS_DESCRIPTOR) {
+ processClassDescriptor(fileText, lexer.getTokenStart(), lexer.getTokenEnd(), processor);
+ } else if (MEMBER_NAME_TOKENS.contains(type)) {
+ processor.process(new WordOccurrence(fileText, lexer.getTokenStart(), lexer.getTokenEnd(), Kind.CODE));
+ } else if (type == SmaliTokens.PARAM_LIST_OR_ID_PRIMITIVE_TYPE) {
+ int tokenStart = lexer.getTokenStart();
+ while (type == SmaliTokens.PARAM_LIST_OR_ID_PRIMITIVE_TYPE) {
+ lexer.advance();
+ type = lexer.getTokenType();
+ }
+ int tokenEnd = lexer.getTokenStart();
+ processor.process(new WordOccurrence(fileText, tokenStart, tokenEnd, Kind.CODE));
+ }
+ lexer.advance();
+ type = lexer.getTokenType();
+ }
+ }
+
+ private void processClassDescriptor(CharSequence fileText, int tokenStart, int tokenEnd,
+ @NotNull Processor<WordOccurrence> processor) {
+ CharSequence tokenText = fileText.subSequence(tokenStart, tokenEnd);
+
+ assert tokenText.charAt(0) == 'L' && tokenText.charAt(tokenText.length()-1) == ';';
+ processor.process(new WordOccurrence(fileText, tokenStart, tokenEnd, Kind.CODE));
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/SmaliCompositeElementFactory.java b/smalidea/src/main/java/org/jf/smalidea/psi/SmaliCompositeElementFactory.java
new file mode 100644
index 00000000..6d5bb105
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/SmaliCompositeElementFactory.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2014, 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.psi;
+
+import org.jf.smalidea.psi.impl.SmaliCompositeElement;
+
+public interface SmaliCompositeElementFactory {
+ SmaliCompositeElement createElement();
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/SmaliCompositeElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/SmaliCompositeElementType.java
new file mode 100644
index 00000000..ae5fc538
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/SmaliCompositeElementType.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014, 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.psi;
+
+import com.intellij.psi.tree.ICompositeElementType;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.SmaliLanguage;
+import org.jf.smalidea.psi.impl.SmaliCompositeElement;
+
+public class SmaliCompositeElementType extends IElementType implements ICompositeElementType {
+ @NotNull private final SmaliCompositeElementFactory factory;
+
+ public SmaliCompositeElementType(@NotNull @NonNls String debugName,
+ @NotNull SmaliCompositeElementFactory factory) {
+ super(debugName, SmaliLanguage.INSTANCE);
+ this.factory = factory;
+ }
+
+ @NotNull @Override public SmaliCompositeElement createCompositeNode() {
+ return factory.createElement();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/SmaliElementTypes.java b/smalidea/src/main/java/org/jf/smalidea/psi/SmaliElementTypes.java
new file mode 100644
index 00000000..bb4bd37a
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/SmaliElementTypes.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2014, 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.psi;
+
+import org.jf.smalidea.psi.impl.*;
+import org.jf.smalidea.psi.stub.element.*;
+
+public class SmaliElementTypes {
+ public static final SmaliFileElementType FILE = SmaliFileElementType.INSTANCE;
+ public static final SmaliClassElementType CLASS = SmaliClassElementType.INSTANCE;
+ public static final SmaliFieldElementType FIELD = SmaliFieldElementType.INSTANCE;
+ public static final SmaliMethodElementType METHOD = SmaliMethodElementType.INSTANCE;
+ public static final SmaliClassStatementElementType CLASS_STATEMENT = SmaliClassStatementElementType.INSTANCE;
+ public static final SmaliMethodPrototypeElementType METHOD_PROTOTYPE = SmaliMethodPrototypeElementType.INSTANCE;
+ public static final SmaliMethodParamListElementType METHOD_PARAM_LIST = SmaliMethodParamListElementType.INSTANCE;
+ public static final SmaliMethodParameterElementType METHOD_PARAMETER = SmaliMethodParameterElementType.INSTANCE;
+ public static final SmaliAnnotationElementType ANNOTATION = SmaliAnnotationElementType.INSTANCE;
+ public static final SmaliModifierListElementType MODIFIER_LIST = SmaliModifierListElementType.INSTANCE;
+ public static final SmaliExtendsListElementType EXTENDS_LIST = SmaliExtendsListElementType.INSTANCE;
+ public static final SmaliImplementsListElementType IMPLEMENTS_LIST = SmaliImplementsListElementType.INSTANCE;
+ public static final SmaliThrowsListElementType THROWS_LIST = SmaliThrowsListElementType.INSTANCE;
+
+ public static final SmaliCompositeElementType LITERAL =
+ new SmaliCompositeElementType("LITERAL", SmaliLiteral.FACTORY);
+ public static final SmaliCompositeElementType SUPER_STATEMENT =
+ new SmaliCompositeElementType("SUPER_STATEMENT", SmaliSuperStatement.FACTORY);
+ public static final SmaliCompositeElementType IMPLEMENTS_STATEMENT =
+ new SmaliCompositeElementType("IMPLEMENTS_STATEMENT", SmaliImplementsStatement.FACTORY);
+ public static final SmaliCompositeElementType SOURCE_STATEMENT =
+ new SmaliCompositeElementType("SOURCE_STATEMENT", SmaliSourceStatement.FACTORY);
+ public static final SmaliCompositeElementType REGISTERS_STATEMENT =
+ new SmaliCompositeElementType("REGISTERS_STATEMENT", SmaliRegistersStatement.FACTORY);
+ public static final SmaliCompositeElementType REGISTER_REFERENCE =
+ new SmaliCompositeElementType("REGISTER_REFERENCE", SmaliRegisterReference.FACTORY);
+ public static final SmaliCompositeElementType MEMBER_NAME =
+ new SmaliCompositeElementType("MEMBER_NAME", SmaliMemberName.FACTORY);
+ public static final SmaliCompositeElementType LOCAL_NAME =
+ new SmaliCompositeElementType("LOCAL_NAME", SmaliLocalName.FACTORY);
+ public static final SmaliCompositeElementType PARAMETER_STATEMENT =
+ new SmaliCompositeElementType("PARAMETER_STATEMENT", SmaliParameterStatement.FACTORY);
+ public static final SmaliCompositeElementType FIELD_INITIALIZER =
+ new SmaliCompositeElementType("FIELD_INITIALIZER", SmaliFieldInitializer.FACTORY);
+ public static final SmaliCompositeElementType INSTRUCTION =
+ new SmaliCompositeElementType("INSTRUCTION", SmaliInstruction.FACTORY);
+ public static final SmaliCompositeElementType ANNOTATION_PARAMETER_LIST =
+ new SmaliCompositeElementType("ANNOTATION_PARAMETER_LIST", SmaliAnnotationParameterList.FACTORY);
+ public static final SmaliCompositeElementType ANNOTATION_ELEMENT =
+ new SmaliCompositeElementType("ANNOTATION_ELEMENT", SmaliAnnotationElement.FACTORY);
+ public static final SmaliCompositeElementType ANNOTATION_ELEMENT_NAME =
+ new SmaliCompositeElementType("ANNOTATION_ELEMENT_NAME", SmaliAnnotationElementName.FACTORY);
+ public static final SmaliCompositeElementType FIELD_REFERENCE =
+ new SmaliCompositeElementType("FIELD_REFERENCE", SmaliFieldReference.FACTORY);
+ public static final SmaliCompositeElementType METHOD_REFERENCE =
+ new SmaliCompositeElementType("METHOD_REFERENCE", SmaliMethodReference.FACTORY);
+ public static final SmaliCompositeElementType METHOD_REFERENCE_PARAM_LIST =
+ new SmaliCompositeElementType("METHOD_REFERENCE_PARAM_LIST", SmaliMethodReferenceParamList.FACTORY);
+ public static final SmaliCompositeElementType LABEL =
+ new SmaliCompositeElementType("LABEL", SmaliLabel.FACTORY);
+ public static final SmaliCompositeElementType LABEL_REFERENCE =
+ new SmaliCompositeElementType("LABEL_REFERENCE", SmaliLabelReference.FACTORY);
+ public static final SmaliCompositeElementType LINE_DEBUG_STATEMENT =
+ new SmaliCompositeElementType("LINE_DEBUG_STATEMENT", SmaliLineDebugStatement.FACTORY);
+ public static final SmaliCompositeElementType LOCAL_DEBUG_STATEMENT =
+ new SmaliCompositeElementType("LOCAL_DEBUG_STATEMENT", SmaliLocalDebugStatement.FACTORY);
+ public static final SmaliCompositeElementType END_LOCAL_DEBUG_STATEMENT =
+ new SmaliCompositeElementType("END_LOCAL_DEBUG_STATEMENT", SmaliEndLocalDebugStatement.FACTORY);
+ public static final SmaliCompositeElementType RESTART_LOCAL_DEBUG_STATEMENT =
+ new SmaliCompositeElementType("RESTART_LOCAL_DEBUG_STATEMENT", SmaliRestartLocalDebugStatement.FACTORY);
+ public static final SmaliCompositeElementType PROLOGUE_DEBUG_STATEMENT =
+ new SmaliCompositeElementType("PROLOGUE_DEBUG_STATEMENT", SmaliPrologueDebugStatement.FACTORY);
+ public static final SmaliCompositeElementType EPILOGUE_DEBUG_STATEMENT =
+ new SmaliCompositeElementType("EPILOGUE_DEBUG_STATEMENT", SmaliEpilogueDebugStatement.FACTORY);
+ public static final SmaliCompositeElementType SOURCE_DEBUG_STATEMENT =
+ new SmaliCompositeElementType("SOURCE_DEBUG_STATEMENT", SmaliSourceDebugStatement.FACTORY);
+ public static final SmaliCompositeElementType PRIMITIVE_TYPE =
+ new SmaliCompositeElementType("PRIMITIVE_TYPE", SmaliPrimitiveTypeElement.FACTORY);
+ public static final SmaliCompositeElementType CLASS_TYPE =
+ new SmaliCompositeElementType("CLASS_TYPE", SmaliClassTypeElement.FACTORY);
+ public static final SmaliCompositeElementType ARRAY_TYPE =
+ new SmaliCompositeElementType("ARRAY_TYPE", SmaliArrayTypeElement.FACTORY);
+ public static final SmaliCompositeElementType VOID_TYPE =
+ new SmaliCompositeElementType("VOID_TYPE", SmaliVoidTypeElement.FACTORY);
+ public static final SmaliCompositeElementType CATCH_STATEMENT =
+ new SmaliCompositeElementType("CATCH_STATEMENT", SmaliCatchStatement.FACTORY);
+ public static final SmaliCompositeElementType CATCH_ALL_STATEMENT =
+ new SmaliCompositeElementType("CATCH_ALL_STATEMENT", SmaliCatchAllStatement.FACTORY);
+ public static final SmaliCompositeElementType PACKED_SWITCH_ELEMENT =
+ new SmaliCompositeElementType("PACKED_SWITCH_ELEMENT", SmaliPackedSwitchElement.FACTORY);
+ public static final SmaliCompositeElementType SPARSE_SWITCH_ELEMENT =
+ new SmaliCompositeElementType("SPARSE_SWITCH_ELEMENT", SmaliSparseSwitchElement.FACTORY);
+ public static final SmaliCompositeElementType ARRAY_DATA_ELEMENT =
+ new SmaliCompositeElementType("ARRAY_DATA_ELEMENT", SmaliArrayDataElement.FACTORY);
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/iface/SmaliModifierListOwner.java b/smalidea/src/main/java/org/jf/smalidea/psi/iface/SmaliModifierListOwner.java
new file mode 100644
index 00000000..3da47c9b
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/iface/SmaliModifierListOwner.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014, 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.psi.iface;
+
+import com.intellij.psi.PsiAnnotationOwner;
+import com.intellij.psi.PsiModifierListOwner;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.impl.SmaliAnnotation;
+import org.jf.smalidea.psi.impl.SmaliModifierList;
+
+public interface SmaliModifierListOwner extends PsiModifierListOwner, PsiAnnotationOwner {
+ @NotNull @Override SmaliAnnotation[] getAnnotations();
+ @NotNull @Override SmaliAnnotation[] getApplicableAnnotations();
+ @Nullable @Override SmaliAnnotation findAnnotation(@NotNull @NonNls String qualifiedName);
+ @NotNull @Override SmaliAnnotation addAnnotation(@NotNull @NonNls String qualifiedName);
+ @Nullable @Override SmaliModifierList getModifierList();
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/LightSmaliClassTypeElement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/LightSmaliClassTypeElement.java
new file mode 100644
index 00000000..acd9a02a
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/LightSmaliClassTypeElement.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.*;
+import com.intellij.psi.impl.light.LightElement;
+import com.intellij.psi.infos.CandidateInfo;
+import com.intellij.psi.scope.PsiScopeProcessor;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.SmaliLanguage;
+import org.jf.smalidea.util.NameUtils;
+
+public class LightSmaliClassTypeElement extends LightElement
+ implements PsiTypeElement, PsiReference, PsiJavaCodeReferenceElement {
+ @NotNull
+ private final String smaliName;
+
+ public LightSmaliClassTypeElement(@NotNull PsiManager manager, @NotNull String smaliName) {
+ super(manager, SmaliLanguage.INSTANCE);
+ this.smaliName = smaliName;
+ }
+
+ @Override public String toString() {
+ return "LightSmaliClassTypeElement:" + smaliName;
+ }
+
+ @NotNull @Override public PsiType getType() {
+ return new SmaliClassType(this);
+ }
+
+ @Nullable @Override public LightSmaliClassTypeElement getInnermostComponentReferenceElement() {
+ return this;
+ }
+
+ @Override public String getText() {
+ return smaliName;
+ }
+
+ @Override public PsiReference getReference() {
+ return this;
+ }
+
+ @Override public PsiElement getElement() {
+ return this;
+ }
+
+ @Override public TextRange getRangeInElement() {
+ return new TextRange(0, getTextLength());
+ }
+
+ @Nullable @Override public PsiClass resolve() {
+ return NameUtils.resolveSmaliType(this, smaliName);
+ }
+
+ @NotNull @Override public String getCanonicalText() {
+ return NameUtils.resolveSmaliToJavaType(this, smaliName);
+ }
+
+ @Override public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean isReferenceTo(PsiElement element) {
+ if (!(element instanceof PsiClassType)) {
+ return false;
+ }
+ return element.getManager().areElementsEquivalent(element, resolve());
+ }
+
+ @NotNull @Override public Object[] getVariants() {
+ throw new RuntimeException("Variants are not available for light references");
+ }
+
+ @Override public boolean isSoft() {
+ return false;
+ }
+
+ @NotNull @Override public PsiAnnotation[] getAnnotations() {
+ return new PsiAnnotation[0];
+ }
+
+ @NotNull @Override public PsiAnnotation[] getApplicableAnnotations() {
+ return new PsiAnnotation[0];
+ }
+
+ @Nullable @Override public PsiAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
+ return null;
+ }
+
+ @NotNull @Override public PsiAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
+ throw new UnsupportedOperationException();
+ }
+
+ // ***************************************************************************
+ // Below are the PsiJavaCodeReferenceElement-specific methods
+
+ @Override public void processVariants(@NotNull PsiScopeProcessor processor) {
+ // TODO: maybe just do nothing?
+ throw new UnsupportedOperationException();
+ }
+
+ @Nullable @Override public PsiElement getReferenceNameElement() {
+ // TODO: implement if needed
+ throw new UnsupportedOperationException();
+ }
+
+ @Nullable @Override public PsiReferenceParameterList getParameterList() {
+ // TODO: (generics) implement this
+ return null;
+ }
+
+ @NotNull @Override public PsiType[] getTypeParameters() {
+ // TODO: (generics) implement this
+ return new PsiType[0];
+ }
+
+ @Override public boolean isQualified() {
+ // TODO: should this return false for classes in the top level package?
+ return true;
+ }
+
+ @Override public String getQualifiedName() {
+ return getCanonicalText();
+ }
+
+ @NotNull @Override public JavaResolveResult advancedResolve(boolean incompleteCode) {
+ PsiClass element = resolve();
+ if (element == null) {
+ return JavaResolveResult.EMPTY;
+ }
+ return new CandidateInfo(element, PsiSubstitutor.EMPTY);
+ }
+
+ @NotNull @Override public JavaResolveResult[] multiResolve(boolean incompleteCode) {
+ PsiClass element = resolve();
+ if (element == null) {
+ return JavaResolveResult.EMPTY_ARRAY;
+ }
+ return new CandidateInfo[] { new CandidateInfo(element, PsiSubstitutor.EMPTY) };
+ }
+
+ @Nullable @Override public PsiElement getQualifier() {
+ // TODO: implement this if needed
+ throw new UnsupportedOperationException();
+ }
+
+ @Nullable @Override public String getReferenceName() {
+ return getName();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotation.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotation.java
new file mode 100644
index 00000000..e36313ba
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotation.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.*;
+import com.intellij.psi.impl.PsiImplUtil;
+import com.intellij.psi.meta.PsiMetaData;
+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.stub.SmaliAnnotationStub;
+
+public class SmaliAnnotation extends SmaliStubBasedPsiElement<SmaliAnnotationStub> implements PsiAnnotation {
+ public SmaliAnnotation(@NotNull SmaliAnnotationStub stub) {
+ super(stub, SmaliElementTypes.ANNOTATION);
+ }
+
+ public SmaliAnnotation(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ @NotNull @Override public SmaliAnnotationParameterList getParameterList() {
+ SmaliAnnotationParameterList paramList = findChildByClass(SmaliAnnotationParameterList.class);
+ // The structure of the parser should ensure the param list is always present, even if there are syntax errors
+ assert paramList != null;
+ return paramList;
+ }
+
+ @Nullable @Override public String getQualifiedName() {
+ PsiJavaCodeReferenceElement nameElement = getNameReferenceElement();
+ if (nameElement != null) {
+ return nameElement.getQualifiedName();
+ }
+ return null;
+ }
+
+ @Nullable public String getSmaliName() {
+ SmaliAnnotationStub stub = getStub();
+ if (stub != null) {
+ return stub.getAnnotationSmaliTypeName();
+ }
+
+ SmaliClassTypeElement classType = findChildByClass(SmaliClassTypeElement.class);
+ if (classType == null) {
+ return null;
+ }
+ return classType.getSmaliName();
+ }
+
+ @Nullable @Override public PsiJavaCodeReferenceElement getNameReferenceElement() {
+ SmaliAnnotationStub stub = getStub();
+ if (stub != null) {
+ String smaliName = stub.getAnnotationSmaliTypeName();
+ if (smaliName != null) {
+ return new LightSmaliClassTypeElement(getManager(), smaliName);
+ }
+ }
+ return findChildByClass(SmaliClassTypeElement.class);
+ }
+
+ @Nullable @Override public PsiAnnotationMemberValue findAttributeValue(@Nullable @NonNls String attributeName) {
+ return PsiImplUtil.findAttributeValue(this, attributeName);
+ }
+
+ @Nullable @Override
+ public PsiAnnotationMemberValue findDeclaredAttributeValue(@Nullable @NonNls String attributeName) {
+ return PsiImplUtil.findDeclaredAttributeValue(this, attributeName);
+ }
+
+ @Override
+ public <T extends PsiAnnotationMemberValue> T setDeclaredAttributeValue(
+ @Nullable @NonNls String attributeName, @Nullable T value) {
+ // TODO: implement this
+ throw new UnsupportedOperationException();
+ }
+
+ @Nullable @Override public PsiAnnotationOwner getOwner() {
+ return (PsiAnnotationOwner)getStubOrPsiParent();
+ }
+
+ @Nullable @Override public PsiMetaData getMetaData() {
+ // I have no idea what this is
+ return null;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotationElement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotationElement.java
new file mode 100644
index 00000000..10784f8f
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotationElement.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiAnnotationMemberValue;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiNameValuePair;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.SmaliTokens;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliAnnotationElement extends SmaliCompositeElement implements PsiNameValuePair {
+ // TODO: consider making this a stub
+
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliAnnotationElement();
+ }
+ };
+
+ public SmaliAnnotationElement() {
+ super(SmaliElementTypes.ANNOTATION_ELEMENT);
+ }
+
+ @Override public String getName() {
+ SmaliAnnotationElementName identifier = getNameIdentifier();
+ if (identifier != null) {
+ return identifier.getName();
+ }
+ return null;
+ }
+
+ @Nullable @Override public SmaliAnnotationElementName getNameIdentifier() {
+ return findChildByClass(SmaliAnnotationElementName.class);
+ }
+
+ @Nullable @Override public PsiAnnotationMemberValue getValue() {
+ ASTNode equalNode = findChildByType(SmaliTokens.EQUAL);
+ if (equalNode == null) {
+ return null;
+ }
+
+ PsiElement nextElement = equalNode.getPsi().getNextSibling();
+ while (nextElement != null) {
+ if (nextElement instanceof PsiAnnotationMemberValue) {
+ return (PsiAnnotationMemberValue)nextElement;
+ }
+ nextElement = nextElement.getNextSibling();
+ }
+ return null;
+ }
+
+ @NotNull @Override public PsiAnnotationMemberValue setValue(@NotNull PsiAnnotationMemberValue newValue) {
+ // TODO: implement this
+ throw new UnsupportedOperationException();
+ }
+
+ @Nullable @Override public String getLiteralValue() {
+ // Not applicable for smali
+ return null;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotationElementName.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotationElementName.java
new file mode 100644
index 00000000..656b4eff
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotationElementName.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.*;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliAnnotationElementName extends SmaliCompositeElement implements PsiIdentifier, PsiReference {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliAnnotationElementName();
+ }
+ };
+
+ public SmaliAnnotationElementName() {
+ super(SmaliElementTypes.ANNOTATION_ELEMENT_NAME);
+ }
+
+ @Override public IElementType getTokenType() {
+ return getElementType();
+ }
+
+ @Override public String getName() {
+ return getText();
+ }
+
+ @Nullable
+ public SmaliAnnotation getContainingAnnotation() {
+ return findAncestorByClass(SmaliAnnotation.class);
+ }
+
+ @Override public PsiElement bindToElement(PsiElement element) throws IncorrectOperationException {
+ //TODO: implement this if needed
+ throw new IncorrectOperationException();
+ }
+
+ @Override public PsiElement getElement() {
+ return this;
+ }
+
+ @Override public TextRange getRangeInElement() {
+ return new TextRange(0, getTextLength());
+ }
+
+ @Nullable @Override public PsiElement resolve() {
+ SmaliAnnotation smaliAnnotation = getContainingAnnotation();
+ if (smaliAnnotation == null) {
+ return null;
+ }
+
+ String annotationType = smaliAnnotation.getQualifiedName();
+ if (annotationType == null) {
+ return null;
+ }
+
+ JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject());
+ PsiClass annotationClass = facade.findClass(annotationType, getResolveScope());
+ if (annotationClass == null) {
+ return null;
+ }
+
+ for (PsiMethod method : annotationClass.findMethodsByName(getName(), true)) {
+ if (method.getParameterList().getParametersCount() == 0) {
+ return method;
+ }
+ }
+ return null;
+ }
+
+ @NotNull @Override public String getCanonicalText() {
+ // TODO: return a full method reference here?
+ String name = getName();
+ if (name == null) {
+ return "";
+ }
+ return name;
+ }
+
+ @Override public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ //TODO: implement this
+ throw new IncorrectOperationException();
+ }
+
+ @Override public boolean isReferenceTo(PsiElement element) {
+ return resolve() == element;
+ }
+
+ @NotNull @Override public Object[] getVariants() {
+ return ArrayUtil.EMPTY_OBJECT_ARRAY;
+ }
+
+ @Override public boolean isSoft() {
+ return false;
+ }
+
+ @Override public PsiReference getReference() {
+ return this;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotationParameterList.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotationParameterList.java
new file mode 100644
index 00000000..7feaa9ee
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotationParameterList.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.psi.PsiAnnotationParameterList;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliAnnotationParameterList extends SmaliCompositeElement implements PsiAnnotationParameterList {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliAnnotationParameterList();
+ }
+ };
+
+ public SmaliAnnotationParameterList() {
+ super(SmaliElementTypes.ANNOTATION_PARAMETER_LIST);
+ }
+
+ @NotNull @Override public SmaliAnnotationElement[] getAttributes() {
+ return findChildrenByClass(SmaliAnnotationElement.class);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliArrayDataElement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliArrayDataElement.java
new file mode 100644
index 00000000..85f62138
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliArrayDataElement.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015, 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.psi.impl;
+
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliArrayDataElement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliArrayDataElement();
+ }
+ };
+
+ public SmaliArrayDataElement() {
+ super(SmaliElementTypes.ARRAY_DATA_ELEMENT);
+ }
+
+ @Nullable
+ public SmaliLiteral getValue() {
+ return findChildByClass(SmaliLiteral.class);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliArrayTypeElement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliArrayTypeElement.java
new file mode 100644
index 00000000..1b54a9c0
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliArrayTypeElement.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiArrayType;
+import com.intellij.psi.PsiType;
+import com.intellij.psi.PsiTypeElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.SmaliTokens;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliArrayTypeElement extends SmaliTypeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliArrayTypeElement();
+ }
+ };
+
+ public SmaliArrayTypeElement() {
+ super(SmaliElementTypes.ARRAY_TYPE);
+ }
+
+ @NotNull @Override public PsiType getType() {
+ ASTNode token = findChildByType(SmaliTokens.ARRAY_TYPE_PREFIX);
+ assert token != null;
+ PsiTypeElement baseType = findChildByClass(PsiTypeElement.class);
+ assert baseType != null;
+
+ PsiArrayType arrayType = new PsiArrayType(baseType.getType());
+ int dimensions = token.getTextLength() - 1;
+ while (dimensions > 0) {
+ arrayType = new PsiArrayType(arrayType);
+ dimensions--;
+ }
+ return arrayType;
+ }
+
+ @Nullable @Override public SmaliClassTypeElement getInnermostComponentReferenceElement() {
+ return findChildByClass(SmaliClassTypeElement.class);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliBaseReferenceList.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliBaseReferenceList.java
new file mode 100644
index 00000000..b47d5126
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliBaseReferenceList.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiReferenceList;
+import com.intellij.psi.StubBasedPsiElement;
+import com.intellij.psi.stubs.IStubElementType;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.stub.SmaliBaseReferenceListStub;
+import org.jf.smalidea.util.NameUtils;
+
+public abstract class SmaliBaseReferenceList<StubT extends SmaliBaseReferenceListStub>
+ extends SmaliStubBasedPsiElement<StubT> implements StubBasedPsiElement<StubT>, PsiReferenceList {
+ protected SmaliBaseReferenceList(@NotNull StubT stub, @NotNull IStubElementType nodeType) {
+ super(stub, nodeType);
+ }
+
+ protected SmaliBaseReferenceList(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ @NotNull @Override public SmaliClassType[] getReferencedTypes() {
+ StubT stub = getStub();
+ if (stub != null) {
+ return stub.getReferencedTypes();
+ }
+
+ SmaliClassTypeElement[] references = getReferenceElements();
+
+ SmaliClassType[] referenceTypes = new SmaliClassType[references.length];
+
+ for (int i=0; i<references.length; i++) {
+ referenceTypes[i] = references[i].getType();
+ }
+ return referenceTypes;
+ }
+
+ @NotNull public String[] getReferenceNames() {
+ SmaliBaseReferenceListStub stub = getStub();
+
+ if (stub != null) {
+ String[] smaliNames = stub.getSmaliTypeNames();
+ String[] referenceNames = new String[smaliNames.length];
+
+ for (int i=0; i<smaliNames.length; i++) {
+ referenceNames[i] = NameUtils.resolveSmaliToJavaType(this, smaliNames[i]);
+ }
+
+ return referenceNames;
+ }
+
+ SmaliClassTypeElement[] references = getReferenceElements();
+
+ String[] referenceNames = new String[references.length];
+
+ for (int i=0; i<references.length; i++) {
+ referenceNames[i] = references[i].getCanonicalText();
+ }
+ return referenceNames;
+ }
+
+ @NotNull public String[] getSmaliNames() {
+ SmaliBaseReferenceListStub stub = getStub();
+
+ if (stub != null) {
+ return stub.getSmaliTypeNames();
+ }
+
+ SmaliClassTypeElement[] references = getReferenceElements();
+
+ String[] smaliNames = new String[references.length];
+
+ for (int i=0; i<references.length; i++) {
+ smaliNames[i] = references[i].getSmaliName();
+ }
+ return smaliNames;
+ }
+
+ @Override public boolean isWritable() {
+ return false;
+ }
+
+ @NotNull @Override public abstract SmaliClassTypeElement[] getReferenceElements();
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliCatchAllStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliCatchAllStatement.java
new file mode 100644
index 00000000..f5c7107f
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliCatchAllStatement.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliCatchAllStatement extends SmaliCatchStatement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliCatchAllStatement();
+ }
+ };
+
+ public SmaliCatchAllStatement() {
+ super(SmaliElementTypes.CATCH_ALL_STATEMENT);
+ }
+
+ @Nullable @Override public SmaliClassTypeElement getExceptionType() {
+ return null;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliCatchStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliCatchStatement.java
new file mode 100644
index 00000000..b8442a6b
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliCatchStatement.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliCatchStatement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliCatchStatement();
+ }
+ };
+
+ public SmaliCatchStatement() {
+ super(SmaliElementTypes.CATCH_STATEMENT);
+ }
+
+ protected SmaliCatchStatement(IElementType elementType) {
+ super(elementType);
+ }
+
+ @Nullable
+ public SmaliClassTypeElement getExceptionType() {
+ return findChildByClass(SmaliClassTypeElement.class);
+ }
+
+ @Nullable
+ public SmaliLabelReference getStartLabel() {
+ return findChildByClass(SmaliLabelReference.class);
+ }
+
+ @Nullable
+ public SmaliLabelReference getEndLabel() {
+ SmaliLabelReference startLabel = getStartLabel();
+ if (startLabel == null) {
+ return null;
+ }
+ return startLabel.findNextSiblingByClass(SmaliLabelReference.class);
+ }
+
+ @Nullable
+ public SmaliLabelReference getHandlerLabel() {
+ SmaliLabelReference endLabel = getEndLabel();
+ if (endLabel == null) {
+ return null;
+ }
+ return endLabel.findNextSiblingByClass(SmaliLabelReference.class);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java
new file mode 100644
index 00000000..684293fa
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.lang.ASTNode;
+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.InheritanceImplUtil;
+import com.intellij.psi.impl.PsiClassImplUtil;
+import com.intellij.psi.impl.PsiImplUtil;
+import com.intellij.psi.javadoc.PsiDocComment;
+import com.intellij.psi.scope.PsiScopeProcessor;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.util.IncorrectOperationException;
+import com.sun.jdi.Location;
+import com.sun.jdi.Method;
+import com.sun.jdi.ReferenceType;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.SmaliIcons;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.iface.SmaliModifierListOwner;
+import org.jf.smalidea.psi.leaf.SmaliClassDescriptor;
+import org.jf.smalidea.psi.stub.SmaliClassStub;
+
+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 SmaliClass(@NotNull SmaliClassStub stub) {
+ super(stub, SmaliElementTypes.CLASS);
+ }
+
+ public SmaliClass(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ String name = getQualifiedName();
+ if (name == null) {
+ return "";
+ }
+ int lastDot = name.lastIndexOf('.');
+ if (lastDot < 0) {
+ return name;
+ }
+ return name.substring(lastDot+1);
+ }
+
+ @Nullable @Override public String getQualifiedName() {
+ SmaliClassStatement classStatement = getStubOrPsiChild(SmaliElementTypes.CLASS_STATEMENT);
+ if (classStatement == null) {
+ return null;
+ }
+ return classStatement.getQualifiedName();
+ }
+
+ @NotNull public String getPackageName() {
+ String name = getQualifiedName();
+ if (name == null) {
+ return "";
+ }
+ int lastDot = name.lastIndexOf('.');
+ if (lastDot < 0) {
+ return "";
+ }
+ return name.substring(0, lastDot);
+ }
+
+ @Override public boolean hasTypeParameters() {
+ // TODO: implement generics
+ return false;
+ }
+
+ @Override public boolean isInterface() {
+ return hasModifierProperty("interface");
+ }
+
+ @Override public boolean isAnnotationType() {
+ return hasModifierProperty("annotation");
+ }
+
+ @Override public boolean isEnum() {
+ return hasModifierProperty("enum");
+ }
+
+ @Nullable public SmaliSuperStatement getSuperStatement() {
+ return findChildByClass(SmaliSuperStatement.class);
+ }
+
+ @NotNull @Override public SmaliExtendsList getExtendsList() {
+ return getRequiredStubOrPsiChild(SmaliElementTypes.EXTENDS_LIST);
+ }
+
+ @NotNull public SmaliImplementsStatement[] getImplementsStatements() {
+ return findChildrenByClass(SmaliImplementsStatement.class);
+ }
+
+ @NotNull @Override public SmaliImplementsList getImplementsList() {
+ return getRequiredStubOrPsiChild(SmaliElementTypes.IMPLEMENTS_LIST);
+ }
+
+ @NotNull @Override public SmaliClassType[] getExtendsListTypes() {
+ return getExtendsList().getReferencedTypes();
+ }
+
+ @NotNull @Override public SmaliClassType[] getImplementsListTypes() {
+ return getImplementsList().getReferencedTypes();
+ }
+
+ @Nullable @Override public PsiClass getSuperClass() {
+ return PsiClassImplUtil.getSuperClass(this);
+ }
+
+ @Override public PsiClass[] getInterfaces() {
+ return PsiClassImplUtil.getInterfaces(this);
+ }
+
+ @NotNull @Override public PsiClass[] getSupers() {
+ return PsiClassImplUtil.getSupers(this);
+ }
+
+ @NotNull @Override public PsiClassType[] getSuperTypes() {
+ return PsiClassImplUtil.getSuperTypes(this);
+ }
+
+ @NotNull @Override public SmaliField[] getFields() {
+ SmaliField[] fields = getStubOrPsiChildren(SmaliElementTypes.FIELD, new SmaliField[0]);
+ List<SmaliField> filteredFields = null;
+ for (int i=fields.length-1; i>=0; i--) {
+ SmaliField field = fields[i];
+ if (field.getName() == null) {
+ if (filteredFields == null) {
+ filteredFields = Lists.newArrayList(fields);
+ }
+ filteredFields.remove(i);
+ }
+ }
+ if (filteredFields != null) {
+ return filteredFields.toArray(new SmaliField[filteredFields.size()]);
+ }
+ return fields;
+ }
+
+ @NotNull @Override public SmaliMethod[] getMethods() {
+ return getStubOrPsiChildren(SmaliElementTypes.METHOD, new SmaliMethod[0]);
+ }
+
+ @NotNull @Override public PsiMethod[] getConstructors() {
+ return PsiImplUtil.getConstructors(this);
+ }
+
+ @NotNull @Override public PsiClass[] getInnerClasses() {
+ return new PsiClass[0];
+ }
+
+ @NotNull @Override public PsiClassInitializer[] getInitializers() {
+ // TODO: do we need to return the <clinit> method here?
+ return new PsiClassInitializer[0];
+ }
+
+ @NotNull @Override public PsiField[] getAllFields() {
+ return PsiClassImplUtil.getAllFields(this);
+ }
+
+ @NotNull @Override public PsiMethod[] getAllMethods() {
+ return PsiClassImplUtil.getAllMethods(this);
+ }
+
+ @NotNull @Override public PsiClass[] getAllInnerClasses() {
+ return new PsiClass[0];
+ }
+
+ @Nullable @Override public PsiField findFieldByName(@NonNls String name, boolean checkBases) {
+ return PsiClassImplUtil.findFieldByName(this, name, checkBases);
+ }
+
+ @Nullable @Override public PsiMethod findMethodBySignature(PsiMethod patternMethod, boolean checkBases) {
+ return PsiClassImplUtil.findMethodBySignature(this, patternMethod, checkBases);
+ }
+
+ @NotNull @Override public PsiMethod[] findMethodsBySignature(PsiMethod patternMethod, boolean checkBases) {
+ return PsiClassImplUtil.findMethodsBySignature(this, patternMethod, checkBases);
+ }
+
+ @NotNull @Override public PsiMethod[] findMethodsByName(@NonNls String name, boolean checkBases) {
+ return PsiClassImplUtil.findMethodsByName(this, name, checkBases);
+ }
+
+ @NotNull @Override
+ public List<Pair<PsiMethod, PsiSubstitutor>> findMethodsAndTheirSubstitutorsByName(@NonNls String name, boolean checkBases) {
+ return PsiClassImplUtil.findMethodsAndTheirSubstitutorsByName(this, name, checkBases);
+ }
+
+ @NotNull @Override public List<Pair<PsiMethod, PsiSubstitutor>> getAllMethodsAndTheirSubstitutors() {
+ return PsiClassImplUtil.getAllWithSubstitutorsByMap(this, PsiClassImplUtil.MemberType.METHOD);
+ }
+
+ @Nullable @Override public PsiClass findInnerClassByName(@NonNls String name, boolean checkBases) {
+ return null;
+ }
+
+ @Nullable @Override public PsiElement getLBrace() {
+ return null;
+ }
+
+ @Nullable @Override public PsiElement getRBrace() {
+ return null;
+ }
+
+ @Nullable public SmaliClassStatement getClassStatement() {
+ return getStubOrPsiChild(SmaliElementTypes.CLASS_STATEMENT);
+ }
+
+ @Nullable @Override public SmaliClassDescriptor getNameIdentifier() {
+ SmaliClassStatement classStatement = getClassStatement();
+ if (classStatement == null) {
+ return null;
+ }
+ return classStatement.getNameIdentifier();
+ }
+
+ @Override public PsiElement getScope() {
+ return null;
+ }
+
+ @Override public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) {
+ return InheritanceImplUtil.isInheritor(this, baseClass, checkDeep);
+ }
+
+ @Override public boolean isInheritorDeep(PsiClass baseClass, @Nullable PsiClass classToByPass) {
+ return InheritanceImplUtil.isInheritorDeep(this, baseClass, classToByPass);
+ }
+
+ @Nullable @Override public PsiClass getContainingClass() {
+ return null;
+ }
+
+ @NotNull @Override public Collection<HierarchicalMethodSignature> getVisibleSignatures() {
+ return ImmutableList.of();
+ }
+
+ @Override public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
+ SmaliClassStatement classStatement = getClassStatement();
+ if (classStatement == null) {
+ throw new IncorrectOperationException();
+ }
+
+ SmaliClassTypeElement classTypeElement = classStatement.getNameElement();
+ if (classTypeElement == null) {
+ throw new IncorrectOperationException();
+ }
+
+ String expectedPath = "/" + getName() + ".smali";
+
+ VirtualFile virtualFile = this.getContainingFile().getVirtualFile();
+ if (virtualFile != null) {
+ String actualPath = virtualFile.getPath();
+ if (actualPath.endsWith(expectedPath)) {
+ getContainingFile().setName(name + ".smali");
+ }
+ }
+
+ String packageName = this.getPackageName();
+ String newName;
+ if (packageName.length() > 0) {
+ newName = packageName + "." + name;
+ } else {
+ newName = name;
+ }
+ classTypeElement.handleElementRename(newName);
+ return this;
+ }
+
+ public void setPackageName(@NonNls @NotNull String packageName) {
+ SmaliClassStatement classStatement = getClassStatement();
+ if (classStatement == null) {
+ throw new IncorrectOperationException();
+ }
+
+ SmaliClassTypeElement classTypeElement = classStatement.getNameElement();
+ if (classTypeElement == null) {
+ throw new IncorrectOperationException();
+ }
+
+ String newName;
+ if (packageName.length() > 0) {
+ newName = packageName + "." + getName();
+ } else {
+ newName = getName();
+ }
+
+ classTypeElement.handleElementRename(newName);
+ }
+
+ @Nullable @Override public PsiDocComment getDocComment() {
+ return null;
+ }
+
+ @Override public boolean isDeprecated() {
+ return false;
+ }
+
+ @Nullable @Override public PsiTypeParameterList getTypeParameterList() {
+ return null;
+ }
+
+ @NotNull @Override public PsiTypeParameter[] getTypeParameters() {
+ return new PsiTypeParameter[0];
+ }
+
+ @Nullable @Override public SmaliModifierList getModifierList() {
+ SmaliClassStatement classStatement = getStubOrPsiChild(SmaliElementTypes.CLASS_STATEMENT);
+ if (classStatement == null) {
+ return null;
+ }
+ return classStatement.getModifierList();
+ }
+
+ @Override public boolean hasModifierProperty(@ModifierConstant @NonNls @NotNull String name) {
+ SmaliModifierList smaliModifierList = getModifierList();
+ return smaliModifierList != null && smaliModifierList.hasModifierProperty(name);
+ }
+
+ @NotNull @Override public SmaliAnnotation[] getAnnotations() {
+ return getStubOrPsiChildren(SmaliElementTypes.ANNOTATION, new SmaliAnnotation[0]);
+ }
+
+ @NotNull @Override public SmaliAnnotation[] getApplicableAnnotations() {
+ return getAnnotations();
+ }
+
+ @Nullable @Override public SmaliAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
+ for (SmaliAnnotation annotation: getAnnotations()) {
+ if (qualifiedName.equals(annotation.getQualifiedName())) {
+ return annotation;
+ }
+ }
+ return null;
+ }
+
+ @NotNull @Override public SmaliAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
+ // TODO: implement this
+ return null;
+ }
+
+ @Nullable public Location getLocationForSourcePosition(@Nonnull ReferenceType type,
+ @Nonnull SourcePosition position) {
+
+ SmaliMethod[] smaliMethods = findChildrenByType(SmaliElementTypes.METHOD, SmaliMethod.class);
+
+ for (SmaliMethod smaliMethod: smaliMethods) {
+ //TODO: check the start line+end line of the method
+ int offset = smaliMethod.getOffsetForLine(position.getLine());
+ if (offset != -1) {
+ List<Method> methods = type.methodsByName(smaliMethod.getName(),
+ smaliMethod.getMethodPrototype().getText());
+ if (methods.size() > 0) {
+ return methods.get(0).locationOfCodeIndex(offset/2);
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state,
+ PsiElement lastParent, @NotNull PsiElement place) {
+ return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place,
+ PsiUtil.getLanguageLevel(place), false);
+ }
+
+ @Nullable @Override protected Icon getElementIcon(@IconFlags int flags) {
+ return SmaliIcons.SmaliIcon;
+ }
+} \ No newline at end of file
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassStatement.java
new file mode 100644
index 00000000..add3c1b2
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassStatement.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.lang.ASTNode;
+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.leaf.SmaliClassDescriptor;
+import org.jf.smalidea.psi.stub.SmaliClassStatementStub;
+import org.jf.smalidea.util.NameUtils;
+
+public class SmaliClassStatement extends SmaliStubBasedPsiElement<SmaliClassStatementStub>
+ implements SmaliModifierListOwner {
+ public SmaliClassStatement(@NotNull SmaliClassStatementStub stub) {
+ super(stub, SmaliElementTypes.CLASS_STATEMENT);
+ }
+
+ public SmaliClassStatement(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ @Nullable
+ public SmaliClassTypeElement getNameElement() {
+ return findChildByClass(SmaliClassTypeElement.class);
+ }
+
+ @Nullable
+ public SmaliClass getContainingClass() {
+ return getStubOrPsiParentOfType(SmaliClass.class);
+ }
+
+ @Nullable
+ public SmaliClassDescriptor getNameIdentifier() {
+ SmaliClassTypeElement classTypeElement = getNameElement();
+ if (classTypeElement == null) {
+ return null;
+ }
+ return classTypeElement.getReferenceNameElement();
+ }
+
+ /**
+ * @return the fully qualified java-style name of the class in this .class statement
+ */
+ @Nullable
+ public String getQualifiedName() {
+ SmaliClassStatementStub stub = getStub();
+ if (stub != null) {
+ return stub.getQualifiedName();
+ }
+
+ SmaliClassTypeElement classType = findChildByClass(SmaliClassTypeElement.class);
+ if (classType == null) {
+ return null;
+ }
+ // Since this is a class declared in smali, we don't have to worry about handling inner classes,
+ // so we can do a pure textual translation of the class name
+ return NameUtils.smaliToJavaType(classType.getSmaliName());
+ }
+
+ @Nullable
+ public SmaliModifierList getModifierList() {
+ return getStubOrPsiChild(SmaliElementTypes.MODIFIER_LIST);
+ }
+
+ @NotNull
+ @Override
+ public SmaliAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
+ SmaliClass containingClass = getContainingClass();
+ if (containingClass == null) {
+ // TODO: what should we do here?
+ return null;
+ }
+ return containingClass.addAnnotation(qualifiedName);
+ }
+
+ @NotNull
+ @Override
+ public SmaliAnnotation[] getAnnotations() {
+ SmaliClass containingClass = getContainingClass();
+ if (containingClass == null) {
+ return new SmaliAnnotation[0];
+ }
+ return containingClass.getAnnotations();
+ }
+
+ @NotNull
+ @Override
+ public SmaliAnnotation[] getApplicableAnnotations() {
+ SmaliClass containingClass = getContainingClass();
+ if (containingClass == null) {
+ return new SmaliAnnotation[0];
+ }
+ return containingClass.getApplicableAnnotations();
+ }
+
+ @Nullable
+ @Override
+ public SmaliAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
+ SmaliClass containingClass = getContainingClass();
+ if (containingClass == null) {
+ return null;
+ }
+ return containingClass.findAnnotation(qualifiedName);
+ }
+
+ @Override
+ public boolean hasModifierProperty(@NonNls @NotNull String name) {
+ SmaliClass containingClass = getContainingClass();
+ if (containingClass == null) {
+ return false;
+ }
+ return containingClass.hasModifierProperty(name);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassType.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassType.java
new file mode 100644
index 00000000..6d5bbaba
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassType.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.util.NameUtils;
+
+public class SmaliClassType extends PsiClassType {
+ private final PsiTypeElement element;
+
+ public SmaliClassType(PsiTypeElement element) {
+ this(element, LanguageLevel.JDK_1_5);
+ }
+
+ public SmaliClassType(PsiTypeElement element, LanguageLevel languageLevel) {
+ super(languageLevel);
+ this.element = element;
+ }
+
+ @Nullable
+ @Override
+ public PsiClass resolve() {
+ PsiReference reference = element.getReference();
+ if (reference == null) {
+ return null;
+ }
+ PsiElement resolved = reference.resolve();
+ if (resolved instanceof PsiClass) {
+ return (PsiClass)resolved;
+ }
+ return null;
+ }
+
+ @Override
+ public String getClassName() {
+ PsiClass resolved = resolve();
+ if (resolved != null) {
+ return NameUtils.shortNameFromQualifiedName(resolved.getQualifiedName());
+ }
+ return NameUtils.shortNameFromQualifiedName(element.getText());
+ }
+
+ @NotNull
+ @Override
+ public PsiType[] getParameters() {
+ // TODO: (generics) implement this
+ return PsiType.EMPTY_ARRAY;
+ }
+
+ @NotNull
+ @Override
+ public ClassResolveResult resolveGenerics() {
+ // TODO: (generics) implement this
+ return new ClassResolveResult() {
+ @Override
+ public PsiClass getElement() {
+ return resolve();
+ }
+
+ @Override
+ public PsiSubstitutor getSubstitutor() {
+ return PsiSubstitutor.EMPTY;
+ }
+
+ @Override
+ public boolean isPackagePrefixPackageReference() {
+ return false;
+ }
+
+ @Override
+ public boolean isAccessible() {
+ return true;
+ }
+
+ @Override
+ public boolean isStaticsScopeCorrect() {
+ return true;
+ }
+
+ @Override
+ public PsiElement getCurrentFileResolveScope() {
+ return null;
+ }
+
+ @Override
+ public boolean isValidResult() {
+ return true;
+ }
+ };
+ }
+
+ @NotNull
+ @Override
+ public SmaliClassType rawType() {
+ // TODO: (generics) implement this
+ return this;
+ }
+
+ @Override
+ @NotNull
+ public String getPresentableText() {
+ return getCanonicalText();
+ }
+
+ @Override
+ @NotNull
+ public String getCanonicalText() {
+ PsiClass psiClass = resolve();
+ if (psiClass != null) {
+ String qualifiedName = psiClass.getQualifiedName();
+ if (qualifiedName != null) {
+ return qualifiedName;
+ }
+ }
+ return NameUtils.smaliToJavaType(element.getText());
+ }
+
+ @Override
+ @NotNull
+ public String getInternalCanonicalText() {
+ return getCanonicalText();
+ }
+
+ @Override
+ public boolean isValid() {
+ return element.isValid();
+ }
+
+ @Override
+ public boolean equalsToText(@NonNls String text) {
+ return text.equals(getCanonicalText());
+ }
+
+ @NotNull
+ @Override
+ public GlobalSearchScope getResolveScope() {
+ return element.getResolveScope();
+ }
+
+ @NotNull
+ @Override
+ public LanguageLevel getLanguageLevel() {
+ return myLanguageLevel;
+ }
+
+ @NotNull
+ @Override
+ public PsiClassType setLanguageLevel(@NotNull LanguageLevel languageLevel) {
+ return new SmaliClassType(element, languageLevel);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassTypeElement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassTypeElement.java
new file mode 100644
index 00000000..b491f6df
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassTypeElement.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.*;
+import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
+import com.intellij.psi.infos.CandidateInfo;
+import com.intellij.psi.scope.PsiScopeProcessor;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.leaf.SmaliClassDescriptor;
+import org.jf.smalidea.util.NameUtils;
+
+public class SmaliClassTypeElement extends SmaliTypeElement implements PsiJavaCodeReferenceElement {
+ public static final SmaliClassTypeElement[] EMPTY_ARRAY = new SmaliClassTypeElement[0];
+
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliClassTypeElement();
+ }
+ };
+
+ @Nullable private SmaliClassType classType = null;
+
+ public SmaliClassTypeElement() {
+ super(SmaliElementTypes.CLASS_TYPE);
+ }
+
+ @NotNull @Override public SmaliClassType getType() {
+ if (classType == null) {
+ classType = new SmaliClassType(this);
+ }
+ return classType;
+ }
+
+ @Override public String getName() {
+ return NameUtils.shortNameFromQualifiedName(getCanonicalText());
+ }
+
+ @Nullable @Override public SmaliClassTypeElement getInnermostComponentReferenceElement() {
+ return this;
+ }
+
+ @Override public PsiElement getElement() {
+ return this;
+ }
+
+ @Override public PsiReference getReference() {
+ return this;
+ }
+
+ @Override public TextRange getRangeInElement() {
+ return new TextRange(0, getTextLength());
+ }
+
+ @Nullable @Override public PsiClass resolve() {
+ return NameUtils.resolveSmaliType(this, getText());
+ }
+
+ @NotNull @Override public String getCanonicalText() {
+ return getQualifiedName();
+ }
+
+ @Override public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ SmaliClassDescriptor descriptor = getReferenceNameElement();
+ if (descriptor == null) {
+ throw new IncorrectOperationException();
+ }
+
+ SmaliClassDescriptor newDescriptor = new SmaliClassDescriptor(NameUtils.javaToSmaliType(newElementName));
+ CodeEditUtil.setNodeGenerated(newDescriptor, true);
+
+ this.replaceChild(descriptor, newDescriptor);
+ return this;
+ }
+
+ @Override public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
+ if (element instanceof PsiClass) {
+ handleElementRename(((PsiClass) element).getQualifiedName());
+ return this;
+ }
+ throw new IncorrectOperationException();
+ }
+
+ @Override public boolean isReferenceTo(PsiElement element) {
+ if (!(element instanceof PsiClass)) {
+ return false;
+ }
+ return element.getManager().areElementsEquivalent(element, resolve());
+ }
+
+ @NotNull @Override public Object[] getVariants() {
+ // TODO: implement this?
+ return new Object[0];
+ }
+
+ @Override public boolean isSoft() {
+ return false;
+ }
+
+ // ***************************************************************************
+ // Below are the PsiJavaCodeReferenceElement-specific methods
+
+ @Override public void processVariants(@NotNull PsiScopeProcessor processor) {
+ // TODO: maybe just do nothing?
+ throw new UnsupportedOperationException();
+ }
+
+ @Nullable @Override public SmaliClassDescriptor getReferenceNameElement() {
+ return findChildByClass(SmaliClassDescriptor.class);
+ }
+
+ @Nullable @Override public PsiReferenceParameterList getParameterList() {
+ // TODO: (generics) implement this
+ return null;
+ }
+
+ @NotNull @Override public PsiType[] getTypeParameters() {
+ // TODO: (generics) implement this
+ return new PsiType[0];
+ }
+
+ @Override public boolean isQualified() {
+ // TODO: should this return false for classes in the top level package?
+ return true;
+ }
+
+ @Override public String getQualifiedName() {
+ PsiClass psiClass = resolve();
+ if (psiClass != null) {
+ return psiClass.getQualifiedName();
+ }
+ return NameUtils.smaliToJavaType(getText());
+ }
+
+ @NotNull @Override public JavaResolveResult advancedResolve(boolean incompleteCode) {
+ PsiClass element = resolve();
+ if (element == null) {
+ return JavaResolveResult.EMPTY;
+ }
+ return new CandidateInfo(element, PsiSubstitutor.EMPTY);
+ }
+
+ @NotNull @Override public JavaResolveResult[] multiResolve(boolean incompleteCode) {
+ PsiClass element = resolve();
+ if (element == null) {
+ return JavaResolveResult.EMPTY_ARRAY;
+ }
+ return new CandidateInfo[] { new CandidateInfo(element, PsiSubstitutor.EMPTY) };
+ }
+
+ @Nullable @Override public PsiElement getQualifier() {
+ return null;
+ }
+
+ @Nullable @Override public String getReferenceName() {
+ return getName();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliCompositeElement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliCompositeElement.java
new file mode 100644
index 00000000..d9c38c4e
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliCompositeElement.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.google.common.collect.ImmutableList;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.impl.source.tree.CompositePsiElement;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class SmaliCompositeElement extends CompositePsiElement {
+ public SmaliCompositeElement(IElementType type) {
+ super(type);
+ }
+
+ @NotNull
+ @SuppressWarnings("unchecked")
+ protected List<ASTNode> findChildrenByType(IElementType elementType) {
+ List<ASTNode> result = ImmutableList.of();
+ ASTNode child = getNode().getFirstChildNode();
+ while (child != null) {
+ if (elementType == child.getElementType()) {
+ if (result.size() == 0) {
+ result = new ArrayList<ASTNode>();
+ }
+ result.add((ASTNode)child.getPsi());
+ }
+ child = child.getTreeNext();
+ }
+ return result;
+ }
+
+ @NotNull
+ @SuppressWarnings("unchecked")
+ protected <T> T[] findChildrenByClass(Class<T> aClass) {
+ List<T> result = new ArrayList<T>();
+ for (PsiElement cur = getFirstChild(); cur != null; cur = cur.getNextSibling()) {
+ if (aClass.isInstance(cur)) result.add((T)cur);
+ }
+ return result.toArray((T[]) Array.newInstance(aClass, result.size()));
+ }
+
+ @Nullable
+ @SuppressWarnings("unchecked")
+ protected <T> T findChildByClass(Class<T> aClass) {
+ for (PsiElement cur = getFirstChild(); cur != null; cur = cur.getNextSibling()) {
+ if (aClass.isInstance(cur)) return (T)cur;
+ }
+ return null;
+ }
+
+ @Nullable
+ @SuppressWarnings("unchecked")
+ protected <T> T findAncestorByClass(Class<T> aClass) {
+ PsiElement parent = getParent();
+ while (parent != null) {
+ if (aClass.isInstance(parent)) {
+ return (T)parent;
+ }
+ parent = parent.getParent();
+ }
+ return null;
+ }
+
+ @Nullable
+ @SuppressWarnings("unchecked")
+ public <T> T findNextSiblingByClass(@NotNull Class<T> cls) {
+ PsiElement prev = getNextSibling();
+ while (true) {
+ if (prev == null) {
+ return null;
+ } else if (cls.isInstance(prev)) {
+ return (T)prev;
+ }
+ prev = prev.getNextSibling();
+ }
+ }
+
+ @Nullable
+ @SuppressWarnings("unchecked")
+ public <T> T findPrevSiblingByClass(@NotNull Class<T> cls) {
+ PsiElement prev = getPrevSibling();
+ while (true) {
+ if (prev == null) {
+ return null;
+ } else if (cls.isInstance(prev)) {
+ return (T)prev;
+ }
+ prev = prev.getPrevSibling();
+ }
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliEndLocalDebugStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliEndLocalDebugStatement.java
new file mode 100644
index 00000000..042596cf
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliEndLocalDebugStatement.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliEndLocalDebugStatement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliEndLocalDebugStatement();
+ }
+ };
+
+ public SmaliEndLocalDebugStatement() {
+ super(SmaliElementTypes.END_LOCAL_DEBUG_STATEMENT);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliEpilogueDebugStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliEpilogueDebugStatement.java
new file mode 100644
index 00000000..faaef090
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliEpilogueDebugStatement.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliEpilogueDebugStatement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliEpilogueDebugStatement();
+ }
+ };
+
+ public SmaliEpilogueDebugStatement() {
+ super(SmaliElementTypes.EPILOGUE_DEBUG_STATEMENT);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliExtendsList.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliExtendsList.java
new file mode 100644
index 00000000..ace9a976
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliExtendsList.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.google.common.collect.Lists;
+import com.intellij.lang.ASTNode;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.stub.SmaliExtendsListStub;
+
+import java.util.List;
+
+public class SmaliExtendsList extends SmaliBaseReferenceList<SmaliExtendsListStub> {
+ public SmaliExtendsList(@NotNull SmaliExtendsListStub stub) {
+ super(stub, SmaliElementTypes.EXTENDS_LIST);
+ }
+
+ public SmaliExtendsList(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ @NotNull @Override public SmaliClassTypeElement[] getReferenceElements() {
+ if (((SmaliClass)getParent()).isInterface()) {
+ return getImplementsElements();
+ } else {
+ return getExtendsElement();
+ }
+ }
+
+ @NotNull private SmaliClassTypeElement[] getImplementsElements() {
+ SmaliClass smaliClass = getStubOrPsiParentOfType(SmaliClass.class);
+ assert smaliClass != null;
+
+ SmaliImplementsStatement[] implementsStatements = smaliClass.getImplementsStatements();
+ if (implementsStatements.length > 0) {
+ // all implemented interfaces go in the extends list for an interface
+ List<SmaliClassTypeElement> types = Lists.newArrayList();
+
+ for (SmaliImplementsStatement implementsStatement: implementsStatements) {
+ SmaliClassTypeElement classReference = implementsStatement.getClassReference();
+ if (classReference != null) {
+ types.add(classReference);
+ }
+ }
+ return types.toArray(new SmaliClassTypeElement[types.size()]);
+ }
+ return new SmaliClassTypeElement[0];
+ }
+
+ @NotNull private SmaliClassTypeElement[] getExtendsElement() {
+ SmaliClass smaliClass = getStubOrPsiParentOfType(SmaliClass.class);
+ assert smaliClass != null;
+
+ SmaliSuperStatement superStatement = smaliClass.getSuperStatement();
+ if (superStatement != null) {
+ SmaliClassTypeElement classReference = superStatement.getClassReference();
+ if (classReference != null) {
+ return new SmaliClassTypeElement[] { classReference };
+ }
+ }
+ return new SmaliClassTypeElement[0];
+ }
+
+ @Override public Role getRole() {
+ return Role.EXTENDS_LIST;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliField.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliField.java
new file mode 100644
index 00000000..7bef4e94
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliField.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.lang.ASTNode;
+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 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.NameUtils;
+
+public class SmaliField extends SmaliStubBasedPsiElement<SmaliFieldStub> implements PsiField, SmaliModifierListOwner {
+ public SmaliField(@NotNull SmaliFieldStub stub) {
+ super(stub, SmaliElementTypes.FIELD);
+ }
+
+ public SmaliField(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ @Nullable @Override public String getName() {
+ SmaliFieldStub stub = getStub();
+ if (stub != null) {
+ return stub.getName();
+ }
+
+ SmaliMemberName smaliMemberName = findChildByClass(SmaliMemberName.class);
+ if (smaliMemberName == null || smaliMemberName.getText().isEmpty()) {
+ return null;
+ }
+ return smaliMemberName.getText();
+ }
+
+ @NotNull @Override public SmaliModifierList getModifierList() {
+ SmaliModifierList modifierList = getStubOrPsiChild(SmaliElementTypes.MODIFIER_LIST);
+ assert modifierList != null;
+ return modifierList;
+ }
+
+ @NotNull @Override public SmaliMemberName getNameIdentifier() {
+ SmaliMemberName memberName = findChildByClass(SmaliMemberName.class);
+ assert memberName != null;
+ return memberName;
+ }
+
+ @Nullable @Override public PsiDocComment getDocComment() {
+ return null;
+ }
+
+ @Override public boolean isDeprecated() {
+ return PsiImplUtil.isDeprecatedByAnnotation(this);
+ }
+
+ @Nullable @Override public PsiClass getContainingClass() {
+ return (PsiClass)getStubOrPsiParent();
+ }
+
+ @NotNull @Override public PsiType getType() {
+ SmaliFieldStub stub = getStub();
+ if (stub != null) {
+ return NameUtils.resolveSmaliToPsiType(this, stub.getSmaliTypeName());
+ }
+ PsiTypeElement typeElement = getTypeElement();
+ if (typeElement == null) {
+ // If we don't have a type (i.e. syntax error), use Object as a safe-ish fallback
+ PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
+ return factory.createTypeFromText("java.lang.Object", this);
+ }
+ return getTypeElement().getType();
+ }
+
+ @Nullable @Override public SmaliTypeElement getTypeElement() {
+ return findChildByClass(SmaliTypeElement.class);
+ }
+
+ @Nullable @Override public PsiExpression getInitializer() {
+ // TODO: implement this
+ return null;
+ }
+
+ @Override public boolean hasInitializer() {
+ // TODO: implement this
+ return false;
+ }
+
+ @Override public void normalizeDeclaration() throws IncorrectOperationException {
+ // not applicable
+ }
+
+ @Nullable @Override public Object computeConstantValue() {
+ // TODO: implement this
+ return null;
+ }
+
+ @Override public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
+ SmaliMemberName smaliMemberName = getNameIdentifier();
+ smaliMemberName.setName(name);
+ return this;
+ }
+
+ @Override public boolean hasModifierProperty(@ModifierConstant @NonNls @NotNull String name) {
+ return getModifierList().hasModifierProperty(name);
+ }
+
+ @NotNull @Override public SmaliAnnotation[] getAnnotations() {
+ return getStubOrPsiChildren(SmaliElementTypes.ANNOTATION, new SmaliAnnotation[0]);
+ }
+
+ @NotNull @Override public SmaliAnnotation[] getApplicableAnnotations() {
+ return getAnnotations();
+ }
+
+ @Nullable @Override public SmaliAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
+ for (SmaliAnnotation annotation: getAnnotations()) {
+ if (qualifiedName.equals(annotation.getQualifiedName())) {
+ return annotation;
+ }
+ }
+ return null;
+ }
+
+ @NotNull @Override public SmaliAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
+ // TODO: implement this
+ return null;
+ }
+
+ @Override public void setInitializer(@Nullable PsiExpression initializer) throws IncorrectOperationException {
+ // TODO: implement this
+ }
+
+ @Override public int getTextOffset() {
+ SmaliMemberName smaliMemberName = getNameIdentifier();
+ if (smaliMemberName != null) {
+ return smaliMemberName.getTextOffset();
+ }
+ return super.getTextOffset();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliFieldInitializer.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliFieldInitializer.java
new file mode 100644
index 00000000..dcf0e858
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliFieldInitializer.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliFieldInitializer extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliFieldInitializer();
+ }
+ };
+
+ public SmaliFieldInitializer() {
+ super(SmaliElementTypes.FIELD_INITIALIZER);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliFieldReference.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliFieldReference.java
new file mode 100644
index 00000000..0626c3a2
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliFieldReference.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiReference;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliFieldReference extends SmaliCompositeElement implements PsiReference {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliFieldReference();
+ }
+ };
+
+ public SmaliFieldReference() {
+ super(SmaliElementTypes.FIELD_REFERENCE);
+ }
+
+ @Nullable
+ public PsiClass getContainingClass() {
+ SmaliClassTypeElement containingClassReference = getContainingType();
+ if (containingClassReference == null) {
+ return null;
+ }
+ PsiClass containingClass = containingClassReference.resolve();
+ if (containingClass == null) {
+ return null;
+ }
+
+ return containingClass;
+ }
+
+ @Nullable
+ public SmaliClassTypeElement getContainingType() {
+ return findChildByClass(SmaliClassTypeElement.class);
+ }
+
+ @Nullable
+ public SmaliMemberName getMemberName() {
+ return findChildByClass(SmaliMemberName.class);
+ }
+
+ @Nullable
+ public SmaliTypeElement getFieldType() {
+ SmaliTypeElement[] types = findChildrenByClass(SmaliTypeElement.class);
+ assert types.length == 2;
+ return types[1];
+ }
+
+ @Override public PsiReference getReference() {
+ return this;
+ }
+
+ @Override public String getName() {
+ SmaliMemberName memberName = getMemberName();
+ if (memberName == null) {
+ return null;
+ }
+ return memberName.getText();
+ }
+
+ @Override public PsiElement getElement() {
+ return this;
+ }
+
+ @Override public TextRange getRangeInElement() {
+ return new TextRange(0, getTextLength());
+ }
+
+ @NotNull @Override public String getCanonicalText() {
+ return getText();
+ }
+
+ @Nullable @Override public PsiField resolve() {
+ PsiClass containingClass = getContainingClass();
+ if (containingClass == null) {
+ return null;
+ }
+
+ SmaliMemberName memberName = getMemberName();
+ if (memberName == null) {
+ return null;
+ }
+
+ return containingClass.findFieldByName(memberName.getText(), true);
+ }
+
+ @Override public boolean isReferenceTo(PsiElement element) {
+ return resolve() == element;
+ }
+
+ @NotNull @Override public Object[] getVariants() {
+ return ArrayUtil.EMPTY_OBJECT_ARRAY;
+ }
+
+ @Override public boolean isSoft() {
+ return false;
+ }
+
+ @Override public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
+ //TODO: implement this
+ throw new IncorrectOperationException();
+ }
+
+ @Override public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ SmaliMemberName memberName = getMemberName();
+ if (memberName == null) {
+ throw new IncorrectOperationException();
+ }
+ memberName.setName(newElementName);
+ return this;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliFile.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliFile.java
new file mode 100644
index 00000000..6ec3bd5f
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliFile.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.extapi.psi.PsiFileBase;
+import com.intellij.psi.FileViewProvider;
+import com.intellij.psi.PsiClassOwner;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.SmaliFileType;
+import org.jf.smalidea.SmaliLanguage;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliFile extends PsiFileBase implements PsiClassOwner {
+ public SmaliFile(FileViewProvider viewProvider) {
+ super(viewProvider, SmaliLanguage.INSTANCE);
+ }
+
+ @NotNull @Override public SmaliFileType getFileType() {
+ return SmaliFileType.INSTANCE;
+ }
+
+ @Nullable
+ public SmaliClass getPsiClass() {
+ StubElement<? extends PsiElement> stub = (StubElement<? extends PsiElement>)getStub();
+ if (stub != null) {
+ StubElement<SmaliClass> classElement = stub.findChildStubByType(SmaliElementTypes.CLASS);
+ if (classElement != null) {
+ return classElement.getPsi();
+ } else {
+ return null;
+ }
+ } else {
+ return findChildByClass(SmaliClass.class);
+ }
+ }
+
+ @NotNull @Override public SmaliClass[] getClasses() {
+ SmaliClass smaliClass = getPsiClass();
+ if (smaliClass == null) {
+ return new SmaliClass[] {};
+ } else {
+ return new SmaliClass[] { smaliClass };
+ }
+ }
+
+ @NotNull @Override public String getPackageName() {
+ SmaliClass smaliClass = getPsiClass();
+ if (smaliClass == null) {
+ return "";
+ }
+ return smaliClass.getPackageName();
+ }
+
+ @Override public void setPackageName(String packageName) throws IncorrectOperationException {
+ SmaliClass smaliClass = getPsiClass();
+ if (smaliClass == null) {
+ return;
+ }
+ smaliClass.setPackageName(packageName);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliImplementsList.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliImplementsList.java
new file mode 100644
index 00000000..8992ab0b
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliImplementsList.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.google.common.collect.Lists;
+import com.intellij.lang.ASTNode;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.stub.SmaliImplementsListStub;
+
+import java.util.List;
+
+public class SmaliImplementsList extends SmaliBaseReferenceList<SmaliImplementsListStub> {
+ public SmaliImplementsList(@NotNull SmaliImplementsListStub stub) {
+ super(stub, SmaliElementTypes.IMPLEMENTS_LIST);
+ }
+
+ public SmaliImplementsList(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ @NotNull @Override public SmaliClassTypeElement[] getReferenceElements() {
+ if (!((SmaliClass)getParent()).isInterface()) {
+ return getImplementsElements();
+ }
+ return new SmaliClassTypeElement[0];
+ }
+
+ @NotNull private SmaliClassTypeElement[] getImplementsElements() {
+ SmaliClass smaliClass = (SmaliClass)getStubOrPsiParent();
+ assert smaliClass != null;
+
+ SmaliImplementsStatement[] implementsStatements = smaliClass.getImplementsStatements();
+ if (implementsStatements.length > 0) {
+ // all implemented interfaces go in the extends list for an interface
+ List<SmaliClassTypeElement> types = Lists.newArrayList();
+
+ for (SmaliImplementsStatement implementsStatement: implementsStatements) {
+ SmaliClassTypeElement classReference = implementsStatement.getClassReference();
+ if (classReference != null) {
+ types.add(classReference);
+ }
+ }
+ return types.toArray(new SmaliClassTypeElement[types.size()]);
+ }
+ return new SmaliClassTypeElement[0];
+ }
+
+ @Override public Role getRole() {
+ return Role.IMPLEMENTS_LIST;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliImplementsStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliImplementsStatement.java
new file mode 100644
index 00000000..e50d8c6b
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliImplementsStatement.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliImplementsStatement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliImplementsStatement();
+ }
+ };
+
+ public SmaliImplementsStatement() {
+ super(SmaliElementTypes.IMPLEMENTS_STATEMENT);
+ }
+
+ @Nullable
+ public SmaliClassTypeElement getClassReference() {
+ return findChildByClass(SmaliClassTypeElement.class);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliInstruction.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliInstruction.java
new file mode 100644
index 00000000..8cb2d77a
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliInstruction.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.google.common.base.Preconditions;
+import com.intellij.lang.ASTNode;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.dexlib2.Format;
+import org.jf.dexlib2.Opcode;
+import org.jf.dexlib2.Opcodes;
+import org.jf.dexlib2.analysis.AnalyzedInstruction;
+import org.jf.dexlib2.analysis.MethodAnalyzer;
+import org.jf.smalidea.SmaliTokens;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class SmaliInstruction extends SmaliCompositeElement {
+ private static final int NO_OFFSET = -1;
+
+ @Nullable private Opcode opcode;
+ private int offset = NO_OFFSET;
+
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliInstruction();
+ }
+ };
+
+ public SmaliInstruction() {
+ super(SmaliElementTypes.INSTRUCTION);
+ }
+
+ @NotNull public SmaliMethod getParentMethod() {
+ SmaliMethod smaliMethod = findAncestorByClass(SmaliMethod.class);
+ assert smaliMethod != null;
+ return smaliMethod;
+ }
+
+ @NotNull public Opcode getOpcode() {
+ if (opcode == null) {
+ ASTNode instructionNode = findChildByType(SmaliTokens.INSTRUCTION_TOKENS);
+ // this should be impossible, based on the parser definition
+ assert instructionNode != null;
+
+ // TODO: put a project level Opcodes instance with the appropriate api level somewhere
+ opcode = new Opcodes(15, false).getOpcodeByName(instructionNode.getText());
+ if (opcode == null) {
+ if (instructionNode.getText().equals(".packed-switch")) {
+ return Opcode.PACKED_SWITCH_PAYLOAD;
+ }
+ if (instructionNode.getText().equals(".sparse-switch")) {
+ return Opcode.SPARSE_SWITCH_PAYLOAD;
+ }
+ if (instructionNode.getText().equals(".array-data")) {
+ return Opcode.ARRAY_PAYLOAD;
+ }
+ assert false;
+ }
+ }
+ return opcode;
+ }
+
+ public int getOffset() {
+ // TODO: don't calculate this recursively. ugh!
+ if (offset == NO_OFFSET) {
+ SmaliInstruction previousInstruction = findPrevSiblingByClass(SmaliInstruction.class);
+ if (previousInstruction == null) {
+ offset = 0;
+ } else {
+ offset = previousInstruction.getOffset() + previousInstruction.getInstructionSize();
+ }
+ }
+ return offset;
+ }
+
+ public int getRegister(int registerIndex) {
+ Preconditions.checkArgument(registerIndex >= 0);
+
+ List<ASTNode> registers = findChildrenByType(SmaliElementTypes.REGISTER_REFERENCE);
+ if (registerIndex >= registers.size()) {
+ return -1;
+ }
+
+ SmaliRegisterReference registerReference = (SmaliRegisterReference)registers.get(registerIndex);
+ return registerReference.getRegisterNumber();
+ }
+
+ @Nullable
+ public SmaliLabelReference getTarget() {
+ return findChildByClass(SmaliLabelReference.class);
+ }
+
+ public int getRegisterCount() {
+ return findChildrenByType(SmaliElementTypes.REGISTER_REFERENCE).size();
+ }
+
+ @Nullable
+ public SmaliLiteral getLiteral() {
+ return findChildByClass(SmaliLiteral.class);
+ }
+
+ @Nullable
+ public SmaliTypeElement getTypeReference() {
+ return findChildByClass(SmaliTypeElement.class);
+ }
+
+ @Nullable
+ public SmaliFieldReference getFieldReference() {
+ return findChildByClass(SmaliFieldReference.class);
+ }
+
+ @Nullable
+ public SmaliMethodReference getMethodReference() {
+ return findChildByClass(SmaliMethodReference.class);
+ }
+
+ @Nullable
+ public SmaliLiteral getPackedSwitchStartKey() {
+ return findChildByClass(SmaliLiteral.class);
+ }
+
+ @NotNull
+ public List<SmaliPackedSwitchElement> getPackedSwitchElements() {
+ return Arrays.asList(findChildrenByClass(SmaliPackedSwitchElement.class));
+ }
+
+ @NotNull
+ public List<SmaliSparseSwitchElement> getSparseSwitchElements() {
+ return Arrays.asList(findChildrenByClass(SmaliSparseSwitchElement.class));
+ }
+
+ @Nullable
+ public SmaliLiteral getArrayDataWidth() {
+ return findChildByClass(SmaliLiteral.class);
+ }
+
+ @NotNull
+ public List<SmaliArrayDataElement> getArrayDataElements() {
+ return Arrays.asList(findChildrenByClass(SmaliArrayDataElement.class));
+ }
+
+ public int getInstructionSize() {
+ Opcode opcode = getOpcode();
+ if (!opcode.format.isPayloadFormat) {
+ return opcode.format.size;
+ } else if (opcode.format == Format.ArrayPayload) {
+ int elementWidth = (int)getArrayDataWidth().getIntegralValue();
+ int elementCount = getArrayDataElements().size();
+
+ return 8 + (elementWidth * elementCount + 1);
+ } else if (opcode.format == Format.PackedSwitchPayload) {
+ return 8 + getPackedSwitchElements().size() * 4;
+ } else if (opcode.format == Format.SparseSwitchPayload) {
+ return 2 + getSparseSwitchElements().size() * 4;
+ }
+ assert false;
+ throw new RuntimeException();
+ }
+
+ private AnalyzedInstruction analyzedInstruction = null;
+
+ @Nullable
+ private AnalyzedInstruction getAnalyzedInstructionFromMethod() {
+ SmaliMethod method = getParentMethod();
+
+ MethodAnalyzer analyzer = method.getMethodAnalyzer();
+ if (analyzer == null) {
+ return null;
+ }
+
+ int thisOffset = this.getOffset() / 2;
+ int codeOffset = 0;
+
+ for (AnalyzedInstruction instruction: analyzer.getAnalyzedInstructions()) {
+ if (codeOffset == thisOffset) {
+ return instruction;
+ }
+ assert codeOffset < thisOffset;
+
+ codeOffset += instruction.getOriginalInstruction().getCodeUnits();
+ }
+ assert false;
+ return null;
+ }
+
+ @Nullable
+ public AnalyzedInstruction getAnalyzedInstruction() {
+ if (analyzedInstruction == null) {
+ analyzedInstruction = getAnalyzedInstructionFromMethod();
+ }
+ return analyzedInstruction;
+ }
+
+ @Override public void clearCaches() {
+ super.clearCaches();
+ analyzedInstruction = null;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLabel.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLabel.java
new file mode 100644
index 00000000..b07220dd
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLabel.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliLabel extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliLabel();
+ }
+ };
+
+ public SmaliLabel() {
+ super(SmaliElementTypes.LABEL);
+ }
+
+ @Override public String getName() {
+ return getText().substring(1);
+ }
+
+ @Nullable
+ public SmaliInstruction getInstruction() {
+ return findNextSiblingByClass(SmaliInstruction.class);
+ }
+
+ @Nullable
+ private SmaliInstruction getPreviousInstruction() {
+ return findPrevSiblingByClass(SmaliInstruction.class);
+ }
+
+ public int getOffset() {
+ SmaliInstruction instruction = getInstruction();
+ if (instruction == null) {
+ instruction = getPreviousInstruction();
+ if (instruction == null) {
+ return 0;
+ }
+ // TODO: handle variable size instructions
+ return instruction.getOffset() + instruction.getOpcode().format.size;
+ }
+ return instruction.getOffset();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLabelReference.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLabelReference.java
new file mode 100644
index 00000000..940f4296
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLabelReference.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliLabelReference extends SmaliCompositeElement implements PsiReference {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliLabelReference();
+ }
+ };
+
+ public SmaliLabelReference() {
+ super(SmaliElementTypes.LABEL_REFERENCE);
+ }
+
+ @Override public String getName() {
+ return getText().substring(1);
+ }
+
+ @Override public PsiReference getReference() {
+ return this;
+ }
+
+ @Override public PsiElement getElement() {
+ return this;
+ }
+
+ @Override public TextRange getRangeInElement() {
+ return new TextRange(0, getTextLength());
+ }
+
+ @Nullable @Override public SmaliLabel resolve() {
+ SmaliMethod method = findAncestorByClass(SmaliMethod.class);
+ if (method == null) {
+ return null;
+ }
+ return method.getLabel(getText());
+ }
+
+ @NotNull @Override public String getCanonicalText() {
+ return getText();
+ }
+
+ @Override public boolean isReferenceTo(PsiElement element) {
+ return resolve() == element;
+ }
+
+ @NotNull @Override public Object[] getVariants() {
+ return ArrayUtil.EMPTY_OBJECT_ARRAY;
+ }
+
+ @Override public boolean isSoft() {
+ return false;
+ }
+
+ @Override public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ //TODO: implement this
+ throw new IncorrectOperationException();
+ }
+
+ @Override public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
+ //TODO: implement this
+ throw new IncorrectOperationException();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLineDebugStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLineDebugStatement.java
new file mode 100644
index 00000000..7ea3227b
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLineDebugStatement.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliLineDebugStatement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliLineDebugStatement();
+ }
+ };
+
+ public SmaliLineDebugStatement() {
+ super(SmaliElementTypes.LINE_DEBUG_STATEMENT);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLiteral.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLiteral.java
new file mode 100644
index 00000000..0a9f5382
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLiteral.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiAnnotationMemberValue;
+import com.intellij.psi.tree.IElementType;
+import org.jf.smali.LiteralTools;
+import org.jf.smalidea.SmaliTokens;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliLiteral extends SmaliCompositeElement implements PsiAnnotationMemberValue {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliLiteral();
+ }
+ };
+
+ public SmaliLiteral() {
+ super(SmaliElementTypes.LITERAL);
+ }
+
+ public long getIntegralValue() {
+ ASTNode literalNode = getNode().getFirstChildNode();
+ IElementType literalType = literalNode.getElementType();
+
+ if (literalType == SmaliTokens.LONG_LITERAL) {
+ return LiteralTools.parseLong(literalNode.getText());
+ } else if (literalType == SmaliTokens.NEGATIVE_INTEGER_LITERAL ||
+ literalType == SmaliTokens.POSITIVE_INTEGER_LITERAL) {
+ return LiteralTools.parseInt(literalNode.getText());
+ } else if (literalType == SmaliTokens.SHORT_LITERAL) {
+ return LiteralTools.parseShort(literalNode.getText());
+ } else if (literalType == SmaliTokens.CHAR_LITERAL) {
+ // TODO: implement this
+ return -1;
+ } else if (literalType == SmaliTokens.BYTE_LITERAL) {
+ return LiteralTools.parseByte(literalNode.getText());
+ } else if (literalType == SmaliTokens.BOOL_LITERAL) {
+ return Boolean.parseBoolean(literalNode.getText())?1:0;
+ } else {
+ throw new RuntimeException("Not an integral literal");
+ }
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLocalDebugStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLocalDebugStatement.java
new file mode 100644
index 00000000..02d1748c
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLocalDebugStatement.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliLocalDebugStatement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliLocalDebugStatement();
+ }
+ };
+
+ public SmaliLocalDebugStatement() {
+ super(SmaliElementTypes.LOCAL_DEBUG_STATEMENT);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLocalName.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLocalName.java
new file mode 100644
index 00000000..6ade23a4
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLocalName.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.psi.PsiIdentifier;
+import com.intellij.psi.tree.IElementType;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliLocalName extends SmaliCompositeElement implements PsiIdentifier {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliLocalName();
+ }
+ };
+
+ public SmaliLocalName() {
+ super(SmaliElementTypes.LOCAL_NAME);
+ }
+
+ @Override public IElementType getTokenType() {
+ return getNode().getElementType();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMemberName.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMemberName.java
new file mode 100644
index 00000000..f3377366
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMemberName.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.psi.PsiIdentifier;
+import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.leaf.SmaliSimpleName;
+
+public class SmaliMemberName extends SmaliCompositeElement implements PsiIdentifier {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliMemberName();
+ }
+ };
+
+ public SmaliMemberName() {
+ super(SmaliElementTypes.MEMBER_NAME);
+ }
+
+ @Override public IElementType getTokenType() {
+ return getElementType();
+ }
+
+ @Override
+ public String getName() {
+ return this.getText();
+ }
+
+ public void setName(@NotNull String newElementName) {
+ removeAllChildren();
+ SmaliSimpleName newNameElement = new SmaliSimpleName(newElementName);
+ CodeEditUtil.setNodeGenerated(newNameElement, true);
+
+ addChild(newNameElement);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java
new file mode 100644
index 00000000..085585bb
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.Maps;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.lang.ASTNode;
+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.util.IncorrectOperationException;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+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;
+
+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 {
+ public SmaliMethod(@NotNull SmaliMethodStub stub) {
+ super(stub, SmaliElementTypes.METHOD);
+ }
+
+ public SmaliMethod(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ @NotNull @Override public String getName() {
+ SmaliMethodStub stub = getStub();
+ String name = null;
+ if (stub != null) {
+ name = stub.getName();
+ } else {
+ SmaliMemberName nameIdentifier = getNameIdentifier();
+ if (nameIdentifier != null) {
+ name = nameIdentifier.getText();
+ }
+ }
+ if (name == null || name.isEmpty()) {
+ name = "<unnamed>";
+ }
+ return name;
+ }
+
+ @Override public boolean hasTypeParameters() {
+ // TODO: (generics) implement this
+ return false;
+ }
+
+ @NotNull
+ public SmaliMethodPrototype getMethodPrototype() {
+ return getRequiredStubOrPsiChild(SmaliElementTypes.METHOD_PROTOTYPE);
+ }
+
+ @Nullable @Override public PsiType getReturnType() {
+ if (isConstructor()) return null;
+ return getMethodPrototype().getReturnType();
+ }
+
+ @Nullable @Override public PsiTypeElement getReturnTypeElement() {
+ if (isConstructor()) return null;
+ return getMethodPrototype().getReturnTypeElement();
+ }
+
+ @NotNull @Override public SmaliMethodParamList getParameterList() {
+ return getMethodPrototype().getParameterList();
+ }
+
+ @NotNull @Override public SmaliThrowsList getThrowsList() {
+ return getRequiredStubOrPsiChild(SmaliElementTypes.THROWS_LIST);
+ }
+
+ @Nullable @Override public PsiCodeBlock getBody() {
+ // not applicable
+ return null;
+ }
+
+ @NotNull public List<SmaliInstruction> getInstructions() {
+ return findChildrenByType(SmaliElementTypes.INSTRUCTION);
+ }
+
+ @NotNull public List<SmaliCatchStatement> getCatchStatements() {
+ return Arrays.asList(findChildrenByClass(SmaliCatchStatement.class));
+ }
+
+ @Nullable public SourcePosition getSourcePositionForCodeOffset(int offset) {
+ for (SmaliInstruction instruction: getInstructions()) {
+ if (instruction.getOffset() >= offset) {
+ return SourcePosition.createFromElement(instruction);
+ }
+ }
+ return null;
+ }
+
+ public int getOffsetForLine(int line) {
+ PsiDocumentManager documentManager = PsiDocumentManager.getInstance(getProject());
+ final Document document = documentManager.getDocument(getContainingFile());
+ if (document == null) {
+ return -1;
+ }
+
+ for (final SmaliInstruction instruction: getInstructions()) {
+ int curLine = document.getLineNumber(instruction.getTextOffset());
+ if (curLine >= line) {
+ return instruction.getOffset();
+ }
+ }
+ return -1;
+ }
+
+ public int getRegisterCount() {
+ SmaliRegistersStatement registersStatement = findChildByClass(SmaliRegistersStatement.class);
+ if (registersStatement == null) {
+ return 0;
+ }
+ return registersStatement.getRegisterCount();
+ }
+
+ public int getParameterRegisterCount() {
+ int parameterRegisterCount = getMethodPrototype().getParameterList().getParameterRegisterCount();
+ if (!isStatic()) {
+ parameterRegisterCount++;
+ }
+ return parameterRegisterCount;
+ }
+
+ @NotNull public SmaliParameterStatement[] getParameterStatements() {
+ return findChildrenByClass(SmaliParameterStatement.class);
+ }
+
+ @Override public boolean isConstructor() {
+ // TODO: should this return true for the class initializer?
+ return hasModifierProperty("constructor") && !hasModifierProperty("static");
+ }
+
+ public boolean isStatic() {
+ return hasModifierProperty("static");
+ }
+
+ @Override public boolean isVarArgs() {
+ return hasModifierProperty("varargs");
+ }
+
+ @NotNull @Override public MethodSignature getSignature(@NotNull PsiSubstitutor substitutor) {
+ return MethodSignatureBackedByPsiMethod.create(this, substitutor);
+ }
+
+ @Nullable @Override public SmaliMemberName getNameIdentifier() {
+ return findChildByClass(SmaliMemberName.class);
+ }
+
+ @NotNull @Override public PsiMethod[] findSuperMethods() {
+ return PsiSuperMethodImplUtil.findSuperMethods(this);
+ }
+
+ @NotNull @Override public PsiMethod[] findSuperMethods(boolean checkAccess) {
+ return PsiSuperMethodImplUtil.findSuperMethods(this, checkAccess);
+ }
+
+ @NotNull @Override public PsiMethod[] findSuperMethods(PsiClass parentClass) {
+ return PsiSuperMethodImplUtil.findSuperMethods(this, parentClass);
+ }
+
+ @NotNull @Override
+ public List<MethodSignatureBackedByPsiMethod> findSuperMethodSignaturesIncludingStatic(boolean checkAccess) {
+ return PsiSuperMethodImplUtil.findSuperMethodSignaturesIncludingStatic(this, checkAccess);
+ }
+
+ @Nullable @Override public PsiMethod findDeepestSuperMethod() {
+ return PsiSuperMethodImplUtil.findDeepestSuperMethod(this);
+ }
+
+ @NotNull @Override public PsiMethod[] findDeepestSuperMethods() {
+ return PsiSuperMethodImplUtil.findDeepestSuperMethods(this);
+ }
+
+ @NotNull @Override public SmaliModifierList getModifierList() {
+ return getRequiredStubOrPsiChild(SmaliElementTypes.MODIFIER_LIST);
+ }
+
+ @Override public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
+ SmaliMemberName smaliMemberName = getNameIdentifier();
+ if (smaliMemberName == null) {
+ throw new IncorrectOperationException();
+ }
+ smaliMemberName.setName(name);
+ return this;
+ }
+
+ @NotNull @Override public HierarchicalMethodSignature getHierarchicalMethodSignature() {
+ return PsiSuperMethodImplUtil.getHierarchicalMethodSignature(this);
+ }
+
+ @Nullable @Override public PsiDocComment getDocComment() {
+ // not applicable
+ return null;
+ }
+
+ @Override public boolean isDeprecated() {
+ return PsiImplUtil.isDeprecatedByAnnotation(this);
+ }
+
+ @Nullable @Override public PsiTypeParameterList getTypeParameterList() {
+ // TODO: (generics) implement this
+ return null;
+ }
+
+ @NotNull @Override public PsiTypeParameter[] getTypeParameters() {
+ // TODO: (generics) implement this
+ return new PsiTypeParameter[0];
+ }
+
+ @Nullable @Override public SmaliClass getContainingClass() {
+ PsiElement parent = getStubOrPsiParent();
+ if (parent instanceof SmaliClass) {
+ return (SmaliClass) parent;
+ }
+ return null;
+ }
+
+ @Override public boolean hasModifierProperty(@ModifierConstant @NonNls @NotNull String name) {
+ return getModifierList().hasModifierProperty(name);
+ }
+
+ @NotNull @Override public SmaliAnnotation[] getAnnotations() {
+ return getStubOrPsiChildren(SmaliElementTypes.ANNOTATION, new SmaliAnnotation[0]);
+ }
+
+ @NotNull @Override public SmaliAnnotation[] getApplicableAnnotations() {
+ return getAnnotations();
+ }
+
+ @Nullable @Override public SmaliAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
+ for (SmaliAnnotation annotation: getAnnotations()) {
+ if (qualifiedName.equals(annotation.getQualifiedName())) {
+ return annotation;
+ }
+ }
+ return null;
+ }
+
+ @NotNull @Override public SmaliAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
+ // TODO: implement this
+ return null;
+ }
+
+ private final Supplier<Map<String, SmaliLabel>> labelMap = Suppliers.memoize(
+ new Supplier<Map<String, SmaliLabel>>() {
+ @Override public Map<String, SmaliLabel> get() {
+ Map<String, SmaliLabel> labelMap = Maps.newHashMap();
+ for (SmaliLabel label: findChildrenByClass(SmaliLabel.class)) {
+ if (!labelMap.containsKey(label.getText())) {
+ labelMap.put(label.getText(), label);
+ }
+ }
+ return labelMap;
+ }
+ });
+
+ @Nullable public SmaliLabel getLabel(String name) {
+ return labelMap.get().get(name);
+ }
+
+ private MethodAnalyzer methodAnalyzer = null;
+
+ @Nullable
+ public MethodAnalyzer getMethodAnalyzer() {
+ if (methodAnalyzer == null) {
+ if (!PsiTreeUtil.hasErrorElements(this)) {
+ ClassPath classPath;
+ try {
+ classPath = new ClassPath(
+ new SmalideaClassProvider(getProject(), getContainingFile().getVirtualFile()));
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ try {
+ methodAnalyzer = new MethodAnalyzer(classPath, new SmalideaMethod(SmaliMethod.this), null, false);
+ } catch (AnalysisException ex) {
+ methodAnalyzer = null;
+ }
+ }
+ }
+ return methodAnalyzer;
+ }
+
+ @Override public void subtreeChanged() {
+ super.subtreeChanged();
+ methodAnalyzer = null;
+ }
+
+ @Override public int getTextOffset() {
+ SmaliMemberName smaliMemberName = getNameIdentifier();
+ if (smaliMemberName != null) {
+ return smaliMemberName.getTextOffset();
+ }
+ return super.getTextOffset();
+ }
+
+ @Nullable @Override public PsiAnnotationMemberValue getDefaultValue() {
+ SmaliClass containingClass = getContainingClass();
+ if (containingClass == null || !containingClass.isAnnotationType()) {
+ return null;
+ }
+
+ for (SmaliAnnotation annotation: containingClass.getAnnotations()) {
+ String annotationType = annotation.getQualifiedName();
+ if (annotationType == null) {
+ continue;
+ }
+ if (annotationType.equals("dalvik.annotation.AnnotationDefault")) {
+ PsiAnnotationMemberValue value = annotation.findAttributeValue("value");
+ if (!(value instanceof SmaliAnnotation)) {
+ return null;
+ }
+ SmaliAnnotation valueSubAnnotation = (SmaliAnnotation)value;
+ return valueSubAnnotation.findAttributeValue(getName());
+ }
+ }
+ return null;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodParamList.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodParamList.java
new file mode 100644
index 00000000..0b759f02
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodParamList.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiParameter;
+import com.intellij.psi.PsiParameterList;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.stub.SmaliMethodParamListStub;
+
+import java.util.Arrays;
+
+public class SmaliMethodParamList extends SmaliStubBasedPsiElement<SmaliMethodParamListStub>
+ implements PsiParameterList {
+ public SmaliMethodParamList(@NotNull SmaliMethodParamListStub stub) {
+ super(stub, SmaliElementTypes.METHOD_PARAM_LIST);
+ }
+
+ public SmaliMethodParamList(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ @NotNull @Override public SmaliMethodParameter[] getParameters() {
+ return getStubOrPsiChildren(SmaliElementTypes.METHOD_PARAMETER, new SmaliMethodParameter[0]);
+ }
+
+ @Override public int getParameterIndex(PsiParameter parameter) {
+ if (!(parameter instanceof SmaliMethodParameter)) {
+ return -1;
+ }
+ return Arrays.asList(getParameters()).indexOf(parameter);
+ }
+
+ @Override public int getParametersCount() {
+ return getParameters().length;
+ }
+
+ /**
+ * Returns the number of registers needed for the parameters in this parameter list
+ *
+ * Note: this does *not* include the implicit "this" parameter, if applicable
+ */
+ public int getParameterRegisterCount() {
+ int count = 0;
+ for (SmaliMethodParameter param: getParameters()) {
+ count += param.getRegisterCount();
+ }
+ return count;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodParameter.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodParameter.java
new file mode 100644
index 00000000..93d376e8
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodParameter.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.*;
+import com.intellij.psi.PsiModifier.ModifierConstant;
+import com.intellij.util.IncorrectOperationException;
+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.SmaliMethodParameterStub;
+import org.jf.smalidea.util.NameUtils;
+
+public class SmaliMethodParameter extends SmaliStubBasedPsiElement<SmaliMethodParameterStub>
+ implements PsiParameter, SmaliModifierListOwner {
+ public SmaliMethodParameter(@NotNull SmaliMethodParameterStub stub) {
+ super(stub, SmaliElementTypes.METHOD_PARAMETER);
+ }
+
+ public SmaliMethodParameter(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ @NotNull @Override public SmaliModifierList getModifierList() {
+ return getRequiredStubOrPsiChild(SmaliElementTypes.MODIFIER_LIST);
+ }
+
+ @NotNull @Override public PsiElement getDeclarationScope() {
+ return getParentMethod();
+ }
+
+ @Override public boolean isVarArgs() {
+ if (getType().getArrayDimensions() == 0 || !getParentMethod().isVarArgs()) {
+ return false;
+ }
+
+ SmaliMethodParamList paramList = getStubOrPsiParentOfType(SmaliMethodParamList.class);
+ if (paramList == null) {
+ return false;
+ }
+ SmaliMethodParameter[] parameters = paramList.getParameters();
+ // is this the last parameter?
+ return parameters[parameters.length-1] == this;
+ }
+
+ @NotNull @Override public SmaliTypeElement getTypeElement() {
+ SmaliTypeElement typeElement = findChildByClass(SmaliTypeElement.class);
+ assert typeElement != null;
+ return typeElement;
+ }
+
+ @NotNull @Override public PsiType getType() {
+ SmaliMethodParameterStub stub = getStub();
+ if (stub != null) {
+ return NameUtils.resolveSmaliToPsiType(this, stub.getSmaliTypeName());
+ }
+ return getTypeElement().getType();
+ }
+
+ @Nullable @Override public PsiExpression getInitializer() {
+ // not applicable
+ return null;
+ }
+
+ @Override public boolean hasInitializer() {
+ return false;
+ }
+
+ @Override public void normalizeDeclaration() throws IncorrectOperationException {
+ // not applicable
+ }
+
+ @Nullable @Override public Object computeConstantValue() {
+ // not applicable
+ return null;
+ }
+
+ @Nullable @Override public String getName() {
+ SmaliMethodParameterStub stub = getStub();
+ if (stub != null) {
+ return stub.getName();
+ }
+ SmaliLocalName name = getNameIdentifier();
+ if (name == null) {
+ return null;
+ }
+ // TODO: get the actual string value
+ return getNameIdentifier().getText();
+ }
+
+ @Nullable @Override public SmaliLocalName getNameIdentifier() {
+ SmaliParameterStatement parameterStatement = findParameterStatement();
+ if (parameterStatement == null) {
+ return null;
+ }
+
+ return parameterStatement.getNameIdentifier();
+ }
+
+ @Override public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
+ // TODO: implement this
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean hasModifierProperty(@ModifierConstant @NonNls @NotNull String name) {
+ // not applicable
+ return false;
+ }
+
+ /**
+ * Returns the number of registers required for this parameter. 1 for most types, but 2 for double/long.
+ */
+ public int getRegisterCount() {
+ PsiType type = getType();
+ if (type == PsiType.DOUBLE || type == PsiType.LONG) {
+ return 2;
+ }
+ return 1;
+ }
+
+ @NotNull public SmaliMethod getParentMethod() {
+ SmaliMethod smaliMethod = findStubOrPsiAncestorOfType(SmaliMethod.class);
+ assert smaliMethod != null;
+ return smaliMethod;
+ }
+
+ /**
+ * Gets the parameter register number of this parameters. This is the number of a pNN style register reference.
+ */
+ public int getParameterRegisterNumber() {
+ // TODO: it might be a good idea to cache this, or at least do it non-recursively
+ PsiElement prevSibling = getPrevSibling();
+ if (prevSibling == null) {
+ return getParentMethod().isStatic() ? 0 : 1;
+ }
+ assert prevSibling instanceof SmaliMethodParameter;
+ SmaliMethodParameter prevParam = (SmaliMethodParameter)prevSibling;
+ return prevParam.getParameterRegisterNumber() + prevParam.getRegisterCount();
+ }
+
+ /**
+ * Gets the register number of this parameters. This is the number of a rNN style register reference.
+ */
+ public int getRegisterNumber() {
+ SmaliMethod parentMethod = getParentMethod();
+ return getParameterRegisterNumber() + parentMethod.getRegisterCount() -
+ parentMethod.getParameterRegisterCount();
+ }
+
+ @Nullable
+ private SmaliParameterStatement findParameterStatement() {
+ SmaliMethod parentMethod = getParentMethod();
+
+ for (SmaliParameterStatement parameterStatement: parentMethod.getParameterStatements()) {
+ SmaliRegisterReference registerReference = parameterStatement.getParameterRegister();
+ if (registerReference != null && registerReference.getRegisterNumber() == getRegisterNumber()) {
+ return parameterStatement;
+ }
+ }
+ return null;
+ }
+
+ @NotNull @Override public SmaliAnnotation[] getAnnotations() {
+ SmaliParameterStatement parameterStatement = findParameterStatement();
+ if (parameterStatement == null) {
+ return new SmaliAnnotation[0];
+ }
+ return parameterStatement.getAnnotations();
+ }
+
+ @NotNull @Override public SmaliAnnotation[] getApplicableAnnotations() {
+ return getAnnotations();
+ }
+
+ @Nullable @Override public SmaliAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
+ SmaliParameterStatement parameterStatement = findParameterStatement();
+ if (parameterStatement == null) {
+ return null;
+ }
+ return parameterStatement.findAnnotation(qualifiedName);
+ }
+
+ @NotNull @Override public SmaliAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
+ SmaliParameterStatement parameterStatement = findParameterStatement();
+ if (parameterStatement == null) {
+ // TODO: add a parameter statement for this parameter if not found
+ throw new UnsupportedOperationException();
+ }
+ return parameterStatement.addAnnotation(qualifiedName);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodPrototype.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodPrototype.java
new file mode 100644
index 00000000..3b2aae3b
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodPrototype.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.stub.SmaliMethodPrototypeStub;
+import org.jf.smalidea.util.NameUtils;
+
+public class SmaliMethodPrototype extends SmaliStubBasedPsiElement<SmaliMethodPrototypeStub> {
+ public SmaliMethodPrototype(@NotNull SmaliMethodPrototypeStub stub) {
+ super(stub, SmaliElementTypes.METHOD_PROTOTYPE);
+ }
+
+ public SmaliMethodPrototype(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ @Nullable
+ public PsiType getReturnType() {
+ SmaliMethodPrototypeStub stub = getStub();
+ if (stub != null) {
+ String returnSmaliTypeName = stub.getReturnSmaliTypeName();
+ if (returnSmaliTypeName == null) {
+ return null;
+ }
+ return NameUtils.resolveSmaliToPsiType(this, returnSmaliTypeName);
+ }
+
+ PsiTypeElement returnTypeElement = getReturnTypeElement();
+ if (returnTypeElement == null) {
+ return null;
+ }
+ return returnTypeElement.getType();
+ }
+
+ @Nullable public SmaliTypeElement getReturnTypeElement() {
+ return findChildByClass(SmaliTypeElement.class);
+ }
+
+ @NotNull
+ public SmaliMethodParamList getParameterList() {
+ return getRequiredStubOrPsiChild(SmaliElementTypes.METHOD_PARAM_LIST);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodReference.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodReference.java
new file mode 100644
index 00000000..f8048e9f
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodReference.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.google.common.collect.Lists;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.PsiType;
+import com.intellij.psi.impl.light.LightMethodBuilder;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.SmaliLanguage;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+import javax.annotation.Nonnull;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SmaliMethodReference extends SmaliCompositeElement implements PsiReference {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliMethodReference();
+ }
+ };
+
+ @Override public String getName() {
+ PsiElement memberName = getMemberName();
+ if (memberName == null) {
+ return null;
+ }
+ return memberName.getText();
+ }
+
+ public SmaliMethodReference() {
+ super(SmaliElementTypes.METHOD_REFERENCE);
+ }
+
+ @Override public PsiReference getReference() {
+ return this;
+ }
+
+ @Override public PsiElement getElement() {
+ return this;
+ }
+
+ @Override public TextRange getRangeInElement() {
+ return new TextRange(0, getTextLength());
+ }
+
+ @Nullable
+ public PsiClass getContainingClass() {
+ SmaliClassTypeElement containingClassReference = getContainingType();
+ if (containingClassReference == null) {
+ return null;
+ }
+ PsiClass containingClass = containingClassReference.resolve();
+ if (containingClass == null) {
+ return null;
+ }
+
+ return containingClass;
+ }
+
+ @Nullable
+ public SmaliClassTypeElement getContainingType() {
+ return findChildByClass(SmaliClassTypeElement.class);
+ }
+
+ @Nullable
+ public SmaliMemberName getMemberName() {
+ return findChildByClass(SmaliMemberName.class);
+ }
+
+ @Nonnull
+ public List<PsiType> getParameterTypes() {
+ SmaliMethodReferenceParamList paramList = findChildByClass(SmaliMethodReferenceParamList.class);
+ if (paramList == null) {
+ return Lists.newArrayList();
+ }
+
+ SmaliTypeElement[] parameterElements = paramList.getParameterTypes();
+
+ List<PsiType> types = new ArrayList<PsiType>(parameterElements.length);
+ for (SmaliTypeElement parameterElement: parameterElements) {
+ types.add(parameterElement.getType());
+ }
+ return types;
+ }
+
+ @Nullable
+ public SmaliTypeElement getReturnType() {
+ SmaliTypeElement[] types = findChildrenByClass(SmaliTypeElement.class);
+ if (types.length < 2) {
+ return null;
+ }
+ return types[1];
+ }
+
+ @Nullable @Override public PsiElement resolve() {
+ PsiClass containingClass = getContainingClass();
+ if (containingClass == null) {
+ return null;
+ }
+
+ SmaliMemberName memberName = getMemberName();
+ if (memberName == null) {
+ return null;
+ }
+
+ LightMethodBuilder pattern = new LightMethodBuilder(getManager(), SmaliLanguage.INSTANCE, memberName.getText());
+
+ for (PsiType type: getParameterTypes()) {
+ pattern.addParameter("", type);
+ }
+
+ SmaliTypeElement returnTypeElement = getReturnType();
+ if (returnTypeElement == null) {
+ return null;
+ }
+
+ pattern.setMethodReturnType(returnTypeElement.getType());
+
+ // TODO: what about static constructor?
+ pattern.setConstructor(memberName.getText().equals("<init>"));
+
+ return containingClass.findMethodBySignature(pattern, true);
+ }
+
+ @NotNull @Override public String getCanonicalText() {
+ return getText();
+ }
+
+ @Override public boolean isReferenceTo(PsiElement element) {
+ return resolve() == element;
+ }
+
+ @NotNull @Override public Object[] getVariants() {
+ return ArrayUtil.EMPTY_OBJECT_ARRAY;
+ }
+
+ @Override public boolean isSoft() {
+ return false;
+ }
+
+ @Override public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ SmaliMemberName memberName = getMemberName();
+ if (memberName == null) {
+ throw new IncorrectOperationException();
+ }
+ memberName.setName(newElementName);
+ return this;
+ }
+
+ @Override public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
+ //TODO: implement this
+ throw new IncorrectOperationException();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodReferenceParamList.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodReferenceParamList.java
new file mode 100644
index 00000000..f9dccf06
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethodReferenceParamList.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliMethodReferenceParamList extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliMethodReferenceParamList();
+ }
+ };
+
+ public SmaliMethodReferenceParamList() {
+ super(SmaliElementTypes.METHOD_REFERENCE_PARAM_LIST);
+ }
+
+ @NotNull public SmaliTypeElement[] getParameterTypes() {
+ return findChildrenByClass(SmaliTypeElement.class);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliModifierList.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliModifierList.java
new file mode 100644
index 00000000..c23763fc
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliModifierList.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiModifier.ModifierConstant;
+import com.intellij.psi.PsiModifierList;
+import com.intellij.psi.PsiModifierListOwner;
+import com.intellij.psi.StubBasedPsiElement;
+import com.intellij.psi.impl.source.tree.Factory;
+import com.intellij.psi.impl.source.tree.TreeElement;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.dexlib2.AccessFlags;
+import org.jf.smalidea.SmaliTokens;
+import org.jf.smalidea.psi.iface.SmaliModifierListOwner;
+import org.jf.smalidea.psi.stub.SmaliModifierListStub;
+import org.jf.smalidea.psi.stub.element.SmaliModifierListElementType;
+
+import javax.annotation.Nonnull;
+
+public class SmaliModifierList extends SmaliStubBasedPsiElement<SmaliModifierListStub>
+ implements StubBasedPsiElement<SmaliModifierListStub>, PsiModifierList {
+ public SmaliModifierList(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ public SmaliModifierList(@NotNull SmaliModifierListStub stub) {
+ super(stub, SmaliModifierListElementType.INSTANCE);
+ }
+
+ public int getAccessFlags() {
+ SmaliModifierListStub stub = getStub();
+ if (stub != null) {
+ return stub.getAccessFlags();
+ }
+
+ int flags = 0;
+
+ for (PsiElement accessSpec: findChildrenByType(SmaliTokens.ACCESS_SPEC)) {
+ AccessFlags flag = AccessFlags.getAccessFlag(accessSpec.getText());
+ if (flag != null) {
+ flags |= flag.getValue();
+ }
+ }
+
+ return flags;
+ }
+
+ @Override public boolean hasModifierProperty(@ModifierConstant @NotNull @NonNls String name) {
+ return hasExplicitModifier(name);
+ }
+
+ @Override public boolean hasExplicitModifier(@ModifierConstant @NotNull @NonNls String name) {
+ SmaliModifierListStub stub = getStub();
+ if (stub != null) {
+ AccessFlags flag = AccessFlags.getAccessFlag(name);
+ if (flag == null) {
+ return false;
+ }
+ return (stub.getAccessFlags() & flag.getValue()) != 0;
+ }
+
+ for (PsiElement accessSpec: findChildrenByType(SmaliTokens.ACCESS_SPEC)) {
+ if (accessSpec.getText().equals(name)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public void setModifierProperty(@ModifierConstant @NotNull @NonNls String name, boolean addModifier)
+ throws IncorrectOperationException {
+ if (addModifier) {
+
+ final TreeElement leaf = Factory.createSingleLeafElement(SmaliTokens.ACCESS_SPEC, name, null, getManager());
+
+ new WriteCommandAction.Simple(getProject(), getContainingFile()) {
+ @Override protected void run() throws Throwable {
+ addInternal(leaf, leaf, null, null);
+ }
+ }.execute();
+ } else {
+ final PsiElement accessSpec = getAccessFlagElement(name);
+ if (accessSpec != null) {
+ new WriteCommandAction.Simple(getProject(), getContainingFile()) {
+ @Override protected void run() throws Throwable {
+ accessSpec.delete();
+ }
+ }.execute();
+ }
+ }
+ }
+
+ @Override
+ public void checkSetModifierProperty(@ModifierConstant @NotNull @NonNls String name, boolean addModifier)
+ throws IncorrectOperationException {
+ }
+
+ @Nonnull
+ private SmaliModifierListOwner getParentForAnnotations() {
+ SmaliModifierListOwner parent = (SmaliModifierListOwner)getStubOrPsiParentOfType(PsiModifierListOwner.class);
+ assert parent != null;
+ return parent;
+ }
+
+ @NotNull @Override public SmaliAnnotation[] getAnnotations() {
+ return getParentForAnnotations().getAnnotations();
+ }
+
+ @NotNull @Override public SmaliAnnotation[] getApplicableAnnotations() {
+ return getParentForAnnotations().getApplicableAnnotations();
+ }
+
+ @Nullable @Override public SmaliAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
+ return getParentForAnnotations().findAnnotation(qualifiedName);
+ }
+
+ @NotNull @Override public SmaliAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
+ return getParentForAnnotations().addAnnotation(qualifiedName);
+ }
+
+ @Nullable public PsiElement getAccessFlagElement(@NotNull String accessFlag) {
+ for (PsiElement accessSpec: findChildrenByType(SmaliTokens.ACCESS_SPEC)) {
+ if (accessSpec.getText().equals(accessFlag)) {
+ return accessSpec;
+ }
+ }
+ return null;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliPackedSwitchElement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliPackedSwitchElement.java
new file mode 100644
index 00000000..b0e04150
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliPackedSwitchElement.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015, 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.psi.impl;
+
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliPackedSwitchElement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliPackedSwitchElement();
+ }
+ };
+
+ public SmaliPackedSwitchElement() {
+ super(SmaliElementTypes.PACKED_SWITCH_ELEMENT);
+ }
+
+ @Nullable
+ public SmaliLabelReference getTarget() {
+ return findChildByClass(SmaliLabelReference.class);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliParameterStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliParameterStatement.java
new file mode 100644
index 00000000..5fa8c4cd
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliParameterStatement.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.psi.PsiAnnotationOwner;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliParameterStatement extends SmaliCompositeElement implements PsiAnnotationOwner {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliParameterStatement();
+ }
+ };
+
+ public SmaliParameterStatement() {
+ super(SmaliElementTypes.PARAMETER_STATEMENT);
+ }
+
+ @Nullable
+ public SmaliLocalName getNameIdentifier() {
+ return findChildByClass(SmaliLocalName.class);
+ }
+
+ @Nullable
+ public SmaliRegisterReference getParameterRegister() {
+ return findChildByClass(SmaliRegisterReference.class);
+ }
+
+ @NotNull @Override public SmaliAnnotation[] getAnnotations() {
+ return findChildrenByClass(SmaliAnnotation.class);
+ }
+
+ @NotNull @Override public SmaliAnnotation[] getApplicableAnnotations() {
+ return getAnnotations();
+ }
+
+ @Nullable @Override public SmaliAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
+ for (SmaliAnnotation annotation: getAnnotations()) {
+ if (qualifiedName.equals(annotation.getQualifiedName())) {
+ return annotation;
+ }
+ }
+ return null;
+ }
+
+ @NotNull @Override public SmaliAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
+ // TODO: implement this
+ return null;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliPrimitiveTypeElement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliPrimitiveTypeElement.java
new file mode 100644
index 00000000..4bdf65a6
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliPrimitiveTypeElement.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.psi.PsiType;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliPrimitiveTypeElement extends SmaliTypeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliPrimitiveTypeElement();
+ }
+ };
+
+ public SmaliPrimitiveTypeElement() {
+ super(SmaliElementTypes.PRIMITIVE_TYPE);
+ }
+
+ @NotNull @Override public PsiType getType() {
+ switch (getText().charAt(0)) {
+ case 'Z':
+ return PsiType.BOOLEAN;
+ case 'B':
+ return PsiType.BYTE;
+ case 'S':
+ return PsiType.SHORT;
+ case 'C':
+ return PsiType.CHAR;
+ case 'I':
+ return PsiType.INT;
+ case 'J':
+ return PsiType.LONG;
+ case 'F':
+ return PsiType.FLOAT;
+ case 'D':
+ return PsiType.DOUBLE;
+ default:
+ throw new RuntimeException("Unexpected primitive type");
+ }
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliPrologueDebugStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliPrologueDebugStatement.java
new file mode 100644
index 00000000..c4f73f0b
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliPrologueDebugStatement.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliPrologueDebugStatement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliPrologueDebugStatement();
+ }
+ };
+
+ public SmaliPrologueDebugStatement() {
+ super(SmaliElementTypes.PROLOGUE_DEBUG_STATEMENT);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegisterReference.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegisterReference.java
new file mode 100644
index 00000000..3c2fe7b2
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegisterReference.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliRegisterReference extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliRegisterReference();
+ }
+ };
+
+ public SmaliRegisterReference() {
+ super(SmaliElementTypes.REGISTER_REFERENCE);
+ }
+
+ @NotNull
+ public SmaliMethod getParentMethod() {
+ SmaliMethod parentMethod = findAncestorByClass(SmaliMethod.class);
+ assert parentMethod != null;
+ return parentMethod;
+ }
+
+ public int getRegisterNumber() {
+ int registerNumber = Integer.parseInt(getText().substring(1));
+
+ if (isParameterRegister()) {
+ SmaliMethod method = getParentMethod();
+ registerNumber += method.getRegisterCount() - method.getParameterRegisterCount();
+ }
+
+ return registerNumber;
+ }
+
+ public boolean isParameterRegister() {
+ return getText().charAt(0) == 'p';
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegistersStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegistersStatement.java
new file mode 100644
index 00000000..93080a70
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegistersStatement.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.SmaliTokens;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliRegistersStatement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliRegistersStatement();
+ }
+ };
+
+ public SmaliRegistersStatement() {
+ super(SmaliElementTypes.REGISTERS_STATEMENT);
+ }
+
+ @NotNull
+ private SmaliMethod getParentMethod() {
+ return findAncestorByClass(SmaliMethod.class);
+ }
+
+ /**
+ * Get the total number of registers for the method
+ */
+ public int getRegisterCount() {
+ SmaliLiteral literal = findChildByClass(SmaliLiteral.class);
+ assert literal != null;
+
+ long registerCount = literal.getIntegralValue();
+ // TODO: check for register count that's too large
+ if (isLocals()) {
+ SmaliMethod parentMethod = getParentMethod();
+ return (int)registerCount + parentMethod.getParameterRegisterCount();
+ }
+ return (int)registerCount;
+ }
+
+ private boolean isLocals() {
+ return findChildByType(SmaliTokens.LOCALS_DIRECTIVE) != null;
+ }
+
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRestartLocalDebugStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRestartLocalDebugStatement.java
new file mode 100644
index 00000000..e2736079
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRestartLocalDebugStatement.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliRestartLocalDebugStatement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliRestartLocalDebugStatement();
+ }
+ };
+
+ public SmaliRestartLocalDebugStatement() {
+ super(SmaliElementTypes.RESTART_LOCAL_DEBUG_STATEMENT);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSourceDebugStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSourceDebugStatement.java
new file mode 100644
index 00000000..758e175e
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSourceDebugStatement.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliSourceDebugStatement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliSourceDebugStatement();
+ }
+ };
+
+ public SmaliSourceDebugStatement() {
+ super(SmaliElementTypes.SOURCE_DEBUG_STATEMENT);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSourceStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSourceStatement.java
new file mode 100644
index 00000000..4f696cf2
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSourceStatement.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliSourceStatement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliSourceStatement();
+ }
+ };
+
+ public SmaliSourceStatement() {
+ super(SmaliElementTypes.SOURCE_STATEMENT);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSparseSwitchElement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSparseSwitchElement.java
new file mode 100644
index 00000000..28fee439
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSparseSwitchElement.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015, 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.psi.impl;
+
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliSparseSwitchElement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliSparseSwitchElement();
+ }
+ };
+
+ public SmaliSparseSwitchElement() {
+ super(SmaliElementTypes.SPARSE_SWITCH_ELEMENT);
+ }
+
+ @Nullable
+ public SmaliLiteral getKey() {
+ return findChildByClass(SmaliLiteral.class);
+ }
+
+ @Nullable
+ public SmaliLabelReference getTarget() {
+ return findChildByClass(SmaliLabelReference.class);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliStubBasedPsiElement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliStubBasedPsiElement.java
new file mode 100644
index 00000000..5df05e25
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliStubBasedPsiElement.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.extapi.psi.StubBasedPsiElementBase;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.StubBasedPsiElement;
+import com.intellij.psi.stubs.IStubElementType;
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public abstract class SmaliStubBasedPsiElement<T extends StubElement> extends StubBasedPsiElementBase<T>
+ implements StubBasedPsiElement<T> {
+ protected SmaliStubBasedPsiElement(@NotNull T stub, @NotNull IStubElementType nodeType) {
+ super(stub, nodeType);
+ }
+
+ protected SmaliStubBasedPsiElement(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Nullable
+ protected <E extends PsiElement> E findStubOrPsiAncestorOfType(@NotNull Class<E> aClass) {
+ T stub = getStub();
+ if (stub != null) {
+ StubElement parent = stub.getParentStub();
+ while (parent != null) {
+ PsiElement parentPsi = parent.getPsi();
+ if (aClass.isInstance(parentPsi)) {
+ return (E)parentPsi;
+ }
+ parent = parent.getParentStub();
+ }
+ return null;
+ }
+
+ PsiElement parent = getParent();
+ while (parent != null) {
+ if (aClass.isInstance(parent)) {
+ return (E)parent;
+ }
+ parent = parent.getParent();
+ }
+ return null;
+ }
+
+ public String toString() {
+ return this.getClass().getSimpleName() + "(" + this.getElementType().toString() + ")";
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSuperStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSuperStatement.java
new file mode 100644
index 00000000..c0948dc9
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliSuperStatement.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliSuperStatement extends SmaliCompositeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliSuperStatement();
+ }
+ };
+
+ public SmaliSuperStatement() {
+ super(SmaliElementTypes.SUPER_STATEMENT);
+ }
+
+ @Nullable
+ public SmaliClassTypeElement getClassReference() {
+ return findChildByClass(SmaliClassTypeElement.class);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliThrowsList.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliThrowsList.java
new file mode 100644
index 00000000..9cff5c34
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliThrowsList.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015, 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.psi.impl;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiReferenceList;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.stub.SmaliThrowsListStub;
+
+public class SmaliThrowsList extends SmaliBaseReferenceList<SmaliThrowsListStub> implements PsiReferenceList {
+ public SmaliThrowsList(@NotNull ASTNode node) {
+ super(node);
+ }
+
+ public SmaliThrowsList(@NotNull SmaliThrowsListStub stub) {
+ super(stub, SmaliElementTypes.THROWS_LIST);
+ }
+
+ @NotNull @Override public SmaliClassTypeElement[] getReferenceElements() {
+ return SmaliClassTypeElement.EMPTY_ARRAY;
+ }
+
+ @Override public Role getRole() {
+ return null;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliTypeElement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliTypeElement.java
new file mode 100644
index 00000000..634cf1a8
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliTypeElement.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiJavaCodeReferenceElement;
+import com.intellij.psi.PsiTypeElement;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public abstract class SmaliTypeElement extends SmaliCompositeElement implements PsiTypeElement {
+ protected SmaliTypeElement(IElementType type) {
+ super(type);
+ }
+
+ @Nullable @Override public PsiJavaCodeReferenceElement getInnermostComponentReferenceElement() {
+ return null;
+ }
+
+ @NotNull
+ public String getSmaliName() {
+ return getText();
+ }
+
+ // Annotations on types are for JSR 308. Not applicable to smali.
+
+ @NotNull @Override public PsiAnnotation[] getAnnotations() {
+ return new PsiAnnotation[0];
+ }
+
+ @NotNull @Override public PsiAnnotation[] getApplicableAnnotations() {
+ return new PsiAnnotation[0];
+ }
+
+ @Nullable @Override public PsiAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
+ return null;
+ }
+
+ @NotNull @Override public PsiAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliVoidTypeElement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliVoidTypeElement.java
new file mode 100644
index 00000000..2b540c6b
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliVoidTypeElement.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014, 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.psi.impl;
+
+import com.intellij.psi.PsiType;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliCompositeElementFactory;
+import org.jf.smalidea.psi.SmaliElementTypes;
+
+public class SmaliVoidTypeElement extends SmaliTypeElement {
+ public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() {
+ @Override public SmaliCompositeElement createElement() {
+ return new SmaliVoidTypeElement();
+ }
+ };
+
+ public SmaliVoidTypeElement() {
+ super(SmaliElementTypes.VOID_TYPE);
+ }
+
+ @NotNull @Override public PsiType getType() {
+ return PsiType.VOID;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/index/SmaliClassFinder.java b/smalidea/src/main/java/org/jf/smalidea/psi/index/SmaliClassFinder.java
new file mode 100644
index 00000000..0ebb1eec
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/index/SmaliClassFinder.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2014, 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.psi.index;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElementFinder;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliClass;
+
+import java.util.Collection;
+
+public class SmaliClassFinder extends PsiElementFinder {
+ @Override
+ public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
+ Collection<SmaliClass> classes = SmaliClassNameIndex.INSTANCE.get(qualifiedName, scope.getProject(), scope);
+ if (classes != null && classes.size() == 1) {
+ return classes.iterator().next();
+ }
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public PsiClass[] findClasses(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
+ PsiClass cls = findClass(qualifiedName, scope);
+ if (cls != null) {
+ return new PsiClass[] {cls};
+ }
+ return PsiClass.EMPTY_ARRAY;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/index/SmaliClassNameIndex.java b/smalidea/src/main/java/org/jf/smalidea/psi/index/SmaliClassNameIndex.java
new file mode 100644
index 00000000..0429597a
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/index/SmaliClassNameIndex.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014, 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.psi.index;
+
+import com.intellij.psi.stubs.StringStubIndexExtension;
+import com.intellij.psi.stubs.StubIndexKey;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliClass;
+
+public class SmaliClassNameIndex extends StringStubIndexExtension<SmaliClass> {
+ public static final StubIndexKey<String, SmaliClass> KEY =
+ StubIndexKey.createIndexKey("smali.class.name");
+
+ public static final SmaliClassNameIndex INSTANCE = new SmaliClassNameIndex();
+
+ private SmaliClassNameIndex() {
+ }
+
+ @NotNull @Override public StubIndexKey<String, SmaliClass> getKey() {
+ return KEY;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/leaf/SmaliClassDescriptor.java b/smalidea/src/main/java/org/jf/smalidea/psi/leaf/SmaliClassDescriptor.java
new file mode 100644
index 00000000..36c59f23
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/leaf/SmaliClassDescriptor.java
@@ -0,0 +1,17 @@
+package org.jf.smalidea.psi.leaf;
+
+import com.intellij.psi.PsiIdentifier;
+import com.intellij.psi.impl.source.tree.LeafPsiElement;
+import com.intellij.psi.tree.IElementType;
+import org.jf.smalidea.SmaliTokens;
+
+public class SmaliClassDescriptor extends LeafPsiElement implements PsiIdentifier {
+ public SmaliClassDescriptor(CharSequence text) {
+ super(SmaliTokens.CLASS_DESCRIPTOR, text);
+ }
+
+ @Override
+ public IElementType getTokenType() {
+ return SmaliTokens.CLASS_DESCRIPTOR;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/leaf/SmaliSimpleName.java b/smalidea/src/main/java/org/jf/smalidea/psi/leaf/SmaliSimpleName.java
new file mode 100644
index 00000000..84b2e501
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/leaf/SmaliSimpleName.java
@@ -0,0 +1,10 @@
+package org.jf.smalidea.psi.leaf;
+
+import com.intellij.psi.impl.source.tree.LeafPsiElement;
+import org.jf.smalidea.SmaliTokens;
+
+public class SmaliSimpleName extends LeafPsiElement {
+ public SmaliSimpleName(CharSequence text) {
+ super(SmaliTokens.SIMPLE_NAME, text);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliAnnotationStub.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliAnnotationStub.java
new file mode 100644
index 00000000..d20882ce
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliAnnotationStub.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014, 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.psi.stub;
+
+import com.intellij.psi.stubs.StubBase;
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.impl.SmaliAnnotation;
+
+public class SmaliAnnotationStub extends StubBase<SmaliAnnotation> {
+ @Nullable
+ private final String annotationSmaliTypeName;
+
+ public SmaliAnnotationStub(StubElement parent, @Nullable String annotationSmaliTypeName) {
+ super(parent, SmaliElementTypes.ANNOTATION);
+ this.annotationSmaliTypeName = annotationSmaliTypeName;
+ }
+
+ @Nullable
+ public String getAnnotationSmaliTypeName() {
+ return annotationSmaliTypeName;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliBaseReferenceListStub.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliBaseReferenceListStub.java
new file mode 100644
index 00000000..8521c4b4
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliBaseReferenceListStub.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2014, 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.psi.stub;
+
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.stubs.IStubElementType;
+import com.intellij.psi.stubs.StubBase;
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.impl.LightSmaliClassTypeElement;
+import org.jf.smalidea.psi.impl.SmaliBaseReferenceList;
+import org.jf.smalidea.psi.impl.SmaliClassType;
+
+public abstract class SmaliBaseReferenceListStub<T extends SmaliBaseReferenceList> extends StubBase<T> {
+ @NotNull private final String[] smaliTypeNames;
+ @Nullable private SmaliClassType[] classTypes = null;
+
+ protected SmaliBaseReferenceListStub(
+ @NotNull StubElement parent, @NotNull IStubElementType elementType, @NotNull String[] smaliTypeNames) {
+ super(parent, elementType);
+ this.smaliTypeNames = smaliTypeNames;
+ }
+
+ @NotNull public String[] getSmaliTypeNames() {
+ return smaliTypeNames;
+ }
+
+ @NotNull
+ public SmaliClassType[] getReferencedTypes() {
+ if (classTypes == null) {
+ classTypes = new SmaliClassType[smaliTypeNames.length];
+ for (int i = 0; i< smaliTypeNames.length; i++) {
+ classTypes[i] = new SmaliClassType(
+ new LightSmaliClassTypeElement(PsiManager.getInstance(getProject()), smaliTypeNames[i]));
+ }
+ }
+ return classTypes;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliClassStatementStub.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliClassStatementStub.java
new file mode 100644
index 00000000..41faccf2
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliClassStatementStub.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2015, 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.psi.stub;
+
+import com.intellij.psi.stubs.StubBase;
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.impl.SmaliClassStatement;
+
+public class SmaliClassStatementStub extends StubBase<SmaliClassStatement> {
+ @Nullable private final String qualifiedName;
+
+ public SmaliClassStatementStub(StubElement parent, @Nullable String qualifiedName) {
+ super(parent, SmaliElementTypes.CLASS_STATEMENT);
+ this.qualifiedName = qualifiedName;
+ }
+
+ @Nullable public String getQualifiedName() {
+ return qualifiedName;
+ }
+
+ @Nullable public String getName() {
+ if (qualifiedName == null) {
+ return null;
+ }
+ int lastDot = qualifiedName.lastIndexOf('.');
+ if (lastDot < 0) {
+ return qualifiedName;
+ }
+ return qualifiedName.substring(lastDot+1);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliClassStub.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliClassStub.java
new file mode 100644
index 00000000..b1656a59
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliClassStub.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.psi.stub;
+
+import com.intellij.psi.stubs.StubBase;
+import com.intellij.psi.stubs.StubElement;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.impl.SmaliClass;
+
+public class SmaliClassStub extends StubBase<SmaliClass> {
+ public SmaliClassStub(StubElement parent) {
+ super(parent, SmaliElementTypes.CLASS);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliExtendsListStub.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliExtendsListStub.java
new file mode 100644
index 00000000..9678a29e
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliExtendsListStub.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.psi.stub;
+
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.impl.SmaliExtendsList;
+
+public class SmaliExtendsListStub extends SmaliBaseReferenceListStub<SmaliExtendsList> {
+ public SmaliExtendsListStub(@NotNull StubElement parent, @NotNull String[] smaliTypeNames) {
+ super(parent, SmaliElementTypes.EXTENDS_LIST, smaliTypeNames);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliFieldStub.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliFieldStub.java
new file mode 100644
index 00000000..15e0fbf0
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliFieldStub.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014, 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.psi.stub;
+
+import com.intellij.psi.stubs.StubBase;
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.impl.SmaliField;
+
+public class SmaliFieldStub extends StubBase<SmaliField> {
+ @Nullable private final String name;
+ @NotNull private final String smaliTypeName;
+
+ public SmaliFieldStub(StubElement parent, @Nullable String name, @NotNull String smaliTypeName) {
+ super(parent, SmaliElementTypes.FIELD);
+ this.name = name;
+ this.smaliTypeName = smaliTypeName;
+ }
+
+ @Nullable public String getName() {
+ return name;
+ }
+
+ @NotNull public String getSmaliTypeName() {
+ return smaliTypeName;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliFileStub.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliFileStub.java
new file mode 100644
index 00000000..be059768
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliFileStub.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2014, 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.psi.stub;
+
+import com.intellij.psi.stubs.PsiFileStubImpl;
+import org.jf.smalidea.psi.impl.SmaliFile;
+
+public class SmaliFileStub extends PsiFileStubImpl<SmaliFile> {
+ public SmaliFileStub(SmaliFile file) {
+ super(file);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliImplementsListStub.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliImplementsListStub.java
new file mode 100644
index 00000000..2b762c9f
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliImplementsListStub.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014, 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.psi.stub;
+
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.impl.SmaliImplementsList;
+
+public class SmaliImplementsListStub extends SmaliBaseReferenceListStub<SmaliImplementsList> {
+ public SmaliImplementsListStub(@NotNull StubElement parent, @NotNull String[] smaliTypeNames) {
+ super(parent, SmaliElementTypes.IMPLEMENTS_LIST, smaliTypeNames);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodParamListStub.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodParamListStub.java
new file mode 100644
index 00000000..f4878660
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodParamListStub.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014, 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.psi.stub;
+
+import com.intellij.psi.stubs.StubBase;
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.impl.SmaliMethodPrototype;
+
+public class SmaliMethodParamListStub extends StubBase<SmaliMethodPrototype> {
+ public SmaliMethodParamListStub(@NotNull StubElement parent) {
+ super(parent, SmaliElementTypes.METHOD_PARAM_LIST);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodParameterStub.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodParameterStub.java
new file mode 100644
index 00000000..e6f1cf25
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodParameterStub.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014, 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.psi.stub;
+
+import com.intellij.psi.stubs.StubBase;
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.impl.SmaliMethodParameter;
+
+public class SmaliMethodParameterStub extends StubBase<SmaliMethodParameter> {
+ @NotNull private final String smaliTypeName;
+ @Nullable private final String name;
+
+ public SmaliMethodParameterStub(@NotNull StubElement parent, @NotNull String smaliTypeName, @Nullable String name) {
+ super(parent, SmaliElementTypes.METHOD_PARAMETER);
+ this.smaliTypeName = smaliTypeName;
+ this.name = name;
+ }
+
+ @NotNull public String getSmaliTypeName() {
+ return smaliTypeName;
+ }
+
+ @Nullable public String getName() {
+ return name;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodPrototypeStub.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodPrototypeStub.java
new file mode 100644
index 00000000..ac0b1e9a
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodPrototypeStub.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014, 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.psi.stub;
+
+import com.intellij.psi.stubs.StubBase;
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.impl.SmaliMethodPrototype;
+
+public class SmaliMethodPrototypeStub extends StubBase<SmaliMethodPrototype> {
+ @Nullable private final String returnSmaliTypeName;
+
+ public SmaliMethodPrototypeStub(@NotNull StubElement parent, @Nullable String returnSmaliTypeName) {
+ super(parent, SmaliElementTypes.METHOD_PROTOTYPE);
+ this.returnSmaliTypeName = returnSmaliTypeName;
+ }
+
+ @Nullable public String getReturnSmaliTypeName() {
+ return returnSmaliTypeName;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodStub.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodStub.java
new file mode 100644
index 00000000..1412980a
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliMethodStub.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014, 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.psi.stub;
+
+import com.intellij.psi.stubs.StubBase;
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+import javax.annotation.Nullable;
+
+public class SmaliMethodStub extends StubBase<SmaliMethod> {
+ @Nullable private final String name;
+
+ public SmaliMethodStub(@NotNull StubElement parent, @Nullable String name) {
+ super(parent, SmaliElementTypes.METHOD);
+ this.name = name;
+ }
+
+ @Nullable public String getName() {
+ return name;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliModifierListStub.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliModifierListStub.java
new file mode 100644
index 00000000..e0a5f0e4
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliModifierListStub.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2014, 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.psi.stub;
+
+import com.intellij.psi.stubs.StubBase;
+import com.intellij.psi.stubs.StubElement;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+import org.jf.smalidea.psi.stub.element.SmaliModifierListElementType;
+
+public class SmaliModifierListStub extends StubBase<SmaliMethod> {
+ private final int accessFlags;
+
+ public SmaliModifierListStub(StubElement parent, int accessFlags) {
+ super(parent, SmaliModifierListElementType.INSTANCE);
+ this.accessFlags = accessFlags;
+ }
+
+ public int getAccessFlags() {
+ return accessFlags;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliThrowsListStub.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliThrowsListStub.java
new file mode 100644
index 00000000..94d239ec
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/SmaliThrowsListStub.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2015, 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.psi.stub;
+
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.impl.SmaliThrowsList;
+
+public class SmaliThrowsListStub extends SmaliBaseReferenceListStub<SmaliThrowsList> {
+ public SmaliThrowsListStub(@NotNull StubElement parent) {
+ super(parent, SmaliElementTypes.THROWS_LIST, new String[0]);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliAnnotationElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliAnnotationElementType.java
new file mode 100644
index 00000000..7085cc0e
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliAnnotationElementType.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2014, 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.psi.stub.element;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.stubs.IndexSink;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.stubs.StubInputStream;
+import com.intellij.psi.stubs.StubOutputStream;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliAnnotation;
+import org.jf.smalidea.psi.stub.SmaliAnnotationStub;
+
+import java.io.IOException;
+
+public class SmaliAnnotationElementType extends SmaliStubElementType<SmaliAnnotationStub, SmaliAnnotation> {
+ public static final SmaliAnnotationElementType INSTANCE = new SmaliAnnotationElementType();
+
+ private SmaliAnnotationElementType() {
+ super("ANNOTATION");
+ }
+
+ @NotNull @Override public String getExternalId() {
+ return "smali.annotation";
+ }
+
+ @Override public SmaliAnnotation createPsi(@NotNull SmaliAnnotationStub stub) {
+ return new SmaliAnnotation(stub);
+ }
+
+ @Override public SmaliAnnotation createPsi(@NotNull ASTNode node) {
+ return new SmaliAnnotation(node);
+ }
+
+ @Override public SmaliAnnotationStub createStub(@NotNull SmaliAnnotation psi, StubElement parentStub) {
+ return new SmaliAnnotationStub(parentStub, psi.getSmaliName());
+ }
+
+ @Override
+ public void serialize(@NotNull SmaliAnnotationStub stub, @NotNull StubOutputStream dataStream) throws IOException {
+ dataStream.writeName(stub.getAnnotationSmaliTypeName());
+ }
+
+ @NotNull @Override
+ public SmaliAnnotationStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
+ return new SmaliAnnotationStub(parentStub, deserializeNullableString(dataStream));
+ }
+
+ @Override public void indexStub(@NotNull SmaliAnnotationStub stub, @NotNull IndexSink sink) {
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliBaseReferenceListElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliBaseReferenceListElementType.java
new file mode 100644
index 00000000..d73a33a1
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliBaseReferenceListElementType.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2014, 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.psi.stub.element;
+
+import com.intellij.psi.stubs.IndexSink;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.stubs.StubInputStream;
+import com.intellij.psi.stubs.StubOutputStream;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliBaseReferenceList;
+import org.jf.smalidea.psi.stub.SmaliBaseReferenceListStub;
+
+import java.io.IOException;
+
+public abstract class SmaliBaseReferenceListElementType<StubT extends SmaliBaseReferenceListStub,
+ PsiT extends SmaliBaseReferenceList> extends SmaliStubElementType<StubT, PsiT> {
+
+ protected SmaliBaseReferenceListElementType(@NotNull @NonNls String debugName) {
+ super(debugName);
+ }
+
+ @Override
+ public void serialize(@NotNull StubT stub, @NotNull StubOutputStream dataStream)
+ throws IOException {
+ String[] references = stub.getSmaliTypeNames();
+ dataStream.writeVarInt(references.length);
+ for (String reference: references) {
+ dataStream.writeName(reference);
+ }
+ }
+
+ @NotNull @Override
+ public StubT deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
+ String[] smaliTypeNames = new String[dataStream.readVarInt()];
+ for (int i=0; i<smaliTypeNames.length; i++) {
+ smaliTypeNames[i] = dataStream.readName().getString();
+ }
+
+ return createStub(parentStub, smaliTypeNames);
+ }
+
+ protected abstract StubT createStub(StubElement parentStub, String[] smaliTypeNames);
+
+ @Override public void indexStub(@NotNull StubT stub, @NotNull IndexSink sink) {
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliClassElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliClassElementType.java
new file mode 100644
index 00000000..dcd7a2c7
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliClassElementType.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2014, 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.psi.stub.element;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.impl.java.stubs.index.JavaStubIndexKeys;
+import com.intellij.psi.stubs.IndexSink;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.stubs.StubInputStream;
+import com.intellij.psi.stubs.StubOutputStream;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.impl.SmaliClass;
+import org.jf.smalidea.psi.index.SmaliClassNameIndex;
+import org.jf.smalidea.psi.stub.SmaliClassStatementStub;
+import org.jf.smalidea.psi.stub.SmaliClassStub;
+
+import java.io.IOException;
+
+public class SmaliClassElementType extends SmaliStubElementType<SmaliClassStub, SmaliClass> {
+ public static final SmaliClassElementType INSTANCE = new SmaliClassElementType();
+
+ private SmaliClassElementType() {
+ super("CLASS");
+ }
+
+ @NotNull @Override public String getExternalId() {
+ return "smali.class";
+ }
+
+ @Override public SmaliClass createPsi(@NotNull SmaliClassStub stub) {
+ return new SmaliClass(stub);
+ }
+
+ @Override public SmaliClass createPsi(@NotNull ASTNode node) {
+ return new SmaliClass(node);
+ }
+
+ @Override public SmaliClassStub createStub(@NotNull SmaliClass psi, StubElement parentStub) {
+ return new SmaliClassStub(parentStub);
+ }
+
+ @Override
+ public void serialize(@NotNull SmaliClassStub stub, @NotNull StubOutputStream dataStream) throws IOException {
+
+ }
+
+ @NotNull @Override
+ public SmaliClassStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
+ return new SmaliClassStub(parentStub);
+ }
+
+ @Override public void indexStub(@NotNull SmaliClassStub stub, @NotNull IndexSink sink) {
+ SmaliClassStatementStub smaliClassStatementStub =
+ (SmaliClassStatementStub)stub.findChildStubByType(SmaliElementTypes.CLASS_STATEMENT);
+ if (smaliClassStatementStub != null) {
+ String qualifiedName = smaliClassStatementStub.getQualifiedName();
+ if (qualifiedName != null) {
+ sink.occurrence(SmaliClassNameIndex.KEY, qualifiedName);
+ }
+
+ final String shortName = smaliClassStatementStub.getName();
+ if (shortName != null) {
+ sink.occurrence(JavaStubIndexKeys.CLASS_SHORT_NAMES, shortName);
+ }
+ }
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliClassStatementElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliClassStatementElementType.java
new file mode 100644
index 00000000..f3029c06
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliClassStatementElementType.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2015, 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.psi.stub.element;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.stubs.IndexSink;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.stubs.StubInputStream;
+import com.intellij.psi.stubs.StubOutputStream;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliClassStatement;
+import org.jf.smalidea.psi.stub.SmaliClassStatementStub;
+
+import java.io.IOException;
+
+public class SmaliClassStatementElementType extends SmaliStubElementType<SmaliClassStatementStub, SmaliClassStatement> {
+ public static final SmaliClassStatementElementType INSTANCE = new SmaliClassStatementElementType();
+
+ public SmaliClassStatementElementType() {
+ super("CLASS_STATEMENT");
+ }
+
+ @Override public SmaliClassStatement createPsi(@NotNull ASTNode node) {
+ return new SmaliClassStatement(node);
+ }
+
+ @Override public SmaliClassStatement createPsi(@NotNull SmaliClassStatementStub stub) {
+ return new SmaliClassStatement(stub);
+ }
+
+ @Override public SmaliClassStatementStub createStub(@NotNull SmaliClassStatement psi, StubElement parentStub) {
+ return new SmaliClassStatementStub(parentStub, psi.getQualifiedName());
+ }
+
+ @NotNull @Override public String getExternalId() {
+ return "smali.class_statement";
+ }
+
+ @Override
+ public void serialize(@NotNull SmaliClassStatementStub stub, @NotNull StubOutputStream dataStream) throws IOException {
+ dataStream.writeName(stub.getQualifiedName());
+ }
+
+ @NotNull @Override
+ public SmaliClassStatementStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
+ return new SmaliClassStatementStub(parentStub, deserializeNullableString(dataStream));
+ }
+
+ @Override public void indexStub(@NotNull SmaliClassStatementStub stub, @NotNull IndexSink sink) {
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliExtendsListElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliExtendsListElementType.java
new file mode 100644
index 00000000..3acfd8fd
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliExtendsListElementType.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2014, 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.psi.stub.element;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliExtendsList;
+import org.jf.smalidea.psi.stub.SmaliExtendsListStub;
+
+public class SmaliExtendsListElementType extends SmaliBaseReferenceListElementType<SmaliExtendsListStub, SmaliExtendsList> {
+ public static final SmaliExtendsListElementType INSTANCE = new SmaliExtendsListElementType ();
+
+ private SmaliExtendsListElementType() {
+ super("EXTENDS_LIST");
+ }
+
+ @NotNull @Override public String getExternalId() {
+ return "smali.extends_list";
+ }
+
+ @Override public SmaliExtendsList createPsi(@NotNull SmaliExtendsListStub stub) {
+ return new SmaliExtendsList(stub);
+ }
+
+ @Override public SmaliExtendsList createPsi(@NotNull ASTNode node) {
+ return new SmaliExtendsList(node);
+ }
+
+ @Override protected SmaliExtendsListStub createStub(StubElement parentStub, String[] smaliTypeNames) {
+ return new SmaliExtendsListStub(parentStub, smaliTypeNames);
+ }
+
+ @Override public SmaliExtendsListStub createStub(@NotNull SmaliExtendsList psi, StubElement parentStub) {
+ return new SmaliExtendsListStub(parentStub, psi.getSmaliNames());
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliFieldElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliFieldElementType.java
new file mode 100644
index 00000000..235e995d
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliFieldElementType.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2014, 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.psi.stub.element;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.project.IndexNotReadyException;
+import com.intellij.psi.stubs.IndexSink;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.stubs.StubInputStream;
+import com.intellij.psi.stubs.StubOutputStream;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliField;
+import org.jf.smalidea.psi.impl.SmaliTypeElement;
+import org.jf.smalidea.psi.stub.SmaliFieldStub;
+
+import java.io.IOException;
+
+public class SmaliFieldElementType extends SmaliStubElementType<SmaliFieldStub, SmaliField> {
+ public static final SmaliFieldElementType INSTANCE = new SmaliFieldElementType();
+
+ private SmaliFieldElementType() {
+ super("FIELD");
+ }
+
+ @NotNull @Override public String getExternalId() {
+ return "smali.field";
+ }
+
+ @Override public SmaliField createPsi(@NotNull SmaliFieldStub stub) {
+ return new SmaliField(stub);
+ }
+
+ @Override public SmaliField createPsi(@NotNull ASTNode node) {
+ return new SmaliField(node);
+ }
+
+ @Override public SmaliFieldStub createStub(@NotNull SmaliField psi, StubElement parentStub) {
+ try {
+ String fieldSmaliTypeName;
+ SmaliTypeElement typeElement = psi.getTypeElement();
+ if (typeElement != null) {
+ fieldSmaliTypeName = typeElement.getSmaliName();
+ } else {
+ fieldSmaliTypeName = "Ljava/lang/Object;";
+ }
+
+ return new SmaliFieldStub(parentStub, psi.getName(), fieldSmaliTypeName);
+ } catch (IndexNotReadyException ex) {
+ System.out.println(psi.getName());
+ throw ex;
+ }
+ }
+
+ @Override
+ public void serialize(@NotNull SmaliFieldStub stub, @NotNull StubOutputStream dataStream) throws IOException {
+ dataStream.writeName(stub.getName());
+ dataStream.writeName(stub.getSmaliTypeName());
+ }
+
+ @NotNull @Override
+ public SmaliFieldStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
+ return new SmaliFieldStub(parentStub, deserializeNullableString(dataStream),
+ dataStream.readName().getString());
+ }
+
+ @Override public void indexStub(@NotNull SmaliFieldStub stub, @NotNull IndexSink sink) {
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliFileElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliFileElementType.java
new file mode 100644
index 00000000..3e1eaf59
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliFileElementType.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2014, 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.psi.stub.element;
+
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.StubBuilder;
+import com.intellij.psi.stubs.DefaultStubBuilder;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.tree.IStubFileElementType;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.SmaliLanguage;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.jf.smalidea.psi.stub.SmaliFileStub;
+
+public class SmaliFileElementType extends IStubFileElementType<SmaliFileStub> {
+ public static final SmaliFileElementType INSTANCE = new SmaliFileElementType();
+
+ private SmaliFileElementType() {
+ super("smali.FILE", SmaliLanguage.INSTANCE);
+ }
+
+ @Override public StubBuilder getBuilder() {
+ return new DefaultStubBuilder() {
+ @Override
+ protected StubElement createStubForFile(@NotNull PsiFile file) {
+ if (file instanceof SmaliFile) {
+ return new SmaliFileStub((SmaliFile)file);
+ }
+ throw new RuntimeException("Unexpected file type");
+ }
+ };
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliImplementsListElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliImplementsListElementType.java
new file mode 100644
index 00000000..3b17bc1a
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliImplementsListElementType.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2014, 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.psi.stub.element;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliImplementsList;
+import org.jf.smalidea.psi.stub.SmaliImplementsListStub;
+
+public class SmaliImplementsListElementType
+ extends SmaliBaseReferenceListElementType<SmaliImplementsListStub, SmaliImplementsList> {
+ public static final SmaliImplementsListElementType INSTANCE = new SmaliImplementsListElementType();
+
+ private SmaliImplementsListElementType() {
+ super("IMPLEMENTS_LIST");
+ }
+
+ @NotNull @Override public String getExternalId() {
+ return "smali.implements_list";
+ }
+
+ @Override public SmaliImplementsList createPsi(@NotNull SmaliImplementsListStub stub) {
+ return new SmaliImplementsList(stub);
+ }
+
+ @Override public SmaliImplementsList createPsi(@NotNull ASTNode node) {
+ return new SmaliImplementsList(node);
+ }
+
+ @Override protected SmaliImplementsListStub createStub(StubElement parentStub, String[] smaliTypeNames) {
+ return new SmaliImplementsListStub(parentStub, smaliTypeNames);
+ }
+
+ @Override public SmaliImplementsListStub createStub(@NotNull SmaliImplementsList psi, StubElement parentStub) {
+ return new SmaliImplementsListStub(parentStub, psi.getSmaliNames());
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodElementType.java
new file mode 100644
index 00000000..1d83f1a2
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodElementType.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2014, 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.psi.stub.element;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.stubs.IndexSink;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.stubs.StubInputStream;
+import com.intellij.psi.stubs.StubOutputStream;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+import org.jf.smalidea.psi.stub.SmaliMethodStub;
+
+import java.io.IOException;
+
+public class SmaliMethodElementType extends SmaliStubElementType<SmaliMethodStub, SmaliMethod> {
+ public static final SmaliMethodElementType INSTANCE = new SmaliMethodElementType();
+
+ private SmaliMethodElementType() {
+ super("METHOD");
+ }
+
+ @NotNull @Override public String getExternalId() {
+ return "smali.method";
+ }
+
+ @Override public SmaliMethod createPsi(@NotNull SmaliMethodStub stub) {
+ return new SmaliMethod(stub);
+ }
+
+ @Override public SmaliMethod createPsi(@NotNull ASTNode node) {
+ return new SmaliMethod(node);
+ }
+
+ @Override public SmaliMethodStub createStub(@NotNull SmaliMethod psi, StubElement parentStub) {
+ return new SmaliMethodStub(parentStub, psi.getName());
+ }
+
+ @Override
+ public void serialize(@NotNull SmaliMethodStub stub, @NotNull StubOutputStream dataStream) throws IOException {
+ dataStream.writeName(stub.getName());
+ }
+
+ @NotNull @Override
+ public SmaliMethodStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub) throws IOException {
+ return new SmaliMethodStub(parentStub, dataStream.readName().getString());
+ }
+
+ @Override public void indexStub(@NotNull SmaliMethodStub stub, @NotNull IndexSink sink) {
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodParamListElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodParamListElementType.java
new file mode 100644
index 00000000..197e682e
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodParamListElementType.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2014, 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.psi.stub.element;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.stubs.IndexSink;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.stubs.StubInputStream;
+import com.intellij.psi.stubs.StubOutputStream;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliMethodParamList;
+import org.jf.smalidea.psi.stub.SmaliMethodParamListStub;
+
+import java.io.IOException;
+
+public class SmaliMethodParamListElementType
+ extends SmaliStubElementType<SmaliMethodParamListStub, SmaliMethodParamList> {
+ public static final SmaliMethodParamListElementType INSTANCE = new SmaliMethodParamListElementType();
+
+ private SmaliMethodParamListElementType() {
+ super("METHOD_PARAM_LIST");
+ }
+
+ @NotNull @Override public String getExternalId() {
+ return "smali.method_param_list";
+ }
+
+ @Override public SmaliMethodParamList createPsi(@NotNull ASTNode node) {
+ return new SmaliMethodParamList(node);
+ }
+
+ @Override public SmaliMethodParamList createPsi(@NotNull SmaliMethodParamListStub stub) {
+ return new SmaliMethodParamList(stub);
+ }
+
+ @Override public SmaliMethodParamListStub createStub(@NotNull SmaliMethodParamList psi, StubElement parentStub) {
+ return new SmaliMethodParamListStub(parentStub);
+ }
+
+ @Override
+ public void serialize(@NotNull SmaliMethodParamListStub stub, @NotNull StubOutputStream dataStream)
+ throws IOException {
+ }
+
+ @NotNull @Override
+ public SmaliMethodParamListStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub)
+ throws IOException {
+ return new SmaliMethodParamListStub(parentStub);
+ }
+
+ @Override public void indexStub(@NotNull SmaliMethodParamListStub stub, @NotNull IndexSink sink) {
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodParameterElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodParameterElementType.java
new file mode 100644
index 00000000..ca5a0106
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodParameterElementType.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2014, 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.psi.stub.element;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.stubs.IndexSink;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.stubs.StubInputStream;
+import com.intellij.psi.stubs.StubOutputStream;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliMethodParameter;
+import org.jf.smalidea.psi.stub.SmaliMethodParameterStub;
+
+import java.io.IOException;
+
+public class SmaliMethodParameterElementType
+ extends SmaliStubElementType<SmaliMethodParameterStub, SmaliMethodParameter> {
+ public static final SmaliMethodParameterElementType INSTANCE = new SmaliMethodParameterElementType();
+
+ private SmaliMethodParameterElementType() {
+ super("METHOD_PARAMETER");
+ }
+
+ @NotNull @Override public String getExternalId() {
+ return "smali.method_parameter";
+ }
+
+ @Override public SmaliMethodParameter createPsi(@NotNull ASTNode node) {
+ return new SmaliMethodParameter(node);
+ }
+
+ @Override public SmaliMethodParameter createPsi(@NotNull SmaliMethodParameterStub stub) {
+ return new SmaliMethodParameter(stub);
+ }
+
+ @Override public SmaliMethodParameterStub createStub(@NotNull SmaliMethodParameter psi, StubElement parentStub) {
+ return new SmaliMethodParameterStub(parentStub, psi.getTypeElement().getSmaliName(), psi.getName());
+ }
+
+ @Override
+ public void serialize(@NotNull SmaliMethodParameterStub stub, @NotNull StubOutputStream dataStream)
+ throws IOException {
+ dataStream.writeName(stub.getSmaliTypeName());
+ dataStream.writeName(stub.getName());
+ }
+
+ @NotNull @Override
+ public SmaliMethodParameterStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub)
+ throws IOException {
+ return new SmaliMethodParameterStub(parentStub, dataStream.readName().getString(),
+ deserializeNullableString(dataStream));
+ }
+
+ @Override public void indexStub(@NotNull SmaliMethodParameterStub stub, @NotNull IndexSink sink) {
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodPrototypeElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodPrototypeElementType.java
new file mode 100644
index 00000000..290b78ca
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliMethodPrototypeElementType.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2014, 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.psi.stub.element;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.stubs.IndexSink;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.stubs.StubInputStream;
+import com.intellij.psi.stubs.StubOutputStream;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliMethodPrototype;
+import org.jf.smalidea.psi.impl.SmaliTypeElement;
+import org.jf.smalidea.psi.stub.SmaliMethodPrototypeStub;
+
+import java.io.IOException;
+
+public class SmaliMethodPrototypeElementType
+ extends SmaliStubElementType<SmaliMethodPrototypeStub, SmaliMethodPrototype> {
+ public static final SmaliMethodPrototypeElementType INSTANCE = new SmaliMethodPrototypeElementType();
+
+ private SmaliMethodPrototypeElementType() {
+ super("METHOD_PROTOTYPE");
+ }
+
+ @NotNull @Override public String getExternalId() {
+ return "smali.method_prototype";
+ }
+
+ @Override public SmaliMethodPrototype createPsi(@NotNull ASTNode node) {
+ return new SmaliMethodPrototype(node);
+ }
+
+ @Override public SmaliMethodPrototype createPsi(@NotNull SmaliMethodPrototypeStub stub) {
+ return new SmaliMethodPrototype(stub);
+ }
+
+ @Override public SmaliMethodPrototypeStub createStub(@NotNull SmaliMethodPrototype psi, StubElement parentStub) {
+ SmaliTypeElement returnType = psi.getReturnTypeElement();
+ String returnSmaliTypeName = null;
+ if (returnType != null) {
+ returnSmaliTypeName = returnType.getSmaliName();
+ }
+
+ return new SmaliMethodPrototypeStub(parentStub, returnSmaliTypeName);
+ }
+
+ @Override
+ public void serialize(@NotNull SmaliMethodPrototypeStub stub, @NotNull StubOutputStream dataStream)
+ throws IOException {
+ dataStream.writeName(stub.getReturnSmaliTypeName());
+ }
+
+ @NotNull @Override
+ public SmaliMethodPrototypeStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub)
+ throws IOException {
+ return new SmaliMethodPrototypeStub(parentStub, deserializeNullableString(dataStream));
+ }
+
+ @Override public void indexStub(@NotNull SmaliMethodPrototypeStub stub, @NotNull IndexSink sink) {
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliModifierListElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliModifierListElementType.java
new file mode 100644
index 00000000..12299b4a
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliModifierListElementType.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2014, 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.psi.stub.element;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.stubs.IndexSink;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.stubs.StubInputStream;
+import com.intellij.psi.stubs.StubOutputStream;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliModifierList;
+import org.jf.smalidea.psi.stub.SmaliModifierListStub;
+
+import java.io.IOException;
+
+public class SmaliModifierListElementType extends SmaliStubElementType<SmaliModifierListStub, SmaliModifierList> {
+ public static final SmaliModifierListElementType INSTANCE = new SmaliModifierListElementType();
+
+ private SmaliModifierListElementType() {
+ super("MODIFIER_LIST");
+ }
+
+ @NotNull @Override public String getExternalId() {
+ return "smali.modifier_list";
+ }
+
+ @Override public SmaliModifierList createPsi(@NotNull SmaliModifierListStub stub) {
+ return new SmaliModifierList(stub);
+ }
+
+ @Override public SmaliModifierList createPsi(@NotNull ASTNode node) {
+ return new SmaliModifierList(node);
+ }
+
+ @Override public SmaliModifierListStub createStub(@NotNull SmaliModifierList psi, StubElement parentStub) {
+ return new SmaliModifierListStub(parentStub, psi.getAccessFlags());
+ }
+
+ @Override
+ public void serialize(@NotNull SmaliModifierListStub stub, @NotNull StubOutputStream dataStream)
+ throws IOException {
+ dataStream.writeVarInt(stub.getAccessFlags());
+ }
+
+ @NotNull @Override
+ public SmaliModifierListStub deserialize(@NotNull StubInputStream dataStream, StubElement parentStub)
+ throws IOException {
+ return new SmaliModifierListStub(parentStub, dataStream.readVarInt());
+ }
+
+ @Override public void indexStub(@NotNull SmaliModifierListStub stub, @NotNull IndexSink sink) {
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliStubElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliStubElementType.java
new file mode 100644
index 00000000..51544b49
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliStubElementType.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2014, 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.psi.stub.element;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.stubs.IStubElementType;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.stubs.StubInputStream;
+import com.intellij.util.io.StringRef;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.SmaliLanguage;
+
+import java.io.IOException;
+
+public abstract class SmaliStubElementType<StubT extends StubElement, PsiT extends PsiElement>
+ extends IStubElementType<StubT, PsiT> {
+ protected SmaliStubElementType(@NotNull @NonNls String debugName) {
+ super(debugName, SmaliLanguage.INSTANCE);
+ }
+
+ public abstract PsiT createPsi(@NotNull ASTNode node);
+
+ @Nullable
+ protected String deserializeNullableString(@NotNull StubInputStream dataStream) throws IOException {
+ StringRef stringRef = dataStream.readName();
+ if (stringRef == null) {
+ return null;
+ }
+ return stringRef.getString();
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliThrowsListElementType.java b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliThrowsListElementType.java
new file mode 100644
index 00000000..b53af341
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/stub/element/SmaliThrowsListElementType.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015, 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.psi.stub.element;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliThrowsList;
+import org.jf.smalidea.psi.stub.SmaliThrowsListStub;
+
+public class SmaliThrowsListElementType
+ extends SmaliBaseReferenceListElementType<SmaliThrowsListStub, SmaliThrowsList> {
+ public static final SmaliThrowsListElementType INSTANCE = new SmaliThrowsListElementType();
+
+ private SmaliThrowsListElementType() {
+ super("THROWS_LIST");
+ }
+
+ @NotNull @Override public String getExternalId() {
+ return "smali.throws_list";
+ }
+
+ @Override public SmaliThrowsList createPsi(@NotNull SmaliThrowsListStub stub) {
+ return new SmaliThrowsList(stub);
+ }
+
+ @Override public SmaliThrowsList createPsi(@NotNull ASTNode node) {
+ return new SmaliThrowsList(node);
+ }
+
+ @Override protected SmaliThrowsListStub createStub(StubElement parentStub, String[] types) {
+ return new SmaliThrowsListStub(parentStub);
+ }
+
+ @Override public SmaliThrowsListStub createStub(@NotNull SmaliThrowsList psi, StubElement parentStub) {
+ return new SmaliThrowsListStub(parentStub);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/util/InstructionUtils.java b/smalidea/src/main/java/org/jf/smalidea/util/InstructionUtils.java
new file mode 100644
index 00000000..e302b01e
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/util/InstructionUtils.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015, 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.util;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jf.dexlib2.Opcode;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+import org.jf.smalidea.psi.impl.SmaliLabel;
+import org.jf.smalidea.psi.impl.SmaliLabelReference;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+
+public class InstructionUtils {
+
+ @Nullable
+ public static SmaliInstruction findFirstInstructionWithTarget(
+ @NotNull SmaliMethod method, @NotNull Opcode opcode, int targetOffset) {
+ for (SmaliInstruction instruction: method.getInstructions()) {
+ if (instruction.getOpcode() == opcode) {
+ SmaliLabelReference labelReference = instruction.getTarget();
+ if (labelReference == null) {
+ continue;
+ }
+
+ SmaliLabel label = labelReference.resolve();
+ if (label == null) {
+ continue;
+ }
+
+ if (label.getOffset() == targetOffset) {
+ return instruction;
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/util/NameUtils.java b/smalidea/src/main/java/org/jf/smalidea/util/NameUtils.java
new file mode 100644
index 00000000..305c7f8a
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/util/NameUtils.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2014, 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.util;
+
+import com.google.common.collect.ImmutableMap;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.impl.ResolveScopeManager;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Map;
+
+public class NameUtils {
+ private static final Map<String, String> javaToSmaliPrimitiveTypes = ImmutableMap.<String, String>builder()
+ .put("boolean", "Z")
+ .put("byte", "B")
+ .put("char", "C")
+ .put("short", "S")
+ .put("int", "I")
+ .put("long", "J")
+ .put("float", "F")
+ .put("double", "D")
+ .build();
+
+ @NotNull
+ public static String javaToSmaliType(@NotNull PsiType psiType) {
+ if (psiType instanceof PsiClassType) {
+ PsiClass psiClass = ((PsiClassType)psiType).resolve();
+ if (psiClass != null) {
+ return javaToSmaliType(psiClass);
+ }
+ }
+ return javaToSmaliType(psiType.getCanonicalText());
+ }
+
+ @NotNull
+ public static String javaToSmaliType(@NotNull PsiClass psiClass) {
+ String qualifiedName = psiClass.getQualifiedName();
+ if (qualifiedName == null) {
+ throw new IllegalArgumentException("This method does not support anonymous classes");
+ }
+ PsiClass parent = psiClass.getContainingClass();
+ if (parent != null) {
+ int offset = qualifiedName.lastIndexOf('.');
+ String parentName = qualifiedName.substring(0, offset);
+ assert parentName.equals(parent.getQualifiedName());
+ String className = qualifiedName.substring(offset+1, qualifiedName.length());
+ assert className.equals(psiClass.getName());
+ return javaToSmaliType(parentName + '$' + className);
+ } else {
+ return javaToSmaliType(psiClass.getQualifiedName());
+ }
+ }
+
+ @NotNull
+ public static String javaToSmaliType(@NotNull String javaType) {
+ if (javaType.charAt(javaType.length()-1) == ']') {
+ int dimensions = 0;
+ int firstArrayChar = -1;
+ for (int i=0; i<javaType.length(); i++) {
+ if (javaType.charAt(i) == '[') {
+ if (firstArrayChar == -1) {
+ firstArrayChar = i;
+ }
+ dimensions++;
+ }
+ }
+ if (dimensions > 0) {
+ StringBuilder sb = new StringBuilder(firstArrayChar + 2 + dimensions);
+ for (int i=0; i<dimensions; i++) {
+ sb.append('[');
+ }
+ convertSimpleJavaToSmaliType(javaType.substring(0, firstArrayChar), sb);
+ return sb.toString();
+ }
+ }
+
+ return simpleJavaToSmaliType(javaType);
+ }
+
+ private static void convertSimpleJavaToSmaliType(@NotNull String javaType, @NotNull StringBuilder dest) {
+ String smaliType = javaToSmaliPrimitiveTypes.get(javaType);
+ if (smaliType != null) {
+ dest.append(smaliType);
+ } else {
+ dest.append('L');
+ for (int i=0; i<javaType.length(); i++) {
+ char c = javaType.charAt(i);
+ if (c == '.') {
+ dest.append('/');
+ } else {
+ dest.append(c);
+ }
+ }
+ dest.append(';');
+ }
+ }
+
+ public static PsiClass resolveSmaliType(@NotNull Project project, @NotNull GlobalSearchScope scope,
+ @NotNull String smaliType) {
+ JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
+
+ String javaType = NameUtils.smaliToJavaType(smaliType);
+
+ PsiClass psiClass = facade.findClass(javaType, scope);
+ if (psiClass != null) {
+ return psiClass;
+ }
+
+ int offset = javaType.lastIndexOf('.');
+ if (offset < 0) {
+ offset = 0;
+ }
+ // find the first $ after the last .
+ offset = javaType.indexOf('$', offset+1);
+ if (offset < 0) {
+ return null;
+ }
+
+ while (offset > 0 && offset < javaType.length()-1) {
+ String left = javaType.substring(0, offset);
+ psiClass = facade.findClass(left, scope);
+ if (psiClass != null) {
+ psiClass = findInnerClass(psiClass, javaType.substring(offset+1, javaType.length()), facade, scope);
+ if (psiClass != null) {
+ return psiClass;
+ }
+ }
+ offset = javaType.indexOf('$', offset+1);
+ }
+ return null;
+ }
+
+ @Nullable
+ public static PsiClass resolveSmaliType(@NotNull PsiElement element, @NotNull String smaliType) {
+ GlobalSearchScope scope = ResolveScopeManager.getElementResolveScope(element);
+ return resolveSmaliType(element.getProject(), scope, smaliType);
+ }
+
+ @Nullable
+ public static PsiClass findInnerClass(@NotNull PsiClass outerClass, String innerText, JavaPsiFacade facade,
+ GlobalSearchScope scope) {
+ int offset = innerText.indexOf('$');
+ if (offset < 0) {
+ offset = innerText.length();
+ }
+
+ while (offset > 0 && offset <= innerText.length()) {
+ String left = innerText.substring(0, offset);
+ String nextInner = outerClass.getQualifiedName() + "." + left;
+ PsiClass psiClass = facade.findClass(nextInner, scope);
+ if (psiClass != null) {
+ if (offset < innerText.length()) {
+ psiClass = findInnerClass(psiClass, innerText.substring(offset+1, innerText.length()), facade,
+ scope);
+ if (psiClass != null) {
+ return psiClass;
+ }
+ } else {
+ return psiClass;
+ }
+ }
+ if (offset >= innerText.length()) {
+ break;
+ }
+ offset = innerText.indexOf('$', offset+1);
+ if (offset < 0) {
+ offset = innerText.length();
+ }
+ }
+ return null;
+ }
+
+ private static String simpleJavaToSmaliType(@NotNull String simpleJavaType) {
+ StringBuilder sb = new StringBuilder(simpleJavaType.length() + 2);
+ convertSimpleJavaToSmaliType(simpleJavaType, sb);
+ sb.trimToSize();
+ return sb.toString();
+ }
+
+ @NotNull
+ public static String smaliToJavaType(@NotNull String smaliType) {
+ if (smaliType.charAt(0) == '[') {
+ return convertSmaliArrayToJava(smaliType);
+ } else {
+ StringBuilder sb = new StringBuilder(smaliType.length());
+ convertAndAppendNonArraySmaliTypeToJava(smaliType, sb);
+ return sb.toString();
+ }
+ }
+
+ @NotNull
+ public static String resolveSmaliToJavaType(@NotNull Project project, @NotNull GlobalSearchScope scope,
+ @NotNull String smaliType) {
+ // First, try to resolve the type and get its qualified name, so that we can make sure
+ // to use the correct name for inner classes
+ PsiClass resolvedType = resolveSmaliType(project, scope, smaliType);
+ if (resolvedType != null) {
+ String qualifiedName = resolvedType.getQualifiedName();
+ if (qualifiedName != null) {
+ return qualifiedName;
+ }
+ }
+
+ // if we can't find it, just do a textual conversion of the name
+ return smaliToJavaType(smaliType);
+ }
+
+ @NotNull
+ public static String resolveSmaliToJavaType(@NotNull PsiElement element, @NotNull String smaliType) {
+ return resolveSmaliToJavaType(element.getProject(), element.getResolveScope(), smaliType);
+ }
+
+ @NotNull
+ public static PsiType resolveSmaliToPsiType(@NotNull PsiElement element, @NotNull String smaliType) {
+ PsiClass resolvedType = resolveSmaliType(element, smaliType);
+ if (resolvedType != null) {
+ PsiElementFactory factory = JavaPsiFacade.getInstance(element.getProject()).getElementFactory();
+ return factory.createType(resolvedType);
+ }
+
+ String javaType = NameUtils.smaliToJavaType(smaliType);
+ PsiElementFactory factory = JavaPsiFacade.getInstance(element.getProject()).getElementFactory();
+ return factory.createTypeFromText(javaType, element);
+ }
+
+ @NotNull
+ private static String convertSmaliArrayToJava(@NotNull String smaliType) {
+ int dimensions=0;
+ while (smaliType.charAt(dimensions) == '[') {
+ dimensions++;
+ }
+
+ StringBuilder sb = new StringBuilder(smaliType.length() + dimensions);
+ convertAndAppendNonArraySmaliTypeToJava(smaliType.substring(dimensions), sb);
+ for (int i=0; i<dimensions; i++) {
+ sb.append("[]");
+ }
+ return sb.toString();
+ }
+
+ private static void convertAndAppendNonArraySmaliTypeToJava(@NotNull String smaliType, @NotNull StringBuilder dest) {
+ switch (smaliType.charAt(0)) {
+ case 'Z':
+ dest.append("boolean");
+ return;
+ case 'B':
+ dest.append("byte");
+ return;
+ case 'C':
+ dest.append("char");
+ return;
+ case 'S':
+ dest.append("short");
+ return;
+ case 'I':
+ dest.append("int");
+ return;
+ case 'J':
+ dest.append("long");
+ return;
+ case 'F':
+ dest.append("float");
+ return;
+ case 'D':
+ dest.append("double");
+ case 'L':
+ for (int i=1; i<smaliType.length()-1; i++) {
+ char c = smaliType.charAt(i);
+ if (c == '/') {
+ dest.append('.');
+ } else {
+ dest.append(c);
+ }
+ }
+ return;
+ case 'V':
+ dest.append("void");
+ 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);
+ }
+ }
+
+ @Nullable
+ public static String shortNameFromQualifiedName(@Nullable String qualifiedName) {
+ if (qualifiedName == null) {
+ return null;
+ }
+
+ int index = qualifiedName.lastIndexOf('.');
+ if (index == -1) {
+ return qualifiedName;
+ }
+ return qualifiedName.substring(index+1);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/util/PsiUtil.java b/smalidea/src/main/java/org/jf/smalidea/util/PsiUtil.java
new file mode 100644
index 00000000..72c5a133
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/util/PsiUtil.java
@@ -0,0 +1,73 @@
+/*
+ * 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.util;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.PsiMatcherExpression;
+
+public class PsiUtil {
+ public static PsiElement searchBackward(PsiElement element, PsiMatcherExpression matcher,
+ PsiMatcherExpression until) {
+ while (!matcher.match(element)) {
+ if (until.match(element)) {
+ return null;
+ }
+ PsiElement prev = element.getPrevSibling();
+ if (prev == null) {
+ prev = element.getParent();
+ if (prev == null) {
+ return null;
+ }
+ }
+ element = prev;
+ }
+ return element;
+ }
+
+ public static PsiElement searchForward(PsiElement element, PsiMatcherExpression matcher,
+ PsiMatcherExpression until) {
+ while (!matcher.match(element)) {
+ if (until.match(element)) {
+ return null;
+ }
+ PsiElement next = element.getNextSibling();
+ if (next == null) {
+ next = element.getParent();
+ if (next == null) {
+ return null;
+ }
+ }
+ element = next;
+ }
+ return element;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/util/StringUtils.java b/smalidea/src/main/java/org/jf/smalidea/util/StringUtils.java
new file mode 100644
index 00000000..e5cc1ccc
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/util/StringUtils.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015, 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.util;
+
+import org.antlr.runtime.CommonToken;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smali.smaliFlexLexer;
+import org.jf.smali.smaliParser;
+
+import java.io.StringReader;
+
+public class StringUtils {
+
+ @Nullable
+ public static String parseQuotedString(String str) {
+ if (str.charAt(0) != '"') {
+ return null;
+ }
+
+ smaliFlexLexer lexer = new smaliFlexLexer(new StringReader(str));
+ lexer.setSuppressErrors(true);
+
+ CommonToken token = (CommonToken)lexer.nextToken();
+ if (token.getType() != smaliParser.STRING_LITERAL) {
+ return null;
+ }
+
+ if (token.getStopIndex() != str.length()-1) {
+ return null;
+ }
+
+ String text = token.getText();
+ return text.substring(1, text.length()-1);
+ }
+}
diff --git a/smalidea/src/main/resources/META-INF/plugin.xml b/smalidea/src/main/resources/META-INF/plugin.xml
new file mode 100644
index 00000000..6e24054b
--- /dev/null
+++ b/smalidea/src/main/resources/META-INF/plugin.xml
@@ -0,0 +1,47 @@
+<idea-plugin version="2">
+ <id>org.jf.smalidea</id>
+ <name>Smalidea</name>
+ <version>0.02</version>
+ <vendor email="jesusfreke@jesusfreke.com" url="http://smali.org">JesusFreke</vendor>
+
+ <description><![CDATA[
+ A smali language plugin for IDEA
+ ]]></description>
+
+ <change-notes><![CDATA[
+ ]]>
+ </change-notes>
+
+ <idea-version since-build="131"/>
+
+ <extensions defaultExtensionNs="com.intellij">
+ <fileTypeFactory implementation="org.jf.smalidea.SmaliFileTypeFactory"/>
+ <syntaxHighlighter key="smali" implementationClass="org.jf.smalidea.SmaliHighlighter"/>
+ <colorSettingsPage implementation="org.jf.smalidea.SmaliColorsPage"/>
+ <lang.parserDefinition language="smali" implementationClass="org.jf.smalidea.SmaliParserDefinition"/>
+ <lang.ast.factory language="smali" implementationClass="org.jf.smalidea.SmaliASTFactory"/>
+ <java.elementFinder implementation="org.jf.smalidea.psi.index.SmaliClassFinder"/>
+ <stubIndex implementation="org.jf.smalidea.psi.index.SmaliClassNameIndex"/>
+ <debugger.positionManagerFactory implementation="org.jf.smalidea.debugging.SmaliPositionManagerFactory"/>
+ <xdebugger.debuggerSupport id="SmaliDebuggerSupport" order="first,before XDebuggerSupport"
+ implementation="org.jf.smalidea.debugging.SmaliDebuggerSupport"/>
+ <debugger.codeFragmentFactory implementation="org.jf.smalidea.debugging.SmaliCodeFragmentFactory"/>
+ <stubElementTypeHolder class="org.jf.smalidea.psi.SmaliElementTypes" />
+ <lang.findUsagesProvider language="smali"
+ implementationClass="org.jf.smalidea.findUsages.SmaliFindUsagesProvider"/>
+ <referencesSearch implementation="org.jf.smalidea.findUsages.SmaliClassReferenceSearcher"/>
+ <usageTargetProvider implementation="org.jf.smalidea.findUsages.SmaliUsageTargetProvider" />
+ <usageTypeProvider implementation="org.jf.smalidea.findUsages.SmaliUsageTypeProvider"/>
+ <errorHandler implementation="org.jf.smalidea.errorReporting.ErrorReporter"/>
+ </extensions>
+
+ <application-components>
+ </application-components>
+
+ <project-components>
+ </project-components>
+
+ <actions>
+ </actions>
+
+</idea-plugin> \ No newline at end of file
diff --git a/smalidea/src/main/resources/icons/smali.png b/smalidea/src/main/resources/icons/smali.png
new file mode 100644
index 00000000..e60efc56
--- /dev/null
+++ b/smalidea/src/main/resources/icons/smali.png
Binary files differ
diff --git a/smalidea/src/test/java/org/jf/smalidea/AnnotationElementNameReferenceTest.java b/smalidea/src/test/java/org/jf/smalidea/AnnotationElementNameReferenceTest.java
new file mode 100644
index 00000000..b11193a8
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/AnnotationElementNameReferenceTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2015, 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;
+
+import com.intellij.psi.*;
+import com.intellij.testFramework.ResolveTestCase;
+import org.junit.Assert;
+
+public class AnnotationElementNameReferenceTest extends ResolveTestCase {
+ public void testSmaliReferenceFromSmali() throws Exception {
+ createFile("AnnotationWithValues.smali", "" +
+ ".class public abstract interface annotation LAnnotationWithValues;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".implements Ljava/lang/annotation/Annotation;\n" +
+ "\n" +
+ ".method public abstract intValue()I\n" +
+ ".end method");
+
+ PsiReference reference = configureByFileText("" +
+ ".class public Lblah;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".annotation runtime LAnnotationWithValues;\n" +
+ " int<ref>Value = 123\n" +
+ ".end annotation", "blah.smali");
+
+ PsiElement resolved = reference.resolve();
+ Assert.assertNotNull(resolved);
+ Assert.assertTrue(resolved instanceof PsiAnnotationMethod);
+ Assert.assertEquals("intValue", ((PsiAnnotationMethod)resolved).getName());
+ Assert.assertEquals("AnnotationWithValues",
+ ((PsiAnnotationMethod)resolved).getContainingClass().getQualifiedName());
+ }
+
+ public void testJavaReferenceFromSmali() throws Exception {
+ createFile("AnnotationWithValues.java", "" +
+ "public @interface AnnotationWithValues {\n" +
+ " int intValue();\n" +
+ "}");
+
+ PsiReference reference = configureByFileText("" +
+ ".class public Lblah;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".annotation runtime LAnnotationWithValues;\n" +
+ " int<ref>Value = 123\n" +
+ ".end annotation", "blah.smali");
+
+ PsiElement resolved = reference.resolve();
+ Assert.assertNotNull(resolved);
+ Assert.assertTrue(resolved instanceof PsiAnnotationMethod);
+ Assert.assertEquals("intValue", ((PsiAnnotationMethod)resolved).getName());
+ Assert.assertEquals("AnnotationWithValues",
+ ((PsiAnnotationMethod)resolved).getContainingClass().getQualifiedName());
+ }
+
+ public void testSmaliReferenceFromJava() throws Exception {
+ createFile("AnnotationWithValues.smali", "" +
+ ".class public abstract interface annotation LAnnotationWithValues;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".implements Ljava/lang/annotation/Annotation;\n" +
+ "\n" +
+ ".method public abstract intValue()I\n" +
+ ".end method");
+
+ PsiReference reference = configureByFileText("" +
+ "@AnnotationWithValues(int<ref>Value=123)\n" +
+ "public class blah {}", "blah.java");
+
+ PsiElement resolved = reference.resolve();
+ Assert.assertNotNull(resolved);
+ Assert.assertTrue(resolved instanceof PsiAnnotationMethod);
+ Assert.assertEquals("intValue", ((PsiAnnotationMethod)resolved).getName());
+ Assert.assertEquals("AnnotationWithValues",
+ ((PsiAnnotationMethod)resolved).getContainingClass().getQualifiedName());
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/ClassMoveTest.java b/smalidea/src/test/java/org/jf/smalidea/ClassMoveTest.java
new file mode 100644
index 00000000..89d45451
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/ClassMoveTest.java
@@ -0,0 +1,55 @@
+package org.jf.smalidea;
+
+import com.intellij.openapi.roots.JavaProjectRootsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.refactoring.MultiFileTestCase;
+import com.intellij.refactoring.PackageWrapper;
+import com.intellij.refactoring.move.moveClassesOrPackages.AutocreatingSingleSourceRootMoveDestination;
+import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesProcessor;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public class ClassMoveTest extends MultiFileTestCase {
+ @Override
+ protected String getTestDataPath() {
+ return "testData";
+ }
+
+ @NotNull
+ @Override
+ protected String getTestRoot() {
+ return "/classMove/";
+ }
+
+ public void testBasicFromNoPackage() {
+ doTest("blah", "my");
+ }
+
+ public void testBasicToNoPackage() {
+ doTest("my.blah", "");
+ }
+
+ private void doTest(@NotNull final String oldQualifiedName, @NotNull final String newPackage) {
+ doTest(new PerformAction() {
+ @Override
+ public void performAction(VirtualFile rootDir, VirtualFile rootAfter) throws Exception {
+ doMove(oldQualifiedName, newPackage);
+ }
+ });
+ }
+
+ private void doMove(String oldQualifiedName, final String newPackage) throws Exception {
+ final PsiClass testClass = myJavaFacade.findClass(oldQualifiedName, GlobalSearchScope.allScope(getProject()));
+
+ final List<VirtualFile> contentSourceRoots =
+ JavaProjectRootsUtil.getSuitableDestinationSourceRoots(getProject());
+
+ new MoveClassesOrPackagesProcessor(getProject(), new PsiClass[] {testClass},
+ new AutocreatingSingleSourceRootMoveDestination(new PackageWrapper(getPsiManager(), newPackage),
+ contentSourceRoots.get(0)), false, false, null).run();
+ }
+
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/ClassReferenceTest.java b/smalidea/src/test/java/org/jf/smalidea/ClassReferenceTest.java
new file mode 100644
index 00000000..05f3b1be
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/ClassReferenceTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
+import com.intellij.psi.JavaResolveResult;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiReference;
+import com.intellij.testFramework.ResolveTestCase;
+import org.jf.smalidea.psi.impl.SmaliClass;
+import org.jf.smalidea.psi.impl.SmaliClassTypeElement;
+import org.junit.Assert;
+
+public class ClassReferenceTest extends ResolveTestCase {
+ /**
+ * Test a reference to a java class from a smali class
+ */
+ public void testJavaReferenceFromSmali() throws Exception {
+ SmaliClassTypeElement typeElement = (SmaliClassTypeElement)configureByFileText(
+ ".class public Lblah; .super L<ref>java/lang/Object;", "blah.smali");
+
+ Assert.assertNotNull(typeElement);
+ Assert.assertEquals("Object", typeElement.getName());
+
+ PsiClass psiClass = typeElement.resolve();
+ Assert.assertNotNull(psiClass);
+ Assert.assertEquals("java.lang.Object", psiClass.getQualifiedName());
+
+ JavaResolveResult resolveResult = typeElement.advancedResolve(false);
+ Assert.assertNotNull(resolveResult.getElement());
+ Assert.assertEquals("java.lang.Object", ((PsiClass)resolveResult.getElement()).getQualifiedName());
+
+ JavaResolveResult[] resolveResults = typeElement.multiResolve(false);
+ Assert.assertEquals(1, resolveResults.length);
+ Assert.assertNotNull(resolveResults[0].getElement());
+ Assert.assertEquals("java.lang.Object", ((PsiClass)resolveResults[0].getElement()).getQualifiedName());
+ }
+
+ /**
+ * Test a reference to a smali class from a smali class
+ */
+ public void testSmaliReferenceFromSmali() throws Exception {
+ createFile("blarg.smali", ".class public Lblarg; .super Ljava/lang/Object;");
+
+ SmaliClassTypeElement typeElement = (SmaliClassTypeElement)configureByFileText(
+ ".class public Lblah; .super L<ref>blarg;", "blah.smali");
+
+ Assert.assertEquals("blarg", typeElement.getName());
+
+ SmaliClass smaliClass = (SmaliClass)typeElement.resolve();
+ Assert.assertNotNull(smaliClass);
+ Assert.assertEquals("blarg", smaliClass.getQualifiedName());
+
+ JavaResolveResult resolveResult = typeElement.advancedResolve(false);
+ Assert.assertNotNull(resolveResult.getElement());
+ Assert.assertEquals("blarg", ((PsiClass)resolveResult.getElement()).getQualifiedName());
+
+ JavaResolveResult[] resolveResults = typeElement.multiResolve(false);
+ Assert.assertEquals(1, resolveResults.length);
+ Assert.assertNotNull(resolveResults[0].getElement());
+ Assert.assertEquals("blarg", ((PsiClass)resolveResults[0].getElement()).getQualifiedName());
+ }
+
+ /**
+ * Test a reference to a smali class from a java class
+ */
+ public void testSmaliReferenceFromJava() throws Exception {
+ createFile("blarg.smali", ".class public Lblarg; .super Ljava/lang/Object;");
+
+ PsiReference reference = configureByFileText(
+ "public class blah extends bla<ref>rg { }", "blah.java");
+
+ SmaliClass smaliClass = (SmaliClass)reference.resolve();
+ Assert.assertNotNull(smaliClass);
+ Assert.assertEquals("blarg", smaliClass.getQualifiedName());
+ }
+
+ @Override
+ protected Sdk getTestProjectJdk() {
+ return JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/ClassRenameTest.java b/smalidea/src/test/java/org/jf/smalidea/ClassRenameTest.java
new file mode 100644
index 00000000..d1c7365b
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/ClassRenameTest.java
@@ -0,0 +1,51 @@
+package org.jf.smalidea;
+
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.refactoring.MultiFileTestCase;
+import com.intellij.refactoring.rename.RenameProcessor;
+import org.jetbrains.annotations.NotNull;
+
+public class ClassRenameTest extends MultiFileTestCase {
+ @Override
+ protected String getTestDataPath() {
+ return "testData";
+ }
+
+ @NotNull
+ @Override
+ protected String getTestRoot() {
+ return "/classRename/";
+ }
+
+ public void testBasicNoPackage() {
+ doTest("blah", "blah2");
+ }
+
+ public void testBasicWithPackage() {
+ doTest("my.blah", "blah2");
+ }
+
+ private void doTest(@NotNull final String oldQualifiedName, @NotNull final String newName) {
+ doTest(new PerformAction() {
+ @Override
+ public void performAction(VirtualFile rootDir, VirtualFile rootAfter) throws Exception {
+ doRename(oldQualifiedName, newName);
+ }
+ });
+ }
+
+ private void doRename(String oldQualifiedName, String newName) throws Exception {
+ PsiClass testClass = myJavaFacade.findClass(oldQualifiedName, GlobalSearchScope.allScope(getProject()));
+
+ RenameProcessor processor = new RenameProcessor(getProject(), testClass, newName, false, false);
+ processor.run();
+
+ PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+ FileDocumentManager.getInstance().saveAllDocuments();
+ }
+
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/FieldReferenceTest.java b/smalidea/src/test/java/org/jf/smalidea/FieldReferenceTest.java
new file mode 100644
index 00000000..78360d8b
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/FieldReferenceTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2015, 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;
+
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiReference;
+import com.intellij.testFramework.ResolveTestCase;
+import org.jf.smalidea.psi.impl.SmaliFieldReference;
+import org.junit.Assert;
+
+public class FieldReferenceTest extends ResolveTestCase {
+ /**
+ * Test a reference to a java field from a smali class
+ */
+ public void testJavaReferenceFromSmali() throws Exception {
+ String text =
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".method public blah()V\n" +
+ " .locals 1\n" +
+ " sget-object v0, Ljava/lang/System;->o<ref>ut:Ljava/io/PrintStream;\n" +
+ " return-void\n" +
+ ".end method";
+
+ SmaliFieldReference fieldReference = (SmaliFieldReference)configureByFileText(text, "blah.smali");
+
+ Assert.assertNotNull(fieldReference);
+ Assert.assertEquals("out", fieldReference.getName());
+ Assert.assertNotNull(fieldReference.getFieldType());
+ Assert.assertEquals("java.io.PrintStream", fieldReference.getFieldType().getType().getCanonicalText());
+
+ PsiField resolvedField = fieldReference.resolve();
+ Assert.assertNotNull(resolvedField);
+ Assert.assertEquals("out", resolvedField.getName());
+ Assert.assertNotNull(resolvedField.getContainingClass());
+ Assert.assertEquals("java.lang.System", resolvedField.getContainingClass().getQualifiedName());
+ Assert.assertEquals("java.io.PrintStream", resolvedField.getType().getCanonicalText());
+ }
+
+ /**
+ * Test a reference to a smali field from a smali class
+ */
+ public void testSmaliReferenceFromSmali() throws Exception {
+ createFile("blarg.smali", ".class public Lblarg; .super Ljava/lang/Object;" +
+ ".field public static blort:I");
+
+ String text =
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".method public blah()V\n" +
+ " .locals 1\n" +
+ " sget v0, Lblarg;->bl<ref>ort:I\n" +
+ " return-void\n" +
+ ".end method";
+
+ SmaliFieldReference fieldReference = (SmaliFieldReference)configureByFileText(text, "blah.smali");
+
+ Assert.assertNotNull(fieldReference);
+ Assert.assertEquals("blort", fieldReference.getName());
+ Assert.assertNotNull(fieldReference.getFieldType());
+ Assert.assertEquals("int", fieldReference.getFieldType().getType().getCanonicalText());
+
+ PsiField resolvedField = fieldReference.resolve();
+ Assert.assertNotNull(resolvedField);
+ Assert.assertEquals("blort", resolvedField.getName());
+ Assert.assertNotNull(resolvedField.getContainingClass());
+ Assert.assertEquals("blarg", resolvedField.getContainingClass().getQualifiedName());
+ Assert.assertEquals("int", resolvedField.getType().getCanonicalText());
+ }
+
+ /**
+ * Test a reference to a smali field from a java class
+ */
+ public void testSmaliReferenceFromJava() throws Exception {
+ createFile("blarg.smali", ".class public Lblarg; .super Ljava/lang/Object;" +
+ ".field public static blort:I");
+
+ String text = "public class blah { public static void something() {" +
+ "blarg.bl<ref>ort = 10;" +
+ "}}";
+
+ PsiReference fieldReference = configureByFileText(text, "blah.java");
+
+ Assert.assertNotNull(fieldReference);
+
+ PsiField resolvedField = (PsiField)fieldReference.resolve();
+ Assert.assertNotNull(resolvedField);
+ Assert.assertEquals("blort", resolvedField.getName());
+ Assert.assertNotNull(resolvedField.getContainingClass());
+ Assert.assertEquals("blarg", resolvedField.getContainingClass().getQualifiedName());
+ Assert.assertEquals("int", resolvedField.getType().getCanonicalText());
+ }
+
+ @Override
+ protected Sdk getTestProjectJdk() {
+ return JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/FieldRenameTest.java b/smalidea/src/test/java/org/jf/smalidea/FieldRenameTest.java
new file mode 100644
index 00000000..4edab84c
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/FieldRenameTest.java
@@ -0,0 +1,50 @@
+package org.jf.smalidea;
+
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiField;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.refactoring.MultiFileTestCase;
+import com.intellij.refactoring.rename.RenameProcessor;
+import org.jetbrains.annotations.NotNull;
+
+public class FieldRenameTest extends MultiFileTestCase {
+ @Override
+ protected String getTestDataPath() {
+ return "testData";
+ }
+
+ @NotNull
+ @Override
+ protected String getTestRoot() {
+ return "/fieldRename/";
+ }
+
+ public void testFieldRename() {
+ doTest("blah", "blah", "blort");
+ }
+
+ private void doTest(@NotNull final String containingClass, @NotNull final String oldFieldName,
+ @NotNull final String newFieldName) {
+ doTest(new PerformAction() {
+ @Override
+ public void performAction(VirtualFile rootDir, VirtualFile rootAfter) throws Exception {
+ doRename(containingClass, oldFieldName, newFieldName);
+ }
+ });
+ }
+
+ private void doRename(String containingClass, String oldFieldName, String newFieldName) throws Exception {
+ PsiClass testClass = myJavaFacade.findClass(containingClass, GlobalSearchScope.allScope(getProject()));
+
+ PsiField field = testClass.findFieldByName(oldFieldName, false);
+
+ RenameProcessor processor = new RenameProcessor(getProject(), field, newFieldName, false, false);
+ processor.run();
+
+ PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+ FileDocumentManager.getInstance().saveAllDocuments();
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/LightCodeInsightParsingTestCase.java b/smalidea/src/test/java/org/jf/smalidea/LightCodeInsightParsingTestCase.java
new file mode 100644
index 00000000..290021ac
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/LightCodeInsightParsingTestCase.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jf.smalidea;
+
+import com.intellij.lang.Language;
+import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.CharsetToolkit;
+import com.intellij.psi.*;
+import com.intellij.psi.impl.DebugUtil;
+import com.intellij.psi.impl.PsiFileFactoryImpl;
+import com.intellij.psi.impl.source.PsiFileImpl;
+import com.intellij.psi.stubs.SerializationManagerImpl;
+import com.intellij.psi.stubs.SerializerNotFoundException;
+import com.intellij.psi.stubs.StubTree;
+import com.intellij.testFramework.LightVirtualFile;
+import com.intellij.testFramework.TestDataFile;
+import com.intellij.testFramework.UsefulTestCase;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+
+/**
+ * A test case for parsing tests.
+ *
+ * This was originally based on com.intellij.testFramework.ParsingTestCase, but was modified
+ * to use the LightCodeInsightFixtureTestCase base class, which provides more functionality
+ */
+public abstract class LightCodeInsightParsingTestCase extends LightCodeInsightFixtureTestCase {
+ protected final String myFilePrefix = "";
+ protected final String myFileExt;
+ @NonNls protected final String myFullDataPath;
+ protected final Language myLanguage;
+
+ protected PsiFile myFile;
+
+ public LightCodeInsightParsingTestCase(@NonNls @NotNull String dataPath, @NotNull String fileExt,
+ @NotNull Language language) {
+ myLanguage = language;
+ myFullDataPath = getTestDataPath() + "/" + dataPath;
+ myFileExt = fileExt;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ myFile = null;
+ }
+
+ protected boolean includeRanges() {
+ return false;
+ }
+
+ protected boolean skipSpaces() {
+ return false;
+ }
+
+ protected boolean checkAllPsiRoots() {
+ return true;
+ }
+
+ protected void doTest(boolean checkResult) {
+ String name = getTestName(false);
+ try {
+ String text = loadFile(name + "." + myFileExt);
+ PsiFile f = createPsiFile(name, text);
+
+ if (f instanceof PsiFileImpl) {
+ // Also want to test stub serialization/deserialization
+ StubTree stubTree = ((PsiFileImpl)f).calcStubTree();
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ SerializationManagerImpl.getInstanceEx().serialize(stubTree.getRoot(), baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ SerializationManagerImpl.getInstanceEx().deserialize(bais);
+ }
+
+ ensureParsed(f);
+ assertEquals("light virtual file text mismatch", text,
+ ((LightVirtualFile)f.getVirtualFile()).getContent().toString());
+ assertEquals("virtual file text mismatch", text, LoadTextUtil.loadText(f.getVirtualFile()));
+ assertEquals("doc text mismatch", text, f.getViewProvider().getDocument().getText());
+ assertEquals("psi text mismatch", text, f.getText());
+ if (checkResult){
+ checkResult(name, f);
+ }
+ else{
+ toParseTreeText(f, skipSpaces(), includeRanges());
+ }
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ } catch (SerializerNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected void doTest(String suffix) throws IOException {
+ String name = getTestName(false);
+ String text = loadFile(name + "." + myFileExt);
+ myFile = createPsiFile(name, text);
+ ensureParsed(myFile);
+ assertEquals(text, myFile.getText());
+ checkResult(name + suffix, myFile);
+ }
+
+ protected void doCodeTest(String code) throws IOException {
+ String name = getTestName(false);
+ myFile = createPsiFile("a", code);
+ ensureParsed(myFile);
+ assertEquals(code, myFile.getText());
+ checkResult(myFilePrefix + name, myFile);
+ }
+
+ protected PsiFile createPsiFile(String name, String text) {
+ return createFile(name + "." + myFileExt, text);
+ }
+
+ protected PsiFile createFile(@NonNls String name, String text) {
+ LightVirtualFile virtualFile = new LightVirtualFile(name, myLanguage, text);
+ virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET);
+ return createFile(virtualFile);
+ }
+
+ protected PsiFile createFile(LightVirtualFile virtualFile) {
+ return ((PsiFileFactoryImpl)PsiFileFactory.getInstance(getProject())).trySetupPsiForFile(
+ virtualFile, myLanguage, true, false);
+ }
+
+ protected void checkResult(@NonNls @TestDataFile String targetDataName, final PsiFile file) throws IOException {
+ doCheckResult(myFullDataPath, file, checkAllPsiRoots(), targetDataName, skipSpaces(), includeRanges());
+ }
+
+ public static void doCheckResult(String myFullDataPath,
+ PsiFile file,
+ boolean checkAllPsiRoots,
+ String targetDataName,
+ boolean skipSpaces,
+ boolean printRanges) throws IOException {
+ FileViewProvider provider = file.getViewProvider();
+ Set<Language> languages = provider.getLanguages();
+
+ if (!checkAllPsiRoots || languages.size() == 1) {
+ doCheckResult(myFullDataPath, targetDataName + ".txt", toParseTreeText(file, skipSpaces, printRanges).trim());
+ return;
+ }
+
+ for (Language language : languages) {
+ PsiFile root = provider.getPsi(language);
+ String expectedName = targetDataName + "." + language.getID() + ".txt";
+ doCheckResult(myFullDataPath, expectedName, toParseTreeText(root, skipSpaces, printRanges).trim());
+ }
+ }
+
+ protected void checkResult(@TestDataFile @NonNls String targetDataName, final String text) throws IOException {
+ doCheckResult(myFullDataPath, targetDataName, text);
+ }
+
+ public static void doCheckResult(String fullPath, String targetDataName, String text) throws IOException {
+ String expectedFileName = fullPath + File.separatorChar + targetDataName;
+ UsefulTestCase.assertSameLinesWithFile(expectedFileName, text);
+ }
+
+ protected static String toParseTreeText(final PsiElement file, boolean skipSpaces, boolean printRanges) {
+ return DebugUtil.psiToString(file, skipSpaces, printRanges);
+ }
+
+ protected String loadFile(@NonNls @TestDataFile String name) throws IOException {
+ return doLoadFile(myFullDataPath, name);
+ }
+
+ private static String doLoadFile(String myFullDataPath, String name) throws IOException {
+ return FileUtil.loadFile(new File(myFullDataPath, name), CharsetToolkit.UTF8, true).trim();
+ }
+
+ public static void ensureParsed(PsiFile file) {
+ file.accept(new PsiElementVisitor() {
+ @Override
+ public void visitElement(PsiElement element) {
+ element.acceptChildren(this);
+ }
+ });
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/MethodReferenceTest.java b/smalidea/src/test/java/org/jf/smalidea/MethodReferenceTest.java
new file mode 100644
index 00000000..1de65983
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/MethodReferenceTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiReference;
+import com.intellij.testFramework.ResolveTestCase;
+import org.jf.smalidea.psi.impl.SmaliMethodReference;
+import org.junit.Assert;
+
+public class MethodReferenceTest extends ResolveTestCase {
+ /**
+ * Test a reference to a java method from a smali class
+ */
+ public void testJavaReferenceFromSmali() throws Exception {
+ String text =
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".method public blah()V\n" +
+ " .locals 1\n" +
+
+ " invoke-static {}, Ljava/lang/System;->nano<ref>Time()J\n" +
+ " return-void\n" +
+ ".end method";
+
+ SmaliMethodReference methodReference = (SmaliMethodReference)configureByFileText(text, "blah.smali");
+
+ Assert.assertNotNull(methodReference);
+ Assert.assertEquals("nanoTime", methodReference.getName());
+
+ PsiMethod resolvedMethod = (PsiMethod)methodReference.resolve();
+ Assert.assertNotNull(resolvedMethod);
+ Assert.assertEquals("nanoTime", resolvedMethod.getName());
+ Assert.assertNotNull(resolvedMethod.getContainingClass());
+ Assert.assertEquals("java.lang.System", resolvedMethod.getContainingClass().getQualifiedName());
+ Assert.assertEquals(0, resolvedMethod.getParameterList().getParametersCount());
+ Assert.assertNotNull(resolvedMethod.getReturnType());
+ Assert.assertEquals("long", resolvedMethod.getReturnType().getCanonicalText());
+ }
+
+ /**
+ * Test a reference to a smali method from a smali class
+ */
+ public void testSmaliReferenceFromSmali() throws Exception {
+ createFile("blarg.smali", ".class public Lblarg; .super Ljava/lang/Object;" +
+ ".method public static blort(ILjava/lang/String;)V\n" +
+ " .locals 0\n" +
+ " return-void\n" +
+ ".end method\n");
+
+ String text =
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".method public blah2()V\n" +
+ " .locals 0\n" +
+ " invoke-static {}, Lblarg;->bl<ref>ort(ILjava/lang/String;)V\n" +
+ " return-void\n" +
+ ".end method";
+
+ SmaliMethodReference methodReference = (SmaliMethodReference)configureByFileText(text, "blah.smali");
+
+ Assert.assertNotNull(methodReference);
+ Assert.assertEquals("blort", methodReference.getName());
+
+ PsiMethod resolvedMethod = (PsiMethod)methodReference.resolve();
+ Assert.assertNotNull(resolvedMethod);
+ Assert.assertEquals("blort", resolvedMethod.getName());
+ Assert.assertNotNull(resolvedMethod.getContainingClass());
+ Assert.assertEquals("blarg", resolvedMethod.getContainingClass().getQualifiedName());
+ Assert.assertEquals(2, resolvedMethod.getParameterList().getParametersCount());
+ Assert.assertEquals("int", resolvedMethod.getParameterList().getParameters()[0].getType().getCanonicalText());
+ Assert.assertEquals("java.lang.String",
+ resolvedMethod.getParameterList().getParameters()[1].getType().getCanonicalText());
+ Assert.assertNotNull(resolvedMethod.getReturnType());
+ Assert.assertEquals("void", resolvedMethod.getReturnType().getCanonicalText());
+ }
+
+ /**
+ * Test a reference to a smali method from a java class
+ */
+ public void testSmaliReferenceFromJava() throws Exception {
+ createFile("blarg.smali", ".class public Lblarg; .super Ljava/lang/Object;" +
+ ".method public static blort(ILjava/lang/String;)V\n" +
+ " .locals 0\n" +
+ " return-void\n" +
+ ".end method\n");
+
+
+ String text = "public class blah { public static void something() {" +
+ "blarg.bl<ref>ort(10, \"bob\");" +
+ "}}";
+
+ PsiReference methodReference = configureByFileText(text, "blah.java");
+
+ Assert.assertNotNull(methodReference);
+
+ PsiMethod resolvedMethod = (PsiMethod)methodReference.resolve();
+ Assert.assertNotNull(resolvedMethod);
+ Assert.assertEquals("blort", resolvedMethod.getName());
+ Assert.assertNotNull(resolvedMethod.getContainingClass());
+ Assert.assertEquals("blarg", resolvedMethod.getContainingClass().getQualifiedName());
+ Assert.assertEquals(2, resolvedMethod.getParameterList().getParametersCount());
+ Assert.assertEquals("int", resolvedMethod.getParameterList().getParameters()[0].getType().getCanonicalText());
+ Assert.assertEquals("java.lang.String",
+ resolvedMethod.getParameterList().getParameters()[1].getType().getCanonicalText());
+ Assert.assertNotNull(resolvedMethod.getReturnType());
+ Assert.assertEquals("void", resolvedMethod.getReturnType().getCanonicalText());
+ }
+
+ @Override
+ protected Sdk getTestProjectJdk() {
+ return JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/MethodRenameTest.java b/smalidea/src/test/java/org/jf/smalidea/MethodRenameTest.java
new file mode 100644
index 00000000..29cf4d36
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/MethodRenameTest.java
@@ -0,0 +1,50 @@
+package org.jf.smalidea;
+
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.refactoring.MultiFileTestCase;
+import com.intellij.refactoring.rename.RenameProcessor;
+import org.jetbrains.annotations.NotNull;
+
+public class MethodRenameTest extends MultiFileTestCase {
+ @Override
+ protected String getTestDataPath() {
+ return "testData";
+ }
+
+ @NotNull
+ @Override
+ protected String getTestRoot() {
+ return "/methodRename/";
+ }
+
+ public void testMethodRename() {
+ doTest("blah", "blah", "blort");
+ }
+
+ private void doTest(@NotNull final String containingClass, @NotNull final String oldMethodName,
+ @NotNull final String newMethodName) {
+ doTest(new PerformAction() {
+ @Override
+ public void performAction(VirtualFile rootDir, VirtualFile rootAfter) throws Exception {
+ doRename(containingClass, oldMethodName, newMethodName);
+ }
+ });
+ }
+
+ private void doRename(String containingClass, String oldMethodName, String newMethodName) throws Exception {
+ PsiClass testClass = myJavaFacade.findClass(containingClass, GlobalSearchScope.allScope(getProject()));
+
+ PsiMethod method = testClass.findMethodsByName(oldMethodName, false)[0];
+
+ RenameProcessor processor = new RenameProcessor(getProject(), method, newMethodName, false, false);
+ processor.run();
+
+ PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+ FileDocumentManager.getInstance().saveAllDocuments();
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/ParserTest.java b/smalidea/src/test/java/org/jf/smalidea/ParserTest.java
new file mode 100644
index 00000000..0504bfe3
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/ParserTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015, 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;
+
+public class ParserTest extends LightCodeInsightParsingTestCase {
+ public ParserTest() {
+ super("", "smalidea", SmaliLanguage.INSTANCE);
+ }
+
+ @Override
+ protected String getTestDataPath() {
+ return "testData";
+ }
+
+ public void testEmpty() throws Exception { doTest(true); }
+ public void testFieldAnnotations() throws Exception { doTest(true); }
+ public void testInvalidAnnotation() throws Exception { doTest(true); }
+ public void testInvalidClassDirective() throws Exception { doTest(true); }
+ public void testInvalidClassDirective2() throws Exception { doTest(true); }
+ public void testInvalidClassDirective3() throws Exception { doTest(true); }
+ public void testInvalidEnumLiteral() throws Exception { doTest(true); }
+ public void testInvalidField() throws Exception { doTest(true); }
+ public void testInvalidField2() throws Exception { doTest(true); }
+ public void testInvalidField3() throws Exception { doTest(true); }
+ public void testInvalidField4() throws Exception { doTest(true); }
+ public void testInvalidInstruction() throws Exception { doTest(true); }
+ public void testInvalidLocal() throws Exception { doTest(true);}
+ public void testParamListInvalidParameter() throws Exception { doTest(true); }
+ public void testSuperClassInvalidSyntax() throws Exception { doTest(true); }
+ public void testSuperClassInvalidSyntax2() throws Exception { doTest(true); }
+ public void testInvalidMethodReference() throws Exception { doTest(true); }
+ public void testInvalidParameter() throws Exception { doTest(true); }
+ public void testInvalidMethod() throws Exception { doTest(true); }
+ public void testInvalidMethod2() throws Exception { doTest(true); }
+ public void testInvalidMethod3() throws Exception { doTest(true); }
+ public void testInvalidMethod4() throws Exception { doTest(true); }
+ public void testMissingDotDot() throws Exception { doTest(true); }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliAnnotationTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliAnnotationTest.java
new file mode 100644
index 00000000..3cd863f9
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliAnnotationTest.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.psi.*;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jf.smalidea.psi.impl.SmaliClass;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.jf.smalidea.psi.impl.SmaliLiteral;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+import org.junit.Assert;
+
+public class SmaliAnnotationTest extends LightCodeInsightFixtureTestCase {
+ // TODO: test default values
+
+ public void testClassAnnotation() {
+ myFixture.addFileToProject("my/TestAnnotation.smali",
+ ".class public interface abstract annotation Lmy/TestAnnotation;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".implements Ljava/lang/annotation/Annotation;\n" +
+ "\n" +
+ ".method public abstract testBooleanValue()Z\n" +
+ ".end method\n" +
+ "\n" +
+ ".method public abstract testStringArrayValue()[Ljava/lang/String;\n" +
+ ".end method\n" +
+ "\n" +
+ ".method public abstract testStringValue()Ljava/lang/String;\n" +
+ ".end method");
+
+ myFixture.addFileToProject("my/TestAnnotation2.smali",
+ ".class public interface abstract annotation Lmy/TestAnnotation2;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".implements Ljava/lang/annotation/Annotation;\n");
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ "\n" +
+ ".annotation runtime Lmy/TestAnnotation;\n" +
+ " testBooleanValue = true\n" +
+ " testStringValue = \"blah\"\n" +
+ " testStringArrayValue = {\n" +
+ " \"blah1\",\n" +
+ " \"blah2\"\n" +
+ " }\n" +
+ ".end annotation\n" +
+ "\n" +
+ ".annotation runtime Lmy/TestAnnotation2;\n" +
+ ".end annotation");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertEquals("my.pkg.blah", smaliClass.getQualifiedName());
+
+ doTest(smaliClass);
+ }
+
+ public void testFieldAnnotation() {
+ myFixture.addFileToProject("my/TestAnnotation.smali",
+ ".class public interface abstract annotation Lmy/TestAnnotation;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".implements Ljava/lang/annotation/Annotation;\n" +
+ "\n" +
+ ".method public abstract testBooleanValue()Z\n" +
+ ".end method\n" +
+ "\n" +
+ ".method public abstract testStringArrayValue()[Ljava/lang/String;\n" +
+ ".end method\n" +
+ "\n" +
+ ".method public abstract testStringValue()Ljava/lang/String;\n" +
+ ".end method");
+
+ myFixture.addFileToProject("my/TestAnnotation2.smali",
+ ".class public interface abstract annotation Lmy/TestAnnotation2;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".implements Ljava/lang/annotation/Annotation;\n");
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ "\n" +
+ ".field public myField:I\n" +
+ " .annotation runtime Lmy/TestAnnotation;\n" +
+ " testBooleanValue = true\n" +
+ " testStringValue = \"blah\"\n" +
+ " testStringArrayValue = {\n" +
+ " \"blah1\",\n" +
+ " \"blah2\"\n" +
+ " }\n" +
+ " .end annotation\n" +
+ " .annotation runtime Lmy/TestAnnotation2;\n" +
+ " .end annotation\n" +
+ ".end field");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertEquals("my.pkg.blah", smaliClass.getQualifiedName());
+
+ PsiField field = smaliClass.findFieldByName("myField", false);
+ doTest((PsiAnnotationOwner)field);
+ }
+
+ public void testMethodAnnotation() {
+ myFixture.addFileToProject("my/TestAnnotation.smali",
+ ".class public interface abstract annotation Lmy/TestAnnotation;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".implements Ljava/lang/annotation/Annotation;\n" +
+ "\n" +
+ ".method public abstract testBooleanValue()Z\n" +
+ ".end method\n" +
+ "\n" +
+ ".method public abstract testStringArrayValue()[Ljava/lang/String;\n" +
+ ".end method\n" +
+ "\n" +
+ ".method public abstract testStringValue()Ljava/lang/String;\n" +
+ ".end method");
+
+ myFixture.addFileToProject("my/TestAnnotation2.smali",
+ ".class public interface abstract annotation Lmy/TestAnnotation2;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".implements Ljava/lang/annotation/Annotation;\n");
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ "\n" +
+ ".method public myMethod()V\n" +
+ " .annotation runtime Lmy/TestAnnotation;\n" +
+ " testBooleanValue = true\n" +
+ " testStringValue = \"blah\"\n" +
+ " testStringArrayValue = {\n" +
+ " \"blah1\",\n" +
+ " \"blah2\"\n" +
+ " }\n" +
+ " .end annotation\n" +
+ " .annotation runtime Lmy/TestAnnotation2;\n" +
+ " .end annotation\n" +
+ ".end method");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertEquals("my.pkg.blah", smaliClass.getQualifiedName());
+
+ SmaliMethod method = smaliClass.getMethods()[0];
+ doTest(method);
+ }
+
+ public void doTest(PsiAnnotationOwner annotationOwner) {
+ Assert.assertEquals(2, annotationOwner.getAnnotations().length);
+
+ Assert.assertEquals("my.TestAnnotation", annotationOwner.getAnnotations()[0].getQualifiedName());
+ PsiJavaCodeReferenceElement annotationNameRef = annotationOwner.getAnnotations()[0].getNameReferenceElement();
+ Assert.assertNotNull(annotationNameRef);
+ SmaliClass smaliAnnotationClass = (SmaliClass)annotationNameRef.resolve();
+ Assert.assertNotNull(smaliAnnotationClass);
+ Assert.assertEquals("my.TestAnnotation", smaliAnnotationClass.getQualifiedName());
+
+ Assert.assertEquals("my.TestAnnotation2", annotationOwner.getAnnotations()[1].getQualifiedName());
+ annotationNameRef = annotationOwner.getAnnotations()[1].getNameReferenceElement();
+ Assert.assertNotNull(annotationNameRef);
+ smaliAnnotationClass = (SmaliClass)annotationNameRef.resolve();
+ Assert.assertNotNull(smaliAnnotationClass);
+ Assert.assertEquals("my.TestAnnotation2", smaliAnnotationClass.getQualifiedName());
+
+ PsiAnnotation smaliAnnotation = annotationOwner.findAnnotation("my.TestAnnotation");
+ Assert.assertNotNull(smaliAnnotation);
+ Assert.assertEquals("my.TestAnnotation", smaliAnnotation.getQualifiedName());
+ PsiAnnotationOwner owner = smaliAnnotation.getOwner();
+ Assert.assertNotNull(owner);
+ Assert.assertSame(annotationOwner, owner);
+ annotationNameRef = smaliAnnotation.getNameReferenceElement();
+ Assert.assertNotNull(annotationNameRef);
+ smaliAnnotationClass = (SmaliClass)annotationNameRef.resolve();
+ Assert.assertNotNull(smaliAnnotationClass);
+ Assert.assertEquals("my.TestAnnotation", smaliAnnotationClass.getQualifiedName());
+
+ PsiAnnotationParameterList parameterList = smaliAnnotation.getParameterList();
+ Assert.assertNotNull(parameterList);
+ Assert.assertEquals(3, parameterList.getAttributes().length);
+ Assert.assertEquals("testBooleanValue", parameterList.getAttributes()[0].getName());
+ PsiAnnotationMemberValue value = parameterList.getAttributes()[0].getValue();
+ Assert.assertNotNull(value);
+ // TODO: test the values rather than the text
+ Assert.assertEquals("true", value.getText());
+ Assert.assertEquals("testStringValue", parameterList.getAttributes()[1].getName());
+ value = parameterList.getAttributes()[1].getValue();
+ Assert.assertNotNull(value);
+ Assert.assertEquals("\"blah\"", value.getText());
+ Assert.assertEquals("testStringArrayValue", parameterList.getAttributes()[2].getName());
+ value = parameterList.getAttributes()[2].getValue();
+ Assert.assertNotNull(value);
+ // TODO: test the individual values, once the array literal stuff is implemented
+
+ value = smaliAnnotation.findAttributeValue("testBooleanValue");
+ Assert.assertNotNull(value);
+ Assert.assertEquals("true", value.getText());
+
+ value = smaliAnnotation.findAttributeValue("testStringValue");
+ Assert.assertNotNull(value);
+ Assert.assertEquals("\"blah\"", value.getText());
+
+ value = smaliAnnotation.findAttributeValue("testStringArrayValue");
+ Assert.assertNotNull(value);
+
+ // TODO: test findAttributeValue vs findDeclaredAttributeValue for default values
+
+ smaliAnnotation = annotationOwner.findAnnotation("my.TestAnnotation2");
+ Assert.assertNotNull(smaliAnnotation);
+ Assert.assertEquals("my.TestAnnotation2", smaliAnnotation.getQualifiedName());
+ owner = smaliAnnotation.getOwner();
+ Assert.assertNotNull(owner);
+ Assert.assertSame(annotationOwner, owner);
+ annotationNameRef = smaliAnnotation.getNameReferenceElement();
+ Assert.assertNotNull(annotationNameRef);
+ smaliAnnotationClass = (SmaliClass)annotationNameRef.resolve();
+ Assert.assertNotNull(smaliAnnotationClass);
+ Assert.assertEquals("my.TestAnnotation2", smaliAnnotationClass.getQualifiedName());
+
+ parameterList = smaliAnnotation.getParameterList();
+ Assert.assertNotNull(parameterList);
+ Assert.assertEquals(0, parameterList.getAttributes().length);
+ }
+
+ public void testDefaultValue() {
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("AnnotationWithDefaultValue.smali", "" +
+ ".class public abstract interface annotation LAnnotationWithValues;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".implements Ljava/lang/annotation/Annotation;\n" +
+ "\n" +
+ ".method public abstract intValue()I\n" +
+ ".end method\n" +
+ "\n" +
+ ".annotation system Ldalvik/annotation/AnnotationDefault;\n" +
+ " value = .subannotation LAnnotationWithValues;\n" +
+ " intValue = 4\n" +
+ " .end subannotation\n" +
+ ".end annotation\n" +
+ "\n");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertNotNull(smaliClass);
+ SmaliMethod method = smaliClass.getMethods()[0];
+ Assert.assertEquals("intValue", method.getName());
+
+ PsiAnnotationMemberValue defaultValue = method.getDefaultValue();
+ Assert.assertTrue(defaultValue instanceof SmaliLiteral);
+ Assert.assertEquals(4, ((SmaliLiteral)defaultValue).getIntegralValue());
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliClassModifierListTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliClassModifierListTest.java
new file mode 100644
index 00000000..a841d0f1
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliClassModifierListTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.psi.PsiModifierListOwner;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jf.dexlib2.AccessFlags;
+import org.jf.smalidea.psi.impl.SmaliAnnotation;
+import org.jf.smalidea.psi.impl.SmaliClass;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.jf.smalidea.psi.impl.SmaliModifierList;
+import org.junit.Assert;
+
+public class SmaliClassModifierListTest extends LightCodeInsightFixtureTestCase {
+ public void testAllClassAccessFlags() {
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public final interface abstract synthetic enum annotation Lmy/pkg/blah; " +
+ ".super Ljava/lang/Object;");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliModifierList modifierList = smaliClass.getModifierList();
+
+ Assert.assertEquals(AccessFlags.PUBLIC.getValue() |
+ AccessFlags.FINAL.getValue() |
+ AccessFlags.INTERFACE.getValue() |
+ AccessFlags.ABSTRACT.getValue() |
+ AccessFlags.SYNTHETIC.getValue() |
+ AccessFlags.ENUM.getValue() |
+ AccessFlags.ANNOTATION.getValue(),
+ modifierList.getAccessFlags());
+
+ Assert.assertTrue(modifierList.hasModifierProperty("public"));
+ Assert.assertTrue(modifierList.hasModifierProperty("final"));
+ Assert.assertTrue(modifierList.hasModifierProperty("interface"));
+ Assert.assertTrue(modifierList.hasModifierProperty("abstract"));
+ Assert.assertTrue(modifierList.hasModifierProperty("synthetic"));
+ Assert.assertTrue(modifierList.hasModifierProperty("enum"));
+ Assert.assertTrue(modifierList.hasModifierProperty("annotation"));
+
+ Assert.assertTrue(modifierList.hasExplicitModifier("public"));
+ Assert.assertTrue(modifierList.hasExplicitModifier("final"));
+ Assert.assertTrue(modifierList.hasExplicitModifier("interface"));
+ Assert.assertTrue(modifierList.hasExplicitModifier("abstract"));
+ Assert.assertTrue(modifierList.hasExplicitModifier("synthetic"));
+ Assert.assertTrue(modifierList.hasExplicitModifier("enum"));
+ Assert.assertTrue(modifierList.hasExplicitModifier("annotation"));
+ }
+
+ public void testNoClassAccessFlags() {
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class Lmy/pkg/blah; " +
+ ".super Ljava/lang/Object;");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliModifierList modifierList = smaliClass.getModifierList();
+
+ Assert.assertEquals(0, modifierList.getAccessFlags());
+
+ Assert.assertFalse(modifierList.hasModifierProperty("public"));
+ Assert.assertFalse(modifierList.hasModifierProperty("final"));
+ Assert.assertFalse(modifierList.hasModifierProperty("interface"));
+ Assert.assertFalse(modifierList.hasModifierProperty("abstract"));
+ Assert.assertFalse(modifierList.hasModifierProperty("synthetic"));
+ Assert.assertFalse(modifierList.hasModifierProperty("enum"));
+ Assert.assertFalse(modifierList.hasModifierProperty("annotation"));
+
+ Assert.assertFalse(modifierList.hasExplicitModifier("public"));
+ Assert.assertFalse(modifierList.hasExplicitModifier("final"));
+ Assert.assertFalse(modifierList.hasExplicitModifier("interface"));
+ Assert.assertFalse(modifierList.hasExplicitModifier("abstract"));
+ Assert.assertFalse(modifierList.hasExplicitModifier("synthetic"));
+ Assert.assertFalse(modifierList.hasExplicitModifier("enum"));
+ Assert.assertFalse(modifierList.hasExplicitModifier("annotation"));
+ }
+
+ public void testAddClassAccessFlag() {
+ final SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public Lmy/pkg/blah;\n" +
+ ".super Ljava/lang/Object;");
+ myFixture.configureFromExistingVirtualFile(file.getVirtualFile());
+
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override public void run() {
+ file.getPsiClass().getModifierList().setModifierProperty("final", true);
+ }
+ });
+
+ myFixture.checkResult(
+ ".class public final Lmy/pkg/blah;\n" +
+ ".super Ljava/lang/Object;");
+ }
+
+ public void testRemoveClassAccessFlag() {
+ final SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public final Lmy/pkg/blah;\n" +
+ ".super Ljava/lang/Object;");
+ myFixture.configureFromExistingVirtualFile(file.getVirtualFile());
+
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override public void run() {
+ file.getPsiClass().getModifierList().setModifierProperty("final", false);
+ }
+ });
+
+ myFixture.checkResult(
+ ".class public Lmy/pkg/blah;\n" +
+ ".super Ljava/lang/Object;");
+ }
+
+ public void testBasicAnnotation() {
+ final SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public final Lmy/pkg/blah;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".annotation Lmy/pkg/anno; .end annotation");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliModifierList modifierList = smaliClass.getModifierList();
+
+ SmaliAnnotation[] annotations = modifierList.getAnnotations();
+ Assert.assertEquals(1, annotations.length);
+
+ Assert.assertEquals("my.pkg.anno", annotations[0].getQualifiedName());
+
+ SmaliAnnotation[] applicableAnnotations = modifierList.getApplicableAnnotations();
+ Assert.assertEquals(1, applicableAnnotations.length);
+ Assert.assertEquals(annotations[0], applicableAnnotations[0]);
+ }
+
+ public void testNoAnnotation() {
+ final SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public final Lmy/pkg/blah;\n" +
+ ".super Ljava/lang/Object;");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliModifierList modifierList = smaliClass.getModifierList();
+
+ // Ensures that the parent of the modifier list is a PsiModifierListOwner
+ // e.g. for code like JavaSuppressionUtil.getInspectionIdsSuppressedInAnnotation,
+ // which assumes the parent is a PsiModifierListOwner
+ Assert.assertTrue(modifierList.getParent() instanceof PsiModifierListOwner);
+
+ Assert.assertEquals(0, modifierList.getAnnotations().length);
+ Assert.assertEquals(0, modifierList.getApplicableAnnotations().length);
+ }
+
+ public void testFindAnnotation() {
+ final SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public final Lmy/pkg/blah;\n" +
+ ".annotation Lanno; .end annotation\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".annotation Lmy/pkg/anno; .end annotation\n" +
+ ".annotation Lmy/pkg/anno2; .end annotation\n" +
+ ".annotation Lmy/pkg/anno3; .end annotation\n");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliModifierList modifierList = smaliClass.getModifierList();
+
+ SmaliAnnotation smaliAnnotation = modifierList.findAnnotation("my.pkg.anno2");
+ Assert.assertNotNull(smaliAnnotation);
+ Assert.assertEquals("my.pkg.anno2", smaliAnnotation.getQualifiedName());
+ }
+
+ // TODO: test modifierList.addAnnotation once implemented
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliClassTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliClassTest.java
new file mode 100644
index 00000000..ba18b662
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliClassTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
+import com.intellij.openapi.roots.ContentEntry;
+import com.intellij.openapi.roots.LanguageLevelModuleExtension;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.psi.JavaPsiFacade;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiClassType;
+import com.intellij.psi.PsiElementFactory;
+import com.intellij.testFramework.LightProjectDescriptor;
+import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.psi.impl.SmaliClass;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.junit.Assert;
+
+public class SmaliClassTest extends LightCodeInsightFixtureTestCase {
+ public void testName() {
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertEquals("my.pkg.blah", smaliClass.getQualifiedName());
+ Assert.assertEquals("my.pkg", smaliClass.getPackageName());
+ Assert.assertEquals("blah", smaliClass.getName());
+ }
+
+ public void testEmptyPackageName() {
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public Lblah; .super Ljava/lang/Object;");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertEquals("blah", smaliClass.getQualifiedName());
+ Assert.assertEquals("", smaliClass.getPackageName());
+ }
+
+ public void testGetSuperclass() {
+ myFixture.addFileToProject("base.smali",
+ ".class public interface Lbase; .super Ljava/lang/Object;");
+
+ myFixture.addFileToProject("iface.smali",
+ ".class public interface Liface; .super Ljava/lang/Object;");
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("blah.smali",
+ ".class public Lblah; .super Lbase; .implements Liface;");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertEquals("blah", smaliClass.getQualifiedName());
+ PsiClass superClass = smaliClass.getSuperClass();
+ Assert.assertNotNull(superClass);
+ Assert.assertEquals("base", smaliClass.getSuperClass().getQualifiedName());
+
+ Assert.assertEquals(2, smaliClass.getSupers().length);
+ Assert.assertEquals("base", smaliClass.getSupers()[0].getQualifiedName());
+ Assert.assertEquals("iface", smaliClass.getSupers()[1].getQualifiedName());
+
+ Assert.assertEquals(2, smaliClass.getSuperTypes().length);
+ Assert.assertEquals("base", smaliClass.getSuperTypes()[0].getCanonicalText());
+ Assert.assertEquals("iface", smaliClass.getSuperTypes()[1].getCanonicalText());
+
+ Assert.assertEquals(1, smaliClass.getInterfaces().length);
+ Assert.assertEquals("iface", smaliClass.getInterfaces()[0].getQualifiedName());
+ }
+
+ public void testGetSuperclassForInterface() {
+ myFixture.addFileToProject("iface.smali",
+ ".class public interface Liface; .super Ljava/lang/Object;");
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("blah.smali",
+ ".class public interface Lblah; .super Ljava/lang/Object; .implements Liface;");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertEquals("blah", smaliClass.getQualifiedName());
+ PsiClass superClass = smaliClass.getSuperClass();
+ Assert.assertNotNull(superClass);
+ Assert.assertEquals("java.lang.Object", smaliClass.getSuperClass().getQualifiedName());
+
+ Assert.assertEquals(2, smaliClass.getSupers().length);
+ Assert.assertEquals("java.lang.Object", smaliClass.getSupers()[0].getQualifiedName());
+ Assert.assertEquals("iface", smaliClass.getSupers()[1].getQualifiedName());
+
+ Assert.assertEquals(1, smaliClass.getSuperTypes().length);
+ Assert.assertEquals("iface", smaliClass.getSuperTypes()[0].getCanonicalText());
+
+ Assert.assertEquals(1, smaliClass.getInterfaces().length);
+ Assert.assertEquals("iface", smaliClass.getInterfaces()[0].getQualifiedName());
+ }
+
+ public void testIsInheritor() {
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("blah.smali",
+ ".class public Lblah; .super Ljava/lang/Exception;");
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertEquals("blah", smaliClass.getQualifiedName());
+
+ PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
+ PsiClassType throwableType = factory.createTypeByFQClassName("java.lang.Throwable", file.getResolveScope());
+ PsiClass throwableClass = throwableType.resolve();
+ Assert.assertNotNull(throwableClass);
+
+ PsiClassType exceptionType = factory.createTypeByFQClassName("java.lang.Exception", file.getResolveScope());
+ PsiClass exceptionClass = exceptionType.resolve();
+ Assert.assertNotNull(exceptionClass);
+
+ PsiClassType objectType = factory.createTypeByFQClassName("java.lang.Object", file.getResolveScope());
+ PsiClass objectClass = objectType.resolve();
+ Assert.assertNotNull(objectClass);
+
+ Assert.assertTrue(smaliClass.isInheritor(exceptionClass, true));
+ Assert.assertTrue(smaliClass.isInheritor(throwableClass, true));
+ Assert.assertTrue(smaliClass.isInheritor(objectClass, true));
+
+ Assert.assertTrue(smaliClass.isInheritorDeep(exceptionClass, null));
+ Assert.assertTrue(smaliClass.isInheritorDeep(throwableClass, null));
+ Assert.assertTrue(smaliClass.isInheritorDeep(objectClass, null));
+
+ Assert.assertTrue(smaliClass.isInheritor(exceptionClass, false));
+ Assert.assertFalse(smaliClass.isInheritor(throwableClass, false));
+ Assert.assertFalse(smaliClass.isInheritor(objectClass, false));
+ }
+
+ @NotNull @Override protected LightProjectDescriptor getProjectDescriptor() {
+ return new DefaultLightProjectDescriptor() {
+ public Sdk getSdk() {
+ return JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();
+ }
+
+ public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) {
+ model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(LanguageLevel.JDK_1_6);
+ }
+ };
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliClassTypeElementTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliClassTypeElementTest.java
new file mode 100644
index 00000000..434c959b
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliClassTypeElementTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jf.smalidea.psi.impl.SmaliClass;
+import org.jf.smalidea.psi.impl.SmaliClassType;
+import org.jf.smalidea.psi.impl.SmaliClassTypeElement;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.junit.Assert;
+
+public class SmaliClassTypeElementTest extends LightCodeInsightFixtureTestCase {
+ public void testGetType() {
+ myFixture.addFileToProject("my/blarg.smali",
+ ".class public Lmy/blarg; " +
+ ".super Ljava/lang/Object;");
+
+ String text = ".class public Lmy/pkg/blah; " +
+ ".super Lmy/bl<ref>arg;";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ text.replace("<ref>", ""));
+
+ SmaliClassTypeElement typeElement =
+ (SmaliClassTypeElement)file.findReferenceAt(text.indexOf("<ref>"));
+ Assert.assertNotNull(typeElement);
+ SmaliClassType type = typeElement.getType();
+
+ Assert.assertEquals("blarg", typeElement.getName());
+ Assert.assertEquals("my.blarg", typeElement.getCanonicalText());
+ Assert.assertEquals("blarg", type.getClassName());
+ Assert.assertEquals("my.blarg", type.getCanonicalText());
+
+ SmaliClass resolvedClass = (SmaliClass)typeElement.resolve();
+ Assert.assertNotNull(resolvedClass);
+ Assert.assertEquals("my.blarg", resolvedClass.getQualifiedName());
+
+ resolvedClass = (SmaliClass)type.resolve();
+ Assert.assertNotNull(resolvedClass);
+ Assert.assertEquals("my.blarg", resolvedClass.getQualifiedName());
+ }
+
+ public void testSimpleInnerClass() {
+ myFixture.addFileToProject("Outer.java", "" +
+ "public class Outer {" +
+ " public static class Inner {" +
+ " }" +
+ "}");
+
+ String text = ".class public Lsmali; " +
+ ".super LOuter$In<ref>ner;";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("smali.smali", text.replace("<ref>", ""));
+
+ SmaliClassTypeElement typeElement =
+ (SmaliClassTypeElement)file.findReferenceAt(text.indexOf("<ref>"));
+ Assert.assertNotNull(typeElement);
+ SmaliClassType type = typeElement.getType();
+
+ Assert.assertEquals("Outer.Inner", typeElement.getQualifiedName());
+ Assert.assertEquals("Outer.Inner", type.getCanonicalText());
+ }
+
+ public void testInnerClassWithPackage() {
+ myFixture.addFileToProject("my/Outer.java", "" +
+ "package my;" +
+ "public class Outer {" +
+ " public static class Inner {" +
+ " }" +
+ "}");
+
+ String text = ".class public Lsmali; " +
+ ".super Lmy/Outer$In<ref>ner;";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("smali.smali", text.replace("<ref>", ""));
+
+ SmaliClassTypeElement typeElement =
+ (SmaliClassTypeElement)file.findReferenceAt(text.indexOf("<ref>"));
+ Assert.assertNotNull(typeElement);
+ SmaliClassType type = typeElement.getType();
+
+ Assert.assertEquals("my.Outer.Inner", typeElement.getQualifiedName());
+ Assert.assertEquals("my.Outer.Inner", type.getCanonicalText());
+ }
+
+ public void testComplexInnerClass() {
+ myFixture.addFileToProject("my/Outer$blah.java", "" +
+ "package my;" +
+ "public class Outer$blah {" +
+ " public static class Inner {" +
+ " }" +
+ " public static class Inner$blah {" +
+ " }" +
+ "}");
+
+ String text = ".class public Lsmali; " +
+ ".super Lmy/Outer$blah$In<ref>ner$blah;";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("smali.smali", text.replace("<ref>", ""));
+
+ SmaliClassTypeElement typeElement =
+ (SmaliClassTypeElement)file.findReferenceAt(text.indexOf("<ref>"));
+ Assert.assertNotNull(typeElement);
+ SmaliClassType type = typeElement.getType();
+
+ Assert.assertEquals("my.Outer$blah.Inner$blah", typeElement.getQualifiedName());
+ Assert.assertEquals("my.Outer$blah.Inner$blah", type.getCanonicalText());
+
+ text = ".class public Lsmali2; " +
+ ".super Lmy/Outer$blah$In<ref>ner;";
+
+ file = (SmaliFile)myFixture.addFileToProject("smali2.smali", text.replace("<ref>", ""));
+
+ typeElement = (SmaliClassTypeElement)file.findReferenceAt(text.indexOf("<ref>"));
+ Assert.assertNotNull(typeElement);
+ type = typeElement.getType();
+
+ Assert.assertEquals("my.Outer$blah.Inner", typeElement.getQualifiedName());
+ Assert.assertEquals("my.Outer$blah.Inner", type.getCanonicalText());
+ }
+
+ public void testInnerClassTrailingDollar() {
+ myFixture.addFileToProject("my/Outer$blah.java", "" +
+ "package my;" +
+ "public class Outer$ {" +
+ " public static class Inner$ {" +
+ " }" +
+ "}");
+
+ String text = ".class public Lsmali; " +
+ ".super Lmy/Outer$$In<ref>ner$;";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("smali.smali", text.replace("<ref>", ""));
+
+ SmaliClassTypeElement typeElement =
+ (SmaliClassTypeElement)file.findReferenceAt(text.indexOf("<ref>"));
+ Assert.assertNotNull(typeElement);
+ SmaliClassType type = typeElement.getType();
+
+ Assert.assertEquals("my.Outer$.Inner$", typeElement.getQualifiedName());
+ Assert.assertEquals("my.Outer$.Inner$", type.getCanonicalText());
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliCodeFragmentFactoryTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliCodeFragmentFactoryTest.java
new file mode 100644
index 00000000..c61d3e44
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliCodeFragmentFactoryTest.java
@@ -0,0 +1,279 @@
+/*
+ * 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;
+
+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;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupManager;
+import com.intellij.debugger.NoDataException;
+import com.intellij.debugger.engine.evaluation.CodeFragmentKind;
+import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
+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.psi.impl.source.tree.java.PsiReferenceExpressionImpl;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.debugging.SmaliCodeFragmentFactory;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.junit.Assert;
+
+import java.util.HashSet;
+import java.util.List;
+
+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" + // 0
+ "\n" +
+ " .line 179\n" +
+ " if-nez p1, :cond_5\n" +
+ "\n" +
+ " move v0, v1\n" + // 2
+ "\n" +
+ " .line 185\n" +
+ " :goto_4\n" +
+ " return v0\n" +
+ "\n" +
+ " .line 182\n" +
+ " :cond_5\n" +
+ " if-ne p1, v1, :cond_f\n" +
+ "\n" +
+ " .line 183\n" +
+ " sget-object v0, Lorg/jf/Penroser/PenroserApp;->random:Ljava/util/Random;\n" +
+ "\n" +
+ " const/4 v1, 0x3\n" + // 6
+ "\n" +
+ " invoke-virtual {v0, v1}, Ljava/util/Random;->nextInt(I)I\n" +
+ "\n" +
+ " move-result v0\n" +
+ "\n" +
+ " goto :goto_4\n" +
+ "\n" +
+ " .line 185\n" +
+ " :cond_f\n" +
+ " sget-object v0, Lorg/jf/Penroser/PenroserApp;->random:Ljava/util/Random;\n" +
+ "\n" +
+ " invoke-virtual {v0, v1}, Ljava/util/Random;->nextInt(I)I\n" +
+ "\n" +
+ " move-result v0\n" +
+ "\n" +
+ " goto :goto_4\n" +
+ ".end method";
+
+ public void testCompletion() throws NoDataException {
+ 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"});
+ assertCompletionContains("p", context, new String[] {"p0", "p1"}, new String[] {"v0", "v1", "v2", "v3"});
+
+ 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,
+ String[] disallowedItems) {
+ SmaliCodeFragmentFactory codeFragmentFactory = new SmaliCodeFragmentFactory();
+ JavaCodeFragment fragment = codeFragmentFactory.createCodeFragment(
+ new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, completionText),
+ context, getProject());
+
+ Editor editor = createEditor(fragment.getVirtualFile());
+ editor.getCaretModel().moveToOffset(completionText.length());
+
+ new CodeCompletionHandlerBase(CompletionType.BASIC).invokeCompletion(getProject(), editor);
+ List<LookupElement> elements = LookupManager.getInstance(getProject()).getActiveLookup().getItems();
+
+ HashSet expectedSet = Sets.newHashSet(expectedItems);
+ HashSet disallowedSet = Sets.newHashSet(disallowedItems);
+
+ for (LookupElement element: elements) {
+ expectedSet.remove(element.toString());
+ Assert.assertFalse(disallowedSet.contains(element.toString()));
+ }
+
+ 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(
+ new OpenFileDescriptor(getProject(), file, 0), false);
+ DaemonCodeAnalyzer.getInstance(getProject()).restart();
+
+ ((EditorImpl)editor).setCaretActive();
+ return editor;
+ }
+
+ @Override
+ protected Sdk getTestProjectJdk() {
+ return JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliFieldTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliFieldTest.java
new file mode 100644
index 00000000..05e46bc2
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliFieldTest.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiPrimitiveType;
+import com.intellij.psi.PsiTypeElement;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jf.dexlib2.AccessFlags;
+import org.jf.smalidea.psi.impl.SmaliClass;
+import org.jf.smalidea.psi.impl.SmaliField;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.jf.smalidea.psi.impl.SmaliModifierList;
+import org.junit.Assert;
+
+public class SmaliFieldTest extends LightCodeInsightFixtureTestCase {
+ public void testBasicField() {
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".field public myField:I");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertEquals("my.pkg.blah", smaliClass.getQualifiedName());
+
+ SmaliField[] fields = smaliClass.getFields();
+ Assert.assertEquals(1, fields.length);
+ Assert.assertEquals("myField", fields[0].getName());
+ Assert.assertTrue(fields[0].getType() instanceof PsiPrimitiveType);
+ Assert.assertEquals("int", fields[0].getType().getCanonicalText());
+ PsiTypeElement typeElement = fields[0].getTypeElement();
+ Assert.assertNotNull("I", typeElement);
+ Assert.assertEquals("I", typeElement.getText());
+
+ SmaliModifierList modifierList = fields[0].getModifierList();
+ Assert.assertNotNull(modifierList);
+ Assert.assertEquals(AccessFlags.PUBLIC.getValue(), modifierList.getAccessFlags());
+ Assert.assertTrue(modifierList.hasExplicitModifier("public"));
+ Assert.assertTrue(modifierList.hasModifierProperty("public"));
+ Assert.assertTrue(fields[0].hasModifierProperty("public"));
+
+ PsiField[] psifields = smaliClass.getAllFields();
+ Assert.assertEquals(1, psifields.length);
+ Assert.assertEquals("myField", psifields[0].getName());
+
+ PsiField field = smaliClass.findFieldByName("myField", true);
+ Assert.assertNotNull(field);
+ Assert.assertEquals("myField", field.getName());
+
+ field = smaliClass.findFieldByName("nonExistantField", true);
+ Assert.assertNull(field);
+ field = smaliClass.findFieldByName("nonExistantField", false);
+ Assert.assertNull(field);
+ }
+
+ public void testSmaliSuperField() {
+ myFixture.addFileToProject("my/pkg/base.smali",
+ ".class public Lmy/pkg/base; .super Ljava/lang/Object;\n" +
+ ".field public baseField:I");
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public Lmy/pkg/blah; .super Lmy/pkg/base;\n" +
+ ".field public myField:I");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertEquals("my.pkg.blah", smaliClass.getQualifiedName());
+
+ PsiField[] fields = smaliClass.getFields();
+ Assert.assertEquals(1, fields.length);
+ Assert.assertEquals("myField", fields[0].getName());
+
+ fields = smaliClass.getAllFields();
+ Assert.assertEquals(2, fields.length);
+
+ Assert.assertTrue(fields[0].getName().equals("myField") || fields[1].getName().equals("myField"));
+ Assert.assertTrue(fields[0].getName().equals("baseField") || fields[1].getName().equals("baseField"));
+
+ PsiField field = smaliClass.findFieldByName("myField", true);
+ Assert.assertNotNull(field);
+ Assert.assertEquals("myField", field.getName());
+
+ field = smaliClass.findFieldByName("myField", false);
+ Assert.assertNotNull(field);
+ Assert.assertEquals("myField", field.getName());
+
+ field = smaliClass.findFieldByName("baseField", false);
+ Assert.assertNull(field);
+
+ field = smaliClass.findFieldByName("baseField", true);
+ Assert.assertNotNull(field);
+ Assert.assertEquals("baseField", field.getName());
+
+ field = smaliClass.findFieldByName("nonExistantField", true);
+ Assert.assertNull(field);
+ field = smaliClass.findFieldByName("nonExistantField", false);
+ Assert.assertNull(field);
+ }
+
+ public void testJavaSuperField() {
+ myFixture.addFileToProject("my/pkg/base.java",
+ "package my.pkg; public class base { public int baseField; }");
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public Lmy/pkg/blah; .super Lmy/pkg/base;\n" +
+ ".field public myField:I");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertEquals("my.pkg.blah", smaliClass.getQualifiedName());
+
+ PsiField[] fields = smaliClass.getFields();
+ Assert.assertEquals(1, fields.length);
+ Assert.assertEquals("myField", fields[0].getName());
+
+ fields = smaliClass.getAllFields();
+ Assert.assertEquals(2, fields.length);
+
+ Assert.assertTrue(fields[0].getName().equals("myField") || fields[1].getName().equals("myField"));
+ Assert.assertTrue(fields[0].getName().equals("baseField") || fields[1].getName().equals("baseField"));
+
+ PsiField field = smaliClass.findFieldByName("myField", true);
+ Assert.assertNotNull(field);
+ Assert.assertEquals("myField", field.getName());
+
+ field = smaliClass.findFieldByName("myField", false);
+ Assert.assertNotNull(field);
+ Assert.assertEquals("myField", field.getName());
+
+ field = smaliClass.findFieldByName("baseField", false);
+ Assert.assertNull(field);
+
+ field = smaliClass.findFieldByName("baseField", true);
+ Assert.assertNotNull(field);
+ Assert.assertEquals("baseField", field.getName());
+
+ field = smaliClass.findFieldByName("nonExistantField", true);
+ Assert.assertNull(field);
+ field = smaliClass.findFieldByName("nonExistantField", false);
+ Assert.assertNull(field);
+ }
+
+ public void testMultipleField() {
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".field public myField:I\n" +
+ ".field public myField2:Ljava/lang/String;\n" +
+ ".field public myField3:[Ljava/lang/String;\n" +
+ ".field public myField4:[[[Ljava/lang/String;\n");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertEquals("my.pkg.blah", smaliClass.getQualifiedName());
+
+ SmaliField[] fields = smaliClass.getFields();
+ Assert.assertEquals(4, fields.length);
+ Assert.assertEquals("myField", fields[0].getName());
+ Assert.assertEquals("myField2", fields[1].getName());
+ Assert.assertEquals("myField3", fields[2].getName());
+ Assert.assertEquals("myField4", fields[3].getName());
+ Assert.assertEquals("int", fields[0].getType().getCanonicalText());
+ Assert.assertEquals("java.lang.String", fields[1].getType().getCanonicalText());
+ Assert.assertEquals("java.lang.String[]", fields[2].getType().getCanonicalText());
+ Assert.assertEquals("java.lang.String[][][]", fields[3].getType().getCanonicalText());
+
+ PsiField field = smaliClass.findFieldByName("myField", true);
+ Assert.assertNotNull(field);
+ Assert.assertEquals("myField", field.getName());
+
+ field = smaliClass.findFieldByName("myField2", true);
+ Assert.assertNotNull(field);
+ Assert.assertEquals("myField2", field.getName());
+
+ field = smaliClass.findFieldByName("myField3", true);
+ Assert.assertNotNull(field);
+ Assert.assertEquals("myField3", field.getName());
+
+ field = smaliClass.findFieldByName("myField4", true);
+ Assert.assertNotNull(field);
+ Assert.assertEquals("myField4", field.getName());
+
+ field = smaliClass.findFieldByName("nonExistantField", true);
+ Assert.assertNull(field);
+ field = smaliClass.findFieldByName("nonExistantField", false);
+ Assert.assertNull(field);
+ }
+
+ public void testFieldAnnotations() {
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".field public myField:I");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertEquals("my.pkg.blah", smaliClass.getQualifiedName());
+
+ SmaliField[] fields = smaliClass.getFields();
+ Assert.assertEquals(1, fields.length);
+ Assert.assertEquals("myField", fields[0].getName());
+ Assert.assertTrue(fields[0].getType() instanceof PsiPrimitiveType);
+ Assert.assertEquals("int", fields[0].getType().getCanonicalText());
+ PsiTypeElement typeElement = fields[0].getTypeElement();
+ Assert.assertNotNull("I", typeElement);
+ Assert.assertEquals("I", typeElement.getText());
+
+ SmaliModifierList modifierList = fields[0].getModifierList();
+ Assert.assertNotNull(modifierList);
+ Assert.assertEquals(AccessFlags.PUBLIC.getValue(), modifierList.getAccessFlags());
+ Assert.assertTrue(modifierList.hasExplicitModifier("public"));
+ Assert.assertTrue(modifierList.hasModifierProperty("public"));
+ Assert.assertTrue(fields[0].hasModifierProperty("public"));
+
+ PsiField[] psifields = smaliClass.getAllFields();
+ Assert.assertEquals(1, psifields.length);
+ Assert.assertEquals("myField", psifields[0].getName());
+
+ PsiField field = smaliClass.findFieldByName("myField", true);
+ Assert.assertNotNull(field);
+ Assert.assertEquals("myField", field.getName());
+
+ field = smaliClass.findFieldByName("nonExistantField", true);
+ Assert.assertNull(field);
+ field = smaliClass.findFieldByName("nonExistantField", false);
+ Assert.assertNull(field);
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliFileTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliFileTest.java
new file mode 100644
index 00000000..e55bdd39
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliFileTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jf.smalidea.psi.impl.SmaliClass;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.junit.Assert;
+
+public class SmaliFileTest extends LightCodeInsightFixtureTestCase {
+ public void testFile() {
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;");
+
+ Assert.assertEquals(SmaliFileType.INSTANCE, file.getFileType());
+
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertNotNull(smaliClass);
+
+ SmaliClass[] smaliClasses = file.getClasses();
+ Assert.assertNotNull(smaliClasses);
+ Assert.assertEquals(1, smaliClasses.length);
+ Assert.assertEquals(smaliClass, smaliClasses[0]);
+
+ String packageName = file.getPackageName();
+ Assert.assertEquals("my.pkg", packageName);
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliFileTypeTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliFileTypeTest.java
new file mode 100644
index 00000000..c2d7336d
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliFileTypeTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.psi.PsiFile;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.junit.Assert;
+
+/**
+ * Tests that .smali files are properly detected
+ */
+public class SmaliFileTypeTest extends LightCodeInsightFixtureTestCase {
+ public void testImportSmaliClass() {
+ PsiFile file = myFixture.addFileToProject("my/pkg/blah.smali", ".class public Lmy/pkg/blah; .super Ljava/lang/Object;");
+ Assert.assertEquals(SmaliFileType.INSTANCE, file.getVirtualFile().getFileType());
+ Assert.assertEquals(SmaliFileType.INSTANCE, file.getFileType());
+ Assert.assertEquals(SmaliLanguage.INSTANCE, file.getLanguage());
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliImplementsExtendsTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliImplementsExtendsTest.java
new file mode 100644
index 00000000..597cf708
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliImplementsExtendsTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jf.smalidea.psi.impl.SmaliClass;
+import org.jf.smalidea.psi.impl.SmaliExtendsList;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.jf.smalidea.psi.impl.SmaliImplementsList;
+import org.junit.Assert;
+
+public class SmaliImplementsExtendsTest extends LightCodeInsightFixtureTestCase {
+ public void testNormalClass() {
+ myFixture.addFileToProject("my/pkg/base.smali",
+ ".class public Lmy/pkg/base; .super Ljava/lang/Object;");
+ myFixture.addFileToProject("my/pkg/iface.smali",
+ ".class public Lmy/pkg/iface; .super Ljava/lang/Object;");
+ myFixture.addFileToProject("my/pkg/iface2.smali",
+ ".class public Lmy/pkg/iface2; .super Ljava/lang/Object;");
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public Lmy/pkg/blah; .implements Lmy/pkg/iface; .super Lmy/pkg/base; " +
+ ".implements Lmy/pkg/iface2;");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliExtendsList extendsList = smaliClass.getExtendsList();
+ Assert.assertEquals(1, extendsList.getReferencedTypes().length);
+ Assert.assertEquals("my.pkg.base", extendsList.getReferencedTypes()[0].getCanonicalText());
+ Assert.assertEquals(1, extendsList.getReferenceNames().length);
+ Assert.assertEquals("my.pkg.base", extendsList.getReferenceNames()[0]);
+ Assert.assertEquals(1, smaliClass.getExtendsListTypes().length);
+ Assert.assertEquals("my.pkg.base", smaliClass.getExtendsListTypes()[0].getCanonicalText());
+
+ PsiClass resolvedSuper = extendsList.getReferencedTypes()[0].resolve();
+ Assert.assertNotNull(resolvedSuper);
+ Assert.assertEquals("my.pkg.base", resolvedSuper.getQualifiedName());
+
+ SmaliImplementsList implementsList = smaliClass.getImplementsList();
+ Assert.assertEquals(2, implementsList.getReferencedTypes().length);
+ Assert.assertEquals("my.pkg.iface", implementsList.getReferencedTypes()[0].getCanonicalText());
+ Assert.assertEquals("my.pkg.iface2", implementsList.getReferencedTypes()[1].getCanonicalText());
+ Assert.assertEquals(2, implementsList.getReferenceNames().length);
+ Assert.assertEquals("my.pkg.iface", implementsList.getReferenceNames()[0]);
+ Assert.assertEquals("my.pkg.iface2", implementsList.getReferenceNames()[1]);
+ Assert.assertEquals(2, smaliClass.getImplementsListTypes().length);
+ Assert.assertEquals("my.pkg.iface", smaliClass.getImplementsListTypes()[0].getCanonicalText());
+ Assert.assertEquals("my.pkg.iface2", smaliClass.getImplementsListTypes()[1].getCanonicalText());
+
+ PsiClass resolvedInterface = implementsList.getReferencedTypes()[0].resolve();
+ Assert.assertNotNull(resolvedInterface);
+ Assert.assertEquals("my.pkg.iface", resolvedInterface.getQualifiedName());
+
+ resolvedInterface = implementsList.getReferencedTypes()[1].resolve();
+ Assert.assertNotNull(resolvedInterface);
+ Assert.assertEquals("my.pkg.iface2", resolvedInterface.getQualifiedName());
+ }
+
+ public void testInterface() {
+ myFixture.addFileToProject("my/pkg/iface.smali",
+ ".class public Lmy/pkg/iface; .super Ljava/lang/Object;");
+ myFixture.addFileToProject("my/pkg/iface2.smali",
+ ".class public Lmy/pkg/iface2; .super Ljava/lang/Object;");
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ ".class public interface Lmy/pkg/blah; .implements Lmy/pkg/iface; .super Ljava/lang/Object; " +
+ ".implements Lmy/pkg/iface2;");
+
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliExtendsList extendsList = smaliClass.getExtendsList();
+
+ Assert.assertEquals(2, extendsList.getReferencedTypes().length);
+ Assert.assertEquals("my.pkg.iface", extendsList.getReferencedTypes()[0].getCanonicalText());
+ Assert.assertEquals("my.pkg.iface2", extendsList.getReferencedTypes()[1].getCanonicalText());
+ Assert.assertEquals(2, extendsList.getReferenceNames().length);
+ Assert.assertEquals("my.pkg.iface", extendsList.getReferenceNames()[0]);
+ Assert.assertEquals("my.pkg.iface2", extendsList.getReferenceNames()[1]);
+ Assert.assertEquals(2, smaliClass.getExtendsListTypes().length);
+ Assert.assertEquals("my.pkg.iface", smaliClass.getExtendsListTypes()[0].getCanonicalText());
+ Assert.assertEquals("my.pkg.iface2", smaliClass.getExtendsListTypes()[1].getCanonicalText());
+
+ PsiClass resolvedInterface = extendsList.getReferencedTypes()[0].resolve();
+ Assert.assertNotNull(resolvedInterface);
+ Assert.assertEquals("my.pkg.iface", resolvedInterface.getQualifiedName());
+
+ resolvedInterface = extendsList.getReferencedTypes()[1].resolve();
+ Assert.assertNotNull(resolvedInterface);
+ Assert.assertEquals("my.pkg.iface2", resolvedInterface.getQualifiedName());
+
+ SmaliImplementsList implementsList = smaliClass.getImplementsList();
+ Assert.assertEquals(0, implementsList.getReferencedTypes().length);
+ Assert.assertEquals(0, implementsList.getReferenceNames().length);
+ Assert.assertEquals(0, smaliClass.getImplementsListTypes().length);
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliInstructionTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliInstructionTest.java
new file mode 100644
index 00000000..37ea555c
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliInstructionTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jf.dexlib2.Opcode;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+import org.junit.Assert;
+
+public class SmaliInstructionTest extends LightCodeInsightFixtureTestCase {
+ public void testSingleInstruction() {
+ String text =
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".method blah(IJLjava/lang/String;)V\n" +
+ " .locals 0\n" +
+ " r<ref>eturn-void\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ text.replace("<ref>", ""));
+
+ PsiElement leafElement = file.findElementAt(text.indexOf("<ref>"));
+ Assert.assertNotNull(leafElement);
+ SmaliInstruction instructionElement = (SmaliInstruction)leafElement.getParent();
+ Assert.assertNotNull(instructionElement);
+
+ Assert.assertEquals(Opcode.RETURN_VOID, instructionElement.getOpcode());
+ Assert.assertEquals(0, instructionElement.getOffset());
+ }
+
+ public void testMultipleInstructions() {
+ String text =
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".method blah(IJLjava/lang/String;)I\n" +
+ " .locals 1\n" +
+ " const v0, 1234\n" +
+ " r<ref>eturn v0\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ text.replace("<ref>", ""));
+
+ PsiElement leafElement = file.findElementAt(text.indexOf("<ref>"));
+ Assert.assertNotNull(leafElement);
+ SmaliInstruction instructionElement = (SmaliInstruction)leafElement.getParent();
+ Assert.assertNotNull(instructionElement);
+
+ Assert.assertEquals(Opcode.RETURN, instructionElement.getOpcode());
+ Assert.assertEquals(6, instructionElement.getOffset());
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliLabelReferenceTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliLabelReferenceTest.java
new file mode 100644
index 00000000..628cf0f5
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliLabelReferenceTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2015, 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;
+
+import com.intellij.testFramework.ResolveTestCase;
+import org.jf.dexlib2.Opcode;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+import org.jf.smalidea.psi.impl.SmaliLabel;
+import org.jf.smalidea.psi.impl.SmaliLabelReference;
+import org.junit.Assert;
+
+public class SmaliLabelReferenceTest extends ResolveTestCase {
+
+ public void testLabelReference() throws Exception {
+ String text =
+ ".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" +
+ "\n" +
+ " .line 179\n" +
+ " if-nez p1, :cond_5\n" +
+ "\n" +
+ " move v0, v1\n" +
+ "\n" +
+ " .line 185\n" +
+ " :goto_4\n" +
+ " return v0\n" +
+ "\n" +
+ " .line 182\n" +
+ " :cond_5\n" +
+ " if-ne p1, v1, :cond_f\n" +
+ "\n" +
+ " .line 183\n" +
+ " sget-object v0, Lorg/jf/Penroser/PenroserApp;->random:Ljava/util/Random;\n" +
+ "\n" +
+ " const/4 v1, 0x3\n" +
+ "\n" +
+ " invoke-virtual {v0, v1}, Ljava/util/Random;->nextInt(I)I\n" +
+ "\n" +
+ " move-result v0\n" +
+ "\n" +
+ " goto :goto_4\n" +
+ "\n" +
+ " .line 185\n" +
+ " :cond_f\n" +
+ " sget-object v0, Lorg/jf/Penroser/PenroserApp;->random:Ljava/util/Random;\n" +
+ "\n" +
+ " invoke-virtual {v0, v1}, Ljava/util/Random;->nextInt(I)I\n" +
+ "\n" +
+ " move-result v0\n" +
+ "\n" +
+ " goto :go<ref>to_4\n" +
+ ".end method";;
+
+ SmaliLabelReference labelReference = (SmaliLabelReference)configureByFileText(text, "blah.smali");
+
+ Assert.assertNotNull(labelReference);
+ Assert.assertEquals("goto_4", labelReference.getName());
+
+ SmaliLabel resolvedLabel = labelReference.resolve();
+ Assert.assertNotNull(resolvedLabel);
+ Assert.assertEquals("goto_4", resolvedLabel.getName());
+
+ SmaliInstruction nextInstruction = resolvedLabel.findNextSiblingByClass(SmaliInstruction.class);
+ Assert.assertNotNull(nextInstruction);
+ Assert.assertEquals(8, nextInstruction.getOffset());
+ Assert.assertEquals(Opcode.RETURN, nextInstruction.getOpcode());
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliLexerTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliLexerTest.java
new file mode 100644
index 00000000..8383f966
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliLexerTest.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.lexer.Lexer;
+import com.intellij.testFramework.LexerTestCase;
+
+import java.util.Random;
+
+/**
+ * This is mostly just a smoke test to make sure the lexer is working. The lexer itself has its
+ * own tests in the smali module
+ */
+public class SmaliLexerTest extends LexerTestCase {
+ public void testHelloWorld() {
+ String text =
+ ".class public LHelloWorld;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method public static main([Ljava/lang/String;)V\n" +
+ " .registers 2\n" +
+ " sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;\n" +
+ " const-string v1, \"Hello World!\"\n" +
+ " invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V\n" +
+ " return-void\n" +
+ ".end method";
+
+ doTest(text,
+ "CLASS_DIRECTIVE ('.class')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "ACCESS_SPEC ('public')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "CLASS_DESCRIPTOR ('LHelloWorld;')\n" +
+ "WHITE_SPACE ('\\n')\n" +
+ "SUPER_DIRECTIVE ('.super')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "CLASS_DESCRIPTOR ('Ljava/lang/Object;')\n" +
+ "WHITE_SPACE ('\\n')\n" +
+ "METHOD_DIRECTIVE ('.method')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "ACCESS_SPEC ('public')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "ACCESS_SPEC ('static')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "SIMPLE_NAME ('main')\n" +
+ "OPEN_PAREN ('(')\n" +
+ "ARRAY_TYPE_PREFIX ('[')\n" +
+ "CLASS_DESCRIPTOR ('Ljava/lang/String;')\n" +
+ "CLOSE_PAREN (')')\n" +
+ "VOID_TYPE ('V')\n" +
+ "WHITE_SPACE ('\\n ')\n" +
+ "REGISTERS_DIRECTIVE ('.registers')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "POSITIVE_INTEGER_LITERAL ('2')\n" +
+ "WHITE_SPACE ('\\n ')\n" +
+ "INSTRUCTION_FORMAT21c_FIELD ('sget-object')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "REGISTER ('v0')\n" +
+ "COMMA (',')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "CLASS_DESCRIPTOR ('Ljava/lang/System;')\n" +
+ "ARROW ('->')\n" +
+ "SIMPLE_NAME ('out')\n" +
+ "COLON (':')\n" +
+ "CLASS_DESCRIPTOR ('Ljava/io/PrintStream;')\n" +
+ "WHITE_SPACE ('\\n ')\n" +
+ "INSTRUCTION_FORMAT21c_STRING ('const-string')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "REGISTER ('v1')\n" +
+ "COMMA (',')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "STRING_LITERAL ('\"Hello World!\"')\n" +
+ "WHITE_SPACE ('\\n ')\n" +
+ "INSTRUCTION_FORMAT35c_METHOD ('invoke-virtual')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "OPEN_BRACE ('{')\n" +
+ "REGISTER ('v0')\n" +
+ "COMMA (',')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "REGISTER ('v1')\n" +
+ "CLOSE_BRACE ('}')\n" +
+ "COMMA (',')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "CLASS_DESCRIPTOR ('Ljava/io/PrintStream;')\n" +
+ "ARROW ('->')\n" +
+ "SIMPLE_NAME ('println')\n" +
+ "OPEN_PAREN ('(')\n" +
+ "CLASS_DESCRIPTOR ('Ljava/lang/String;')\n" +
+ "CLOSE_PAREN (')')\n" +
+ "VOID_TYPE ('V')\n" +
+ "WHITE_SPACE ('\\n ')\n" +
+ "INSTRUCTION_FORMAT10x ('return-void')\n" +
+ "WHITE_SPACE ('\\n')\n" +
+ "END_METHOD_DIRECTIVE ('.end method')"
+ );
+ }
+
+ @Override protected Lexer createLexer() {
+ return new SmaliLexer();
+ }
+
+ @Override protected String getDirPath() {
+ return "";
+ }
+
+ public void testErrorToken() {
+ String text = ".class public .blah";
+ doTest(text,
+ "CLASS_DIRECTIVE ('.class')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "ACCESS_SPEC ('public')\n" +
+ "WHITE_SPACE (' ')\n" +
+ "BAD_CHARACTER ('.blah')\n");
+ }
+
+ /**
+ * Type out an example smali file character by character, ensuring that no exceptions are thrown
+ */
+ public void testPartialText() {
+ String text =
+ ".class public LHelloWorld;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method public static main([Ljava/lang/String;)V\n" +
+ " .registers 2\n" +
+ " sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;\n" +
+ " const-string v1, \"Hello World!\"\n" +
+ " invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V\n" +
+ " return-void\n" +
+ ".end method";
+
+ for (int i=1; i<text.length(); i++) {
+ printTokens(text.substring(i), 0);
+ }
+ }
+
+ /**
+ * Generate some random text and make sure the lexer doesn't throw any exceptions
+ */
+ public void testRandomText() {
+ for (int i=0; i<100; i++) {
+ String randomString = randomString(1000);
+
+ printTokens(randomString, 0);
+ }
+ }
+
+ private Random random = new Random(123456789);
+ private String randomString(int length) {
+ StringBuilder sb = new StringBuilder();
+ for (int i=0; i<length; i++) {
+ int type = random.nextInt(10);
+
+ if (type == 9) {
+ int randomCodepoint;
+ do {
+ randomCodepoint = random.nextInt();
+ } while(!Character.isValidCodePoint(randomCodepoint));
+ sb.appendCodePoint(randomCodepoint);
+ } else if (type == 8) {
+ char randomChar;
+ do {
+ randomChar = (char)random.nextInt(2^16);
+ } while(!Character.isValidCodePoint(randomChar));
+ sb.append(randomChar);
+ } else if (type > 4) {
+ sb.append((char)random.nextInt(256));
+ } else if (type == 4) {
+ sb.append(' ');
+ } else {
+ sb.append((char)random.nextInt(128));
+ }
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliLiteralTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliLiteralTest.java
new file mode 100644
index 00000000..64d38a93
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliLiteralTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.jf.smalidea.psi.impl.SmaliLiteral;
+import org.junit.Assert;
+
+public class SmaliLiteralTest extends LightCodeInsightFixtureTestCase {
+ private void doTest(long expectedValue, String literalValue) {
+ String text =
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".method blah()V\n" +
+ " .registers <ref>" + literalValue + "\n" +
+ " return-void\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ text.replace("<ref>", ""));
+
+ PsiElement leafElement = file.findElementAt(text.indexOf("<ref>"));
+ Assert.assertNotNull(leafElement);
+ SmaliLiteral literalElement = (SmaliLiteral)leafElement.getParent();
+ Assert.assertNotNull(literalElement);
+
+ Assert.assertEquals(expectedValue, literalElement.getIntegralValue());
+ }
+
+ public void testIntegerValue() {
+ doTest(123, "123");
+ }
+
+ public void testLongValue() {
+ doTest(100, "100L");
+ }
+
+ public void testShortValue() {
+ doTest(99, "99s");
+ }
+
+ public void testByteValue() {
+ doTest(127, "127t");
+ }
+
+ // TODO: test char
+ // TODO: test bool
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliMethodTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliMethodTest.java
new file mode 100644
index 00000000..6af96757
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliMethodTest.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.debugger.SourcePosition;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiPrimitiveType;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jf.dexlib2.Opcode;
+import org.jf.smalidea.psi.impl.*;
+import org.junit.Assert;
+
+import java.util.List;
+
+public class SmaliMethodTest extends LightCodeInsightFixtureTestCase {
+ public void testMethodRegisters() {
+ String text =
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".me<ref>thod blah()V\n" +
+ " .registers 123\n" +
+ " return-void\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ text.replace("<ref>", ""));
+
+ PsiElement leafElement = file.findElementAt(text.indexOf("<ref>"));
+ Assert.assertNotNull(leafElement);
+ SmaliMethod methodElement = (SmaliMethod)leafElement.getParent();
+ Assert.assertNotNull(methodElement);
+
+ Assert.assertEquals(123, methodElement.getRegisterCount());
+ Assert.assertEquals(1, methodElement.getParameterRegisterCount());
+ }
+
+ public void testMethodRegisters2() {
+ String text =
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".me<ref>thod blah(IJLjava/lang/String;)V\n" +
+ " .locals 123\n" +
+ " return-void\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ text.replace("<ref>", ""));
+
+ PsiElement leafElement = file.findElementAt(text.indexOf("<ref>"));
+ Assert.assertNotNull(leafElement);
+ SmaliMethod methodElement = (SmaliMethod)leafElement.getParent();
+ Assert.assertNotNull(methodElement);
+
+ Assert.assertEquals(128, methodElement.getRegisterCount());
+ Assert.assertEquals(5, methodElement.getParameterRegisterCount());
+ }
+
+ public void testStaticRegisterCount() {
+ String text =
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".method static blah(IJLjava/lang/String;)V\n" +
+ " .locals 123\n" +
+ " return-void\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text);
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliMethod smaliMethod = smaliClass.getMethods()[0];
+
+ Assert.assertEquals(127, smaliMethod.getRegisterCount());
+ Assert.assertEquals(4, smaliMethod.getParameterRegisterCount());
+
+ Assert.assertEquals(0, smaliMethod.getParameterList().getParameters()[0].getParameterRegisterNumber());
+ Assert.assertEquals(123, smaliMethod.getParameterList().getParameters()[0].getRegisterNumber());
+ }
+
+ public void testMethodParams() {
+ myFixture.addFileToProject("my/TestAnnotation.smali",
+ ".class public interface abstract annotation Lmy/TestAnnotation;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".implements Ljava/lang/annotation/Annotation;\n" +
+ "\n" +
+ ".method public abstract testBooleanValue()Z\n" +
+ ".end method\n" +
+ "\n" +
+ ".method public abstract testStringArrayValue()[Ljava/lang/String;\n" +
+ ".end method\n" +
+ "\n" +
+ ".method public abstract testStringValue()Ljava/lang/String;\n" +
+ ".end method");
+
+ String text =
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".method blah(IJLjava/lang/String;)V\n" +
+ " .locals 123\n" +
+ " .param p1, \"anInt\"\n" +
+ " .param p2\n" +
+ " .annotation runtime Lmy/TestAnnotation;\n" +
+ " testStringValue = \"myValue\"\n" +
+ " .end annotation\n" +
+ " .end param\n" +
+ " return-void\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text);
+
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliMethod smaliMethod = smaliClass.getMethods()[0];
+
+ SmaliMethodParamList paramList = smaliMethod.getParameterList();
+ SmaliMethodParameter[] parameters = paramList.getParameters();
+ Assert.assertEquals(3, parameters.length);
+
+ Assert.assertEquals("int", parameters[0].getType().getCanonicalText());
+ Assert.assertEquals("\"anInt\"", parameters[0].getName());
+ Assert.assertEquals(1, parameters[0].getRegisterCount());
+ Assert.assertEquals(124, parameters[0].getRegisterNumber());
+ Assert.assertEquals(1, parameters[0].getParameterRegisterNumber());
+ Assert.assertEquals(0, parameters[0].getAnnotations().length);
+
+ Assert.assertEquals("long", parameters[1].getType().getCanonicalText());
+ Assert.assertNull(parameters[1].getName());
+ Assert.assertEquals(2, parameters[1].getRegisterCount());
+ Assert.assertEquals(125, parameters[1].getRegisterNumber());
+ Assert.assertEquals(2, parameters[1].getParameterRegisterNumber());
+ Assert.assertEquals(1, parameters[1].getAnnotations().length);
+ Assert.assertEquals("my.TestAnnotation", parameters[1].getAnnotations()[0].getQualifiedName());
+
+ Assert.assertEquals("java.lang.String", parameters[2].getType().getCanonicalText());
+ Assert.assertNull(parameters[2].getName());
+ Assert.assertEquals(1, parameters[2].getRegisterCount());
+ Assert.assertEquals(127, parameters[2].getRegisterNumber());
+ Assert.assertEquals(4, parameters[2].getParameterRegisterNumber());
+ Assert.assertEquals(0, parameters[2].getAnnotations().length);
+ }
+
+ public void testVarArgsMethod() {
+ String text =
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".method varargs static blah(IJ[Ljava/lang/String;)V\n" +
+ " .locals 123\n" +
+ " return-void\n" +
+ ".end method\n" +
+ ".method varargs static blah2(IJLjava/lang/String;)V\n" +
+ " .locals 123\n" +
+ " return-void\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text);
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliMethod smaliMethod = smaliClass.getMethods()[0];
+
+ Assert.assertTrue(smaliMethod.isVarArgs());
+ Assert.assertFalse(smaliMethod.getParameterList().getParameters()[0].isVarArgs());
+ Assert.assertFalse(smaliMethod.getParameterList().getParameters()[1].isVarArgs());
+ Assert.assertTrue(smaliMethod.getParameterList().getParameters()[2].isVarArgs());
+
+ smaliMethod = smaliClass.getMethods()[1];
+ Assert.assertTrue(smaliMethod.isVarArgs());
+ Assert.assertFalse(smaliMethod.getParameterList().getParameters()[0].isVarArgs());
+ Assert.assertFalse(smaliMethod.getParameterList().getParameters()[1].isVarArgs());
+ Assert.assertFalse(smaliMethod.getParameterList().getParameters()[2].isVarArgs());
+ }
+
+ private static final String instructionsTestClass =
+ ".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" +
+ "\n" +
+ " .line 179\n" +
+ " if-nez p1, :cond_5\n" +
+ "\n" +
+ " move v0, v1\n" +
+ "\n" +
+ " .line 185\n" +
+ " :goto_4\n" +
+ " return v0\n" +
+ "\n" +
+ " .line 182\n" +
+ " :cond_5\n" +
+ " if-ne p1, v1, :cond_f\n" +
+ "\n" +
+ " .line 183\n" +
+ " sget-object v0, Lorg/jf/Penroser/PenroserApp;->random:Ljava/util/Random;\n" +
+ "\n" +
+ " const/4 v1, 0x3\n" +
+ "\n" +
+ " invoke-virtual {v0, v1}, Ljava/util/Random;->nextInt(I)I\n" +
+ "\n" +
+ " move-result v0\n" +
+ "\n" +
+ " goto :goto_4\n" +
+ "\n" +
+ " .line 185\n" +
+ " :cond_f\n" +
+ " sget-object v0, Lorg/jf/Penroser/PenroserApp;->random:Ljava/util/Random;\n" +
+ "\n" +
+ " invoke-virtual {v0, v1}, Ljava/util/Random;->nextInt(I)I\n" +
+ "\n" +
+ " move-result v0\n" +
+ "\n" +
+ " goto :goto_4\n" +
+ ".end method";
+
+ public void testGetInstructions() {
+ String text = instructionsTestClass;
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text);
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliMethod smaliMethod = smaliClass.getMethods()[0];
+
+ List<SmaliInstruction> instructions = smaliMethod.getInstructions();
+ Assert.assertEquals(14, instructions.size());
+ }
+
+ private void checkSourcePosition(SmaliMethod smaliMethod, int codeOffset, Opcode opcode) {
+ SourcePosition sourcePosition = smaliMethod.getSourcePositionForCodeOffset(codeOffset);
+ Assert.assertNotNull(sourcePosition);
+
+ SmaliInstruction instruction = (SmaliInstruction)sourcePosition.getElementAt();
+ Assert.assertEquals(opcode, instruction.getOpcode());
+ Assert.assertEquals(codeOffset, instruction.getOffset());
+ }
+
+ public void testGetSourcePositionForCodeOffset() {
+ String text = instructionsTestClass;
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text);
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliMethod smaliMethod = smaliClass.getMethods()[0];
+
+ checkSourcePosition(smaliMethod, 0, Opcode.CONST_4);
+ checkSourcePosition(smaliMethod, 2, Opcode.IF_NEZ);
+ checkSourcePosition(smaliMethod, 6, Opcode.MOVE);
+ checkSourcePosition(smaliMethod, 8, Opcode.RETURN);
+ checkSourcePosition(smaliMethod, 10, Opcode.IF_NE);
+ checkSourcePosition(smaliMethod, 14, Opcode.SGET_OBJECT);
+ checkSourcePosition(smaliMethod, 18, Opcode.CONST_4);
+ checkSourcePosition(smaliMethod, 20, Opcode.INVOKE_VIRTUAL);
+ checkSourcePosition(smaliMethod, 26, Opcode.MOVE_RESULT);
+ checkSourcePosition(smaliMethod, 28, Opcode.GOTO);
+ checkSourcePosition(smaliMethod, 30, Opcode.SGET_OBJECT);
+ checkSourcePosition(smaliMethod, 34, Opcode.INVOKE_VIRTUAL);
+ checkSourcePosition(smaliMethod, 40, Opcode.MOVE_RESULT);
+ checkSourcePosition(smaliMethod, 42, Opcode.GOTO);
+ }
+
+ public void testThrowsList() {
+ String text = instructionsTestClass;
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text);
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliMethod smaliMethod = smaliClass.getMethods()[0];
+
+ SmaliThrowsList throwsList = smaliMethod.getThrowsList();
+ Assert.assertNotNull(throwsList);
+ Assert.assertEquals(0, throwsList.getReferencedTypes().length);
+ Assert.assertEquals(0, throwsList.getReferenceElements().length);
+ }
+
+ public void testPrimitiveReturnType() {
+ String text = "" +
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".method blah()I\n" +
+ " .registers 123\n" +
+ " return-void\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text);
+ SmaliClass smaliClass = file.getPsiClass();
+ Assert.assertNotNull(smaliClass);
+ SmaliMethod smaliMethod = smaliClass.getMethods()[0];
+
+ Assert.assertNotNull(smaliMethod.getReturnType());
+ Assert.assertTrue(smaliMethod.getReturnType().isConvertibleFrom(PsiPrimitiveType.INT));
+ Assert.assertTrue(smaliMethod.getReturnType().isAssignableFrom(PsiPrimitiveType.INT));
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliPositionManagerTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliPositionManagerTest.java
new file mode 100644
index 00000000..596c11ed
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliPositionManagerTest.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2014, 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;
+
+import com.google.common.collect.Lists;
+import com.intellij.debugger.NoDataException;
+import com.intellij.debugger.PositionManager;
+import com.intellij.debugger.SourcePosition;
+import com.intellij.debugger.engine.DebugProcess;
+import com.intellij.debugger.engine.DebugProcessListener;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContext;
+import com.intellij.debugger.engine.jdi.VirtualMachineProxy;
+import com.intellij.debugger.engine.managerThread.DebuggerManagerThread;
+import com.intellij.debugger.requests.RequestManager;
+import com.intellij.execution.ExecutionResult;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jf.dexlib2.Opcode;
+import org.jf.smalidea.debugging.SmaliPositionManager;
+import org.jf.smalidea.psi.impl.SmaliInstruction;
+import org.junit.Assert;
+
+import java.util.List;
+import java.util.Map;
+
+public class SmaliPositionManagerTest extends LightCodeInsightFixtureTestCase {
+ private static final String testClass =
+ "\n\n.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" +
+ "\n" +
+ " .line 179\n" +
+ " if-nez p1, :cond_5\n" +
+ "\n" +
+ " move v0, v1\n" +
+ "\n" +
+ " .line 185\n" +
+ " :goto_4\n" +
+ " return v0\n" +
+ "\n" +
+ " .line 182\n" +
+ " :cond_5\n" +
+ " if-ne p1, v1, :cond_f\n" +
+ "\n" +
+ " .line 183\n" +
+ " sget-object v0, Lorg/jf/Penroser/PenroserApp;->random:Ljava/util/Random;\n" +
+ "\n" +
+ " const/4 v1, 0x3\n" +
+ "\n" +
+ " invoke-virtual {v0, v1}, Ljava/util/Random;->nextInt(I)I\n" +
+ "\n" +
+ " move-result v0\n" +
+ "\n" +
+ " goto :goto_4\n" +
+ "\n" +
+ " .line 185\n" +
+ " :cond_f\n" +
+ " sget-object v0, Lorg/jf/Penroser/PenroserApp;->random:Ljava/util/Random;\n" +
+ "\n" +
+ " invoke-virtual {v0, v1}, Ljava/util/Random;->nextInt(I)I\n" +
+ "\n" +
+ " move-result v0\n" +
+ "\n" +
+ " goto :goto_4\n" +
+ ".end method";
+
+ public void testGetSourcePosition() throws NoDataException {
+ myFixture.addFileToProject("my/pkg/blah.smali", testClass);
+
+ SmaliPositionManager positionManager = new SmaliPositionManager(new MockDebugProcess());
+
+ SourcePosition sourcePosition = positionManager.getSourcePosition(
+ "my.pkg.blah", "getRandomParentType", "(I)I", 0);
+ Assert.assertEquals(Opcode.CONST_4, ((SmaliInstruction)sourcePosition.getElementAt()).getOpcode());
+ Assert.assertEquals(0, ((SmaliInstruction)sourcePosition.getElementAt()).getOffset());
+
+ sourcePosition = positionManager.getSourcePosition("my.pkg.blah", "getRandomParentType", "(I)I", 10);
+ Assert.assertEquals(Opcode.INVOKE_VIRTUAL, ((SmaliInstruction)sourcePosition.getElementAt()).getOpcode());
+ Assert.assertEquals(20, ((SmaliInstruction)sourcePosition.getElementAt()).getOffset());
+ }
+
+ public void testGetAllClasses() throws NoDataException {
+ myFixture.addFileToProject("my/pkg/blah.smali", testClass);
+
+ SmaliPositionManager positionManager = new SmaliPositionManager(new MockDebugProcess());
+
+ List<ReferenceType> classes = positionManager.getAllClasses(positionManager.getSourcePosition(
+ "my.pkg.blah", "getRandomParentType", "(I)I", 0));
+ Assert.assertEquals(1, classes.size());
+ Assert.assertEquals("my.pkg.blah", classes.get(0).name());
+ }
+
+ private class MockDebugProcess implements DebugProcess {
+ @Override public Project getProject() {
+ return SmaliPositionManagerTest.this.getProject();
+ }
+
+ @Override public VirtualMachineProxy getVirtualMachineProxy() {
+ return new VirtualMachineProxy() {
+ @Override public List<ReferenceType> classesByName(final String s) {
+ return Lists.<ReferenceType>newArrayList(new MockReferenceType(s));
+ }
+
+ @Override public List<ReferenceType> allClasses() { return null; }
+ @Override public boolean canGetBytecodes() { return false; }
+ @Override public boolean versionHigher(String version) { return false; }
+ @Override public boolean canWatchFieldModification() { return false; }
+ @Override public boolean canWatchFieldAccess() { return false; }
+ @Override public boolean canInvokeMethods() { return false; }
+ @Override public DebugProcess getDebugProcess() { return null; }
+ @Override public List<ReferenceType> nestedTypes(ReferenceType refType) { return null; }
+ };
+ }
+
+ @Override public void addDebugProcessListener(DebugProcessListener listener) {}
+ @Override public <T> T getUserData(Key<T> key) { return null; }
+ @Override public <T> void putUserData(Key<T> key, T value) {}
+ @Override public RequestManager getRequestsManager() { return null; }
+ @Override public PositionManager getPositionManager() { return null; }
+ @Override public void removeDebugProcessListener(DebugProcessListener listener) {}
+ @Override public void appendPositionManager(PositionManager positionManager) {}
+ @Override public void waitFor() {}
+ @Override public void waitFor(long timeout) {}
+ @Override public void stop(boolean forceTerminate) {}
+ @Override public ExecutionResult getExecutionResult() { return null; }
+ @Override public DebuggerManagerThread getManagerThread() { return null; }
+ @Override public Value invokeMethod(EvaluationContext evaluationContext, ObjectReference objRef, Method method, List args) throws EvaluateException { return null; }
+ @Override public Value invokeMethod(EvaluationContext evaluationContext, ClassType classType, Method method, List args) throws EvaluateException { return null; }
+ @Override public Value invokeInstanceMethod(EvaluationContext evaluationContext, ObjectReference objRef, Method method, List args, int invocationOptions) throws EvaluateException { return null; }
+ @Override public ReferenceType findClass(EvaluationContext evaluationContext, String name, ClassLoaderReference classLoader) throws EvaluateException { return null; }
+ @Override public ArrayReference newInstance(ArrayType arrayType, int dimension) throws EvaluateException { return null; }
+ @Override public ObjectReference newInstance(EvaluationContext evaluationContext, ClassType classType, Method constructor, List paramList) throws EvaluateException { return null; }
+ @Override public boolean isAttached() { return false; }
+ @Override public boolean isDetached() { return false; }
+ @Override public boolean isDetaching() { return false; }
+ @NotNull @Override public GlobalSearchScope getSearchScope() { return null; }
+ @Override public void printToConsole(String text) {}
+ @Override public ProcessHandler getProcessHandler() { return null; }
+ }
+
+ private static class MockReferenceType implements ReferenceType {
+ private final String name;
+
+ public MockReferenceType(String name) {
+ this.name = name;
+ }
+
+ @Override public String name() {
+ return name;
+ }
+
+ @Override public List<Field> allFields() { return null; }
+ @Override public String genericSignature() { return null; }
+ @Override public ClassLoaderReference classLoader() { return null; }
+ @Override public String sourceName() throws AbsentInformationException { return null; }
+ @Override public List<String> sourceNames(String s) throws AbsentInformationException { return null; }
+ @Override public List<String> sourcePaths(String s) throws AbsentInformationException { return null; }
+ @Override public String sourceDebugExtension() throws AbsentInformationException { return null; }
+ @Override public boolean isStatic() { return false; }
+ @Override public boolean isAbstract() { return false; }
+ @Override public boolean isFinal() { return false; }
+ @Override public boolean isPrepared() { return false; }
+ @Override public boolean isVerified() { return false; }
+ @Override public boolean isInitialized() { return false; }
+ @Override public boolean failedToInitialize() { return false; }
+ @Override public List<Field> fields() { return null; }
+ @Override public List<Field> visibleFields() { return null; }
+ @Override public Field fieldByName(String s) { return null; }
+ @Override public List<Method> methods() { return null; }
+ @Override public List<Method> visibleMethods() { return null; }
+ @Override public List<Method> allMethods() { return null; }
+ @Override public List<Method> methodsByName(String s) { return null; }
+ @Override public List<Method> methodsByName(String s, String s1) { return null; }
+ @Override public List<ReferenceType> nestedTypes() { return null; }
+ @Override public Value getValue(Field field) { return null; }
+ @Override public Map<Field, Value> getValues(List<? extends Field> list) { return null; }
+ @Override public ClassObjectReference classObject() { return null; }
+ @Override public List<Location> allLineLocations() throws AbsentInformationException { return null; }
+ @Override public List<Location> allLineLocations(String s, String s1) throws AbsentInformationException { return null; }
+ @Override public List<Location> locationsOfLine(int i) throws AbsentInformationException { return null; }
+ @Override public List<Location> locationsOfLine(String s, String s1, int i) throws AbsentInformationException { return null; }
+ @Override public List<String> availableStrata() { return null; }
+ @Override public String defaultStratum() { return null; }
+ @Override public List<ObjectReference> instances(long l) { return null; }
+ @Override public int majorVersion() { return 0; }
+ @Override public int minorVersion() { return 0; }
+ @Override public int constantPoolCount() { return 0; }
+ @Override public byte[] constantPool() { return new byte[0]; }
+ @Override public int modifiers() { return 0; }
+ @Override public boolean isPrivate() { return false; }
+ @Override public boolean isPackagePrivate() { return false; }
+ @Override public boolean isProtected() { return false; }
+ @Override public boolean isPublic() { return false; }
+ @Override public int compareTo(ReferenceType o) { return 0; }
+ @Override public String signature() { return null; }
+ @Override public VirtualMachine virtualMachine() { return null; }
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliRegisterTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliRegisterTest.java
new file mode 100644
index 00000000..fbb4b627
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/SmaliRegisterTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2014, 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;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.jf.smalidea.psi.impl.SmaliRegisterReference;
+import org.junit.Assert;
+
+public class SmaliRegisterTest extends LightCodeInsightFixtureTestCase {
+ public void testRegisterReference() {
+ String text =
+ ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".method blah()V\n" +
+ " .registers 123\n" +
+ " const <ref>v10, 123\n" +
+ " return-void\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali",
+ text.replace("<ref>", ""));
+
+ PsiElement leafElement = file.findElementAt(text.indexOf("<ref>"));
+ Assert.assertNotNull(leafElement);
+ SmaliRegisterReference registerReference = (SmaliRegisterReference)leafElement.getParent();
+ Assert.assertNotNull(registerReference);
+
+ Assert.assertEquals(10, registerReference.getRegisterNumber());
+ // TODO: test parameter register
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/dexlib/SmalideaMethodTest.java b/smalidea/src/test/java/org/jf/smalidea/dexlib/SmalideaMethodTest.java
new file mode 100644
index 00000000..515c9bb7
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/dexlib/SmalideaMethodTest.java
@@ -0,0 +1,580 @@
+/*
+ * Copyright 2015, 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.Lists;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import org.jf.dexlib2.AccessFlags;
+import org.jf.dexlib2.Opcode;
+import org.jf.dexlib2.iface.ExceptionHandler;
+import org.jf.dexlib2.iface.MethodImplementation;
+import org.jf.dexlib2.iface.MethodParameter;
+import org.jf.dexlib2.iface.TryBlock;
+import org.jf.dexlib2.iface.instruction.Instruction;
+import org.jf.dexlib2.iface.instruction.SwitchElement;
+import org.jf.dexlib2.iface.instruction.formats.*;
+import org.jf.dexlib2.iface.reference.FieldReference;
+import org.jf.dexlib2.iface.reference.StringReference;
+import org.jf.dexlib2.util.ReferenceUtil;
+import org.jf.smalidea.psi.impl.SmaliClass;
+import org.jf.smalidea.psi.impl.SmaliFile;
+import org.jf.smalidea.psi.impl.SmaliMethod;
+import org.junit.Assert;
+
+import java.util.List;
+
+public class SmalideaMethodTest extends LightCodeInsightFixtureTestCase {
+
+ public void testSmalideaMethod() {
+ String text = ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".method public someMethodName(I)I\n" +
+ " .registers 4\n" +
+ " .param p1, \"edge\" # I\n" +
+
+ " goto :here #0: 10t\n" +
+ " :here\n" +
+ " return-void #1: 21c\n" +
+ " const/4 v0, 1234 #2: 11n\n" +
+ " monitor-enter v1, #3: 11x\n" +
+ " move v1, v0 #4: 12x\n" +
+ " goto/16 :here #5: 20t\n" +
+ " sget v0, La/b/c;->blah:I #6: 21c\n" +
+ " const/high16 v0, 0x12340000 #7: 21ih\n" +
+ " const-wide/high16 v0, 0x1234000000000000L #8: 21lh\n" +
+ " const-wide/16 v0, 1234 #9: 21s\n" +
+ " if-eqz v0, :here #10: 21t\n" +
+ " add-int/lit8 v0, v1, 123 #11: 22b\n" +
+ " iget v1, v2, Labc;->blort:Z #12: 22c\n" +
+ " add-int/lit16 v0, v1, 1234 #13: 22s\n" +
+ " if-eq v0, v1, :here #14: 22t\n" +
+ " move/from16 v0, v1 #15: 22x\n" +
+ " cmpl-float v0, v1, v2 #16: 23x\n" +
+ " goto/32 :here #17: 30t\n" +
+ " const-string/jumbo v0, \"abcd\" #18: 31c\n" +
+ " const v0, 1234 #19: 31i\n" +
+ " move/16 v0, v1 #20: 32x\n" +
+ " invoke-virtual {v0, v1, v2, v3, v4}, Lblah;->blort(IIII)I #21: 35c\n" +
+ " invoke-virtual/range {v0..v4}, Lblah;->blort(IIII)I #22: 3rc\n" +
+ " const-wide v0, 0x1234567890L #23: 51i\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text);
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliMethod smaliMethod = smaliClass.getMethods()[0];
+
+ SmalideaMethod method = new SmalideaMethod(smaliMethod);
+ Assert.assertEquals("Lmy/pkg/blah;", method.getDefiningClass());
+ Assert.assertEquals("someMethodName", method.getName());
+ Assert.assertEquals("I", method.getReturnType());
+
+ List<? extends CharSequence> parameterTypes = method.getParameterTypes();
+ Assert.assertEquals(1, parameterTypes.size());
+ Assert.assertEquals("I", parameterTypes.get(0));
+
+ List<? extends MethodParameter> parameters = method.getParameters();
+ Assert.assertEquals(1, parameters.size());
+ Assert.assertEquals("I", parameters.get(0).getType());
+ Assert.assertEquals("edge", parameters.get(0).getName());
+
+ Assert.assertEquals(AccessFlags.PUBLIC.getValue(), method.getAccessFlags());
+
+ MethodImplementation impl = method.getImplementation();
+ Assert.assertNotNull(impl);
+
+ Assert.assertEquals(4, impl.getRegisterCount());
+
+ List<? extends Instruction> instructions = Lists.newArrayList(impl.getInstructions());
+
+ {
+ Instruction10t instruction = (Instruction10t)instructions.get(0);
+ Assert.assertEquals(Opcode.GOTO, instruction.getOpcode());
+ Assert.assertEquals(1, instruction.getCodeOffset());
+ }
+
+ {
+ Instruction10x instruction = (Instruction10x)instructions.get(1);
+ Assert.assertEquals(Opcode.RETURN_VOID, instruction.getOpcode());
+ }
+
+ {
+ Instruction11n instruction = (Instruction11n)instructions.get(2);
+ Assert.assertEquals(Opcode.CONST_4, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals(1234, instruction.getNarrowLiteral());
+ }
+
+ {
+ Instruction11x instruction = (Instruction11x)instructions.get(3);
+ Assert.assertEquals(Opcode.MONITOR_ENTER, instruction.getOpcode());
+ Assert.assertEquals(1, instruction.getRegisterA());
+ }
+
+ {
+ Instruction12x instruction = (Instruction12x)instructions.get(4);
+ Assert.assertEquals(Opcode.MOVE, instruction.getOpcode());
+ Assert.assertEquals(1, instruction.getRegisterA());
+ Assert.assertEquals(0, instruction.getRegisterB());
+ }
+
+ {
+ Instruction20t instruction = (Instruction20t)instructions.get(5);
+ Assert.assertEquals(Opcode.GOTO_16, instruction.getOpcode());
+ Assert.assertEquals(-4, instruction.getCodeOffset());
+ }
+
+ {
+ Instruction21c instruction = (Instruction21c)instructions.get(6);
+ Assert.assertEquals(Opcode.SGET, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals("La/b/c;->blah:I", ReferenceUtil.getFieldDescriptor(
+ (FieldReference)instruction.getReference()));
+ }
+
+ {
+ Instruction21ih instruction = (Instruction21ih)instructions.get(7);
+ Assert.assertEquals(Opcode.CONST_HIGH16, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals(0x1234, instruction.getHatLiteral());
+ Assert.assertEquals(0x12340000, instruction.getNarrowLiteral());
+ Assert.assertEquals(0x12340000, instruction.getWideLiteral());
+ }
+
+ {
+ Instruction21lh instruction = (Instruction21lh)instructions.get(8);
+ Assert.assertEquals(Opcode.CONST_WIDE_HIGH16, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals(0x1234, instruction.getHatLiteral());
+ Assert.assertEquals(0x1234000000000000L, instruction.getWideLiteral());
+ }
+
+ {
+ Instruction21s instruction = (Instruction21s)instructions.get(9);
+ Assert.assertEquals(Opcode.CONST_WIDE_16, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals(1234, instruction.getWideLiteral());
+ }
+
+ {
+ Instruction21t instruction = (Instruction21t)instructions.get(10);
+ Assert.assertEquals(Opcode.IF_EQZ, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals(-14, instruction.getCodeOffset());
+ }
+
+ {
+ Instruction22b instruction = (Instruction22b)instructions.get(11);
+ Assert.assertEquals(Opcode.ADD_INT_LIT8, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals(1, instruction.getRegisterB());
+ Assert.assertEquals(123, instruction.getNarrowLiteral());
+ }
+
+ {
+ Instruction22c instruction = (Instruction22c)instructions.get(12);
+ Assert.assertEquals(Opcode.IGET, instruction.getOpcode());
+ Assert.assertEquals(1, instruction.getRegisterA());
+ Assert.assertEquals(2, instruction.getRegisterB());
+ Assert.assertEquals("Labc;->blort:Z", ReferenceUtil.getFieldDescriptor(
+ (FieldReference)instruction.getReference()));
+ }
+
+ {
+ Instruction22s instruction = (Instruction22s)instructions.get(13);
+ Assert.assertEquals(Opcode.ADD_INT_LIT16, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals(1, instruction.getRegisterB());
+ Assert.assertEquals(1234, instruction.getNarrowLiteral());
+ }
+
+ {
+ Instruction22t instruction = (Instruction22t)instructions.get(14);
+ Assert.assertEquals(Opcode.IF_EQ, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals(1, instruction.getRegisterB());
+ Assert.assertEquals(-22, instruction.getCodeOffset());
+ }
+
+ {
+ Instruction22x instruction = (Instruction22x)instructions.get(15);
+ Assert.assertEquals(Opcode.MOVE_FROM16, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals(1, instruction.getRegisterB());
+ }
+
+ {
+ Instruction23x instruction = (Instruction23x)instructions.get(16);
+ Assert.assertEquals(Opcode.CMPL_FLOAT, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals(1, instruction.getRegisterB());
+ Assert.assertEquals(2, instruction.getRegisterC());
+ }
+
+ {
+ Instruction30t instruction = (Instruction30t)instructions.get(17);
+ Assert.assertEquals(Opcode.GOTO_32, instruction.getOpcode());
+ Assert.assertEquals(-28, instruction.getCodeOffset());
+ }
+
+ {
+ Instruction31c instruction = (Instruction31c)instructions.get(18);
+ Assert.assertEquals(Opcode.CONST_STRING_JUMBO, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals("abcd", ((StringReference)instruction.getReference()).getString());
+ }
+
+ {
+ Instruction31i instruction = (Instruction31i)instructions.get(19);
+ Assert.assertEquals(Opcode.CONST, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals(1234, instruction.getNarrowLiteral());
+ }
+
+ {
+ Instruction32x instruction = (Instruction32x)instructions.get(20);
+ Assert.assertEquals(Opcode.MOVE_16, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals(1, instruction.getRegisterB());
+ }
+
+ {
+ Instruction35c instruction = (Instruction35c)instructions.get(21);
+ Assert.assertEquals(Opcode.INVOKE_VIRTUAL, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterC());
+ Assert.assertEquals(1, instruction.getRegisterD());
+ Assert.assertEquals(2, instruction.getRegisterE());
+ Assert.assertEquals(3, instruction.getRegisterF());
+ Assert.assertEquals(4, instruction.getRegisterG());
+ Assert.assertEquals("Lblah;->blort(IIII)I", ReferenceUtil.getReferenceString(instruction.getReference()));
+ }
+
+ {
+ Instruction3rc instruction = (Instruction3rc)instructions.get(22);
+ Assert.assertEquals(Opcode.INVOKE_VIRTUAL_RANGE, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getStartRegister());
+ Assert.assertEquals(5, instruction.getRegisterCount());
+ Assert.assertEquals("Lblah;->blort(IIII)I", ReferenceUtil.getReferenceString(instruction.getReference()));
+ }
+
+ {
+ Instruction51l instruction = (Instruction51l)instructions.get(23);
+ Assert.assertEquals(Opcode.CONST_WIDE, instruction.getOpcode());
+ Assert.assertEquals(0, instruction.getRegisterA());
+ Assert.assertEquals(0x1234567890L, instruction.getWideLiteral());
+ }
+ }
+
+ public void testCatchBlocks() {
+ String text = ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
+ ".method public onCreateEngine()Landroid/service/wallpaper/WallpaperService$Engine;\n" +
+ " .registers 5\n" +
+ "\n" +
+ " .prologue\n" +
+ " .line 88\n" +
+ " new-instance v0, Lorg/jf/Penroser/PenroserLiveWallpaper$PenroserGLEngine;\n" +
+ "\n" +
+ " invoke-direct {v0, p0}, Lorg/jf/Penroser/PenroserLiveWallpaper$PenroserGLEngine;-><init>(Lorg/jf/Penroser/PenroserLiveWallpaper;)V\n" +
+ "\n" +
+ " .line 89\n" +
+ " .local v0, \"engine\":Lorg/jf/Penroser/PenroserLiveWallpaper$PenroserGLEngine;\n" +
+ " sget-object v1, Lorg/jf/Penroser/PenroserLiveWallpaper;->engines:Ljava/util/LinkedList;\n" +
+ "\n" +
+ " monitor-enter v1\n" +
+ "\n" +
+ " .line 90\n" +
+ " :try_start_8\n" +
+ " sget-object v2, Lorg/jf/Penroser/PenroserLiveWallpaper;->engines:Ljava/util/LinkedList;\n" +
+ "\n" +
+ " new-instance v3, Ljava/lang/ref/WeakReference;\n" +
+ "\n" +
+ " invoke-direct {v3, v0}, Ljava/lang/ref/WeakReference;-><init>(Ljava/lang/Object;)V\n" +
+ "\n" +
+ " invoke-virtual {v2, v3}, Ljava/util/LinkedList;->addLast(Ljava/lang/Object;)V\n" +
+ "\n" +
+ " .line 91\n" +
+ " monitor-exit v1\n" +
+ "\n" +
+ " .line 92\n" +
+ " return-object v0\n" +
+ "\n" +
+ " .line 91\n" +
+ " :catchall_14\n" +
+ " move-exception v2\n" +
+ "\n" +
+ " monitor-exit v1\n" +
+ " :try_end_16\n" +
+ " .catch Ljava/lang/RuntimeException; {:try_start_8 .. :try_end_16} :newcatch\n" +
+ " .catchall {:try_start_8 .. :try_end_16} :catchall_14\n" +
+ "\n" +
+ " throw v2\n" +
+ "\n" +
+ " :newcatch\n" +
+ " move-exception v2\n" +
+ " throw v2\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text);
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliMethod smaliMethod = smaliClass.getMethods()[0];
+
+ SmalideaMethod method = new SmalideaMethod(smaliMethod);
+
+ MethodImplementation impl = method.getImplementation();
+ Assert.assertNotNull(impl);
+
+ List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = impl.getTryBlocks();
+ Assert.assertEquals(2, tryBlocks.size());
+
+ TryBlock<? extends ExceptionHandler> tryBlock = tryBlocks.get(0);
+ Assert.assertEquals(8, tryBlock.getStartCodeAddress());
+ Assert.assertEquals(14, tryBlock.getCodeUnitCount());
+ Assert.assertEquals(1, tryBlock.getExceptionHandlers().size());
+ Assert.assertEquals("Ljava/lang/RuntimeException;", tryBlock.getExceptionHandlers().get(0).getExceptionType());
+ Assert.assertEquals(23, tryBlock.getExceptionHandlers().get(0).getHandlerCodeAddress());
+
+ tryBlock = tryBlocks.get(1);
+ Assert.assertEquals(8, tryBlock.getStartCodeAddress());
+ Assert.assertEquals(14, tryBlock.getCodeUnitCount());
+ Assert.assertEquals(1, tryBlock.getExceptionHandlers().size());
+ Assert.assertEquals(null, tryBlock.getExceptionHandlers().get(0).getExceptionType());
+ Assert.assertEquals(20, tryBlock.getExceptionHandlers().get(0).getHandlerCodeAddress());
+ }
+
+ private static void checkSwitchElement(SwitchElement element, int key, int offset) {
+ Assert.assertEquals(key, element.getKey());
+ Assert.assertEquals(offset, element.getOffset());
+ }
+
+ public void testPackedSwitch() {
+ String text =
+ ".class public LFormat31t;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".source \"Format31t.smali\"" +
+ "\n" +
+ ".method public test_packed-switch()V\n" +
+ " .registers 1\n" +
+ " .annotation runtime Lorg/junit/Test;\n" +
+ " .end annotation\n" +
+ "\n" +
+ " const v0, 12\n" +
+ "\n" +
+ ":switch\n" +
+ " packed-switch v0, :PackedSwitch\n" +
+ "\n" +
+ ":Label10\n" +
+ " invoke-static {}, Lorg/junit/Assert;->fail()V\n" +
+ " return-void\n" +
+ "\n" +
+ ":Label11\n" +
+ " invoke-static {}, Lorg/junit/Assert;->fail()V\n" +
+ " return-void\n" +
+ "\n" +
+ ":Label12\n" +
+ " return-void\n" +
+ "\n" +
+ ":Label13\n" +
+ " invoke-static {}, Lorg/junit/Assert;->fail()V\n" +
+ " return-void\n" +
+ "\n" +
+ ":PackedSwitch\n" +
+ " .packed-switch 10\n" +
+ " :Label10\n" +
+ " :Label11\n" +
+ " :Label12\n" +
+ " :Label13\n" +
+ " .end packed-switch\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text);
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliMethod smaliMethod = smaliClass.getMethods()[0];
+
+ SmalideaMethod method = new SmalideaMethod(smaliMethod);
+
+ MethodImplementation impl = method.getImplementation();
+ Assert.assertNotNull(impl);
+
+ List<Instruction> instructions = Lists.newArrayList(impl.getInstructions());
+
+ PackedSwitchPayload packedSwitchPayload = (PackedSwitchPayload)instructions.get(9);
+ List<? extends SwitchElement> switchElements = packedSwitchPayload.getSwitchElements();
+ Assert.assertEquals(4, switchElements.size());
+
+ checkSwitchElement(switchElements.get(0), 10, 6);
+ checkSwitchElement(switchElements.get(1), 11, 14);
+ checkSwitchElement(switchElements.get(2), 12, 22);
+ checkSwitchElement(switchElements.get(3), 13, 24);
+ }
+
+ public void testSparseSwitch() {
+ String text =
+ ".class public LFormat31t;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".source \"Format31t.smali\"" +
+ "\n" +
+ ".method public test_sparse-switch()V\n" +
+ " .registers 1\n" +
+ " .annotation runtime Lorg/junit/Test;\n" +
+ " .end annotation\n" +
+ "\n" +
+ " const v0, 13\n" +
+ "\n" +
+ ":switch\n" +
+ " sparse-switch v0, :SparseSwitch\n" +
+ "\n" +
+ ":Label10\n" +
+ " invoke-static {}, Lorg/junit/Assert;->fail()V\n" +
+ " return-void\n" +
+ "\n" +
+ ":Label20\n" +
+ " invoke-static {}, Lorg/junit/Assert;->fail()V\n" +
+ " return-void\n" +
+ "\n" +
+ ":Label15\n" +
+ " invoke-static {}, Lorg/junit/Assert;->fail()V\n" +
+ " return-void\n" +
+ "\n" +
+ ":Label13\n" +
+ " return-void\n" +
+ "\n" +
+ ":Label99\n" +
+ " invoke-static {}, Lorg/junit/Assert;->fail()V\n" +
+ " return-void\n" +
+ "\n" +
+ ":SparseSwitch\n" +
+ " .sparse-switch\n" +
+ " 10 -> :Label10\n" +
+ " 13 -> :Label13\n" +
+ " 15 -> :Label15\n" +
+ " 20 -> :Label20\n" +
+ " 99 -> :Label99\n" +
+ " .end sparse-switch\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text);
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliMethod smaliMethod = smaliClass.getMethods()[0];
+
+ SmalideaMethod method = new SmalideaMethod(smaliMethod);
+
+ MethodImplementation impl = method.getImplementation();
+ Assert.assertNotNull(impl);
+
+ List<Instruction> instructions = Lists.newArrayList(impl.getInstructions());
+
+ SparseSwitchPayload sparseSwitchPayload = (SparseSwitchPayload)instructions.get(11);
+ List<? extends SwitchElement> switchElements = sparseSwitchPayload.getSwitchElements();
+ Assert.assertEquals(5, switchElements.size());
+
+ checkSwitchElement(switchElements.get(0), 10, 6);
+ checkSwitchElement(switchElements.get(1), 13, 30);
+ checkSwitchElement(switchElements.get(2), 15, 22);
+ checkSwitchElement(switchElements.get(3), 20, 14);
+ checkSwitchElement(switchElements.get(4), 99, 32);
+ }
+
+ public void testArrayData() {
+ String text =
+ ".class public LFormat31t;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".source \"Format31t.smali\"" +
+ "\n" +
+ ".method public test_fill-array-data()V\n" +
+ " .registers 3\n" +
+ " .annotation runtime Lorg/junit/Test;\n" +
+ " .end annotation\n" +
+ "\n" +
+ " const v0, 6\n" +
+ " new-array v0, v0, [I\n" +
+ " fill-array-data v0, :ArrayData\n" +
+ "\n" +
+ " const v1, 0\n" +
+ " aget v2, v0, v1\n" +
+ " const v1, 1\n" +
+ " invoke-static {v1, v2}, LAssert;->assertEquals(II)V\n" +
+ "\n" +
+ " const v1, 1\n" +
+ " aget v2, v0, v1\n" +
+ " const v1, 2\n" +
+ " invoke-static {v1, v2}, LAssert;->assertEquals(II)V\n" +
+ "\n" +
+ " const v1, 2\n" +
+ " aget v2, v0, v1\n" +
+ " const v1, 3\n" +
+ " invoke-static {v1, v2}, LAssert;->assertEquals(II)V\n" +
+ "\n" +
+ " const v1, 3\n" +
+ " aget v2, v0, v1\n" +
+ " const v1, 4\n" +
+ " invoke-static {v1, v2}, LAssert;->assertEquals(II)V\n" +
+ "\n" +
+ " const v1, 4\n" +
+ " aget v2, v0, v1\n" +
+ " const v1, 5\n" +
+ " invoke-static {v1, v2}, LAssert;->assertEquals(II)V\n" +
+ "\n" +
+ " const v1, 5\n" +
+ " aget v2, v0, v1\n" +
+ " const v1, 6\n" +
+ " invoke-static {v1, v2}, LAssert;->assertEquals(II)V\n" +
+ "\n" +
+ " return-void\n" +
+ "\n" +
+ ":ArrayData\n" +
+ " .array-data 4\n" +
+ " 1 2 128 -256 65536 0x7fffffff\n" +
+ " .end array-data\n" +
+ ".end method";
+
+ SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text);
+ SmaliClass smaliClass = file.getPsiClass();
+ SmaliMethod smaliMethod = smaliClass.getMethods()[0];
+
+ SmalideaMethod method = new SmalideaMethod(smaliMethod);
+
+ MethodImplementation impl = method.getImplementation();
+ Assert.assertNotNull(impl);
+
+ List<Instruction> instructions = Lists.newArrayList(impl.getInstructions());
+
+ ArrayPayload arrayPayload = (ArrayPayload)instructions.get(28);
+ Assert.assertEquals(4, arrayPayload.getElementWidth());
+ List<Number> elements = arrayPayload.getArrayElements();
+ Assert.assertEquals(6, elements.size());
+
+ Assert.assertEquals(1L, elements.get(0).longValue());
+ Assert.assertEquals(2L, elements.get(1).longValue());
+ Assert.assertEquals(128L, elements.get(2));
+ Assert.assertEquals(-256L, elements.get(3));
+ Assert.assertEquals(65536L, elements.get(4));
+ Assert.assertEquals(0x7fffffffL, elements.get(5));
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/findUsages/ClassUsageTypeTest.java b/smalidea/src/test/java/org/jf/smalidea/findUsages/ClassUsageTypeTest.java
new file mode 100644
index 00000000..18a61941
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/findUsages/ClassUsageTypeTest.java
@@ -0,0 +1,74 @@
+package org.jf.smalidea.findUsages;
+
+import com.intellij.usages.impl.rules.UsageType;
+
+public class ClassUsageTypeTest extends UsageTypeTest {
+ public ClassUsageTypeTest() {
+ super(new SmaliUsageTypeProvider());
+ }
+
+ public void testClassUsageTypes() throws Exception {
+ doTest("blah.smali", "" +
+ ".class public Lbl<ref:1>ah;\n" +
+ ".super Lbl<ref:2>ah;\n" +
+ ".implements Lbl<ref:3>ah;\n" +
+ "\n" +
+ ".annotation build Lbl<ref:22>ah;\n" +
+ " value = .subannotation Lbl<ref:23>ah;\n" +
+ " value = Lbl<ref:24>ah;\n" +
+ " .end subannotation\n" +
+ ".end annotation\n" +
+ "\n" +
+ ".field static public blah:Lbl<ref:4>ah; = Lbl<ref:25>ah;\n" +
+ "\n" +
+ ".method public blah(Lbl<ref:5>ah;)Lbl<ref:6>ah;\n" +
+ " .registers 2\n" +
+ " .local p0, \"this\":Lbl<ref:7>ah;\n" +
+ "\n" +
+ " :start\n" +
+ " iget-object v0, v0, Lbl<ref:8>ah;->blah:Lbl<ref:9>ah;\n" +
+ "\n" +
+ " invoke-virtual {v0}, Lbl<ref:10>ah;->blah(Lbl<ref:11>ah;)Lbl<ref:12>ah;\n" +
+ "\n" +
+ " instance-of v0, v0, Lbl<ref:13>ah;\n" +
+ " check-cast v0, Lbl<ref:14>ah;\n" +
+ " new-instance v0, Lbl<ref:15>ah;\n" +
+ " const-class v0, Lbl<ref:16>ah;\n" +
+ " throw-verification-error generic-error, Lbl<ref:17>ah;\n" +
+ "\n" +
+ " filled-new-array {v0, v0, v0, v0, v0}, Lbl<ref:18>ah;\n" +
+ " new-array v0, v0, Lbl<ref:19>ah;\n" +
+ " filled-new-array/range {v0}, Lbl<ref:20>ah;\n" +
+ " :end\n" +
+ "\n" +
+ " .catch Lbl<ref:21>ah; { :start .. :end } :handler\n" +
+ " :handler\n" +
+ " return-void\n" +
+ ".end method",
+ 1, SmaliUsageTypeProvider.CLASS_DECLARATION,
+ 2, UsageType.CLASS_EXTENDS_IMPLEMENTS_LIST,
+ 3, UsageType.CLASS_EXTENDS_IMPLEMENTS_LIST,
+ 4, UsageType.CLASS_FIELD_DECLARATION,
+ 5, UsageType.CLASS_METHOD_PARAMETER_DECLARATION,
+ 6, UsageType.CLASS_METHOD_RETURN_TYPE,
+ 7, UsageType.CLASS_LOCAL_VAR_DECLARATION,
+ 8, SmaliUsageTypeProvider.FIELD_DECLARING_TYPE_REFERENCE,
+ 9, SmaliUsageTypeProvider.FIELD_TYPE_REFERENCE,
+ 10, SmaliUsageTypeProvider.METHOD_DECLARING_TYPE_REFERENCE,
+ 11, SmaliUsageTypeProvider.METHOD_PARAM_REFERENCE,
+ 12, SmaliUsageTypeProvider.METHOD_RETURN_TYPE_REFERENCE,
+ 13, UsageType.CLASS_INSTANCE_OF,
+ 14, UsageType.CLASS_CAST_TO,
+ 15, UsageType.CLASS_NEW_OPERATOR,
+ 16, UsageType.CLASS_CLASS_OBJECT_ACCESS,
+ 17, SmaliUsageTypeProvider.VERIFICATION_ERROR,
+ 18, UsageType.CLASS_NEW_ARRAY,
+ 19, UsageType.CLASS_NEW_ARRAY,
+ 20, UsageType.CLASS_NEW_ARRAY,
+ 21, UsageType.CLASS_CATCH_CLAUSE_PARAMETER_DECLARATION,
+ 22, UsageType.ANNOTATION,
+ 23, UsageType.ANNOTATION,
+ 24, SmaliUsageTypeProvider.LITERAL,
+ 25, SmaliUsageTypeProvider.LITERAL);
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/findUsages/FieldUsageTypeTest.java b/smalidea/src/test/java/org/jf/smalidea/findUsages/FieldUsageTypeTest.java
new file mode 100644
index 00000000..128c97b5
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/findUsages/FieldUsageTypeTest.java
@@ -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);
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/findUsages/FindAnnotationElementUsagesTest.java b/smalidea/src/test/java/org/jf/smalidea/findUsages/FindAnnotationElementUsagesTest.java
new file mode 100644
index 00000000..ec889cca
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/findUsages/FindAnnotationElementUsagesTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2015, 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.findUsages;
+
+public class FindAnnotationElementUsagesTest extends FindUsagesTest {
+ public void testSmaliUsageInSmaliFile() throws Exception {
+ addFile("AnnotationWithValues.smali", "" +
+ ".class public abstract interface annotation LAnnotationWithValues;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".implements Ljava/lang/annotation/Annotation;\n" +
+ "\n" +
+ ".method public abstract intValue()I\n" +
+ ".end method\n" +
+ ".annotation system Ldalvik/annotation/AnnotationDefault;\n" +
+ " value = .subannotation LAnnotationWithValues;\n" +
+ " int<usage>Value = 4\n" +
+ " .end subannotation\n" +
+ ".end annotation");
+ addFile("blarg.smali", "" +
+ ".class public Lblah;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".annotation runtime LAnnotationWithValues;\n" +
+ " int<usage><ref>Value = 123\n" +
+ ".end annotation");
+ doTest();
+ }
+
+ public void testJavaUsageInSmaliFile() throws Exception {
+ addFile("AnnotationWithValues.java", "" +
+ "\n" +
+ "public @interface AnnotationWithValues {\n" +
+ " int int<ref>Value() default 4;\n" +
+ "}");
+ addFile("blarg.smali", "" +
+ ".class public Lblah;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".annotation runtime LAnnotationWithValues;\n" +
+ " int<usage>Value = 123\n" +
+ ".end annotation");
+ doTest();
+ }
+
+ public void testSmaliUsageInJavaFile() throws Exception {
+ addFile("AnnotationWithValues.smali", "" +
+ ".class public abstract interface annotation LAnnotationWithValues;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".implements Ljava/lang/annotation/Annotation;\n" +
+ "\n" +
+ ".method public abstract intValue()I\n" +
+ ".end method\n" +
+ ".annotation system Ldalvik/annotation/AnnotationDefault;\n" +
+ " value = .subannotation LAnnotationWithValues;\n" +
+ " int<usage><ref>Value = 4\n" +
+ " .end subannotation\n" +
+ ".end annotation");
+ addFile("blarg.java", "" +
+ "\n" +
+ "@AnnotationWithValues(int<usage>Value=123)\n" +
+ "public class blarg {}");
+ doTest();
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/findUsages/FindClassUsagesTest.java b/smalidea/src/test/java/org/jf/smalidea/findUsages/FindClassUsagesTest.java
new file mode 100644
index 00000000..810ac5b1
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/findUsages/FindClassUsagesTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015, 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.findUsages;
+
+public class FindClassUsagesTest extends FindUsagesTest {
+ public void testSmaliUsageInSmaliFile() throws Exception {
+ addFile("blah.smali", ".class public Lbl<ref><usage>ah; .super Ljava/lang/Object;");
+ addFile("blarg.smali", "" +
+ ".class public Lblarg; .super Ljava/lang/Object;\n" +
+ ".method public doSomething()V\n" +
+ " .registers 1\n" +
+ " new-instance v0, Lbl<usage>ah;\n" +
+ " invoke-direct {v0}, Lbl<usage>ah;-><init>()V\n" +
+ " return-void\n" +
+ ".end method");
+ doTest();
+ }
+
+ public void testSmaliUsageInJavaFile() throws Exception {
+ addFile("blah.smali", ".class public Lbl<ref><usage>ah; .super Ljava/lang/Object;");
+ addFile("blarg.java", "" +
+ "public class blarg {\n" +
+ " public void blargMethod() {\n" +
+ " new bl<usage>ah();\n" +
+ " }\n" +
+ "}");
+ doTest();
+ }
+
+ public void testJavaUsageInSmaliFile() throws Exception {
+ addFile("blah.java", "" +
+ "public class blah {\n" +
+ " public bl<usage>ah blahMethod() {\n" +
+ " return new bl<usage><ref>ah();\n" +
+ " }\n" +
+ "}");
+ addFile("blarg.smali", "" +
+ ".class public Lblarg; .super Ljava/lang/Object;\n" +
+ ".method public doSomething()V\n" +
+ " .registers 1\n" +
+ " new-instance v0, Lbl<usage>ah;\n" +
+ " invoke-direct {v0}, Lbl<usage>ah;-><init>()V\n" +
+ " return-void\n" +
+ ".end method");
+ doTest();
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/findUsages/FindFieldUsagesTest.java b/smalidea/src/test/java/org/jf/smalidea/findUsages/FindFieldUsagesTest.java
new file mode 100644
index 00000000..80c00547
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/findUsages/FindFieldUsagesTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2015, 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.findUsages;
+
+public class FindFieldUsagesTest extends FindUsagesTest {
+ public void testSmaliUsageInSmaliFile() throws Exception {
+ addFile("blah.smali", "" +
+ ".class public Lblah;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".field blah<ref>Field:I");
+ addFile("blarg.smali", "" +
+ ".class public Lblarg;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract blargMethod()V\n" +
+ " iget v0, v0, Lblah;->blah<usage>Field:I\n" +
+ ".end method");
+ doTest();
+ }
+
+ public void testSmaliUsageInJavaFile() throws Exception {
+ addFile("blah.smali", "" +
+ ".class public Lblah;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".field blah<ref>Field:I");
+ addFile("blarg.java", "" +
+ "public class blarg {\n" +
+ " public int blargMethod() {\n" +
+ " blah b = new blah();\n" +
+ " return b.blah<usage>Field;\n" +
+ " }\n" +
+ "}");
+ doTest();
+ }
+
+ public void testJavaUsageInSmaliFile() throws Exception {
+ addFile("blah.java", "" +
+ "public class blah {\n" +
+ " public int blah<ref>Field;\n" +
+ "}");
+ addFile("blarg.smali", "" +
+ ".class public Lblarg;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract blargMethod()V\n" +
+ " iget v0, v0, Lblah;->blah<usage>Field:I\n" +
+ ".end method");
+ doTest();
+ }
+
+ public void testPrimitiveListMethod() throws Exception {
+ addFile("blah.smali", "" +
+ ".class public Lblah;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".field II<ref>II:I");
+ addFile("blarg.smali", "" +
+ ".class public Lblarg;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract blargMethod()V\n" +
+ " iget v0, v0, Lblah;->II<usage>II:I\n" +
+ ".end method");
+ doTest();
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/findUsages/FindMethodUsagesTest.java b/smalidea/src/test/java/org/jf/smalidea/findUsages/FindMethodUsagesTest.java
new file mode 100644
index 00000000..311c9eef
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/findUsages/FindMethodUsagesTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2015, 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.findUsages;
+
+public class FindMethodUsagesTest extends FindUsagesTest {
+ public void testSmaliUsageInSmaliFile() throws Exception {
+ addFile("blah.smali", "" +
+ ".class public Lblah;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract blah<ref>Method()V\n" +
+ ".end method");
+ addFile("blarg.smali", "" +
+ ".class public Lblarg;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract blargMethod()V\n" +
+ " invoke-virtual {v0}, Lblah;->blah<usage>Method()V\n" +
+ ".end method");
+ doTest();
+ }
+
+ public void testSmaliUsageInJavaFile() throws Exception {
+ addFile("blah.smali", "" +
+ ".class public Lblah;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract blah<ref>Method()V\n" +
+ ".end method");
+ addFile("blarg.java", "" +
+ "public class blarg {\n" +
+ " public void blargMethod() {\n" +
+ " blah b = new blah();\n" +
+ " b.blah<usage>Method();\n" +
+ " }\n" +
+ "}");
+ doTest();
+ }
+
+ public void testJavaUsageInSmaliFile() throws Exception {
+ addFile("blah.java", "" +
+ "public class blah {\n" +
+ " public void blah<ref>Method() {\n" +
+ " }\n" +
+ "}");
+ addFile("blarg.smali", "" +
+ ".class public Lblarg;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract blargMethod()V\n" +
+ " invoke-virtual {v0}, Lblah;->blah<usage>Method()V\n" +
+ ".end method");
+ doTest();
+ }
+
+ public void testPrimitiveListMethod() throws Exception {
+ addFile("blah.smali", "" +
+ ".class public Lblah;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract II<ref>II()V\n" +
+ ".end method");
+ addFile("blarg.smali", "" +
+ ".class public Lblarg;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract blargMethod()V\n" +
+ " invoke-virtual {v0}, Lblah;->II<usage>II()V\n" +
+ ".end method");
+ doTest();
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/findUsages/FindUsagesTest.java b/smalidea/src/test/java/org/jf/smalidea/findUsages/FindUsagesTest.java
new file mode 100644
index 00000000..f4e2b0ff
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/findUsages/FindUsagesTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2015, 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.findUsages;
+
+import com.google.common.collect.Lists;
+import com.intellij.codeInsight.TargetElementUtilBase;
+import com.intellij.find.FindManager;
+import com.intellij.find.findUsages.FindUsagesHandler;
+import com.intellij.find.findUsages.FindUsagesManager;
+import com.intellij.find.findUsages.FindUsagesOptions;
+import com.intellij.find.impl.FindManagerImpl;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiReference;
+import com.intellij.testFramework.PsiTestCase;
+import com.intellij.usageView.UsageInfo;
+import com.intellij.usages.PsiElementUsageTarget;
+import com.intellij.usages.UsageTarget;
+import com.intellij.usages.UsageTargetUtil;
+import com.intellij.util.CommonProcessors;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public abstract class FindUsagesTest extends PsiTestCase {
+ public static final String USAGE_TAG = "<usage>";
+ public static final String REF_TAG = "<ref>";
+
+ private class TestFile {
+ @NotNull public final String fileName;
+ @NotNull public final String fileText;
+ @NotNull public final PsiFile psiFile;
+
+ public TestFile(@NotNull String fileName, @NotNull String fileText) throws Exception {
+ this.fileName = fileName;
+ this.fileText = fileText;
+ this.psiFile = createFile(fileName, getText());
+ }
+
+ @NotNull
+ public String getText() {
+ return fileText.replace(REF_TAG, "").replace(USAGE_TAG, "");
+ }
+
+ public int getRefIndex() {
+ return fileText.replace(USAGE_TAG, "").indexOf(REF_TAG);
+ }
+
+ public List<Integer> getUsageIndices() {
+ Matcher matcher = Pattern.compile(USAGE_TAG).matcher(fileText.replace(REF_TAG, ""));
+ List<Integer> matches = Lists.newArrayList();
+
+ int adjustment = 0;
+ while (matcher.find()) {
+ matches.add(matcher.start() - adjustment);
+ adjustment += USAGE_TAG.length();
+ }
+ return matches;
+ }
+ }
+
+ private List<TestFile> testFiles;
+
+ @Override
+ public void setUp() throws Exception {
+ testFiles = Lists.newArrayList();
+ super.setUp();
+ }
+
+ protected void addFile(String fileName, String fileText) throws Exception {
+ testFiles.add(new TestFile(fileName, fileText));
+ }
+
+ protected void doTest() {
+
+ PsiReference reference = null;
+ PsiElement targetElement = null;
+
+ for (TestFile testFile: testFiles) {
+ int refIndex = testFile.getRefIndex();
+ if (refIndex != -1) {
+ PsiElement element = testFile.psiFile.findElementAt(refIndex);
+
+ UsageTarget[] targets = UsageTargetUtil.findUsageTargets(element);
+ if (targets != null) {
+ for (UsageTarget target : targets) {
+ if (target instanceof PsiElementUsageTarget) {
+ targetElement = ((PsiElementUsageTarget)target).getElement();
+ break;
+ }
+ }
+ }
+
+ if (targetElement == null) {
+ reference = testFile.psiFile.findReferenceAt(refIndex);
+ if (reference != null) {
+ targetElement = reference.resolve();
+ } else {
+ targetElement = TargetElementUtilBase.getInstance().getNamedElement(
+ testFile.psiFile.findElementAt(refIndex), 0);
+ }
+ }
+ break;
+ }
+ }
+
+ Assert.assertNotNull(targetElement);
+
+ Collection<UsageInfo> usages = findUsages(targetElement);
+ for (TestFile testFile: testFiles) {
+ assertUsages(testFile, usages);
+ }
+ }
+
+ private void assertUsages(@NotNull TestFile testFile, @NotNull Collection<UsageInfo> usages) {
+ List<UsageInfo> fileUsages = Lists.newArrayList();
+ for (UsageInfo usage: usages) {
+ if (usage.getFile().getName().equals(testFile.fileName)) {
+ fileUsages.add(usage);
+ }
+ }
+
+ for (Integer usageIndex: testFile.getUsageIndices()) {
+ boolean found = false;
+ for (UsageInfo usage: fileUsages) {
+ int startOffset = usage.getElement().getNode().getStartOffset();
+ int length = usage.getElement().getTextLength();
+
+ if (usageIndex >= startOffset && usageIndex < startOffset + length) {
+ fileUsages.remove(usage);
+ found = true;
+ break;
+ }
+ }
+ Assert.assertTrue(found);
+ }
+ Assert.assertEquals(0, fileUsages.size());
+ }
+
+ private Collection<UsageInfo> findUsages(@NotNull PsiElement element) {
+ FindUsagesManager findUsagesManager =
+ ((FindManagerImpl)FindManager.getInstance(getProject())).getFindUsagesManager();
+
+ FindUsagesHandler findUsagesHandler =
+ findUsagesManager.getFindUsagesHandler(element, false);
+ Assert.assertNotNull(findUsagesHandler);
+
+ final FindUsagesOptions options = findUsagesHandler.getFindUsagesOptions();
+ final CommonProcessors.CollectProcessor<UsageInfo> processor =
+ new CommonProcessors.CollectProcessor<UsageInfo>();
+
+ for (PsiElement primaryElement : findUsagesHandler.getPrimaryElements()) {
+ findUsagesHandler.processElementUsages(primaryElement, processor, options);
+ }
+
+ for (PsiElement secondaryElement: findUsagesHandler.getSecondaryElements()) {
+ findUsagesHandler.processElementUsages(secondaryElement, processor, options);
+ }
+
+ return processor.getResults();
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/findUsages/HighlightLocalClassUsagesTest.java b/smalidea/src/test/java/org/jf/smalidea/findUsages/HighlightLocalClassUsagesTest.java
new file mode 100644
index 00000000..ffec82cd
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/findUsages/HighlightLocalClassUsagesTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.findUsages;
+
+import com.google.common.collect.Lists;
+import com.intellij.codeInsight.TargetElementUtilBase;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.search.LocalSearchScope;
+import com.intellij.psi.search.searches.ReferencesSearch;
+import com.intellij.testFramework.PsiTestCase;
+import org.junit.Assert;
+
+import java.util.List;
+
+public class HighlightLocalClassUsagesTest extends PsiTestCase {
+ public void testHighlightLocalClassUsage() throws Exception {
+ String fileText = "" +
+ ".class public Lbl<ref>arg; .super Ljava/lang/Object;\n" +
+ ".method public doSomething()V\n" +
+ " .registers 1\n" +
+ " new-instance v0, Lbl<ref>arg;\n" +
+ " invoke-direct {v0}, Lblah;-><init>()V\n" +
+ " return-void\n" +
+ ".end method";
+
+ PsiFile file = createFile("blarg.smali", fileText.replace("<ref>", ""));
+ PsiElement target;
+
+ int refIndex = fileText.indexOf("<ref>");
+ PsiReference reference = file.findReferenceAt(refIndex);
+ if (reference != null) {
+ target = reference.resolve();
+ } else {
+ target = TargetElementUtilBase.getInstance().getNamedElement(
+ file.findElementAt(refIndex), 0);
+ }
+
+ final LocalSearchScope scope = new LocalSearchScope(file);
+
+ List<PsiReference> refs = Lists.newArrayList(ReferencesSearch.search(target, scope).findAll());
+ Assert.assertEquals(2, refs.size());
+
+ Assert.assertEquals(file.findElementAt(refIndex).getTextOffset(), refs.get(0).getElement().getTextOffset());
+ Assert.assertEquals(file.findElementAt(fileText.replaceFirst("<ref>", "").indexOf("<ref>")).getTextOffset(),
+ refs.get(1).getElement().getTextOffset());
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/findUsages/MethodUsageTypeTest.java b/smalidea/src/test/java/org/jf/smalidea/findUsages/MethodUsageTypeTest.java
new file mode 100644
index 00000000..eea3b156
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/findUsages/MethodUsageTypeTest.java
@@ -0,0 +1,54 @@
+package org.jf.smalidea.findUsages;
+
+import com.intellij.usages.impl.rules.UsageType;
+
+public class MethodUsageTypeTest extends UsageTypeTest {
+ public MethodUsageTypeTest() {
+ super(new SmaliUsageTypeProvider());
+ }
+
+ public void testMethodUsageTypes() 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()V;\n" +
+ ".end annotation\n" +
+ "\n" +
+ ".method public blah()V\n" +
+ " .registers 2\n" +
+ "\n" +
+ " invoke-direct {v0}, Lblah;->bl<ref:2>ah()V\n" +
+ " invoke-direct/empty {v0}, Lblah;->bl<ref:3>ah()V\n" +
+ " invoke-direct/range {v0}, Lblah;->bl<ref:4>ah()V\n" +
+ " invoke-interface {v0}, Lblah;->bl<ref:5>ah()V\n" +
+ " invoke-interface/range {v0}, Lblah;->bl<ref:6>ah()V\n" +
+ " invoke-object-init/range {v0}, Lblah;->bl<ref:7>ah()V\n" +
+ " invoke-static {v0}, Lblah;->bl<ref:8>ah()V\n" +
+ " invoke-static/range {v0}, Lblah;->bl<ref:9>ah()V\n" +
+ " invoke-super {v0}, Lblah;->bl<ref:10>ah()V\n" +
+ " invoke-super/range {v0}, Lblah;->bl<ref:11>ah()V\n" +
+ " invoke-virtual {v0}, Lblah;->bl<ref:12>ah()V\n" +
+ " invoke-virtual/range {v0}, Lblah;->bl<ref:13>ah()V\n" +
+ "\n" +
+ " throw-verification-error generic-error, Lblah;->bl<ref:14>ah()V\n" +
+ "\n" +
+ " return-void\n" +
+ ".end method\n",
+ 1, SmaliUsageTypeProvider.LITERAL,
+ 2, UsageType.UNCLASSIFIED,
+ 3, UsageType.UNCLASSIFIED,
+ 4, UsageType.UNCLASSIFIED,
+ 5, UsageType.UNCLASSIFIED,
+ 6, UsageType.UNCLASSIFIED,
+ 7, UsageType.UNCLASSIFIED,
+ 8, UsageType.UNCLASSIFIED,
+ 9, UsageType.UNCLASSIFIED,
+ 10, UsageType.UNCLASSIFIED,
+ 11, UsageType.UNCLASSIFIED,
+ 12, UsageType.UNCLASSIFIED,
+ 13, UsageType.UNCLASSIFIED,
+ 14, SmaliUsageTypeProvider.VERIFICATION_ERROR);
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/findUsages/UsageTypeTest.java b/smalidea/src/test/java/org/jf/smalidea/findUsages/UsageTypeTest.java
new file mode 100644
index 00000000..44c2f49f
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/findUsages/UsageTypeTest.java
@@ -0,0 +1,73 @@
+package org.jf.smalidea.findUsages;
+
+import com.google.common.collect.Maps;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
+import com.intellij.testFramework.PsiTestCase;
+import com.intellij.usages.impl.rules.UsageType;
+import com.intellij.usages.impl.rules.UsageTypeProvider;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public abstract class UsageTypeTest extends PsiTestCase {
+ // e.g. <ref:1>, <ref:1234>, etc.
+ private static final Pattern REF_PATTERN = Pattern.compile("(<ref:([0-9]+)>)");
+
+ @NotNull
+ private final UsageTypeProvider usageTypeProvider;
+
+ public UsageTypeTest(@NotNull UsageTypeProvider usageTypeProvider) {
+ this.usageTypeProvider = usageTypeProvider;
+ }
+
+ protected void doTest(@NotNull String fileName, @NotNull String text, @NotNull Object... expectedUsageTypes)
+ throws Exception {
+ Assert.assertTrue(expectedUsageTypes.length % 2 == 0);
+
+ Map<Integer, UsageType> expectedUsageTypesMap = Maps.newHashMap();
+ for (int i=0; i<expectedUsageTypes.length; i+=2) {
+ expectedUsageTypesMap.put((Integer) expectedUsageTypes[i], (UsageType) expectedUsageTypes[i + 1]);
+ }
+
+ PsiFile psiFile = createFile(fileName, REF_PATTERN.matcher(text).replaceAll(""));
+ Map<Integer, Integer> refIndexMap = getRefIndexes(text);
+
+ for (Map.Entry<Integer, Integer> entry: refIndexMap.entrySet()) {
+ int refId = entry.getKey();
+ int index = entry.getValue();
+
+ PsiReference reference = psiFile.getFirstChild().findReferenceAt(index);
+ Assert.assertNotNull(reference);
+ if (reference instanceof PsiMultiReference) {
+ // If there are multiple reference parents, the default seems to be the last one,
+ // i.e. the highest parent. We actually want the lowest one here.
+ reference = ((PsiMultiReference) reference).getReferences()[0];
+ }
+
+ UsageType usageType = usageTypeProvider.getUsageType(reference.getElement());
+ Assert.assertNotNull(usageType);
+ Assert.assertSame(expectedUsageTypesMap.get(refId), usageType);
+ expectedUsageTypesMap.remove(refId);
+ }
+ Assert.assertTrue(expectedUsageTypesMap.isEmpty());
+ }
+
+ @NotNull
+ private Map<Integer, Integer> getRefIndexes(@NotNull String text) {
+ Matcher m = REF_PATTERN.matcher(text);
+ int correction = 0;
+ Map<Integer, Integer> refIndexes = new HashMap<Integer, Integer>();
+ while (m.find()) {
+ int refId = Integer.parseInt(m.group(2));
+ refIndexes.put(refId, m.start() - correction);
+ correction += m.end() - m.start();
+ }
+ return refIndexes;
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/util/NameUtilsTest.java b/smalidea/src/test/java/org/jf/smalidea/util/NameUtilsTest.java
new file mode 100644
index 00000000..60aef8ba
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/util/NameUtilsTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2014, 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.util;
+
+import junit.framework.Assert;
+import org.junit.Test;
+
+public class NameUtilsTest {
+
+ @Test
+ public void testConversions() {
+ testConversion("boolean", "Z");
+ testConversion("byte", "B");
+ testConversion("char", "C");
+ testConversion("short", "S");
+ testConversion("int", "I");
+ testConversion("long", "J");
+ testConversion("float", "F");
+ testConversion("double", "D");
+
+ testConversion("blah", "Lblah;");
+ testConversion("my.blah", "Lmy/blah;");
+
+ testConversion("boolean[]", "[Z");
+ testConversion("byte[]", "[B");
+ testConversion("char[]", "[C");
+ testConversion("short[]", "[S");
+ testConversion("int[]", "[I");
+ testConversion("long[]", "[J");
+ testConversion("float[]", "[F");
+ testConversion("double[]", "[D");
+
+ testConversion("blah[]", "[Lblah;");
+ testConversion("my.blah[]", "[Lmy/blah;");
+
+ testConversion("boolean[][][][]", "[[[[Z");
+ testConversion("byte[][][][]", "[[[[B");
+ testConversion("char[][][][]", "[[[[C");
+ testConversion("short[][][][]", "[[[[S");
+ testConversion("int[][][][]", "[[[[I");
+ testConversion("long[][][][]", "[[[[J");
+ testConversion("float[][][][]", "[[[[F");
+ testConversion("double[][][][]", "[[[[D");
+
+ testConversion("blah[][][][]", "[[[[Lblah;");
+ testConversion("my.blah[][][][]", "[[[[Lmy/blah;");
+ }
+
+ private static void testConversion(String javaType, String smaliType) {
+ Assert.assertEquals(javaType, NameUtils.smaliToJavaType(smaliType));
+ Assert.assertEquals(smaliType, NameUtils.javaToSmaliType(javaType));
+ }
+
+ public void testShortNameFromQualifiedName() {
+ Assert.assertEquals("blah", NameUtils.shortNameFromQualifiedName("org.blah.blah"));
+ Assert.assertEquals("blah", NameUtils.shortNameFromQualifiedName("blah"));
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/util/StringUtilsTest.java b/smalidea/src/test/java/org/jf/smalidea/util/StringUtilsTest.java
new file mode 100644
index 00000000..4c5a9a68
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/util/StringUtilsTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015, 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.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class StringUtilsTest {
+ @Test
+ public void testStringUtilsBasic() throws Exception {
+ String parsedString = StringUtils.parseQuotedString("\"abcd\"");
+ Assert.assertEquals("abcd", parsedString);
+ }
+
+ @Test
+ public void testStringUtilsQuotedChars() throws Exception {
+ String parsedString = StringUtils.parseQuotedString("\"a\\\\b\\nc\\uabcdd\"");
+ Assert.assertEquals("a\\b\nc\uabcdd", parsedString);
+ }
+}
diff --git a/smalidea/testData/Empty.smalidea b/smalidea/testData/Empty.smalidea
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/smalidea/testData/Empty.smalidea
diff --git a/smalidea/testData/Empty.txt b/smalidea/testData/Empty.txt
new file mode 100644
index 00000000..91655095
--- /dev/null
+++ b/smalidea/testData/Empty.txt
@@ -0,0 +1,8 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ PsiErrorElement:required (...)+ loop did not match anything at input '<EOF>'
+ <empty list> \ No newline at end of file
diff --git a/smalidea/testData/FieldAnnotations.smalidea b/smalidea/testData/FieldAnnotations.smalidea
new file mode 100644
index 00000000..37167693
--- /dev/null
+++ b/smalidea/testData/FieldAnnotations.smalidea
@@ -0,0 +1,15 @@
+.field public blah:I
+
+.field public blah2:I
+ .annotation runtime Lblah;
+ .end annotation
+ .annotation runtime Lblah;
+ .end annotation
+.end field
+
+.field public blah2:I
+
+.annotation runtime Lblah;
+.end annotation
+.annotation runtime Lblah;
+.end annotation
diff --git a/smalidea/testData/FieldAnnotations.txt b/smalidea/testData/FieldAnnotations.txt
new file mode 100644
index 00000000..80332e59
--- /dev/null
+++ b/smalidea/testData/FieldAnnotations.txt
@@ -0,0 +1,91 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliField(FIELD)
+ PsiElement(FIELD_DIRECTIVE)('.field')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ PsiElement(ACCESS_SPEC)('public')
+ PsiWhiteSpace(' ')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiElement(COLON)(':')
+ PsiElement(PRIMITIVE_TYPE)
+ PsiElement(PRIMITIVE_TYPE)('I')
+ PsiWhiteSpace('\n\n')
+ SmaliField(FIELD)
+ PsiElement(FIELD_DIRECTIVE)('.field')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ PsiElement(ACCESS_SPEC)('public')
+ PsiWhiteSpace(' ')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah2')
+ PsiElement(COLON)(':')
+ PsiElement(PRIMITIVE_TYPE)
+ PsiElement(PRIMITIVE_TYPE)('I')
+ PsiWhiteSpace('\n ')
+ SmaliAnnotation(ANNOTATION)
+ PsiElement(ANNOTATION_DIRECTIVE)('.annotation')
+ PsiWhiteSpace(' ')
+ PsiElement(ANNOTATION_VISIBILITY)('runtime')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiWhiteSpace('\n ')
+ PsiElement(ANNOTATION_PARAMETER_LIST)
+ <empty list>
+ PsiElement(END_ANNOTATION_DIRECTIVE)('.end annotation')
+ PsiWhiteSpace('\n ')
+ SmaliAnnotation(ANNOTATION)
+ PsiElement(ANNOTATION_DIRECTIVE)('.annotation')
+ PsiWhiteSpace(' ')
+ PsiElement(ANNOTATION_VISIBILITY)('runtime')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiWhiteSpace('\n ')
+ PsiElement(ANNOTATION_PARAMETER_LIST)
+ <empty list>
+ PsiElement(END_ANNOTATION_DIRECTIVE)('.end annotation')
+ PsiWhiteSpace('\n')
+ PsiElement(END_FIELD_DIRECTIVE)('.end field')
+ PsiWhiteSpace('\n\n')
+ SmaliField(FIELD)
+ PsiElement(FIELD_DIRECTIVE)('.field')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ PsiElement(ACCESS_SPEC)('public')
+ PsiWhiteSpace(' ')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah2')
+ PsiElement(COLON)(':')
+ PsiElement(PRIMITIVE_TYPE)
+ PsiElement(PRIMITIVE_TYPE)('I')
+ PsiWhiteSpace('\n\n')
+ SmaliAnnotation(ANNOTATION)
+ PsiElement(ANNOTATION_DIRECTIVE)('.annotation')
+ PsiWhiteSpace(' ')
+ PsiElement(ANNOTATION_VISIBILITY)('runtime')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiWhiteSpace('\n')
+ PsiElement(ANNOTATION_PARAMETER_LIST)
+ <empty list>
+ PsiElement(END_ANNOTATION_DIRECTIVE)('.end annotation')
+ PsiWhiteSpace('\n')
+ SmaliAnnotation(ANNOTATION)
+ PsiElement(ANNOTATION_DIRECTIVE)('.annotation')
+ PsiWhiteSpace(' ')
+ PsiElement(ANNOTATION_VISIBILITY)('runtime')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiWhiteSpace('\n')
+ PsiElement(ANNOTATION_PARAMETER_LIST)
+ <empty list>
+ PsiElement(END_ANNOTATION_DIRECTIVE)('.end annotation') \ No newline at end of file
diff --git a/smalidea/testData/InvalidAnnotation.smalidea b/smalidea/testData/InvalidAnnotation.smalidea
new file mode 100644
index 00000000..9825e293
--- /dev/null
+++ b/smalidea/testData/InvalidAnnotation.smalidea
@@ -0,0 +1,19 @@
+.annotation .blah Lblah;
+.end annotation
+
+.annotation runtime .blah
+.end annotation
+
+.annotation runtime Lblah;
+ blah .blah .blah
+.end annotation
+
+.annotation runtime Lblah;
+ blah = .blah .blah
+.end annotation
+
+.annotation runtime Lblah;
+ blah = .subannotation Lblah2;
+ blah = "blah"
+ .blah
+.end annotation \ No newline at end of file
diff --git a/smalidea/testData/InvalidAnnotation.txt b/smalidea/testData/InvalidAnnotation.txt
new file mode 100644
index 00000000..3799410f
--- /dev/null
+++ b/smalidea/testData/InvalidAnnotation.txt
@@ -0,0 +1,108 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliAnnotation(ANNOTATION)
+ PsiElement(ANNOTATION_DIRECTIVE)('.annotation')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:mismatched input '.blah' expecting ANNOTATION_VISIBILITY
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiWhiteSpace('\n')
+ PsiElement(ANNOTATION_PARAMETER_LIST)
+ <empty list>
+ PsiElement(END_ANNOTATION_DIRECTIVE)('.end annotation')
+ PsiWhiteSpace('\n\n')
+ SmaliAnnotation(ANNOTATION)
+ PsiElement(ANNOTATION_DIRECTIVE)('.annotation')
+ PsiWhiteSpace(' ')
+ PsiElement(ANNOTATION_VISIBILITY)('runtime')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:mismatched input '.blah' expecting CLASS_DESCRIPTOR
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace('\n')
+ PsiElement(ANNOTATION_PARAMETER_LIST)
+ <empty list>
+ PsiElement(END_ANNOTATION_DIRECTIVE)('.end annotation')
+ PsiWhiteSpace('\n\n')
+ SmaliAnnotation(ANNOTATION)
+ PsiElement(ANNOTATION_DIRECTIVE)('.annotation')
+ PsiWhiteSpace(' ')
+ PsiElement(ANNOTATION_VISIBILITY)('runtime')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiWhiteSpace('\n ')
+ PsiElement(ANNOTATION_PARAMETER_LIST)
+ PsiElement(ANNOTATION_ELEMENT)
+ PsiElement(ANNOTATION_ELEMENT_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:mismatched input '.blah' expecting EQUAL
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace(' ')
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace('\n')
+ PsiElement(END_ANNOTATION_DIRECTIVE)('.end annotation')
+ PsiWhiteSpace('\n\n')
+ SmaliAnnotation(ANNOTATION)
+ PsiElement(ANNOTATION_DIRECTIVE)('.annotation')
+ PsiWhiteSpace(' ')
+ PsiElement(ANNOTATION_VISIBILITY)('runtime')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiWhiteSpace('\n ')
+ PsiElement(ANNOTATION_PARAMETER_LIST)
+ PsiElement(ANNOTATION_ELEMENT)
+ PsiElement(ANNOTATION_ELEMENT_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiWhiteSpace(' ')
+ PsiElement(EQUAL)('=')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:no viable alternative at input '.blah'
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace(' ')
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace('\n')
+ PsiElement(END_ANNOTATION_DIRECTIVE)('.end annotation')
+ PsiWhiteSpace('\n\n')
+ SmaliAnnotation(ANNOTATION)
+ PsiElement(ANNOTATION_DIRECTIVE)('.annotation')
+ PsiWhiteSpace(' ')
+ PsiElement(ANNOTATION_VISIBILITY)('runtime')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiWhiteSpace('\n ')
+ PsiElement(ANNOTATION_PARAMETER_LIST)
+ PsiElement(ANNOTATION_ELEMENT)
+ PsiElement(ANNOTATION_ELEMENT_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiWhiteSpace(' ')
+ PsiElement(EQUAL)('=')
+ PsiWhiteSpace(' ')
+ SmaliAnnotation(ANNOTATION)
+ PsiElement(SUBANNOTATION_DIRECTIVE)('.subannotation')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah2;')
+ PsiWhiteSpace('\n ')
+ PsiElement(ANNOTATION_PARAMETER_LIST)
+ PsiElement(ANNOTATION_ELEMENT)
+ PsiElement(ANNOTATION_ELEMENT_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiWhiteSpace(' ')
+ PsiElement(EQUAL)('=')
+ PsiWhiteSpace(' ')
+ PsiElement(LITERAL)
+ PsiElement(STRING_LITERAL)('"blah"')
+ PsiWhiteSpace('\n ')
+ PsiErrorElement:mismatched input '.blah' expecting END_SUBANNOTATION_DIRECTIVE
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace('\n')
+ PsiElement(END_ANNOTATION_DIRECTIVE)('.end annotation') \ No newline at end of file
diff --git a/smalidea/testData/InvalidClassDirective.smalidea b/smalidea/testData/InvalidClassDirective.smalidea
new file mode 100644
index 00000000..9f6b5ba5
--- /dev/null
+++ b/smalidea/testData/InvalidClassDirective.smalidea
@@ -0,0 +1 @@
+.class \ No newline at end of file
diff --git a/smalidea/testData/InvalidClassDirective.txt b/smalidea/testData/InvalidClassDirective.txt
new file mode 100644
index 00000000..e9f89c0d
--- /dev/null
+++ b/smalidea/testData/InvalidClassDirective.txt
@@ -0,0 +1,12 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliClassStatement(CLASS_STATEMENT)
+ PsiElement(CLASS_DIRECTIVE)('.class')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiErrorElement:mismatched input '<EOF>' expecting CLASS_DESCRIPTOR
+ <empty list> \ No newline at end of file
diff --git a/smalidea/testData/InvalidClassDirective2.smalidea b/smalidea/testData/InvalidClassDirective2.smalidea
new file mode 100644
index 00000000..ee4d27e5
--- /dev/null
+++ b/smalidea/testData/InvalidClassDirective2.smalidea
@@ -0,0 +1,2 @@
+.class
+.super Ljava/lang/Object; \ No newline at end of file
diff --git a/smalidea/testData/InvalidClassDirective2.txt b/smalidea/testData/InvalidClassDirective2.txt
new file mode 100644
index 00000000..6f36abe8
--- /dev/null
+++ b/smalidea/testData/InvalidClassDirective2.txt
@@ -0,0 +1,15 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliClassStatement(CLASS_STATEMENT)
+ PsiElement(CLASS_DIRECTIVE)('.class')
+ PsiWhiteSpace('\n')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiErrorElement:extraneous input '.super' expecting CLASS_DESCRIPTOR
+ PsiElement(SUPER_DIRECTIVE)('.super')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_DESCRIPTOR)('Ljava/lang/Object;') \ No newline at end of file
diff --git a/smalidea/testData/InvalidClassDirective3.smalidea b/smalidea/testData/InvalidClassDirective3.smalidea
new file mode 100644
index 00000000..fd5d3608
--- /dev/null
+++ b/smalidea/testData/InvalidClassDirective3.smalidea
@@ -0,0 +1 @@
+.class public .class Ltest; \ No newline at end of file
diff --git a/smalidea/testData/InvalidClassDirective3.txt b/smalidea/testData/InvalidClassDirective3.txt
new file mode 100644
index 00000000..ed98ac64
--- /dev/null
+++ b/smalidea/testData/InvalidClassDirective3.txt
@@ -0,0 +1,16 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliClassStatement(CLASS_STATEMENT)
+ PsiElement(CLASS_DIRECTIVE)('.class')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ PsiElement(ACCESS_SPEC)('public')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:extraneous input '.class' expecting CLASS_DESCRIPTOR
+ PsiElement(CLASS_DIRECTIVE)('.class')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_DESCRIPTOR)('Ltest;') \ No newline at end of file
diff --git a/smalidea/testData/InvalidEnumLiteral.smalidea b/smalidea/testData/InvalidEnumLiteral.smalidea
new file mode 100644
index 00000000..8853cc3a
--- /dev/null
+++ b/smalidea/testData/InvalidEnumLiteral.smalidea
@@ -0,0 +1 @@
+.field public static blah:Ljava/lang/Object; = .enum Lblah;->blah .blah Lblah; \ No newline at end of file
diff --git a/smalidea/testData/InvalidEnumLiteral.txt b/smalidea/testData/InvalidEnumLiteral.txt
new file mode 100644
index 00000000..b2acd87d
--- /dev/null
+++ b/smalidea/testData/InvalidEnumLiteral.txt
@@ -0,0 +1,38 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliField(FIELD)
+ PsiElement(FIELD_DIRECTIVE)('.field')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ PsiElement(ACCESS_SPEC)('public')
+ PsiWhiteSpace(' ')
+ PsiElement(ACCESS_SPEC)('static')
+ PsiWhiteSpace(' ')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiElement(COLON)(':')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Ljava/lang/Object;')
+ PsiWhiteSpace(' ')
+ PsiElement(FIELD_INITIALIZER)
+ PsiElement(EQUAL)('=')
+ PsiWhiteSpace(' ')
+ PsiElement(LITERAL)
+ PsiElement(ENUM_DIRECTIVE)('.enum')
+ PsiWhiteSpace(' ')
+ 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;') \ No newline at end of file
diff --git a/smalidea/testData/InvalidField.smalidea b/smalidea/testData/InvalidField.smalidea
new file mode 100644
index 00000000..8eb11200
--- /dev/null
+++ b/smalidea/testData/InvalidField.smalidea
@@ -0,0 +1 @@
+.field \ No newline at end of file
diff --git a/smalidea/testData/InvalidField.txt b/smalidea/testData/InvalidField.txt
new file mode 100644
index 00000000..99aa29ee
--- /dev/null
+++ b/smalidea/testData/InvalidField.txt
@@ -0,0 +1,13 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliField(FIELD)
+ PsiElement(FIELD_DIRECTIVE)('.field')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiErrorElement:no viable alternative at input '<EOF>'
+ <empty list> \ No newline at end of file
diff --git a/smalidea/testData/InvalidField2.smalidea b/smalidea/testData/InvalidField2.smalidea
new file mode 100644
index 00000000..8de7a3a6
--- /dev/null
+++ b/smalidea/testData/InvalidField2.smalidea
@@ -0,0 +1 @@
+.field public blah .blah \ No newline at end of file
diff --git a/smalidea/testData/InvalidField2.txt b/smalidea/testData/InvalidField2.txt
new file mode 100644
index 00000000..b3e8227b
--- /dev/null
+++ b/smalidea/testData/InvalidField2.txt
@@ -0,0 +1,17 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliField(FIELD)
+ PsiElement(FIELD_DIRECTIVE)('.field')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ PsiElement(ACCESS_SPEC)('public')
+ PsiWhiteSpace(' ')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:mismatched input '.blah' expecting COLON
+ PsiElement(BAD_CHARACTER)('.blah') \ No newline at end of file
diff --git a/smalidea/testData/InvalidField3.smalidea b/smalidea/testData/InvalidField3.smalidea
new file mode 100644
index 00000000..9de31427
--- /dev/null
+++ b/smalidea/testData/InvalidField3.smalidea
@@ -0,0 +1,3 @@
+.field public public:I
+.blah
+.end field \ No newline at end of file
diff --git a/smalidea/testData/InvalidField3.txt b/smalidea/testData/InvalidField3.txt
new file mode 100644
index 00000000..508df467
--- /dev/null
+++ b/smalidea/testData/InvalidField3.txt
@@ -0,0 +1,22 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliField(FIELD)
+ PsiElement(FIELD_DIRECTIVE)('.field')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ PsiElement(ACCESS_SPEC)('public')
+ PsiWhiteSpace(' ')
+ PsiElement(MEMBER_NAME)
+ PsiElement(ACCESS_SPEC)('public')
+ PsiElement(COLON)(':')
+ PsiElement(PRIMITIVE_TYPE)
+ PsiElement(PRIMITIVE_TYPE)('I')
+ PsiWhiteSpace('\n')
+ PsiErrorElement:Unexpected tokens
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace('\n')
+ PsiElement(END_FIELD_DIRECTIVE)('.end field') \ No newline at end of file
diff --git a/smalidea/testData/InvalidField4.smalidea b/smalidea/testData/InvalidField4.smalidea
new file mode 100644
index 00000000..11a8cb20
--- /dev/null
+++ b/smalidea/testData/InvalidField4.smalidea
@@ -0,0 +1 @@
+.field public blah:.blah \ No newline at end of file
diff --git a/smalidea/testData/InvalidField4.txt b/smalidea/testData/InvalidField4.txt
new file mode 100644
index 00000000..4eedd931
--- /dev/null
+++ b/smalidea/testData/InvalidField4.txt
@@ -0,0 +1,17 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliField(FIELD)
+ PsiElement(FIELD_DIRECTIVE)('.field')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ PsiElement(ACCESS_SPEC)('public')
+ PsiWhiteSpace(' ')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiElement(COLON)(':')
+ PsiErrorElement:no viable alternative at input '.blah'
+ PsiElement(BAD_CHARACTER)('.blah') \ No newline at end of file
diff --git a/smalidea/testData/InvalidInstruction.smalidea b/smalidea/testData/InvalidInstruction.smalidea
new file mode 100644
index 00000000..0960b886
--- /dev/null
+++ b/smalidea/testData/InvalidInstruction.smalidea
@@ -0,0 +1,31 @@
+.method blah()V
+.registers 1
+invoke-virtual .blah v0}, Lblah;->blah()V
+.end method
+
+.method blah2()V
+.registers 1
+invoke-virtual {v1, v2} .blah Lblah;->blah()V
+.end method
+
+.method blah3()V
+ .array-data 4
+ 1
+ 2
+ .blah
+.end method
+
+.method blah4()V
+ .packed-switch 1
+ :blah
+ :blah2
+ .blah
+.end method
+
+.method blah5()V
+ .sparse-switch
+ 1 -> :blah
+ 3 -> :blah2
+ 5 -> :blah3
+ .blah
+.end method \ No newline at end of file
diff --git a/smalidea/testData/InvalidInstruction.txt b/smalidea/testData/InvalidInstruction.txt
new file mode 100644
index 00000000..76502573
--- /dev/null
+++ b/smalidea/testData/InvalidInstruction.txt
@@ -0,0 +1,236 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(REGISTERS_STATEMENT)
+ PsiElement(REGISTERS_DIRECTIVE)('.registers')
+ PsiWhiteSpace(' ')
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('1')
+ PsiWhiteSpace('\n')
+ PsiElement(INSTRUCTION)
+ PsiElement(INSTRUCTION_FORMAT35c_METHOD)('invoke-virtual')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:mismatched input '.blah' expecting OPEN_BRACE
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace(' ')
+ PsiElement(REGISTER_REFERENCE)
+ PsiElement(REGISTER)('v0')
+ PsiElement(CLOSE_BRACE)('}')
+ PsiElement(COMMA)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(METHOD_REFERENCE)
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiElement(ARROW)('->')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiElement(OPEN_PAREN)('(')
+ PsiElement(METHOD_REFERENCE_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah2')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(REGISTERS_STATEMENT)
+ PsiElement(REGISTERS_DIRECTIVE)('.registers')
+ PsiWhiteSpace(' ')
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('1')
+ PsiWhiteSpace('\n')
+ PsiElement(INSTRUCTION)
+ PsiElement(INSTRUCTION_FORMAT35c_METHOD)('invoke-virtual')
+ PsiWhiteSpace(' ')
+ PsiElement(OPEN_BRACE)('{')
+ PsiElement(REGISTER_REFERENCE)
+ PsiElement(REGISTER)('v1')
+ PsiElement(COMMA)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(REGISTER_REFERENCE)
+ PsiElement(REGISTER)('v2')
+ PsiElement(CLOSE_BRACE)('}')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:mismatched input '.blah' expecting COMMA
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace(' ')
+ PsiElement(METHOD_REFERENCE)
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiElement(ARROW)('->')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiElement(OPEN_PAREN)('(')
+ PsiElement(METHOD_REFERENCE_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah3')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n ')
+ PsiElement(INSTRUCTION)
+ PsiElement(ARRAY_DATA_DIRECTIVE)('.array-data')
+ PsiWhiteSpace(' ')
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('4')
+ PsiWhiteSpace('\n ')
+ PsiElement(ARRAY_DATA_ELEMENT)
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('1')
+ PsiWhiteSpace('\n ')
+ PsiElement(ARRAY_DATA_ELEMENT)
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('2')
+ PsiWhiteSpace('\n ')
+ PsiErrorElement:mismatched input '.blah' expecting END_ARRAY_DATA_DIRECTIVE
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah4')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n ')
+ PsiElement(INSTRUCTION)
+ PsiElement(PACKED_SWITCH_DIRECTIVE)('.packed-switch')
+ PsiWhiteSpace(' ')
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('1')
+ PsiWhiteSpace('\n ')
+ PsiElement(PACKED_SWITCH_ELEMENT)
+ PsiElement(LABEL_REFERENCE)
+ PsiElement(COLON)(':')
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiWhiteSpace('\n ')
+ PsiElement(PACKED_SWITCH_ELEMENT)
+ PsiElement(LABEL_REFERENCE)
+ PsiElement(COLON)(':')
+ PsiElement(SIMPLE_NAME)('blah2')
+ PsiWhiteSpace('\n ')
+ PsiErrorElement:mismatched input '.blah' expecting END_PACKED_SWITCH_DIRECTIVE
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah5')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n ')
+ PsiElement(INSTRUCTION)
+ PsiElement(SPARSE_SWITCH_DIRECTIVE)('.sparse-switch')
+ PsiWhiteSpace('\n ')
+ PsiElement(SPARSE_SWITCH_ELEMENT)
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('1')
+ PsiWhiteSpace(' ')
+ PsiElement(ARROW)('->')
+ PsiWhiteSpace(' ')
+ PsiElement(LABEL_REFERENCE)
+ PsiElement(COLON)(':')
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiWhiteSpace('\n ')
+ PsiElement(SPARSE_SWITCH_ELEMENT)
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('3')
+ PsiWhiteSpace(' ')
+ PsiElement(ARROW)('->')
+ PsiWhiteSpace(' ')
+ PsiElement(LABEL_REFERENCE)
+ PsiElement(COLON)(':')
+ PsiElement(SIMPLE_NAME)('blah2')
+ PsiWhiteSpace('\n ')
+ PsiElement(SPARSE_SWITCH_ELEMENT)
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('5')
+ PsiWhiteSpace(' ')
+ PsiElement(ARROW)('->')
+ PsiWhiteSpace(' ')
+ PsiElement(LABEL_REFERENCE)
+ PsiElement(COLON)(':')
+ PsiElement(SIMPLE_NAME)('blah3')
+ PsiWhiteSpace('\n ')
+ PsiErrorElement:mismatched input '.blah' expecting END_SPARSE_SWITCH_DIRECTIVE
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method') \ No newline at end of file
diff --git a/smalidea/testData/InvalidLocal.smalidea b/smalidea/testData/InvalidLocal.smalidea
new file mode 100644
index 00000000..48bcd081
--- /dev/null
+++ b/smalidea/testData/InvalidLocal.smalidea
@@ -0,0 +1,7 @@
+.method public blah()V
+ .local v0,
+.end method
+
+.method public blah()V
+ .local v0,"":
+.end method \ No newline at end of file
diff --git a/smalidea/testData/InvalidLocal.txt b/smalidea/testData/InvalidLocal.txt
new file mode 100644
index 00000000..b639c46f
--- /dev/null
+++ b/smalidea/testData/InvalidLocal.txt
@@ -0,0 +1,66 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ PsiElement(ACCESS_SPEC)('public')
+ PsiWhiteSpace(' ')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n ')
+ PsiElement(LOCAL_DEBUG_STATEMENT)
+ PsiElement(LOCAL_DIRECTIVE)('.local')
+ PsiWhiteSpace(' ')
+ PsiElement(REGISTER_REFERENCE)
+ PsiElement(REGISTER)('v0')
+ PsiElement(COMMA)(',')
+ PsiErrorElement:no viable alternative at input '.end method'
+ <empty list>
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ PsiElement(ACCESS_SPEC)('public')
+ PsiWhiteSpace(' ')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n ')
+ PsiElement(LOCAL_DEBUG_STATEMENT)
+ PsiElement(LOCAL_DIRECTIVE)('.local')
+ PsiWhiteSpace(' ')
+ PsiElement(REGISTER_REFERENCE)
+ PsiElement(REGISTER)('v0')
+ PsiElement(COMMA)(',')
+ PsiElement(LITERAL)
+ PsiElement(STRING_LITERAL)('""')
+ PsiElement(COLON)(':')
+ PsiErrorElement:no viable alternative at input '.end method'
+ <empty list>
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method') \ No newline at end of file
diff --git a/smalidea/testData/InvalidMethod.smalidea b/smalidea/testData/InvalidMethod.smalidea
new file mode 100644
index 00000000..57245e9f
--- /dev/null
+++ b/smalidea/testData/InvalidMethod.smalidea
@@ -0,0 +1,4 @@
+.class Ltest;
+.super Ljava/lang/Object;
+
+.method .blah \ No newline at end of file
diff --git a/smalidea/testData/InvalidMethod.txt b/smalidea/testData/InvalidMethod.txt
new file mode 100644
index 00000000..421e084f
--- /dev/null
+++ b/smalidea/testData/InvalidMethod.txt
@@ -0,0 +1,33 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliClassStatement(CLASS_STATEMENT)
+ PsiElement(CLASS_DIRECTIVE)('.class')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Ltest;')
+ PsiWhiteSpace('\n')
+ PsiElement(SUPER_STATEMENT)
+ PsiElement(SUPER_DIRECTIVE)('.super')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Ljava/lang/Object;')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiErrorElement:no viable alternative at input '.blah'
+ PsiElement(BAD_CHARACTER)('.blah')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list> \ No newline at end of file
diff --git a/smalidea/testData/InvalidMethod2.smalidea b/smalidea/testData/InvalidMethod2.smalidea
new file mode 100644
index 00000000..d5301430
--- /dev/null
+++ b/smalidea/testData/InvalidMethod2.smalidea
@@ -0,0 +1,6 @@
+.class Ltest;
+.super Ljava/lang/Object;
+
+.method blah
+
+.method \ No newline at end of file
diff --git a/smalidea/testData/InvalidMethod2.txt b/smalidea/testData/InvalidMethod2.txt
new file mode 100644
index 00000000..1a3a1cdb
--- /dev/null
+++ b/smalidea/testData/InvalidMethod2.txt
@@ -0,0 +1,49 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliClassStatement(CLASS_STATEMENT)
+ PsiElement(CLASS_DIRECTIVE)('.class')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Ltest;')
+ PsiWhiteSpace('\n')
+ PsiElement(SUPER_STATEMENT)
+ PsiElement(SUPER_DIRECTIVE)('.super')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Ljava/lang/Object;')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiWhiteSpace('\n\n')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiErrorElement:mismatched input '.method' expecting OPEN_PAREN
+ <empty list>
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiErrorElement:missing END_METHOD_DIRECTIVE at '.method'
+ <empty list>
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiErrorElement:no viable alternative at input '<EOF>'
+ <empty list>
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list> \ No newline at end of file
diff --git a/smalidea/testData/InvalidMethod3.smalidea b/smalidea/testData/InvalidMethod3.smalidea
new file mode 100644
index 00000000..24e66b6f
--- /dev/null
+++ b/smalidea/testData/InvalidMethod3.smalidea
@@ -0,0 +1,11 @@
+.method blah()V
+.end
+
+
+
+.method return-object()V
+.registers 0
+
+
+
+.method \ No newline at end of file
diff --git a/smalidea/testData/InvalidMethod3.txt b/smalidea/testData/InvalidMethod3.txt
new file mode 100644
index 00000000..ce143718
--- /dev/null
+++ b/smalidea/testData/InvalidMethod3.txt
@@ -0,0 +1,63 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiErrorElement:mismatched input '.end' expecting END_METHOD_DIRECTIVE
+ PsiElement(BAD_CHARACTER)('.end')
+ PsiWhiteSpace('\n\n\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(INSTRUCTION_FORMAT11x)('return-object')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(REGISTERS_STATEMENT)
+ PsiElement(REGISTERS_DIRECTIVE)('.registers')
+ PsiWhiteSpace(' ')
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('0')
+ PsiErrorElement:missing END_METHOD_DIRECTIVE at '.method'
+ <empty list>
+ PsiWhiteSpace('\n\n\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiErrorElement:no viable alternative at input '<EOF>'
+ <empty list>
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list> \ No newline at end of file
diff --git a/smalidea/testData/InvalidMethod4.smalidea b/smalidea/testData/InvalidMethod4.smalidea
new file mode 100644
index 00000000..ff86bf37
--- /dev/null
+++ b/smalidea/testData/InvalidMethod4.smalidea
@@ -0,0 +1,8 @@
+.method blah .blah )V
+.end method
+
+.method blah(I .blah V
+.end method
+
+.method blah())V
+.end method \ No newline at end of file
diff --git a/smalidea/testData/InvalidMethod4.txt b/smalidea/testData/InvalidMethod4.txt
new file mode 100644
index 00000000..aae80654
--- /dev/null
+++ b/smalidea/testData/InvalidMethod4.txt
@@ -0,0 +1,73 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiWhiteSpace(' ')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiErrorElement:mismatched input '.blah' expecting OPEN_PAREN
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace(' ')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ SmaliMethodParameter(METHOD_PARAMETER)
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(PRIMITIVE_TYPE)
+ PsiElement(PRIMITIVE_TYPE)('I')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:mismatched input '.blah' expecting CLOSE_PAREN
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace(' ')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiErrorElement:no viable alternative at input ')'
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method') \ No newline at end of file
diff --git a/smalidea/testData/InvalidMethodReference.smalidea b/smalidea/testData/InvalidMethodReference.smalidea
new file mode 100644
index 00000000..8ee6d79a
--- /dev/null
+++ b/smalidea/testData/InvalidMethodReference.smalidea
@@ -0,0 +1,24 @@
+.method blah()V
+.registers 1
+invoke-virtual {v0}, .blah->
+.end method
+
+.method blah2()V
+.registers 1
+invoke-virtual {v0}, Lblah;.blah
+.end method
+
+.method blah3()V
+.registers 1
+invoke-virtual {v0}, Lblah;->blah .blah )V
+.end method
+
+.method blah4()V
+.registers 1
+invoke-virtual {v0}, Lblah;->blah(I .blah V
+.end method
+
+.method blah5()V
+.registers 1
+invoke-virtual {v0}, Lblah;->blah())V
+.end method
diff --git a/smalidea/testData/InvalidMethodReference.txt b/smalidea/testData/InvalidMethodReference.txt
new file mode 100644
index 00000000..490d38cf
--- /dev/null
+++ b/smalidea/testData/InvalidMethodReference.txt
@@ -0,0 +1,241 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(REGISTERS_STATEMENT)
+ PsiElement(REGISTERS_DIRECTIVE)('.registers')
+ PsiWhiteSpace(' ')
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('1')
+ PsiWhiteSpace('\n')
+ PsiElement(INSTRUCTION)
+ PsiElement(INSTRUCTION_FORMAT35c_METHOD)('invoke-virtual')
+ PsiWhiteSpace(' ')
+ PsiElement(OPEN_BRACE)('{')
+ PsiElement(REGISTER_REFERENCE)
+ PsiElement(REGISTER)('v0')
+ PsiElement(CLOSE_BRACE)('}')
+ PsiElement(COMMA)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(METHOD_REFERENCE)
+ PsiErrorElement:no viable alternative at input '.blah-'
+ PsiElement(BAD_CHARACTER)('.blah-')
+ PsiElement(BAD_CHARACTER)('>')
+ PsiWhiteSpace('\n')
+ PsiElement(MEMBER_NAME)
+ <empty list>
+ PsiElement(METHOD_REFERENCE_PARAM_LIST)
+ <empty list>
+ PsiElement(END_METHOD_DIRECTIVE)('.end method')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah2')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(REGISTERS_STATEMENT)
+ PsiElement(REGISTERS_DIRECTIVE)('.registers')
+ PsiWhiteSpace(' ')
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('1')
+ PsiWhiteSpace('\n')
+ PsiElement(INSTRUCTION)
+ PsiElement(INSTRUCTION_FORMAT35c_METHOD)('invoke-virtual')
+ PsiWhiteSpace(' ')
+ PsiElement(OPEN_BRACE)('{')
+ PsiElement(REGISTER_REFERENCE)
+ PsiElement(REGISTER)('v0')
+ PsiElement(CLOSE_BRACE)('}')
+ PsiElement(COMMA)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(METHOD_REFERENCE)
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiErrorElement:mismatched input '.blah' expecting ARROW
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace('\n')
+ PsiElement(MEMBER_NAME)
+ <empty list>
+ PsiElement(METHOD_REFERENCE_PARAM_LIST)
+ <empty list>
+ PsiElement(END_METHOD_DIRECTIVE)('.end method')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah3')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(REGISTERS_STATEMENT)
+ PsiElement(REGISTERS_DIRECTIVE)('.registers')
+ PsiWhiteSpace(' ')
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('1')
+ PsiWhiteSpace('\n')
+ PsiElement(INSTRUCTION)
+ PsiElement(INSTRUCTION_FORMAT35c_METHOD)('invoke-virtual')
+ PsiWhiteSpace(' ')
+ PsiElement(OPEN_BRACE)('{')
+ PsiElement(REGISTER_REFERENCE)
+ PsiElement(REGISTER)('v0')
+ PsiElement(CLOSE_BRACE)('}')
+ PsiElement(COMMA)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(METHOD_REFERENCE)
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiElement(ARROW)('->')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:mismatched input '.blah' expecting OPEN_PAREN
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace(' ')
+ PsiElement(METHOD_REFERENCE_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah4')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(REGISTERS_STATEMENT)
+ PsiElement(REGISTERS_DIRECTIVE)('.registers')
+ PsiWhiteSpace(' ')
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('1')
+ PsiWhiteSpace('\n')
+ PsiElement(INSTRUCTION)
+ PsiElement(INSTRUCTION_FORMAT35c_METHOD)('invoke-virtual')
+ PsiWhiteSpace(' ')
+ PsiElement(OPEN_BRACE)('{')
+ PsiElement(REGISTER_REFERENCE)
+ PsiElement(REGISTER)('v0')
+ PsiElement(CLOSE_BRACE)('}')
+ PsiElement(COMMA)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(METHOD_REFERENCE)
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiElement(ARROW)('->')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiElement(OPEN_PAREN)('(')
+ PsiElement(METHOD_REFERENCE_PARAM_LIST)
+ PsiElement(PRIMITIVE_TYPE)
+ PsiElement(PRIMITIVE_TYPE)('I')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:mismatched input '.blah' expecting CLOSE_PAREN
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace(' ')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah5')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(REGISTERS_STATEMENT)
+ PsiElement(REGISTERS_DIRECTIVE)('.registers')
+ PsiWhiteSpace(' ')
+ PsiElement(LITERAL)
+ PsiElement(POSITIVE_INTEGER_LITERAL)('1')
+ PsiWhiteSpace('\n')
+ PsiElement(INSTRUCTION)
+ PsiElement(INSTRUCTION_FORMAT35c_METHOD)('invoke-virtual')
+ PsiWhiteSpace(' ')
+ PsiElement(OPEN_BRACE)('{')
+ PsiElement(REGISTER_REFERENCE)
+ PsiElement(REGISTER)('v0')
+ PsiElement(CLOSE_BRACE)('}')
+ PsiElement(COMMA)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(METHOD_REFERENCE)
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiElement(ARROW)('->')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiElement(OPEN_PAREN)('(')
+ PsiElement(METHOD_REFERENCE_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiErrorElement:no viable alternative at input ')'
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method') \ No newline at end of file
diff --git a/smalidea/testData/InvalidParameter.smalidea b/smalidea/testData/InvalidParameter.smalidea
new file mode 100644
index 00000000..014299fd
--- /dev/null
+++ b/smalidea/testData/InvalidParameter.smalidea
@@ -0,0 +1,10 @@
+.method public blah()V
+ .param v0, "blah"
+ .a
+.end method
+
+.method public blah()V
+ .param v0, "blah"
+ .annotation runtime Lblah; .end annotation
+ .
+.end method \ No newline at end of file
diff --git a/smalidea/testData/InvalidParameter.txt b/smalidea/testData/InvalidParameter.txt
new file mode 100644
index 00000000..27168efe
--- /dev/null
+++ b/smalidea/testData/InvalidParameter.txt
@@ -0,0 +1,85 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ PsiElement(ACCESS_SPEC)('public')
+ PsiWhiteSpace(' ')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n ')
+ PsiElement(PARAMETER_STATEMENT)
+ PsiElement(PARAMETER_DIRECTIVE)('.param')
+ PsiWhiteSpace(' ')
+ PsiElement(REGISTER_REFERENCE)
+ PsiElement(REGISTER)('v0')
+ PsiElement(COMMA)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(LOCAL_NAME)
+ PsiElement(LITERAL)
+ PsiElement(STRING_LITERAL)('"blah"')
+ PsiWhiteSpace('\n ')
+ PsiErrorElement:no viable alternative at input '.a'
+ PsiElement(BAD_CHARACTER)('.a')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ PsiElement(ACCESS_SPEC)('public')
+ PsiWhiteSpace(' ')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n ')
+ PsiElement(PARAMETER_STATEMENT)
+ PsiElement(PARAMETER_DIRECTIVE)('.param')
+ PsiWhiteSpace(' ')
+ PsiElement(REGISTER_REFERENCE)
+ PsiElement(REGISTER)('v0')
+ PsiElement(COMMA)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(LOCAL_NAME)
+ PsiElement(LITERAL)
+ PsiElement(STRING_LITERAL)('"blah"')
+ PsiWhiteSpace('\n ')
+ SmaliAnnotation(ANNOTATION)
+ PsiElement(ANNOTATION_DIRECTIVE)('.annotation')
+ PsiWhiteSpace(' ')
+ PsiElement(ANNOTATION_VISIBILITY)('runtime')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiWhiteSpace(' ')
+ PsiElement(ANNOTATION_PARAMETER_LIST)
+ <empty list>
+ PsiElement(END_ANNOTATION_DIRECTIVE)('.end annotation')
+ PsiWhiteSpace('\n ')
+ PsiErrorElement:no viable alternative at input '.'
+ PsiElement(BAD_CHARACTER)('.')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method') \ No newline at end of file
diff --git a/smalidea/testData/MissingDotDot.smalidea b/smalidea/testData/MissingDotDot.smalidea
new file mode 100644
index 00000000..5e8e6b6e
--- /dev/null
+++ b/smalidea/testData/MissingDotDot.smalidea
@@ -0,0 +1,9 @@
+.method public blah()V
+ invoke-virtual/range {v0 v1}, Lblah;->blah()V
+
+ invoke-virtual/range {v0 .blah v1}, Lblah;->blah()V
+
+ .catch Ljava/lang/Exception; { :blah1 :blah2 } :blah3
+
+ .catch Ljava/lang/Exception; { :blah1 .blah :blah2 } :blah3
+.end method \ No newline at end of file
diff --git a/smalidea/testData/MissingDotDot.txt b/smalidea/testData/MissingDotDot.txt
new file mode 100644
index 00000000..53a1eccf
--- /dev/null
+++ b/smalidea/testData/MissingDotDot.txt
@@ -0,0 +1,126 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ PsiElement(ACCESS_SPEC)('public')
+ PsiWhiteSpace(' ')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n ')
+ PsiElement(INSTRUCTION)
+ PsiElement(INSTRUCTION_FORMAT3rc_METHOD)('invoke-virtual/range')
+ PsiWhiteSpace(' ')
+ PsiElement(OPEN_BRACE)('{')
+ PsiElement(REGISTER_REFERENCE)
+ PsiElement(REGISTER)('v0')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:extraneous input 'v1' expecting CLOSE_BRACE
+ PsiElement(REGISTER)('v1')
+ PsiElement(CLOSE_BRACE)('}')
+ PsiElement(COMMA)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(METHOD_REFERENCE)
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiElement(ARROW)('->')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiElement(OPEN_PAREN)('(')
+ PsiElement(METHOD_REFERENCE_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n\n ')
+ PsiElement(INSTRUCTION)
+ PsiElement(INSTRUCTION_FORMAT3rc_METHOD)('invoke-virtual/range')
+ PsiWhiteSpace(' ')
+ PsiElement(OPEN_BRACE)('{')
+ PsiElement(REGISTER_REFERENCE)
+ PsiElement(REGISTER)('v0')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:mismatched input '.blah' expecting CLOSE_BRACE
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace(' ')
+ PsiElement(REGISTER)('v1')
+ PsiElement(CLOSE_BRACE)('}')
+ PsiElement(COMMA)(',')
+ PsiWhiteSpace(' ')
+ PsiElement(METHOD_REFERENCE)
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiElement(ARROW)('->')
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ PsiElement(OPEN_PAREN)('(')
+ PsiElement(METHOD_REFERENCE_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n\n ')
+ PsiElement(CATCH_STATEMENT)
+ PsiElement(CATCH_DIRECTIVE)('.catch')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Ljava/lang/Exception;')
+ PsiWhiteSpace(' ')
+ PsiElement(OPEN_BRACE)('{')
+ PsiWhiteSpace(' ')
+ PsiElement(LABEL_REFERENCE)
+ PsiElement(COLON)(':')
+ PsiElement(SIMPLE_NAME)('blah1')
+ PsiErrorElement:missing DOTDOT at ':'
+ <empty list>
+ PsiWhiteSpace(' ')
+ PsiElement(LABEL_REFERENCE)
+ PsiElement(COLON)(':')
+ PsiElement(SIMPLE_NAME)('blah2')
+ PsiWhiteSpace(' ')
+ PsiElement(CLOSE_BRACE)('}')
+ PsiWhiteSpace(' ')
+ PsiElement(LABEL_REFERENCE)
+ PsiElement(COLON)(':')
+ PsiElement(SIMPLE_NAME)('blah3')
+ PsiWhiteSpace('\n\n ')
+ PsiElement(CATCH_STATEMENT)
+ PsiElement(CATCH_DIRECTIVE)('.catch')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Ljava/lang/Exception;')
+ PsiWhiteSpace(' ')
+ PsiElement(OPEN_BRACE)('{')
+ PsiWhiteSpace(' ')
+ PsiElement(LABEL_REFERENCE)
+ PsiElement(COLON)(':')
+ PsiElement(SIMPLE_NAME)('blah1')
+ PsiWhiteSpace(' ')
+ PsiErrorElement:mismatched input '.blah' expecting DOTDOT
+ PsiElement(BAD_CHARACTER)('.blah')
+ PsiWhiteSpace(' ')
+ PsiElement(LABEL_REFERENCE)
+ PsiElement(COLON)(':')
+ PsiElement(SIMPLE_NAME)('blah2')
+ PsiWhiteSpace(' ')
+ PsiElement(CLOSE_BRACE)('}')
+ PsiWhiteSpace(' ')
+ PsiElement(LABEL_REFERENCE)
+ PsiElement(COLON)(':')
+ PsiElement(SIMPLE_NAME)('blah3')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method') \ No newline at end of file
diff --git a/smalidea/testData/ParamListInvalidParameter.smalidea b/smalidea/testData/ParamListInvalidParameter.smalidea
new file mode 100644
index 00000000..f9a8728c
--- /dev/null
+++ b/smalidea/testData/ParamListInvalidParameter.smalidea
@@ -0,0 +1,5 @@
+.class Lblah;
+.super Ljava/lang/Object;
+
+.method blah(f)
+.end method \ No newline at end of file
diff --git a/smalidea/testData/ParamListInvalidParameter.txt b/smalidea/testData/ParamListInvalidParameter.txt
new file mode 100644
index 00000000..ea94d463
--- /dev/null
+++ b/smalidea/testData/ParamListInvalidParameter.txt
@@ -0,0 +1,38 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliClassStatement(CLASS_STATEMENT)
+ PsiElement(CLASS_DIRECTIVE)('.class')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiWhiteSpace('\n')
+ PsiElement(SUPER_STATEMENT)
+ PsiElement(SUPER_DIRECTIVE)('.super')
+ PsiWhiteSpace(' ')
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Ljava/lang/Object;')
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiErrorElement:extraneous input 'f' expecting CLOSE_PAREN
+ PsiElement(SIMPLE_NAME)('f')
+ PsiElement(CLOSE_PAREN)(')')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method') \ No newline at end of file
diff --git a/smalidea/testData/SuperClassInvalidSyntax.smalidea b/smalidea/testData/SuperClassInvalidSyntax.smalidea
new file mode 100644
index 00000000..cea9d102
--- /dev/null
+++ b/smalidea/testData/SuperClassInvalidSyntax.smalidea
@@ -0,0 +1,2 @@
+.class Lblah;
+.super \ No newline at end of file
diff --git a/smalidea/testData/SuperClassInvalidSyntax.txt b/smalidea/testData/SuperClassInvalidSyntax.txt
new file mode 100644
index 00000000..316041cd
--- /dev/null
+++ b/smalidea/testData/SuperClassInvalidSyntax.txt
@@ -0,0 +1,18 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliClassStatement(CLASS_STATEMENT)
+ PsiElement(CLASS_DIRECTIVE)('.class')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiWhiteSpace('\n')
+ PsiElement(SUPER_STATEMENT)
+ PsiElement(SUPER_DIRECTIVE)('.super')
+ PsiErrorElement:mismatched input '<EOF>' expecting CLASS_DESCRIPTOR
+ <empty list> \ No newline at end of file
diff --git a/smalidea/testData/SuperClassInvalidSyntax2.smalidea b/smalidea/testData/SuperClassInvalidSyntax2.smalidea
new file mode 100644
index 00000000..8793e8cb
--- /dev/null
+++ b/smalidea/testData/SuperClassInvalidSyntax2.smalidea
@@ -0,0 +1,5 @@
+.class Lblah;
+.super
+
+.method blah()V
+.end method \ No newline at end of file
diff --git a/smalidea/testData/SuperClassInvalidSyntax2.txt b/smalidea/testData/SuperClassInvalidSyntax2.txt
new file mode 100644
index 00000000..348fab47
--- /dev/null
+++ b/smalidea/testData/SuperClassInvalidSyntax2.txt
@@ -0,0 +1,37 @@
+smali.FILE
+ SmaliClass(CLASS)
+ SmaliExtendsList(EXTENDS_LIST)
+ <empty list>
+ SmaliImplementsList(IMPLEMENTS_LIST)
+ <empty list>
+ SmaliClassStatement(CLASS_STATEMENT)
+ PsiElement(CLASS_DIRECTIVE)('.class')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(CLASS_TYPE)
+ PsiElement(CLASS_DESCRIPTOR)('Lblah;')
+ PsiWhiteSpace('\n')
+ PsiElement(SUPER_STATEMENT)
+ PsiElement(SUPER_DIRECTIVE)('.super')
+ PsiErrorElement:missing CLASS_DESCRIPTOR at '.method'
+ <empty list>
+ PsiWhiteSpace('\n\n')
+ SmaliMethod(METHOD)
+ SmaliThrowsList(THROWS_LIST)
+ <empty list>
+ PsiElement(METHOD_DIRECTIVE)('.method')
+ PsiWhiteSpace(' ')
+ SmaliModifierList(MODIFIER_LIST)
+ <empty list>
+ PsiElement(MEMBER_NAME)
+ PsiElement(SIMPLE_NAME)('blah')
+ SmaliMethodPrototype(METHOD_PROTOTYPE)
+ PsiElement(OPEN_PAREN)('(')
+ SmaliMethodParamList(METHOD_PARAM_LIST)
+ <empty list>
+ PsiElement(CLOSE_PAREN)(')')
+ PsiElement(VOID_TYPE)
+ PsiElement(VOID_TYPE)('V')
+ PsiWhiteSpace('\n')
+ PsiElement(END_METHOD_DIRECTIVE)('.end method') \ No newline at end of file
diff --git a/smalidea/testData/classMove/basicFromNoPackage/after/my/blah.smali b/smalidea/testData/classMove/basicFromNoPackage/after/my/blah.smali
new file mode 100644
index 00000000..dc4522cc
--- /dev/null
+++ b/smalidea/testData/classMove/basicFromNoPackage/after/my/blah.smali
@@ -0,0 +1,36 @@
+.class public Lmy/blah;
+.super Lmy/blah;
+.implements Lmy/blah;
+
+.annotation build Lmy/blah;
+ value = .subannotation Lmy/blah;
+ value = Lmy/blah;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lmy/blah; = Lmy/blah;
+
+.method public blah(Lmy/blah;)Lmy/blah;
+ .registers 2
+ .local p0, "this":Lmy/blah;
+
+ :start
+ iget-object v0, v0, Lmy/blah;->blah:Lmy/blah;
+
+ invoke-virtual {v0}, Lmy/blah;->blah(Lmy/blah;)Lmy/blah;
+
+ instance-of v0, v0, Lmy/blah;
+ check-cast v0, Lmy/blah;
+ new-instance v0, Lmy/blah;
+ const-class v0, Lmy/blah;
+ throw-verification-error generic-error, Lmy/blah;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lmy/blah;
+ new-array v0, v0, Lmy/blah;
+ filled-new-array/range {v0}, Lmy/blah;
+ :end
+
+ .catch Lmy/blah; { :start .. :end } :handler
+ :handler
+ return-void
+.end method \ No newline at end of file
diff --git a/smalidea/testData/classMove/basicFromNoPackage/before/blah.smali b/smalidea/testData/classMove/basicFromNoPackage/before/blah.smali
new file mode 100644
index 00000000..0a72c715
--- /dev/null
+++ b/smalidea/testData/classMove/basicFromNoPackage/before/blah.smali
@@ -0,0 +1,36 @@
+.class public Lblah;
+.super Lblah;
+.implements Lblah;
+
+.annotation build Lblah;
+ value = .subannotation Lblah;
+ value = Lblah;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lblah; = Lblah;
+
+.method public blah(Lblah;)Lblah;
+ .registers 2
+ .local p0, "this":Lblah;
+
+ :start
+ iget-object v0, v0, Lblah;->blah:Lblah;
+
+ invoke-virtual {v0}, Lblah;->blah(Lblah;)Lblah;
+
+ instance-of v0, v0, Lblah;
+ check-cast v0, Lblah;
+ new-instance v0, Lblah;
+ const-class v0, Lblah;
+ throw-verification-error generic-error, Lblah;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lblah;
+ new-array v0, v0, Lblah;
+ filled-new-array/range {v0}, Lblah;
+ :end
+
+ .catch Lblah; { :start .. :end } :handler
+ :handler
+ return-void
+.end method \ No newline at end of file
diff --git a/smalidea/testData/classMove/basicToNoPackage/after/blah.smali b/smalidea/testData/classMove/basicToNoPackage/after/blah.smali
new file mode 100644
index 00000000..0a72c715
--- /dev/null
+++ b/smalidea/testData/classMove/basicToNoPackage/after/blah.smali
@@ -0,0 +1,36 @@
+.class public Lblah;
+.super Lblah;
+.implements Lblah;
+
+.annotation build Lblah;
+ value = .subannotation Lblah;
+ value = Lblah;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lblah; = Lblah;
+
+.method public blah(Lblah;)Lblah;
+ .registers 2
+ .local p0, "this":Lblah;
+
+ :start
+ iget-object v0, v0, Lblah;->blah:Lblah;
+
+ invoke-virtual {v0}, Lblah;->blah(Lblah;)Lblah;
+
+ instance-of v0, v0, Lblah;
+ check-cast v0, Lblah;
+ new-instance v0, Lblah;
+ const-class v0, Lblah;
+ throw-verification-error generic-error, Lblah;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lblah;
+ new-array v0, v0, Lblah;
+ filled-new-array/range {v0}, Lblah;
+ :end
+
+ .catch Lblah; { :start .. :end } :handler
+ :handler
+ return-void
+.end method \ No newline at end of file
diff --git a/smalidea/testData/classMove/basicToNoPackage/after/my/placeholder.smali b/smalidea/testData/classMove/basicToNoPackage/after/my/placeholder.smali
new file mode 100644
index 00000000..02813447
--- /dev/null
+++ b/smalidea/testData/classMove/basicToNoPackage/after/my/placeholder.smali
@@ -0,0 +1,2 @@
+.class public Lmy/placeholder;
+.super Ljava/lang/Object; \ No newline at end of file
diff --git a/smalidea/testData/classMove/basicToNoPackage/before/my/blah.smali b/smalidea/testData/classMove/basicToNoPackage/before/my/blah.smali
new file mode 100644
index 00000000..dc4522cc
--- /dev/null
+++ b/smalidea/testData/classMove/basicToNoPackage/before/my/blah.smali
@@ -0,0 +1,36 @@
+.class public Lmy/blah;
+.super Lmy/blah;
+.implements Lmy/blah;
+
+.annotation build Lmy/blah;
+ value = .subannotation Lmy/blah;
+ value = Lmy/blah;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lmy/blah; = Lmy/blah;
+
+.method public blah(Lmy/blah;)Lmy/blah;
+ .registers 2
+ .local p0, "this":Lmy/blah;
+
+ :start
+ iget-object v0, v0, Lmy/blah;->blah:Lmy/blah;
+
+ invoke-virtual {v0}, Lmy/blah;->blah(Lmy/blah;)Lmy/blah;
+
+ instance-of v0, v0, Lmy/blah;
+ check-cast v0, Lmy/blah;
+ new-instance v0, Lmy/blah;
+ const-class v0, Lmy/blah;
+ throw-verification-error generic-error, Lmy/blah;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lmy/blah;
+ new-array v0, v0, Lmy/blah;
+ filled-new-array/range {v0}, Lmy/blah;
+ :end
+
+ .catch Lmy/blah; { :start .. :end } :handler
+ :handler
+ return-void
+.end method \ No newline at end of file
diff --git a/smalidea/testData/classMove/basicToNoPackage/before/my/placeholder.smali b/smalidea/testData/classMove/basicToNoPackage/before/my/placeholder.smali
new file mode 100644
index 00000000..02813447
--- /dev/null
+++ b/smalidea/testData/classMove/basicToNoPackage/before/my/placeholder.smali
@@ -0,0 +1,2 @@
+.class public Lmy/placeholder;
+.super Ljava/lang/Object; \ No newline at end of file
diff --git a/smalidea/testData/classRename/basicNoPackage/after/blah2.smali b/smalidea/testData/classRename/basicNoPackage/after/blah2.smali
new file mode 100644
index 00000000..112b106e
--- /dev/null
+++ b/smalidea/testData/classRename/basicNoPackage/after/blah2.smali
@@ -0,0 +1,36 @@
+.class public Lblah2;
+.super Lblah2;
+.implements Lblah2;
+
+.annotation build Lblah2;
+ value = .subannotation Lblah2;
+ value = Lblah2;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lblah2; = Lblah2;
+
+.method public blah(Lblah2;)Lblah2;
+ .registers 2
+ .local p0, "this":Lblah2;
+
+ :start
+ iget-object v0, v0, Lblah2;->blah:Lblah2;
+
+ invoke-virtual {v0}, Lblah2;->blah(Lblah2;)Lblah2;
+
+ instance-of v0, v0, Lblah2;
+ check-cast v0, Lblah2;
+ new-instance v0, Lblah2;
+ const-class v0, Lblah2;
+ throw-verification-error generic-error, Lblah2;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lblah2;
+ new-array v0, v0, Lblah2;
+ filled-new-array/range {v0}, Lblah2;
+ :end
+
+ .catch Lblah2; { :start .. :end } :handler
+ :handler
+ return-void
+.end method \ No newline at end of file
diff --git a/smalidea/testData/classRename/basicNoPackage/before/blah.smali b/smalidea/testData/classRename/basicNoPackage/before/blah.smali
new file mode 100644
index 00000000..0a72c715
--- /dev/null
+++ b/smalidea/testData/classRename/basicNoPackage/before/blah.smali
@@ -0,0 +1,36 @@
+.class public Lblah;
+.super Lblah;
+.implements Lblah;
+
+.annotation build Lblah;
+ value = .subannotation Lblah;
+ value = Lblah;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lblah; = Lblah;
+
+.method public blah(Lblah;)Lblah;
+ .registers 2
+ .local p0, "this":Lblah;
+
+ :start
+ iget-object v0, v0, Lblah;->blah:Lblah;
+
+ invoke-virtual {v0}, Lblah;->blah(Lblah;)Lblah;
+
+ instance-of v0, v0, Lblah;
+ check-cast v0, Lblah;
+ new-instance v0, Lblah;
+ const-class v0, Lblah;
+ throw-verification-error generic-error, Lblah;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lblah;
+ new-array v0, v0, Lblah;
+ filled-new-array/range {v0}, Lblah;
+ :end
+
+ .catch Lblah; { :start .. :end } :handler
+ :handler
+ return-void
+.end method \ No newline at end of file
diff --git a/smalidea/testData/classRename/basicWithPackage/after/my/blah2.smali b/smalidea/testData/classRename/basicWithPackage/after/my/blah2.smali
new file mode 100644
index 00000000..f08d5137
--- /dev/null
+++ b/smalidea/testData/classRename/basicWithPackage/after/my/blah2.smali
@@ -0,0 +1,36 @@
+.class public Lmy/blah2;
+.super Lmy/blah2;
+.implements Lmy/blah2;
+
+.annotation build Lmy/blah2;
+ value = .subannotation Lmy/blah2;
+ value = Lmy/blah2;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lmy/blah2; = Lmy/blah2;
+
+.method public blah(Lmy/blah2;)Lmy/blah2;
+ .registers 2
+ .local p0, "this":Lmy/blah2;
+
+ :start
+ iget-object v0, v0, Lmy/blah2;->blah:Lmy/blah2;
+
+ invoke-virtual {v0}, Lmy/blah2;->blah(Lmy/blah2;)Lmy/blah2;
+
+ instance-of v0, v0, Lmy/blah2;
+ check-cast v0, Lmy/blah2;
+ new-instance v0, Lmy/blah2;
+ const-class v0, Lmy/blah2;
+ throw-verification-error generic-error, Lmy/blah2;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lmy/blah2;
+ new-array v0, v0, Lmy/blah2;
+ filled-new-array/range {v0}, Lmy/blah2;
+ :end
+
+ .catch Lmy/blah2; { :start .. :end } :handler
+ :handler
+ return-void
+.end method \ No newline at end of file
diff --git a/smalidea/testData/classRename/basicWithPackage/before/my/blah.smali b/smalidea/testData/classRename/basicWithPackage/before/my/blah.smali
new file mode 100644
index 00000000..dc4522cc
--- /dev/null
+++ b/smalidea/testData/classRename/basicWithPackage/before/my/blah.smali
@@ -0,0 +1,36 @@
+.class public Lmy/blah;
+.super Lmy/blah;
+.implements Lmy/blah;
+
+.annotation build Lmy/blah;
+ value = .subannotation Lmy/blah;
+ value = Lmy/blah;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lmy/blah; = Lmy/blah;
+
+.method public blah(Lmy/blah;)Lmy/blah;
+ .registers 2
+ .local p0, "this":Lmy/blah;
+
+ :start
+ iget-object v0, v0, Lmy/blah;->blah:Lmy/blah;
+
+ invoke-virtual {v0}, Lmy/blah;->blah(Lmy/blah;)Lmy/blah;
+
+ instance-of v0, v0, Lmy/blah;
+ check-cast v0, Lmy/blah;
+ new-instance v0, Lmy/blah;
+ const-class v0, Lmy/blah;
+ throw-verification-error generic-error, Lmy/blah;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lmy/blah;
+ new-array v0, v0, Lmy/blah;
+ filled-new-array/range {v0}, Lmy/blah;
+ :end
+
+ .catch Lmy/blah; { :start .. :end } :handler
+ :handler
+ return-void
+.end method \ No newline at end of file
diff --git a/smalidea/testData/fieldRename/fieldRename/after/blah.smali b/smalidea/testData/fieldRename/fieldRename/after/blah.smali
new file mode 100644
index 00000000..e2a23690
--- /dev/null
+++ b/smalidea/testData/fieldRename/fieldRename/after/blah.smali
@@ -0,0 +1,59 @@
+.class public Lblah;
+.super Ljava/lang/Object;
+
+.annotation runtime Lblah;
+ element = Lblah;->blort:Lblah;
+ element2 = .enum Lblah;->blort:Lblah;
+.end annotation
+
+.field public blort:Lblah;
+
+.method public blah(Lblah;)Lblah;
+ .registers 2
+
+ iget v0, v0, Lblah;->blort:Lblah;
+ iget-object v0, v0, Lblah;->blort:Lblah;
+ iget-byte v0, v0, Lblah;->blort:Lblah;
+ iget-char v0, v0, Lblah;->blort:Lblah;
+ iget-object v0, v0, Lblah;->blort:Lblah;
+ iget-object-volatile v0, v0, Lblah;->blort:Lblah;
+ iget-short v0, v0, Lblah;->blort:Lblah;
+ iget-volatile v0, v0, Lblah;->blort:Lblah;
+ iget-wide v0, v0, Lblah;->blort:Lblah;
+ iget-wide-volatile v0, v0, Lblah;->blort:Lblah;
+ sget v0, Lblah;->blort:Lblah;
+ sget-boolean v0, Lblah;->blort:Lblah;
+ sget-byte v0, Lblah;->blort:Lblah;
+ sget-char v0, Lblah;->blort:Lblah;
+ sget-object v0, Lblah;->blort:Lblah;
+ sget-object-volatile v0, Lblah;->blort:Lblah;
+ sget-short v0, Lblah;->blort:Lblah;
+ sget-volatile v0, Lblah;->blort:Lblah;
+ sget-wide v0, Lblah;->blort:Lblah;
+ sget-wide-volatile v0, Lblah;->blort:Lblah;
+
+ iput v0, v0, Lblah;->blort:Lblah;
+ iput-object v0, v0, Lblah;->blort:Lblah;
+ iput-byte v0, v0, Lblah;->blort:Lblah;
+ iput-char v0, v0, Lblah;->blort:Lblah;
+ iput-object v0, v0, Lblah;->blort:Lblah;
+ iput-object-volatile v0, v0, Lblah;->blort:Lblah;
+ iput-short v0, v0, Lblah;->blort:Lblah;
+ iput-volatile v0, v0, Lblah;->blort:Lblah;
+ iput-wide v0, v0, Lblah;->blort:Lblah;
+ iput-wide-volatile v0, v0, Lblah;->blort:Lblah;
+ sput v0, Lblah;->blort:Lblah;
+ sput-boolean v0, Lblah;->blort:Lblah;
+ sput-byte v0, Lblah;->blort:Lblah;
+ sput-char v0, Lblah;->blort:Lblah;
+ sput-object v0, Lblah;->blort:Lblah;
+ sput-object-volatile v0, Lblah;->blort:Lblah;
+ sput-short v0, Lblah;->blort:Lblah;
+ sput-volatile v0, Lblah;->blort:Lblah;
+ sput-wide v0, Lblah;->blort:Lblah;
+ sput-wide-volatile v0, Lblah;->blort:Lblah;
+
+ throw-verification-error generic-error, Lblah;->blort:Lblah;
+
+ return-void
+.end method
diff --git a/smalidea/testData/fieldRename/fieldRename/before/blah.smali b/smalidea/testData/fieldRename/fieldRename/before/blah.smali
new file mode 100644
index 00000000..ab4dc6c2
--- /dev/null
+++ b/smalidea/testData/fieldRename/fieldRename/before/blah.smali
@@ -0,0 +1,59 @@
+.class public Lblah;
+.super Ljava/lang/Object;
+
+.annotation runtime Lblah;
+ element = Lblah;->blah:Lblah;
+ element2 = .enum Lblah;->blah:Lblah;
+.end annotation
+
+.field public blah:Lblah;
+
+.method public blah(Lblah;)Lblah;
+ .registers 2
+
+ iget v0, v0, Lblah;->blah:Lblah;
+ iget-object v0, v0, Lblah;->blah:Lblah;
+ iget-byte v0, v0, Lblah;->blah:Lblah;
+ iget-char v0, v0, Lblah;->blah:Lblah;
+ iget-object v0, v0, Lblah;->blah:Lblah;
+ iget-object-volatile v0, v0, Lblah;->blah:Lblah;
+ iget-short v0, v0, Lblah;->blah:Lblah;
+ iget-volatile v0, v0, Lblah;->blah:Lblah;
+ iget-wide v0, v0, Lblah;->blah:Lblah;
+ iget-wide-volatile v0, v0, Lblah;->blah:Lblah;
+ sget v0, Lblah;->blah:Lblah;
+ sget-boolean v0, Lblah;->blah:Lblah;
+ sget-byte v0, Lblah;->blah:Lblah;
+ sget-char v0, Lblah;->blah:Lblah;
+ sget-object v0, Lblah;->blah:Lblah;
+ sget-object-volatile v0, Lblah;->blah:Lblah;
+ sget-short v0, Lblah;->blah:Lblah;
+ sget-volatile v0, Lblah;->blah:Lblah;
+ sget-wide v0, Lblah;->blah:Lblah;
+ sget-wide-volatile v0, Lblah;->blah:Lblah;
+
+ iput v0, v0, Lblah;->blah:Lblah;
+ iput-object v0, v0, Lblah;->blah:Lblah;
+ iput-byte v0, v0, Lblah;->blah:Lblah;
+ iput-char v0, v0, Lblah;->blah:Lblah;
+ iput-object v0, v0, Lblah;->blah:Lblah;
+ iput-object-volatile v0, v0, Lblah;->blah:Lblah;
+ iput-short v0, v0, Lblah;->blah:Lblah;
+ iput-volatile v0, v0, Lblah;->blah:Lblah;
+ iput-wide v0, v0, Lblah;->blah:Lblah;
+ iput-wide-volatile v0, v0, Lblah;->blah:Lblah;
+ sput v0, Lblah;->blah:Lblah;
+ sput-boolean v0, Lblah;->blah:Lblah;
+ sput-byte v0, Lblah;->blah:Lblah;
+ sput-char v0, Lblah;->blah:Lblah;
+ sput-object v0, Lblah;->blah:Lblah;
+ sput-object-volatile v0, Lblah;->blah:Lblah;
+ sput-short v0, Lblah;->blah:Lblah;
+ sput-volatile v0, Lblah;->blah:Lblah;
+ sput-wide v0, Lblah;->blah:Lblah;
+ sput-wide-volatile v0, Lblah;->blah:Lblah;
+
+ throw-verification-error generic-error, Lblah;->blah:Lblah;
+
+ return-void
+.end method
diff --git a/smalidea/testData/methodRename/methodRename/after/blah.smali b/smalidea/testData/methodRename/methodRename/after/blah.smali
new file mode 100644
index 00000000..2343699e
--- /dev/null
+++ b/smalidea/testData/methodRename/methodRename/after/blah.smali
@@ -0,0 +1,27 @@
+.class public Lblah;
+.super Ljava/lang/Object;
+
+.annotation runtime Lblah;
+ element = Lblah;->blort()V;
+.end annotation
+
+.method public blort()V
+ .registers 2
+
+ invoke-direct {v0}, Lblah;->blort()V
+ invoke-direct/empty {v0}, Lblah;->blort()V
+ invoke-direct/range {v0}, Lblah;->blort()V
+ invoke-interface {v0}, Lblah;->blort()V
+ invoke-interface/range {v0}, Lblah;->blort()V
+ invoke-object-init/range {v0}, Lblah;->blort()V
+ invoke-static {v0}, Lblah;->blort()V
+ invoke-static/range {v0}, Lblah;->blort()V
+ invoke-super {v0}, Lblah;->blort()V
+ invoke-super/range {v0}, Lblah;->blort()V
+ invoke-virtual {v0}, Lblah;->blort()V
+ invoke-virtual/range {v0}, Lblah;->blort()V
+
+ throw-verification-error generic-error, Lblah;->blort()V
+
+ return-void
+.end method
diff --git a/smalidea/testData/methodRename/methodRename/before/blah.smali b/smalidea/testData/methodRename/methodRename/before/blah.smali
new file mode 100644
index 00000000..9a800dc5
--- /dev/null
+++ b/smalidea/testData/methodRename/methodRename/before/blah.smali
@@ -0,0 +1,27 @@
+.class public Lblah;
+.super Ljava/lang/Object;
+
+.annotation runtime Lblah;
+ element = Lblah;->blah()V;
+.end annotation
+
+.method public blah()V
+ .registers 2
+
+ invoke-direct {v0}, Lblah;->blah()V
+ invoke-direct/empty {v0}, Lblah;->blah()V
+ invoke-direct/range {v0}, Lblah;->blah()V
+ invoke-interface {v0}, Lblah;->blah()V
+ invoke-interface/range {v0}, Lblah;->blah()V
+ invoke-object-init/range {v0}, Lblah;->blah()V
+ invoke-static {v0}, Lblah;->blah()V
+ invoke-static/range {v0}, Lblah;->blah()V
+ invoke-super {v0}, Lblah;->blah()V
+ invoke-super/range {v0}, Lblah;->blah()V
+ invoke-virtual {v0}, Lblah;->blah()V
+ invoke-virtual/range {v0}, Lblah;->blah()V
+
+ throw-verification-error generic-error, Lblah;->blah()V
+
+ return-void
+.end method
diff --git a/util/src/main/java/org/jf/util/BlankReader.java b/util/src/main/java/org/jf/util/BlankReader.java
new file mode 100644
index 00000000..ca55dd0f
--- /dev/null
+++ b/util/src/main/java/org/jf/util/BlankReader.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014, 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.util;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+import java.io.Reader;
+
+public class BlankReader extends Reader {
+ public static final BlankReader INSTANCE = new BlankReader();
+
+ @Override public int read(@Nonnull char[] chars, int i, int i2) throws IOException {
+ return -1;
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+}