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