Merge remote-tracking branch 'aosp/upstream-master' into incr-dex
- Brings up smali to 2.1.2 with support for creating version 37 dex
files and other miscellaneous fixes.
Bug: 27809626
Change-Id: Iff12b1e384355bcb261b55afd16af3bcac6ef1a0
diff --git a/.gitignore b/.gitignore
index 45e097e..b7db779 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 4ce4514..e29e98b 100644
--- a/NOTICE
+++ b/NOTICE
@@ -82,4 +82,24 @@
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 5784899..ccae135 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,8 @@
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 4780cd7..f3a14b1 100644
--- a/baksmali/build.gradle
+++ b/baksmali/build.gradle
@@ -51,16 +51,13 @@
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 b3f9ae1..fc43d6f 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 @@
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 4081a75..ef2110a 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 @@
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 @@
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 @@
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 fa54f09..f532938 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 @@
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 @@
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 47fa406..5060734 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.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 @@
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 b6cc157..32685dd 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.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 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 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 1ef7df0..79405e5 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.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 @@
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 71598fa..2d6ed8c 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 @@
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 @@
}
/**
+ * 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 @@
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 @@
if (bcp != null && bcp.charAt(0) == ':') {
options.addExtraClassPath(bcp);
} else {
- setBootClassPath = true;
options.setBootClassPath(bcp);
}
break;
@@ -217,12 +253,15 @@
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 @@
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:");
- if (dexFile.isOdexFile()) {
+ for (OatDexFile oatDexFile: ex.oatFile.getDexFiles()) {
+ System.err.println(oatDexFile.filename);
+ }
+ System.exit(1);
+ }
+
+ 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 @@
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 @@
.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 @@
"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 @@
basicOptions.addOption(noImplicitReferencesOption);
basicOptions.addOption(dexEntryOption);
basicOptions.addOption(checkPackagePrivateAccessOption);
+ basicOptions.addOption(normalizeVirtualMethods);
debugOptions.addOption(dumpOption);
debugOptions.addOption(ignoreErrorsOption);
@@ -547,8 +578,7 @@
"/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 @@
"/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 725032a..2bb04dd 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 @@
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 0000000..5a4db65
--- /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 35304f7..1a34e8c 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 @@
* 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 @@
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 0000000..78fabc0
--- /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 0000000..42f7239
--- /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 0000000..4e59351
--- /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 0000000..8571715
--- /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 edf156f..80ac25f 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 @@
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 @@
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 @@
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 @@
}
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 0000000..8aa9ea9
--- /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 113b60a..60488ba 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 @@
// 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 @@
} 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 3b082ee..3a64235 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),
+ 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((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),
+ 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((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),
+ 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((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),
+ 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((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),
+ 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 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 @@
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();
- Opcode(short opcodeValue, String opcodeName, int apiConstraints, int referenceType, Format format) {
- this(opcodeValue, opcodeName, apiConstraints, referenceType, format, 0, (short)-1);
- }
+ 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);
+ }
+ }
- Opcode(short opcodeValue, String opcodeName, int apiConstraints, int referenceType, Format format, int flags) {
- this(opcodeValue, opcodeName, apiConstraints, referenceType, format, flags, (short)-1);
- }
-
- Opcode(short opcodeValue, String opcodeName, int apiConstraints, int referenceType, Format format, int flags,
- short jumboOpcodeValue) {
- this.value = opcodeValue;
+ this.apiToValueMap = apiToValueBuilder.build();
+ this.artVersionToValueMap = artVersionToValueBuilder.build();
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;
}
- /**
- * @return the minimum api level that can use this opcode (inclusive)
- */
- public int getMinApi() {
- return apiConstraints & 0xFFFF;
+ private static List<VersionConstraint> firstApi(int opcodeValue, int api) {
+ return Lists.newArrayList(new VersionConstraint(Range.atLeast(api), 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> lastApi(int opcodeValue, int api) {
+ Range range;
+ return Lists.newArrayList(new VersionConstraint(Range.atMost(api), Range.openClosed(0, 0), opcodeValue));
+ }
+
+ 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));
+ }
+
+ private static List<VersionConstraint> allApis(int opcodeValue) {
+ return Lists.newArrayList(new VersionConstraint(Range.<Integer>all(), Range.openClosed(0, 0), opcodeValue));
+ }
+
+ 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 @@
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 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 e718e27..17f8013 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 @@
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 0000000..42802bc
--- /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 30cc906..f6fc95a 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 @@
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 @@
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 @@
* 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 @@
/**
* 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;
+ }
- RegisterType oldRegisterType = postRegisterMap[registerNumber];
- if (oldRegisterType.equals(registerType)) {
- return false;
- }
+ postRegisterMap[registerNumber] = registerType;
+ return true;
+ }
- 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);
+
+ if (preRegisterMap[registerNumber].equals(mergedType)) {
+ return false;
+ }
+
+ preRegisterMap[registerNumber] = mergedType;
+ verifiedInstructions.clear(instructionIndex);
+
+ 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 @@
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 0000000..775a819
--- /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 8fcfc8c..4aa9a5e 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 @@
@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 bd9cfb1..9f9e396 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 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;
+
+ 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 array of DexFile objects. When loading a class, these dex files will be searched in order
+ * @param classProviders An iterable of ClassProviders. When loading a class, these providers will be searched in
+ * order
*/
- public ClassPath(DexFile... classPath) throws IOException {
- this(Lists.newArrayList(classPath), 15);
+ 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 api API level
+ * @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, int api) {
- this(Lists.newArrayList(classPath), api == 17);
- }
-
- /**
- * Creates a new ClassPath instance that can load classes from the given dex files
- *
- * @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
- */
- 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 @@
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 @@
@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 @@
@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 @@
}
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 @@
"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 @@
}
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 f4f1dc7..e407de7 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.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.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 @@
@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 @@
return vtable.get(vtableIndex);
}
- @Nonnull SparseArray<FieldReference> getInstanceFields() {
- return instanceFieldsSupplier.get();
+ 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 private final Supplier<SparseArray<FieldReference>> instanceFieldsSupplier =
+ @Nonnull SparseArray<FieldReference> getInstanceFields() {
+ if (classPath.isArt()) {
+ return artInstanceFieldsSupplier.get();
+ } else {
+ return dalvikInstanceFieldsSupplier.get();
+ }
+ }
+
+ @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,19 +537,6 @@
return fields;
}
- private 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
- }
- }
-
private void swap(byte[] fieldTypes, List<Field> fields, int position1, int position2) {
byte tempType = fieldTypes[position1];
fieldTypes[position1] = fieldTypes[position2];
@@ -542,23 +547,215 @@
}
});
+ 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;
+ /* 64 bit */
+ case 'J':
+ return 1;
+ case 'D':
+ 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 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 @@
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 @@
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 0000000..7c823ff
--- /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 0000000..c460cc3
--- /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 4402c62..f874f1b 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.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 @@
@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 @@
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 @@
int objectRegisterNumber;
switch (instruction.getOpcode().format) {
case Format10x:
- analyzeReturnVoidBarrier(analyzedInstruction, false);
+ analyzeOdexReturnVoid(analyzedInstruction, false);
continue;
case Format21c:
case Format22c:
@@ -333,6 +337,48 @@
registerType);
}
+ 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.
+ while (!changedInstructions.isEmpty()) {
+ for (int instructionIndex=changedInstructions.nextSetBit(0);
+ instructionIndex>=0;
+ instructionIndex=changedInstructions.nextSetBit(instructionIndex+1)) {
+
+ changedInstructions.clear(instructionIndex);
+
+ propagateRegisterToSuccessors(analyzedInstructions.valueAt(instructionIndex), registerNumber,
+ 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) {
@@ -342,25 +388,9 @@
return;
}
- propagateRegisterToSuccessors(analyzedInstruction, registerNumber, changedInstructions);
+ propagateRegisterToSuccessors(analyzedInstruction, registerNumber, changedInstructions, false);
- //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.
- while (!changedInstructions.isEmpty()) {
- for (int instructionIndex=changedInstructions.nextSetBit(0);
- instructionIndex>=0;
- instructionIndex=changedInstructions.nextSetBit(instructionIndex+1)) {
-
- changedInstructions.clear(instructionIndex);
-
- propagateRegisterToSuccessors(analyzedInstructions.valueAt(instructionIndex), registerNumber,
- changedInstructions);
- }
- }
+ propagateChanges(changedInstructions, registerNumber, false);
if (registerType.category == RegisterType.LONG_LO) {
checkWidePair(registerNumber, analyzedInstruction);
@@ -372,10 +402,10 @@
}
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 @@
//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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
resolvedMethod = superType.getMethodByVtableIndex(methodIndex);
- } else{
+ } else {
resolvedMethod = objectRegisterTypeProto.getMethodByVtableIndex(methodIndex);
}
@@ -1628,12 +1797,13 @@
// 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 @@
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 @@
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 49136c3..0ed1fef 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 @@
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 @@
case 'C':
return 3;
case 'I':
- case 'F':
return 4;
- case 'J':
- case 'D':
+ case 'F':
return 5;
- case 'L':
- case '[':
+ case 'J':
return 6;
- default:
+ case 'D':
+ return 7;
+ case 'L':
+ return 8;
+ case '[':
+ 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;
+ private static boolean isGet(@Nonnull Opcode opcode) {
+ return (opcode.flags & Opcode.SETS_REGISTER) != 0;
+ }
+
+ private static boolean isStatic(@Nonnull Opcode opcode) {
+ return (opcode.flags & Opcode.STATIC_FIELD_ACCESSOR) != 0;
+ }
+
+ public OdexedFieldInstructionMapper(boolean isArt) {
+ FieldOpcode[] opcodes;
+ if (isArt) {
+ opcodes = artFieldOpcodes;
+ } else {
+ opcodes = dalvikFieldOpcodes;
}
- throw new RuntimeException(String.format("Not an odexed field access opcode: %s", opcode.name));
+
+ for (FieldOpcode fieldOpcode: opcodes) {
+ opcodeMap[isGet(fieldOpcode.normalOpcode)?GET:PUT]
+ [isStatic(fieldOpcode.normalOpcode)?STATIC:INSTANCE]
+ [getTypeIndex(fieldOpcode.type)] = fieldOpcode;
+
+ if (fieldOpcode.quickOpcode != null) {
+ opcodeValueTypeMap.put(fieldOpcode.quickOpcode, getValueType(fieldOpcode.type));
+ }
+ if (fieldOpcode.volatileOpcode != null) {
+ opcodeValueTypeMap.put(fieldOpcode.volatileOpcode, getValueType(fieldOpcode.type));
+ }
+ }
}
@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));
+ public Opcode getAndCheckDeodexedOpcode(@Nonnull String fieldType, @Nonnull Opcode odexedOpcode) {
+ FieldOpcode fieldOpcode = opcodeMap[isGet(odexedOpcode)?GET:PUT]
+ [isStatic(odexedOpcode)?STATIC:INSTANCE]
+ [getTypeIndex(fieldType.charAt(0))];
- Opcode correctOdexedOpcode, deodexedOpcode;
-
- correctOdexedOpcode = opcodeMap[opcodeType][opcodeSubType][0][typeIndex];
- deodexedOpcode = opcodeMap[opcodeType][opcodeSubType][1][typeIndex];
-
- if (correctOdexedOpcode != odexedOpcode) {
+ 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 06ab8e1..2c28393 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 @@
@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 f6db239..776363b 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 @@
@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 38256fb..3287345 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 @@
@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 0313c7c..e2adf1c 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 @@
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 8498122..b1e5dbb 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 @@
} 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 7d06bff..eeb2822 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 @@
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 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 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 @@
(((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 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 @@
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 96645b8..13c0a7b 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 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 @@
}
}
- offset = end;
+ offset = end - dexBuf.baseOffset;
return result;
}
@@ -93,7 +93,7 @@
}
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 @@
}
}
- offset = end;
+ offset = end - dexBuf.baseOffset;
return result;
}
@@ -150,7 +150,7 @@
* @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 @@
}
}
- 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 @@
}
}
- offset = end;
+ offset = end - dexBuf.baseOffset;
}
public int readSmallUint() {
@@ -285,7 +285,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 1774096..32505ee 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.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 @@
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 @@
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 1aa9c1e..12f19db 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 @@
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 @@
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 0000000..dbeb67c
--- /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 3499ead..531ff46 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 @@
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 @@
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 @@
}
}
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 1fac80b..204a29d 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 @@
@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 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 45707f0..474bfb1 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 @@
* @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 e911eb3..2112bd0 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 @@
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 e482cd0..839ac09 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 @@
@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 631b892..dc978da 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 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 @@
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 @@
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 aa428b0..674d518 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_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 a46a18f..7808f84 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.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 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 @@
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 02890b8..6be21af 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 @@
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 be23978..4e81f7f 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.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 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 @@
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 @@
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 @@
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 @@
}
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 @@
// 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 c9aa73a..f16256c 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 @@
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 @@
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 @@
@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 @@
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 9a727b2..d119024 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 @@
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 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 @@
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 d7f6392..27d8044 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 @@
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 @@
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 c46f9ba..96ac536 100644
--- a/dexlib2/src/main/ragel/SyntheticAccessorFSM.rl
+++ b/dexlib2/src/main/ragel/SyntheticAccessorFSM.rl
@@ -34,6 +34,7 @@
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 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 @@
%%{
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 924d3fd..4c8f85b 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 @@
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 f3b1094..3f1ee56 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 @@
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 @@
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;"),
+ 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;"),
+ // 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;")
- )));
+ // 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 65a82f0..90a6359 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.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 @@
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 @@
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 @@
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 59b0d27..84cd284 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 @@
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 @@
public class SuperclassChainTest {
-
@Test
public void testGetSuperclassChain() throws IOException {
ClassDef objectClassDef = TestUtils.makeClassDef("Ljava/lang/Object;", null);
@@ -56,7 +57,7 @@
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 @@
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 0000000..0df5ab3
--- /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 8ba975a..1a0a289 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 @@
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 @@
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 7e504a1..c246e0e 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 @@
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 @@
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 @@
@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 @@
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 7e79327..692d204 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 6c4f08c..f7a6cf7 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 0e5cbf2..75001d7 100644
--- a/smali/build.gradle
+++ b/smali/build.gradle
@@ -52,6 +52,15 @@
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 @@
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 6d07452..fcccbe8 100644
--- a/smali/src/main/antlr/smaliParser.g
+++ b/smali/src/main/antlr/smaliParser.g
@@ -39,7 +39,7 @@
ANNOTATION_DIRECTIVE;
ANNOTATION_VISIBILITY;
ARRAY_DATA_DIRECTIVE;
- ARRAY_DESCRIPTOR;
+ ARRAY_TYPE_PREFIX;
ARROW;
BOOL_LITERAL;
BYTE_LITERAL;
@@ -133,10 +133,7 @@
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 @@
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 @@
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 @@
};
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 @@
: 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_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 8eed2b2..c3a5099 100644
--- a/smali/src/main/antlr/smaliTreeWalker.g
+++ b/smali/src/main/antlr/smaliTreeWalker.g
@@ -77,7 +77,7 @@
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 @@
$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 0000000..165c3a8
--- /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 26de008..bef0741 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 @@
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 @@
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 98fb7a1..e556280 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.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 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 @@
}
/**
+ * 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 @@
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 @@
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 @@
}
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 @@
}
}
- 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 @@
}
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 @@
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 bc17362..2f57a43 100644
--- a/smali/src/main/jflex/smaliLexer.jflex
+++ b/smali/src/main/jflex/smaliLexer.jflex
@@ -172,6 +172,20 @@
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 @@
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 @@
}
<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 @@
return newToken(INSTRUCTION_FORMAT10x);
}
- "return-void-barrier" {
+ "return-void-barrier" | "return-void-no-barrier" {
return newToken(INSTRUCTION_FORMAT10x_ODEX);
}
@@ -507,7 +522,9 @@
"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 @@
}
}
+<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 f6dcbb1..174cff8 100644
--- a/smali/src/test/resources/LexerTest/InstructionTest.smali
+++ b/smali/src/test/resources/LexerTest/InstructionTest.smali
@@ -2,6 +2,7 @@
return-void
nop
return-void-barrier
+return-void-no-barrier
const/4
move-result
move-result-wide
@@ -132,6 +133,10 @@
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 fb5503b..fa959ba 100644
--- a/smali/src/test/resources/LexerTest/InstructionTest.tokens
+++ b/smali/src/test/resources/LexerTest/InstructionTest.tokens
@@ -2,6 +2,7 @@
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("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 ba40c2f..f9b096f 100644
--- a/smali/src/test/resources/LexerTest/RealSmaliFileTest.tokens
+++ b/smali/src/test/resources/LexerTest/RealSmaliFileTest.tokens
@@ -184,7 +184,8 @@
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 @@
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 @@
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 @@
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 @@
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 2120d33..9becb91 100644
--- a/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.smali
+++ b/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.smali
@@ -23,6 +23,8 @@
[D
[Ljava/lang/String;
[LI/I/I;
+[[LI/I/I;
+[[I
IIIII
ZBSCIJFD
@@ -49,4 +51,6 @@
<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 d99d2c2..b0b66db 100644
--- a/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.tokens
+++ b/smali/src/test/resources/LexerTest/TypeAndIdentifierTest.tokens
@@ -13,63 +13,72 @@
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_START("")
+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")
+
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 @@
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("")
+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")
-PRIMITIVE_TYPE("I")
-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 0000000..f8be399
--- /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 0000000..6b855d7
--- /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 0000000..0da263f
--- /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 0000000..0000400
--- /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 0000000..4e0208c
--- /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 0000000..b0ed5c0
--- /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 0000000..e840bb8
--- /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 0000000..b5834c1
--- /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 0000000..71e206a
--- /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 0000000..eba5fd3
--- /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 0000000..449e71b
--- /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 0000000..f437ec2
--- /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 0000000..67e5945
--- /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 0000000..5103dd9
--- /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 0000000..ed0fb19
--- /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 0000000..77f1623
--- /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 0000000..8332764
--- /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 0000000..5e2dd0c
--- /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 0000000..f822fd1
--- /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 0000000..89bba29
--- /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 0000000..781a856
--- /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 0000000..d78b57c
--- /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 0000000..ad55a9f
--- /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 0000000..e42da25
--- /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 0000000..bc0e6a3
--- /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 0000000..0c536dd
--- /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 0000000..dc41bbb
--- /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 0000000..62ac420
--- /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 0000000..e4a0b33
--- /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 0000000..ae9e17a
--- /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 0000000..54041cd
--- /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 0000000..87b13ca
--- /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 0000000..e1c1aaf
--- /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 0000000..9f50bf3
--- /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 0000000..65d3635
--- /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 0000000..10a5fa3
--- /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 0000000..88fd007
--- /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 0000000..05f05d6
--- /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 0000000..61a13f8
--- /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 0000000..746a629
--- /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 0000000..a7f6bdc
--- /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 0000000..c954702
--- /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 0000000..72909b6
--- /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 0000000..7b98174
--- /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 0000000..abc4dda
--- /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 0000000..49d75c8
--- /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 0000000..6fbab59
--- /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 0000000..9d2a14a
--- /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 0000000..26f2daf
--- /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 0000000..b5b259a
--- /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 0000000..80a4ba6
--- /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 0000000..0480451
--- /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 0000000..1b185dd
--- /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 0000000..7e8fbf4
--- /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 0000000..c6cba0a
--- /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 0000000..1c0a921
--- /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 0000000..f2ac6f1
--- /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 0000000..ce5f598
--- /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 0000000..3ef0850
--- /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 0000000..5ae7506
--- /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 0000000..11e1756
--- /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 0000000..f136046
--- /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 0000000..4d7dacb
--- /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 0000000..8189768
--- /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 0000000..8f4811d
--- /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 0000000..5cc8b00
--- /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 0000000..3cc60d8
--- /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 0000000..324fc77
--- /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 0000000..ffea217
--- /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 0000000..0fef667
--- /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 0000000..142fd44
--- /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 0000000..1ac27de
--- /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 0000000..a3ddcce
--- /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 0000000..509e6b7
--- /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 0000000..3b58628
--- /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 0000000..9d2a0fc
--- /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 0000000..15eaea2
--- /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 0000000..92aef72
--- /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 0000000..ab54dc6
--- /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 0000000..5bf93e3
--- /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 0000000..63e4d6f
--- /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 0000000..335bce2
--- /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 0000000..e87782b
--- /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 0000000..ad86942
--- /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 0000000..56bbdaf
--- /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 0000000..6d5bb10
--- /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 0000000..ae5fc53
--- /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 0000000..bb4bd37
--- /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 0000000..3da47c9
--- /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 0000000..acd9a02
--- /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 0000000..e36313b
--- /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 0000000..10784f8
--- /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 0000000..656b4ef
--- /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 0000000..7feaa9e
--- /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 0000000..85f6213
--- /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 0000000..1b54a9c
--- /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 0000000..b47d512
--- /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 0000000..f5c7107
--- /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 0000000..b8442a6
--- /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 0000000..684293f
--- /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 0000000..add3c1b
--- /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 0000000..6d5bbab
--- /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 0000000..b491f6d
--- /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 0000000..d9c38c4
--- /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 0000000..042596c
--- /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 0000000..faaef09
--- /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 0000000..ace9a97
--- /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 0000000..7bef4e9
--- /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 0000000..dcf0e85
--- /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 0000000..0626c3a
--- /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 0000000..6ec3bd5
--- /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 0000000..8992ab0
--- /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 0000000..e50d8c6
--- /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 0000000..8cb2d77
--- /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 0000000..b07220d
--- /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 0000000..940f429
--- /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 0000000..7ea3227
--- /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 0000000..0a9f538
--- /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 0000000..02d1748
--- /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 0000000..6ade23a
--- /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 0000000..f337736
--- /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 0000000..085585b
--- /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 0000000..0b759f0
--- /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 0000000..93d376e
--- /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 0000000..3b2aae3
--- /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 0000000..f8048e9
--- /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 0000000..f9dccf0
--- /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 0000000..c23763f
--- /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 0000000..b0e0415
--- /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 0000000..5fa8c4c
--- /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 0000000..4bdf65a
--- /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 0000000..c4f73f0
--- /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 0000000..3c2fe7b
--- /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 0000000..93080a7
--- /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 0000000..e273607
--- /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 0000000..758e175
--- /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 0000000..4f696cf
--- /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 0000000..28fee43
--- /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 0000000..5df05e2
--- /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 0000000..c0948dc
--- /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 0000000..9cff5c3
--- /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 0000000..634cf1a
--- /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 0000000..2b540c6
--- /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 0000000..0ebb1ee
--- /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 0000000..0429597
--- /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 0000000..36c59f2
--- /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 0000000..84b2e50
--- /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 0000000..d20882c
--- /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 0000000..8521c4b
--- /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 0000000..41faccf
--- /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 0000000..b1656a5
--- /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 0000000..9678a29
--- /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 0000000..15e0fbf
--- /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 0000000..be05976
--- /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 0000000..2b762c9
--- /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 0000000..f487866
--- /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 0000000..e6f1cf2
--- /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 0000000..ac0b1e9
--- /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 0000000..1412980
--- /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 0000000..e0a5f0e
--- /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 0000000..94d239e
--- /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 0000000..7085cc0
--- /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 0000000..d73a33a
--- /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 0000000..dcd7a2c
--- /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 0000000..f3029c0
--- /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 0000000..3acfd8f
--- /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 0000000..235e995
--- /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 0000000..3e1eaf5
--- /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 0000000..3b17bc1
--- /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 0000000..1d83f1a
--- /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 0000000..197e682
--- /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 0000000..ca5a010
--- /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 0000000..290b78c
--- /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 0000000..12299b4
--- /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 0000000..51544b4
--- /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 0000000..b53af34
--- /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 0000000..e302b01
--- /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 0000000..305c7f8
--- /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 0000000..72c5a13
--- /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 0000000..e5cc1cc
--- /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 0000000..6e24054
--- /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 0000000..e60efc5
--- /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 0000000..b11193a
--- /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 0000000..89d4545
--- /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 0000000..05f3b1b
--- /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 0000000..d1c7365
--- /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 0000000..78360d8
--- /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 0000000..4edab84
--- /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 0000000..290021a
--- /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 0000000..1de6598
--- /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 0000000..29cf4d3
--- /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 0000000..0504bfe
--- /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 0000000..3cd863f
--- /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 0000000..a841d0f
--- /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 0000000..ba18b66
--- /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 0000000..434c959
--- /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 0000000..c61d3e4
--- /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 0000000..05e46bc
--- /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 0000000..e55bdd3
--- /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 0000000..c2d7336
--- /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 0000000..597cf70
--- /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 0000000..37ea555
--- /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 0000000..628cf0f
--- /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 0000000..8383f96
--- /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 0000000..64d38a9
--- /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 0000000..6af9675
--- /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 0000000..596c11e
--- /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 0000000..fbb4b62
--- /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 0000000..515c9bb
--- /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 0000000..18a6194
--- /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 0000000..128c97b
--- /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 0000000..ec889cc
--- /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 0000000..810ac5b
--- /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 0000000..80c0054
--- /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 0000000..311c9ee
--- /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 0000000..f4e2b0f
--- /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 0000000..ffec82c
--- /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 0000000..eea3b15
--- /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 0000000..44c2f49
--- /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 0000000..60aef8b
--- /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 0000000..4c5a9a6
--- /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 0000000..e69de29
--- /dev/null
+++ b/smalidea/testData/Empty.smalidea
diff --git a/smalidea/testData/Empty.txt b/smalidea/testData/Empty.txt
new file mode 100644
index 0000000..9165509
--- /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 0000000..3716769
--- /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 0000000..80332e5
--- /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 0000000..9825e29
--- /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 0000000..3799410
--- /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 0000000..9f6b5ba
--- /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 0000000..e9f89c0
--- /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 0000000..ee4d27e
--- /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 0000000..6f36abe
--- /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 0000000..fd5d360
--- /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 0000000..ed98ac6
--- /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 0000000..8853cc3
--- /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 0000000..b2acd87
--- /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 0000000..8eb1120
--- /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 0000000..99aa29e
--- /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 0000000..8de7a3a
--- /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 0000000..b3e8227
--- /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 0000000..9de3142
--- /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 0000000..508df46
--- /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 0000000..11a8cb2
--- /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 0000000..4eedd93
--- /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 0000000..0960b88
--- /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 0000000..7650257
--- /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 0000000..48bcd08
--- /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 0000000..b639c46
--- /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 0000000..57245e9
--- /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 0000000..421e084
--- /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 0000000..d530143
--- /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 0000000..1a3a1cd
--- /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 0000000..24e66b6
--- /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 0000000..ce14371
--- /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 0000000..ff86bf3
--- /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 0000000..aae8065
--- /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 0000000..8ee6d79
--- /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 0000000..490d38c
--- /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 0000000..014299f
--- /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 0000000..27168ef
--- /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 0000000..5e8e6b6
--- /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 0000000..53a1ecc
--- /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 0000000..f9a8728
--- /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 0000000..ea94d46
--- /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 0000000..cea9d10
--- /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 0000000..316041c
--- /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 0000000..8793e8c
--- /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 0000000..348fab4
--- /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 0000000..dc4522c
--- /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 0000000..0a72c71
--- /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 0000000..0a72c71
--- /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 0000000..0281344
--- /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 0000000..dc4522c
--- /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 0000000..0281344
--- /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 0000000..112b106
--- /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 0000000..0a72c71
--- /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 0000000..f08d513
--- /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 0000000..dc4522c
--- /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 0000000..e2a2369
--- /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 0000000..ab4dc6c
--- /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 0000000..2343699
--- /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 0000000..9a800dc
--- /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 0000000..ca55dd0
--- /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 {
+ }
+}