diff --git a/smalidea/src/main/antlr3/smalideaParser.g b/smalidea/src/main/antlr3/smalideaParser.g index 7d8d4e5d..b753cc25 100644 --- a/smalidea/src/main/antlr3/smalideaParser.g +++ b/smalidea/src/main/antlr3/smalideaParser.g @@ -287,7 +287,7 @@ simple_name | DOUBLE_LITERAL_OR_ID | BOOL_LITERAL | NULL_LITERAL - | REGISTER + | register | param_list_or_id | PRIMITIVE_TYPE | VOID_TYPE @@ -536,11 +536,11 @@ label_ref finally { marker.done(SmaliElementTypes.LABEL_REFERENCE); } register_list - : REGISTER (COMMA REGISTER)* + : register (COMMA register)* | /* epsilon */; register_range - : (REGISTER (DOTDOT REGISTER)?)?; + : (register (DOTDOT register)?)?; verification_error_reference : class_descriptor | fully_qualified_field | fully_qualified_method; @@ -560,12 +560,17 @@ or method annotations until we determine if there is an .end parameter directive 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 - : PARAMETER_DIRECTIVE REGISTER (COMMA string_literal)? + : PARAMETER_DIRECTIVE register (COMMA string_literal)? ({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation)* ( END_PARAMETER_DIRECTIVE | /*epsilon*/ ); +register + @init { Marker marker = mark(); } + : REGISTER; + finally { marker.done(SmaliElementTypes.REGISTER_REFERENCE); } + debug_directive : line_directive | local_directive @@ -582,18 +587,18 @@ line_directive local_directive @init { Marker marker = mark(); } - : LOCAL_DIRECTIVE REGISTER (COMMA (null_literal | string_literal) COLON (void_type | nonvoid_type_descriptor) + : LOCAL_DIRECTIVE register (COMMA (null_literal | string_literal) COLON (void_type | nonvoid_type_descriptor) (COMMA string_literal)? )?; finally { marker.done(SmaliElementTypes.LOCAL_DEBUG_STATEMENT); } end_local_directive @init { Marker marker = mark(); } - : END_LOCAL_DIRECTIVE REGISTER; + : END_LOCAL_DIRECTIVE register; finally { marker.done(SmaliElementTypes.END_LOCAL_DEBUG_STATEMENT); } restart_local_directive @init { Marker marker = mark(); } - : RESTART_LOCAL_DIRECTIVE REGISTER; + : RESTART_LOCAL_DIRECTIVE register; finally { marker.done(SmaliElementTypes.RESTART_LOCAL_DEBUG_STATEMENT); } prologue_directive @@ -686,15 +691,15 @@ insn_format10x_odex insn_format11n : //e.g. const/4 v0, 5 - INSTRUCTION_FORMAT11n REGISTER COMMA integral_literal; + INSTRUCTION_FORMAT11n register COMMA integral_literal; insn_format11x : //e.g. move-result-object v1 - INSTRUCTION_FORMAT11x REGISTER; + INSTRUCTION_FORMAT11x register; insn_format12x : //e.g. move v1 v2 - instruction_format12x REGISTER COMMA REGISTER; + instruction_format12x register COMMA register; insn_format20bc : //e.g. throw-verification-error generic-error, Lsome/class; @@ -706,71 +711,71 @@ insn_format20t insn_format21c_field : //e.g. sget-object v0, java/lang/System/out LJava/io/PrintStream; - INSTRUCTION_FORMAT21c_FIELD REGISTER COMMA fully_qualified_field; + 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; + 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; + 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; + INSTRUCTION_FORMAT21c_TYPE register COMMA nonvoid_type_descriptor; insn_format21ih : //e.g. const/high16 v1, 1234 - INSTRUCTION_FORMAT21ih REGISTER COMMA fixed_32bit_literal; + INSTRUCTION_FORMAT21ih register COMMA fixed_32bit_literal; insn_format21lh : //e.g. const-wide/high16 v1, 1234 - INSTRUCTION_FORMAT21lh REGISTER COMMA fixed_32bit_literal; + INSTRUCTION_FORMAT21lh register COMMA fixed_32bit_literal; insn_format21s : //e.g. const/16 v1, 1234 - INSTRUCTION_FORMAT21s REGISTER COMMA integral_literal; + INSTRUCTION_FORMAT21s register COMMA integral_literal; insn_format21t : //e.g. if-eqz v0, endloop: - INSTRUCTION_FORMAT21t REGISTER COMMA label_ref; + INSTRUCTION_FORMAT21t register COMMA label_ref; insn_format22b : //e.g. add-int v0, v1, 123 - INSTRUCTION_FORMAT22b REGISTER COMMA REGISTER COMMA integral_literal; + 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; + 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; + 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; + 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; + 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; + 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; + INSTRUCTION_FORMAT22t register COMMA register COMMA label_ref; insn_format22x : //e.g. move/from16 v1, v1234 - INSTRUCTION_FORMAT22x REGISTER COMMA REGISTER; + INSTRUCTION_FORMAT22x register COMMA register; insn_format23x : //e.g. add-int v1, v2, v3 - INSTRUCTION_FORMAT23x REGISTER COMMA REGISTER COMMA REGISTER; + INSTRUCTION_FORMAT23x register COMMA register COMMA register; insn_format30t : //e.g. goto/32 endloop: @@ -778,19 +783,19 @@ insn_format30t insn_format31c : //e.g. const-string/jumbo v1 "Hello World!" - INSTRUCTION_FORMAT31c REGISTER COMMA string_literal; + INSTRUCTION_FORMAT31c register COMMA string_literal; insn_format31i : //e.g. const v0, 123456 - instruction_format31i REGISTER COMMA fixed_32bit_literal; + instruction_format31i register COMMA fixed_32bit_literal; insn_format31t : //e.g. fill-array-data v0, ArrayData: - INSTRUCTION_FORMAT31t REGISTER COMMA label_ref; + INSTRUCTION_FORMAT31t register COMMA label_ref; insn_format32x : //e.g. move/16 v4567, v1234 - INSTRUCTION_FORMAT32x REGISTER COMMA REGISTER; + INSTRUCTION_FORMAT32x register COMMA register; insn_format35c_method : //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V @@ -834,7 +839,7 @@ insn_format3rms_method insn_format51l : //e.g. const-wide v0, 5000000000L - INSTRUCTION_FORMAT51l REGISTER COMMA fixed_literal; + INSTRUCTION_FORMAT51l register COMMA fixed_literal; insn_array_data_directive : ARRAY_DATA_DIRECTIVE diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/SmaliElementTypes.java b/smalidea/src/main/java/org/jf/smalidea/psi/SmaliElementTypes.java index c4a46c37..e5a7dc0d 100644 --- a/smalidea/src/main/java/org/jf/smalidea/psi/SmaliElementTypes.java +++ b/smalidea/src/main/java/org/jf/smalidea/psi/SmaliElementTypes.java @@ -56,6 +56,8 @@ public class SmaliElementTypes { 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 ACCESS_LIST = new SmaliCompositeElementType("ACCESS_LIST", SmaliAccessList.FACTORY); public static final SmaliCompositeElementType MEMBER_NAME = 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 index ca46c142..912b1d10 100644 --- a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliCompositeElement.java +++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliCompositeElement.java @@ -84,4 +84,16 @@ public abstract class SmaliCompositeElement extends CompositePsiElement { } return null; } + + @SuppressWarnings("unchecked") + protected T findAncestorByClass(Class aClass) { + PsiElement parent = getParent(); + while (parent != null) { + if (ReflectionCache.isInstance(parent, aClass)) { + return (T)parent; + } + parent = parent.getParent(); + } + return null; + } } 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 index 3aee4f01..0a9f5382 100644 --- a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLiteral.java +++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliLiteral.java @@ -31,7 +31,11 @@ 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; @@ -45,4 +49,27 @@ public class SmaliLiteral extends SmaliCompositeElement implements PsiAnnotation 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/SmaliMethod.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java index 4dd9e934..4644ff3a 100644 --- a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java +++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java @@ -44,4 +44,17 @@ public class SmaliMethod extends SmaliStubBasedPsiElement { public SmaliMethod(@NotNull ASTNode node) { super(node); } + + public int getRegisterCount() { + SmaliRegistersStatement registersStatement = findChildByClass(SmaliRegistersStatement.class); + if (registersStatement == null) { + return 0; + } + return registersStatement.getRegisterCount(); + } + + public int getParameterRegisterCount() { + // TODO: implement this + return 0; + } } diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegisterReference.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegisterReference.java new file mode 100644 index 00000000..3c2fe7b2 --- /dev/null +++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegisterReference.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.smalidea.psi.impl; + +import org.jetbrains.annotations.NotNull; +import org.jf.smalidea.psi.SmaliCompositeElementFactory; +import org.jf.smalidea.psi.SmaliElementTypes; + +public class SmaliRegisterReference extends SmaliCompositeElement { + public static final SmaliCompositeElementFactory FACTORY = new SmaliCompositeElementFactory() { + @Override public SmaliCompositeElement createElement() { + return new SmaliRegisterReference(); + } + }; + + public SmaliRegisterReference() { + super(SmaliElementTypes.REGISTER_REFERENCE); + } + + @NotNull + public SmaliMethod getParentMethod() { + SmaliMethod parentMethod = findAncestorByClass(SmaliMethod.class); + assert parentMethod != null; + return parentMethod; + } + + public int getRegisterNumber() { + int registerNumber = Integer.parseInt(getText().substring(1)); + + if (isParameterRegister()) { + SmaliMethod method = getParentMethod(); + registerNumber += method.getRegisterCount() - method.getParameterRegisterCount(); + } + + return registerNumber; + } + + public boolean isParameterRegister() { + return getText().charAt(0) == 'p'; + } +} diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegistersStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegistersStatement.java index 4c6871ce..93080a70 100644 --- a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegistersStatement.java +++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliRegistersStatement.java @@ -31,6 +31,8 @@ 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; @@ -44,4 +46,30 @@ public class SmaliRegistersStatement extends SmaliCompositeElement { 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/test/java/org/jf/smalidea/SmaliLiteralTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliLiteralTest.java new file mode 100644 index 00000000..9a10e873 --- /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 junit.framework.Assert; +import org.jf.smalidea.psi.impl.SmaliFile; +import org.jf.smalidea.psi.impl.SmaliLiteral; + +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 " + literalValue + "\n" + + " return-void\n" + + ".end method"; + + SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", + text.replace("", "")); + + PsiElement leafElement = file.findElementAt(text.indexOf("")); + Assert.assertNotNull(leafElement); + SmaliLiteral literalElement = (SmaliLiteral)leafElement.getParent(); + Assert.assertNotNull(literalElement); + + Assert.assertEquals(expectedValue, literalElement.getIntegralValue()); + } + + public void testIntegerValue() { + doTest(123, "123"); + } + + public void testLongValue() { + doTest(100, "100L"); + } + + public void testShortValue() { + doTest(99, "99s"); + } + + public void testByteValue() { + doTest(127, "127t"); + } + + // TODO: test char + // TODO: test bool +} diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliMethodTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliMethodTest.java new file mode 100644 index 00000000..8dd92b67 --- /dev/null +++ b/smalidea/src/test/java/org/jf/smalidea/SmaliMethodTest.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 junit.framework.Assert; +import org.jf.smalidea.psi.impl.SmaliFile; +import org.jf.smalidea.psi.impl.SmaliMethod; + +public class SmaliMethodTest extends LightCodeInsightFixtureTestCase { + public void testMethodRegisters() { + String text = + ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" + + ".method blah()V\n" + + " .registers 123\n" + + " return-void\n" + + ".end method"; + + SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", + text.replace("", "")); + + PsiElement leafElement = file.findElementAt(text.indexOf("")); + Assert.assertNotNull(leafElement); + SmaliMethod methodElement = (SmaliMethod)leafElement.getParent(); + Assert.assertNotNull(methodElement); + + Assert.assertEquals(123, methodElement.getRegisterCount()); + // TODO: test getParameterRegisterCount() + // TODO: test .locals directive + } +} diff --git a/smalidea/src/test/java/org/jf/smalidea/SmaliRegisterTest.java b/smalidea/src/test/java/org/jf/smalidea/SmaliRegisterTest.java new file mode 100644 index 00000000..b75b30f8 --- /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 junit.framework.Assert; +import org.jf.smalidea.psi.impl.SmaliFile; +import org.jf.smalidea.psi.impl.SmaliRegisterReference; + +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 v10, 123\n" + + " return-void\n" + + ".end method"; + + SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", + text.replace("", "")); + + PsiElement leafElement = file.findElementAt(text.indexOf("")); + Assert.assertNotNull(leafElement); + SmaliRegisterReference registerReference = (SmaliRegisterReference)leafElement.getParent(); + Assert.assertNotNull(registerReference); + + Assert.assertEquals(10, registerReference.getRegisterNumber()); + // TODO: test parameter register + } +}