136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com/* 236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * [The "BSD licence"] 300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * Copyright (c) 2010 Ben Gruver (JesusFreke) 436836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * All rights reserved. 536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * 636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * Redistribution and use in source and binary forms, with or without 736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * modification, are permitted provided that the following conditions 836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * are met: 936836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * 1. Redistributions of source code must retain the above copyright 1036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * notice, this list of conditions and the following disclaimer. 1136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * 2. Redistributions in binary form must reproduce the above copyright 1236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * notice, this list of conditions and the following disclaimer in the 1336836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * documentation and/or other materials provided with the distribution. 1436836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * 3. The name of the author may not be used to endorse or promote products 1536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * derived from this software without specific prior written permission. 1636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * 1736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1936836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2136836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2336836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2436836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com */ 2836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 296ef13753e78bb7abc7e7683d5e533c3395d4a9b6JesusFreke@JesusFreke.compackage org.jf.baksmali.Adaptors; 3036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 315a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruverimport org.jf.baksmali.BaksmaliOptions; 324e3124206a058ceb1be7b893d83b9201744db380Ben Gruverimport org.jf.dexlib2.AccessFlags; 338979759556f31af324257fec9ebd47d3444cede0Ben Gruverimport org.jf.dexlib2.dexbacked.DexBackedClassDef; 344f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruverimport org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex; 358b1508ee58f4918835d8c01483725b508d21be29Ben Gruverimport org.jf.dexlib2.iface.*; 3660631f684fe900940670409c46b7752c5713ae51Ben Gruverimport org.jf.dexlib2.iface.instruction.Instruction; 3760631f684fe900940670409c46b7752c5713ae51Ben Gruverimport org.jf.dexlib2.iface.instruction.formats.Instruction21c; 3860631f684fe900940670409c46b7752c5713ae51Ben Gruverimport org.jf.dexlib2.iface.reference.FieldReference; 3960631f684fe900940670409c46b7752c5713ae51Ben Gruverimport org.jf.dexlib2.util.ReferenceUtil; 404b72225e9d81201838f387171a68a832486903f9JesusFreke@JesusFreke.comimport org.jf.util.IndentingWriter; 41c6e54994a7be1bdbdd751ede7c96e07e7fb1c84fBen Gruverimport org.jf.util.StringUtils; 4236836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 438b1508ee58f4918835d8c01483725b508d21be29Ben Gruverimport javax.annotation.Nonnull; 446eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.comimport java.io.IOException; 458979759556f31af324257fec9ebd47d3444cede0Ben Gruverimport java.util.*; 4636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 4736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.compublic class ClassDefinition { 485a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver @Nonnull public final BaksmaliOptions options; 49754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver @Nonnull public final ClassDef classDef; 5060631f684fe900940670409c46b7752c5713ae51Ben Gruver @Nonnull private final HashSet<String> fieldsSetInStaticConstructor; 51090e553f34a176bc558f0d70392181c0fbd83fe8JesusFreke@JesusFreke.com 52c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com protected boolean validationErrors; 53c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com 545a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver public ClassDefinition(@Nonnull BaksmaliOptions options, @Nonnull ClassDef classDef) { 5593aa50139c4641d931b05608f73af8879c0de1c2Ben Gruver this.options = options; 568b1508ee58f4918835d8c01483725b508d21be29Ben Gruver this.classDef = classDef; 575a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver fieldsSetInStaticConstructor = findFieldsSetInStaticConstructor(classDef); 58fa07a1972e3cff56d5615c18a8797ff58fc9f739JesusFreke@JesusFreke.com } 59fa07a1972e3cff56d5615c18a8797ff58fc9f739JesusFreke@JesusFreke.com 60c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com public boolean hadValidationErrors() { 61c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com return validationErrors; 62c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com } 63c9be5e13034da9827b5598a6257376164745b827JesusFreke@JesusFreke.com 6460631f684fe900940670409c46b7752c5713ae51Ben Gruver @Nonnull 655a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver private static HashSet<String> findFieldsSetInStaticConstructor(@Nonnull ClassDef classDef) { 668b1508ee58f4918835d8c01483725b508d21be29Ben Gruver HashSet<String> fieldsSetInStaticConstructor = new HashSet<String>(); 678b1508ee58f4918835d8c01483725b508d21be29Ben Gruver 680a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver for (Method method: classDef.getDirectMethods()) { 698b1508ee58f4918835d8c01483725b508d21be29Ben Gruver if (method.getName().equals("<clinit>")) { 708b1508ee58f4918835d8c01483725b508d21be29Ben Gruver MethodImplementation impl = method.getImplementation(); 718b1508ee58f4918835d8c01483725b508d21be29Ben Gruver if (impl != null) { 728b1508ee58f4918835d8c01483725b508d21be29Ben Gruver for (Instruction instruction: impl.getInstructions()) { 738b1508ee58f4918835d8c01483725b508d21be29Ben Gruver switch (instruction.getOpcode()) { 748b1508ee58f4918835d8c01483725b508d21be29Ben Gruver case SPUT: 758b1508ee58f4918835d8c01483725b508d21be29Ben Gruver case SPUT_BOOLEAN: 768b1508ee58f4918835d8c01483725b508d21be29Ben Gruver case SPUT_BYTE: 778b1508ee58f4918835d8c01483725b508d21be29Ben Gruver case SPUT_CHAR: 788b1508ee58f4918835d8c01483725b508d21be29Ben Gruver case SPUT_OBJECT: 798b1508ee58f4918835d8c01483725b508d21be29Ben Gruver case SPUT_SHORT: 808b1508ee58f4918835d8c01483725b508d21be29Ben Gruver case SPUT_WIDE: { 818b1508ee58f4918835d8c01483725b508d21be29Ben Gruver Instruction21c ins = (Instruction21c)instruction; 824f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver FieldReference fieldRef = null; 834f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver try { 844f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver fieldRef = (FieldReference)ins.getReference(); 854f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver } catch (InvalidItemIndex ex) { 864f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver // just ignore it for now. We'll deal with it later, when processing the instructions 874f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver // themselves 884f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver } 894f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver if (fieldRef != null && 904f2620415d505a35d2d14b866cde10a54b1b7c8cBen Gruver fieldRef.getDefiningClass().equals((classDef.getType()))) { 9160631f684fe900940670409c46b7752c5713ae51Ben Gruver fieldsSetInStaticConstructor.add(ReferenceUtil.getShortFieldDescriptor(fieldRef)); 928b1508ee58f4918835d8c01483725b508d21be29Ben Gruver } 938b1508ee58f4918835d8c01483725b508d21be29Ben Gruver break; 948b1508ee58f4918835d8c01483725b508d21be29Ben Gruver } 95d863324ffb94f70dbb59f1dab4dabd2ce1b39cfdBen Gruver } 96fda2e631ac0b1ca092973b7fff4b2f38d2c23437JesusFreke@JesusFreke.com } 97fda2e631ac0b1ca092973b7fff4b2f38d2c23437JesusFreke@JesusFreke.com } 98090e553f34a176bc558f0d70392181c0fbd83fe8JesusFreke@JesusFreke.com } 99090e553f34a176bc558f0d70392181c0fbd83fe8JesusFreke@JesusFreke.com } 1008b1508ee58f4918835d8c01483725b508d21be29Ben Gruver return fieldsSetInStaticConstructor; 10160631f684fe900940670409c46b7752c5713ae51Ben Gruver } 102090e553f34a176bc558f0d70392181c0fbd83fe8JesusFreke@JesusFreke.com 1030b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com public void writeTo(IndentingWriter writer) throws IOException { 1046eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com writeClass(writer); 1056eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com writeSuper(writer); 1066eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com writeSourceFile(writer); 1076eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com writeInterfaces(writer); 1086eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com writeAnnotations(writer); 1098979759556f31af324257fec9ebd47d3444cede0Ben Gruver Set<String> staticFields = writeStaticFields(writer); 1108979759556f31af324257fec9ebd47d3444cede0Ben Gruver writeInstanceFields(writer, staticFields); 1118979759556f31af324257fec9ebd47d3444cede0Ben Gruver Set<String> directMethods = writeDirectMethods(writer); 1128979759556f31af324257fec9ebd47d3444cede0Ben Gruver writeVirtualMethods(writer, directMethods); 1136eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com } 11436836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 1150b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com private void writeClass(IndentingWriter writer) throws IOException { 1166eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com writer.write(".class "); 1176eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com writeAccessFlags(writer); 118db389aa3a1d898d3a452f3f0b2220b334b23cb4cBen Gruver writer.write(classDef.getType()); 1190b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com writer.write('\n'); 1206eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com } 1216eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com 1220b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com private void writeAccessFlags(IndentingWriter writer) throws IOException { 1238b1508ee58f4918835d8c01483725b508d21be29Ben Gruver for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForClass(classDef.getAccessFlags())) { 1246eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com writer.write(accessFlag.toString()); 1256eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com writer.write(' '); 12636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com } 12736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com } 12836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 1290b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com private void writeSuper(IndentingWriter writer) throws IOException { 1308b1508ee58f4918835d8c01483725b508d21be29Ben Gruver String superClass = classDef.getSuperclass(); 13169c3abb483d8a6329f38fb3c30afa3d138d3adc0JesusFreke@JesusFreke.com if (superClass != null) { 1326eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com writer.write(".super "); 1338b1508ee58f4918835d8c01483725b508d21be29Ben Gruver writer.write(superClass); 1340b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com writer.write('\n'); 13569c3abb483d8a6329f38fb3c30afa3d138d3adc0JesusFreke@JesusFreke.com } 136b6547e8fd56242dde90275d9b0ba6f3639083a61JesusFreke@JesusFreke.com } 137b6547e8fd56242dde90275d9b0ba6f3639083a61JesusFreke@JesusFreke.com 1380b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com private void writeSourceFile(IndentingWriter writer) throws IOException { 1398b1508ee58f4918835d8c01483725b508d21be29Ben Gruver String sourceFile = classDef.getSourceFile(); 1406eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com if (sourceFile != null) { 1416eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com writer.write(".source \""); 1428b1508ee58f4918835d8c01483725b508d21be29Ben Gruver StringUtils.writeEscapedString(writer, sourceFile); 1430b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com writer.write("\"\n"); 144630a384c6bb90358cc64c7fcbec6884fdac8f50dJesusFreke@JesusFreke.com } 14536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com } 14636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 1470b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com private void writeInterfaces(IndentingWriter writer) throws IOException { 148c456c55c40d0731edb9913fae73f16b9d94ac45bAlex Light List<String> interfaces = classDef.getInterfaces(); 149e77b5a7354f99f417f8d80df629d528e02ef5f9cBen Gruver 1508b1508ee58f4918835d8c01483725b508d21be29Ben Gruver if (interfaces.size() != 0) { 1510b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com writer.write('\n'); 1528b1508ee58f4918835d8c01483725b508d21be29Ben Gruver writer.write("# interfaces\n"); 1538b1508ee58f4918835d8c01483725b508d21be29Ben Gruver for (String interfaceName: interfaces) { 1548b1508ee58f4918835d8c01483725b508d21be29Ben Gruver writer.write(".implements "); 1558b1508ee58f4918835d8c01483725b508d21be29Ben Gruver writer.write(interfaceName); 1560b2f7d6a57e90424b3ee455c041aab3996c05f2cJesusFreke@JesusFreke.com writer.write('\n'); 1576eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com } 15836836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com } 15936836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com } 16036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 1618b1508ee58f4918835d8c01483725b508d21be29Ben Gruver private void writeAnnotations(IndentingWriter writer) throws IOException { 162c6e54994a7be1bdbdd751ede7c96e07e7fb1c84fBen Gruver Collection<? extends Annotation> classAnnotations = classDef.getAnnotations(); 1638b1508ee58f4918835d8c01483725b508d21be29Ben Gruver if (classAnnotations.size() != 0) { 1648b1508ee58f4918835d8c01483725b508d21be29Ben Gruver writer.write("\n\n"); 1658b1508ee58f4918835d8c01483725b508d21be29Ben Gruver writer.write("# annotations\n"); 166d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver 167d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver String containingClass = null; 1685a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver if (options.implicitReferences) { 169d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver containingClass = classDef.getType(); 170d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver } 171d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver 172d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver AnnotationFormatter.writeTo(writer, classAnnotations, containingClass); 1736eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com } 1748b1508ee58f4918835d8c01483725b508d21be29Ben Gruver } 17536836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 1768979759556f31af324257fec9ebd47d3444cede0Ben Gruver private Set<String> writeStaticFields(IndentingWriter writer) throws IOException { 1774e3124206a058ceb1be7b893d83b9201744db380Ben Gruver boolean wroteHeader = false; 1788979759556f31af324257fec9ebd47d3444cede0Ben Gruver Set<String> writtenFields = new HashSet<String>(); 1798979759556f31af324257fec9ebd47d3444cede0Ben Gruver 1808979759556f31af324257fec9ebd47d3444cede0Ben Gruver Iterable<? extends Field> staticFields; 1818979759556f31af324257fec9ebd47d3444cede0Ben Gruver if (classDef instanceof DexBackedClassDef) { 1828979759556f31af324257fec9ebd47d3444cede0Ben Gruver staticFields = ((DexBackedClassDef)classDef).getStaticFields(false); 1838979759556f31af324257fec9ebd47d3444cede0Ben Gruver } else { 1848979759556f31af324257fec9ebd47d3444cede0Ben Gruver staticFields = classDef.getStaticFields(); 1858979759556f31af324257fec9ebd47d3444cede0Ben Gruver } 1868979759556f31af324257fec9ebd47d3444cede0Ben Gruver 1878979759556f31af324257fec9ebd47d3444cede0Ben Gruver for (Field field: staticFields) { 1880a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver if (!wroteHeader) { 1890a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver writer.write("\n\n"); 1900a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver writer.write("# static fields"); 1910a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver wroteHeader = true; 1920a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver } 1930a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver writer.write('\n'); 1944e3124206a058ceb1be7b893d83b9201744db380Ben Gruver 1958979759556f31af324257fec9ebd47d3444cede0Ben Gruver boolean setInStaticConstructor; 1968979759556f31af324257fec9ebd47d3444cede0Ben Gruver IndentingWriter fieldWriter = writer; 1978979759556f31af324257fec9ebd47d3444cede0Ben Gruver String fieldString = ReferenceUtil.getShortFieldDescriptor(field); 1988979759556f31af324257fec9ebd47d3444cede0Ben Gruver if (!writtenFields.add(fieldString)) { 1998979759556f31af324257fec9ebd47d3444cede0Ben Gruver writer.write("# duplicate field ignored\n"); 2008979759556f31af324257fec9ebd47d3444cede0Ben Gruver fieldWriter = new CommentingIndentingWriter(writer); 2018979759556f31af324257fec9ebd47d3444cede0Ben Gruver System.err.println(String.format("Ignoring duplicate field: %s->%s", classDef.getType(), fieldString)); 2028979759556f31af324257fec9ebd47d3444cede0Ben Gruver setInStaticConstructor = false; 2038979759556f31af324257fec9ebd47d3444cede0Ben Gruver } else { 2048979759556f31af324257fec9ebd47d3444cede0Ben Gruver setInStaticConstructor = fieldsSetInStaticConstructor.contains(fieldString); 2058979759556f31af324257fec9ebd47d3444cede0Ben Gruver } 206d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver FieldDefinition.writeTo(options, fieldWriter, field, setInStaticConstructor); 2074e3124206a058ceb1be7b893d83b9201744db380Ben Gruver } 2088979759556f31af324257fec9ebd47d3444cede0Ben Gruver return writtenFields; 2094e3124206a058ceb1be7b893d83b9201744db380Ben Gruver } 2104e3124206a058ceb1be7b893d83b9201744db380Ben Gruver 2118979759556f31af324257fec9ebd47d3444cede0Ben Gruver private void writeInstanceFields(IndentingWriter writer, Set<String> staticFields) throws IOException { 2124e3124206a058ceb1be7b893d83b9201744db380Ben Gruver boolean wroteHeader = false; 2138979759556f31af324257fec9ebd47d3444cede0Ben Gruver Set<String> writtenFields = new HashSet<String>(); 2148979759556f31af324257fec9ebd47d3444cede0Ben Gruver 2158979759556f31af324257fec9ebd47d3444cede0Ben Gruver Iterable<? extends Field> instanceFields; 2168979759556f31af324257fec9ebd47d3444cede0Ben Gruver if (classDef instanceof DexBackedClassDef) { 2178979759556f31af324257fec9ebd47d3444cede0Ben Gruver instanceFields = ((DexBackedClassDef)classDef).getInstanceFields(false); 2188979759556f31af324257fec9ebd47d3444cede0Ben Gruver } else { 2198979759556f31af324257fec9ebd47d3444cede0Ben Gruver instanceFields = classDef.getInstanceFields(); 2208979759556f31af324257fec9ebd47d3444cede0Ben Gruver } 2218979759556f31af324257fec9ebd47d3444cede0Ben Gruver 2228979759556f31af324257fec9ebd47d3444cede0Ben Gruver for (Field field: instanceFields) { 2230a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver if (!wroteHeader) { 2240a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver writer.write("\n\n"); 2250a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver writer.write("# instance fields"); 2260a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver wroteHeader = true; 2274e3124206a058ceb1be7b893d83b9201744db380Ben Gruver } 2280a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver writer.write('\n'); 2290a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver 2308979759556f31af324257fec9ebd47d3444cede0Ben Gruver IndentingWriter fieldWriter = writer; 2318979759556f31af324257fec9ebd47d3444cede0Ben Gruver String fieldString = ReferenceUtil.getShortFieldDescriptor(field); 2328979759556f31af324257fec9ebd47d3444cede0Ben Gruver if (!writtenFields.add(fieldString)) { 2338979759556f31af324257fec9ebd47d3444cede0Ben Gruver writer.write("# duplicate field ignored\n"); 2348979759556f31af324257fec9ebd47d3444cede0Ben Gruver fieldWriter = new CommentingIndentingWriter(writer); 2358979759556f31af324257fec9ebd47d3444cede0Ben Gruver System.err.println(String.format("Ignoring duplicate field: %s->%s", classDef.getType(), fieldString)); 2368979759556f31af324257fec9ebd47d3444cede0Ben Gruver } else if (staticFields.contains(fieldString)) { 2378979759556f31af324257fec9ebd47d3444cede0Ben Gruver System.err.println(String.format("Duplicate static+instance field found: %s->%s", 2388979759556f31af324257fec9ebd47d3444cede0Ben Gruver classDef.getType(), fieldString)); 2398979759556f31af324257fec9ebd47d3444cede0Ben Gruver System.err.println("You will need to rename one of these fields, including all references."); 2408979759556f31af324257fec9ebd47d3444cede0Ben Gruver 2418979759556f31af324257fec9ebd47d3444cede0Ben Gruver writer.write("# There is both a static and instance field with this signature.\n" + 2428979759556f31af324257fec9ebd47d3444cede0Ben Gruver "# You will need to rename one of these fields, including all references.\n"); 2438979759556f31af324257fec9ebd47d3444cede0Ben Gruver } 244d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver FieldDefinition.writeTo(options, fieldWriter, field, false); 2456eae34831fee1f116f3a453bdc5e143d68e05e03JesusFreke@JesusFreke.com } 24636836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com } 24736836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com 2488979759556f31af324257fec9ebd47d3444cede0Ben Gruver private Set<String> writeDirectMethods(IndentingWriter writer) throws IOException { 249754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver boolean wroteHeader = false; 2508979759556f31af324257fec9ebd47d3444cede0Ben Gruver Set<String> writtenMethods = new HashSet<String>(); 2518979759556f31af324257fec9ebd47d3444cede0Ben Gruver 2528979759556f31af324257fec9ebd47d3444cede0Ben Gruver Iterable<? extends Method> directMethods; 2538979759556f31af324257fec9ebd47d3444cede0Ben Gruver if (classDef instanceof DexBackedClassDef) { 2548979759556f31af324257fec9ebd47d3444cede0Ben Gruver directMethods = ((DexBackedClassDef)classDef).getDirectMethods(false); 2558979759556f31af324257fec9ebd47d3444cede0Ben Gruver } else { 2568979759556f31af324257fec9ebd47d3444cede0Ben Gruver directMethods = classDef.getDirectMethods(); 2578979759556f31af324257fec9ebd47d3444cede0Ben Gruver } 2588979759556f31af324257fec9ebd47d3444cede0Ben Gruver 2598979759556f31af324257fec9ebd47d3444cede0Ben Gruver for (Method method: directMethods) { 2600a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver if (!wroteHeader) { 2610a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver writer.write("\n\n"); 2620a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver writer.write("# direct methods"); 2630a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver wroteHeader = true; 2640a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver } 2650a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver writer.write('\n'); 2668979759556f31af324257fec9ebd47d3444cede0Ben Gruver 2670a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver // TODO: check for method validation errors 268d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver String methodString = ReferenceUtil.getMethodDescriptor(method, true); 2698979759556f31af324257fec9ebd47d3444cede0Ben Gruver 2708979759556f31af324257fec9ebd47d3444cede0Ben Gruver IndentingWriter methodWriter = writer; 2718979759556f31af324257fec9ebd47d3444cede0Ben Gruver if (!writtenMethods.add(methodString)) { 2728979759556f31af324257fec9ebd47d3444cede0Ben Gruver writer.write("# duplicate method ignored\n"); 2738979759556f31af324257fec9ebd47d3444cede0Ben Gruver methodWriter = new CommentingIndentingWriter(writer); 2748979759556f31af324257fec9ebd47d3444cede0Ben Gruver } 2750a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver 2760a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver MethodImplementation methodImpl = method.getImplementation(); 2770a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver if (methodImpl == null) { 27844c5c07c5724e9448d803b3585c9ef47117c3d4eBen Gruver MethodDefinition.writeEmptyMethodTo(methodWriter, method, options); 2790a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver } else { 2800a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver MethodDefinition methodDefinition = new MethodDefinition(this, method, methodImpl); 2818979759556f31af324257fec9ebd47d3444cede0Ben Gruver methodDefinition.writeTo(methodWriter); 282754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver } 283754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver } 2848979759556f31af324257fec9ebd47d3444cede0Ben Gruver return writtenMethods; 285754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver } 286754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver 2878979759556f31af324257fec9ebd47d3444cede0Ben Gruver private void writeVirtualMethods(IndentingWriter writer, Set<String> directMethods) throws IOException { 288754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver boolean wroteHeader = false; 2898979759556f31af324257fec9ebd47d3444cede0Ben Gruver Set<String> writtenMethods = new HashSet<String>(); 2908979759556f31af324257fec9ebd47d3444cede0Ben Gruver 2918979759556f31af324257fec9ebd47d3444cede0Ben Gruver Iterable<? extends Method> virtualMethods; 2928979759556f31af324257fec9ebd47d3444cede0Ben Gruver if (classDef instanceof DexBackedClassDef) { 2938979759556f31af324257fec9ebd47d3444cede0Ben Gruver virtualMethods = ((DexBackedClassDef)classDef).getVirtualMethods(false); 2948979759556f31af324257fec9ebd47d3444cede0Ben Gruver } else { 2958979759556f31af324257fec9ebd47d3444cede0Ben Gruver virtualMethods = classDef.getVirtualMethods(); 2968979759556f31af324257fec9ebd47d3444cede0Ben Gruver } 2978979759556f31af324257fec9ebd47d3444cede0Ben Gruver 2988979759556f31af324257fec9ebd47d3444cede0Ben Gruver for (Method method: virtualMethods) { 2990a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver if (!wroteHeader) { 3000a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver writer.write("\n\n"); 3010a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver writer.write("# virtual methods"); 3020a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver wroteHeader = true; 3030a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver } 3040a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver writer.write('\n'); 3058979759556f31af324257fec9ebd47d3444cede0Ben Gruver 3060a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver // TODO: check for method validation errors 307d33fd6773cc3e527b4dbb79245796d556b7facdeBen Gruver String methodString = ReferenceUtil.getMethodDescriptor(method, true); 3088979759556f31af324257fec9ebd47d3444cede0Ben Gruver 3098979759556f31af324257fec9ebd47d3444cede0Ben Gruver IndentingWriter methodWriter = writer; 3108979759556f31af324257fec9ebd47d3444cede0Ben Gruver if (!writtenMethods.add(methodString)) { 3118979759556f31af324257fec9ebd47d3444cede0Ben Gruver writer.write("# duplicate method ignored\n"); 3128979759556f31af324257fec9ebd47d3444cede0Ben Gruver methodWriter = new CommentingIndentingWriter(writer); 3138979759556f31af324257fec9ebd47d3444cede0Ben Gruver } else if (directMethods.contains(methodString)) { 3148979759556f31af324257fec9ebd47d3444cede0Ben Gruver writer.write("# There is both a direct and virtual method with this signature.\n" + 3158979759556f31af324257fec9ebd47d3444cede0Ben Gruver "# You will need to rename one of these methods, including all references.\n"); 3168979759556f31af324257fec9ebd47d3444cede0Ben Gruver System.err.println(String.format("Duplicate direct+virtual method found: %s->%s", 3178979759556f31af324257fec9ebd47d3444cede0Ben Gruver classDef.getType(), methodString)); 3188979759556f31af324257fec9ebd47d3444cede0Ben Gruver System.err.println("You will need to rename one of these methods, including all references."); 3198979759556f31af324257fec9ebd47d3444cede0Ben Gruver } 3200a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver 3210a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver MethodImplementation methodImpl = method.getImplementation(); 3220a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver if (methodImpl == null) { 32344c5c07c5724e9448d803b3585c9ef47117c3d4eBen Gruver MethodDefinition.writeEmptyMethodTo(methodWriter, method, options); 3240a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver } else { 3250a18ea7f8b62e51945a79ac37802133a24c9a742Ben Gruver MethodDefinition methodDefinition = new MethodDefinition(this, method, methodImpl); 3268979759556f31af324257fec9ebd47d3444cede0Ben Gruver methodDefinition.writeTo(methodWriter); 327754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver } 328754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver } 329754b3c4dc009b7a02e39001560c3f0fd6a7cc2c0Ben Gruver } 33036836121d7ecf72050d3ef065b7ab5fa86548319JesusFreke@JesusFreke.com} 331