1 /* 2 * Copyright 2014, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 package org.jf.smalidea; 33 34 import com.intellij.debugger.SourcePosition; 35 import com.intellij.psi.PsiElement; 36 import com.intellij.psi.PsiPrimitiveType; 37 import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; 38 import org.jf.dexlib2.Opcode; 39 import org.jf.smalidea.psi.impl.*; 40 import org.junit.Assert; 41 42 import java.util.List; 43 44 public class SmaliMethodTest extends LightCodeInsightFixtureTestCase { 45 public void testMethodRegisters() { 46 String text = 47 ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" + 48 ".me<ref>thod blah()V\n" + 49 " .registers 123\n" + 50 " return-void\n" + 51 ".end method"; 52 53 SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", 54 text.replace("<ref>", "")); 55 56 PsiElement leafElement = file.findElementAt(text.indexOf("<ref>")); 57 Assert.assertNotNull(leafElement); 58 SmaliMethod methodElement = (SmaliMethod)leafElement.getParent(); 59 Assert.assertNotNull(methodElement); 60 61 Assert.assertEquals(123, methodElement.getRegisterCount()); 62 Assert.assertEquals(1, methodElement.getParameterRegisterCount()); 63 } 64 65 public void testMethodRegisters2() { 66 String text = 67 ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" + 68 ".me<ref>thod blah(IJLjava/lang/String;)V\n" + 69 " .locals 123\n" + 70 " return-void\n" + 71 ".end method"; 72 73 SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", 74 text.replace("<ref>", "")); 75 76 PsiElement leafElement = file.findElementAt(text.indexOf("<ref>")); 77 Assert.assertNotNull(leafElement); 78 SmaliMethod methodElement = (SmaliMethod)leafElement.getParent(); 79 Assert.assertNotNull(methodElement); 80 81 Assert.assertEquals(128, methodElement.getRegisterCount()); 82 Assert.assertEquals(5, methodElement.getParameterRegisterCount()); 83 } 84 85 public void testStaticRegisterCount() { 86 String text = 87 ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" + 88 ".method static blah(IJLjava/lang/String;)V\n" + 89 " .locals 123\n" + 90 " return-void\n" + 91 ".end method"; 92 93 SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text); 94 SmaliClass smaliClass = file.getPsiClass(); 95 SmaliMethod smaliMethod = smaliClass.getMethods()[0]; 96 97 Assert.assertEquals(127, smaliMethod.getRegisterCount()); 98 Assert.assertEquals(4, smaliMethod.getParameterRegisterCount()); 99 100 Assert.assertEquals(0, smaliMethod.getParameterList().getParameters()[0].getParameterRegisterNumber()); 101 Assert.assertEquals(123, smaliMethod.getParameterList().getParameters()[0].getRegisterNumber()); 102 } 103 104 public void testMethodParams() { 105 myFixture.addFileToProject("my/TestAnnotation.smali", 106 ".class public interface abstract annotation Lmy/TestAnnotation;\n" + 107 ".super Ljava/lang/Object;\n" + 108 ".implements Ljava/lang/annotation/Annotation;\n" + 109 "\n" + 110 ".method public abstract testBooleanValue()Z\n" + 111 ".end method\n" + 112 "\n" + 113 ".method public abstract testStringArrayValue()[Ljava/lang/String;\n" + 114 ".end method\n" + 115 "\n" + 116 ".method public abstract testStringValue()Ljava/lang/String;\n" + 117 ".end method"); 118 119 String text = 120 ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" + 121 ".method blah(IJLjava/lang/String;)V\n" + 122 " .locals 123\n" + 123 " .param p1, \"anInt\"\n" + 124 " .param p2\n" + 125 " .annotation runtime Lmy/TestAnnotation;\n" + 126 " testStringValue = \"myValue\"\n" + 127 " .end annotation\n" + 128 " .end param\n" + 129 " return-void\n" + 130 ".end method"; 131 132 SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text); 133 134 SmaliClass smaliClass = file.getPsiClass(); 135 SmaliMethod smaliMethod = smaliClass.getMethods()[0]; 136 137 SmaliMethodParamList paramList = smaliMethod.getParameterList(); 138 SmaliMethodParameter[] parameters = paramList.getParameters(); 139 Assert.assertEquals(3, parameters.length); 140 141 Assert.assertEquals("int", parameters[0].getType().getCanonicalText()); 142 Assert.assertEquals("\"anInt\"", parameters[0].getName()); 143 Assert.assertEquals(1, parameters[0].getRegisterCount()); 144 Assert.assertEquals(124, parameters[0].getRegisterNumber()); 145 Assert.assertEquals(1, parameters[0].getParameterRegisterNumber()); 146 Assert.assertEquals(0, parameters[0].getAnnotations().length); 147 148 Assert.assertEquals("long", parameters[1].getType().getCanonicalText()); 149 Assert.assertNull(parameters[1].getName()); 150 Assert.assertEquals(2, parameters[1].getRegisterCount()); 151 Assert.assertEquals(125, parameters[1].getRegisterNumber()); 152 Assert.assertEquals(2, parameters[1].getParameterRegisterNumber()); 153 Assert.assertEquals(1, parameters[1].getAnnotations().length); 154 Assert.assertEquals("my.TestAnnotation", parameters[1].getAnnotations()[0].getQualifiedName()); 155 156 Assert.assertEquals("java.lang.String", parameters[2].getType().getCanonicalText()); 157 Assert.assertNull(parameters[2].getName()); 158 Assert.assertEquals(1, parameters[2].getRegisterCount()); 159 Assert.assertEquals(127, parameters[2].getRegisterNumber()); 160 Assert.assertEquals(4, parameters[2].getParameterRegisterNumber()); 161 Assert.assertEquals(0, parameters[2].getAnnotations().length); 162 } 163 164 public void testVarArgsMethod() { 165 String text = 166 ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" + 167 ".method varargs static blah(IJ[Ljava/lang/String;)V\n" + 168 " .locals 123\n" + 169 " return-void\n" + 170 ".end method\n" + 171 ".method varargs static blah2(IJLjava/lang/String;)V\n" + 172 " .locals 123\n" + 173 " return-void\n" + 174 ".end method"; 175 176 SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text); 177 SmaliClass smaliClass = file.getPsiClass(); 178 SmaliMethod smaliMethod = smaliClass.getMethods()[0]; 179 180 Assert.assertTrue(smaliMethod.isVarArgs()); 181 Assert.assertFalse(smaliMethod.getParameterList().getParameters()[0].isVarArgs()); 182 Assert.assertFalse(smaliMethod.getParameterList().getParameters()[1].isVarArgs()); 183 Assert.assertTrue(smaliMethod.getParameterList().getParameters()[2].isVarArgs()); 184 185 smaliMethod = smaliClass.getMethods()[1]; 186 Assert.assertTrue(smaliMethod.isVarArgs()); 187 Assert.assertFalse(smaliMethod.getParameterList().getParameters()[0].isVarArgs()); 188 Assert.assertFalse(smaliMethod.getParameterList().getParameters()[1].isVarArgs()); 189 Assert.assertFalse(smaliMethod.getParameterList().getParameters()[2].isVarArgs()); 190 } 191 192 private static final String instructionsTestClass = 193 ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" + 194 ".method public getRandomParentType(I)I\n" + 195 " .registers 4\n" + 196 " .param p1, \"edge\" # I\n" + 197 "\n" + 198 " .prologue\n" + 199 " const/4 v1, 0x2\n" + 200 "\n" + 201 " .line 179\n" + 202 " if-nez p1, :cond_5\n" + 203 "\n" + 204 " move v0, v1\n" + 205 "\n" + 206 " .line 185\n" + 207 " :goto_4\n" + 208 " return v0\n" + 209 "\n" + 210 " .line 182\n" + 211 " :cond_5\n" + 212 " if-ne p1, v1, :cond_f\n" + 213 "\n" + 214 " .line 183\n" + 215 " sget-object v0, Lorg/jf/Penroser/PenroserApp;->random:Ljava/util/Random;\n" + 216 "\n" + 217 " const/4 v1, 0x3\n" + 218 "\n" + 219 " invoke-virtual {v0, v1}, Ljava/util/Random;->nextInt(I)I\n" + 220 "\n" + 221 " move-result v0\n" + 222 "\n" + 223 " goto :goto_4\n" + 224 "\n" + 225 " .line 185\n" + 226 " :cond_f\n" + 227 " sget-object v0, Lorg/jf/Penroser/PenroserApp;->random:Ljava/util/Random;\n" + 228 "\n" + 229 " invoke-virtual {v0, v1}, Ljava/util/Random;->nextInt(I)I\n" + 230 "\n" + 231 " move-result v0\n" + 232 "\n" + 233 " goto :goto_4\n" + 234 ".end method"; 235 236 public void testGetInstructions() { 237 String text = instructionsTestClass; 238 239 SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text); 240 SmaliClass smaliClass = file.getPsiClass(); 241 SmaliMethod smaliMethod = smaliClass.getMethods()[0]; 242 243 List<SmaliInstruction> instructions = smaliMethod.getInstructions(); 244 Assert.assertEquals(14, instructions.size()); 245 } 246 247 private void checkSourcePosition(SmaliMethod smaliMethod, int codeOffset, Opcode opcode) { 248 SourcePosition sourcePosition = smaliMethod.getSourcePositionForCodeOffset(codeOffset); 249 Assert.assertNotNull(sourcePosition); 250 251 SmaliInstruction instruction = (SmaliInstruction)sourcePosition.getElementAt(); 252 Assert.assertEquals(opcode, instruction.getOpcode()); 253 Assert.assertEquals(codeOffset, instruction.getOffset()); 254 } 255 256 public void testGetSourcePositionForCodeOffset() { 257 String text = instructionsTestClass; 258 259 SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text); 260 SmaliClass smaliClass = file.getPsiClass(); 261 SmaliMethod smaliMethod = smaliClass.getMethods()[0]; 262 263 checkSourcePosition(smaliMethod, 0, Opcode.CONST_4); 264 checkSourcePosition(smaliMethod, 2, Opcode.IF_NEZ); 265 checkSourcePosition(smaliMethod, 6, Opcode.MOVE); 266 checkSourcePosition(smaliMethod, 8, Opcode.RETURN); 267 checkSourcePosition(smaliMethod, 10, Opcode.IF_NE); 268 checkSourcePosition(smaliMethod, 14, Opcode.SGET_OBJECT); 269 checkSourcePosition(smaliMethod, 18, Opcode.CONST_4); 270 checkSourcePosition(smaliMethod, 20, Opcode.INVOKE_VIRTUAL); 271 checkSourcePosition(smaliMethod, 26, Opcode.MOVE_RESULT); 272 checkSourcePosition(smaliMethod, 28, Opcode.GOTO); 273 checkSourcePosition(smaliMethod, 30, Opcode.SGET_OBJECT); 274 checkSourcePosition(smaliMethod, 34, Opcode.INVOKE_VIRTUAL); 275 checkSourcePosition(smaliMethod, 40, Opcode.MOVE_RESULT); 276 checkSourcePosition(smaliMethod, 42, Opcode.GOTO); 277 } 278 279 public void testThrowsList() { 280 String text = instructionsTestClass; 281 282 SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text); 283 SmaliClass smaliClass = file.getPsiClass(); 284 SmaliMethod smaliMethod = smaliClass.getMethods()[0]; 285 286 SmaliThrowsList throwsList = smaliMethod.getThrowsList(); 287 Assert.assertNotNull(throwsList); 288 Assert.assertEquals(0, throwsList.getReferencedTypes().length); 289 Assert.assertEquals(0, throwsList.getReferenceElements().length); 290 } 291 292 public void testPrimitiveReturnType() { 293 String text = "" + 294 ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" + 295 ".method blah()I\n" + 296 " .registers 123\n" + 297 " return-void\n" + 298 ".end method"; 299 300 SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", text); 301 SmaliClass smaliClass = file.getPsiClass(); 302 Assert.assertNotNull(smaliClass); 303 SmaliMethod smaliMethod = smaliClass.getMethods()[0]; 304 305 Assert.assertNotNull(smaliMethod.getReturnType()); 306 Assert.assertTrue(smaliMethod.getReturnType().isConvertibleFrom(PsiPrimitiveType.INT)); 307 Assert.assertTrue(smaliMethod.getReturnType().isAssignableFrom(PsiPrimitiveType.INT)); 308 } 309 } 310