1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 package proguard.classfile.util;
22 
23 import proguard.classfile.*;
24 import proguard.classfile.attribute.CodeAttribute;
25 import proguard.classfile.attribute.annotation.*;
26 import proguard.classfile.attribute.annotation.visitor.ElementValueVisitor;
27 import proguard.classfile.attribute.visitor.AllAttributeVisitor;
28 import proguard.classfile.constant.*;
29 import proguard.classfile.constant.visitor.ConstantVisitor;
30 import proguard.classfile.instruction.*;
31 import proguard.classfile.instruction.visitor.*;
32 import proguard.classfile.visitor.MemberVisitor;
33 
34 /**
35  * This ElementValueVisitor initializes the field references of the
36  * EnumConstantElementValue instances that it visits.
37  *
38  * @author Eric Lafortune
39  */
40 public class EnumFieldReferenceInitializer
41 extends      SimplifiedVisitor
42 implements   ElementValueVisitor,
43              InstructionVisitor,
44              ConstantVisitor
45 {
46     //*
47     private static final boolean DEBUG = false;
48     /*/
49     private static       boolean DEBUG = true;
50     //*/
51 
52     private MemberVisitor enumFieldFinder = new AllAttributeVisitor(
53                                             new AllInstructionVisitor(this));
54 
55     // Fields acting as parameters and return values for the visitors.
56     private String  enumTypeName;
57     private String  enumConstantName;
58     private boolean enumConstantNameFound;
59     private Clazz   referencedEnumClass;
60     private Field   referencedEnumField;
61 
62 
63     // Implementations for ElementValueVisitor.
64 
visitAnyElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue)65     public void visitAnyElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue) {}
66 
67 
visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)68     public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
69     {
70 
71         if (enumConstantElementValue.referencedClasses != null    &&
72             enumConstantElementValue.referencedClasses.length > 0)
73         {
74             referencedEnumClass = enumConstantElementValue.referencedClasses[0];
75             if (referencedEnumClass != null)
76             {
77                 // Try to find the enum field through the static enum
78                 // initialization code (at least for program classes).
79                 enumTypeName        = enumConstantElementValue.getTypeName(clazz);
80                 enumConstantName    = enumConstantElementValue.getConstantName(clazz);
81                 referencedEnumField = null;
82                 referencedEnumClass.methodAccept(ClassConstants.METHOD_NAME_CLINIT,
83                                                  ClassConstants.METHOD_TYPE_CLINIT,
84                                                  enumFieldFinder);
85 
86                 // Otherwise try to find the enum field through its name.
87                 // The constant name could be different from the field name, if
88                 // the latter is already obfuscated.
89                 if (referencedEnumField == null)
90                 {
91                     referencedEnumField =
92                         referencedEnumClass.findField(enumConstantName,
93                                                       enumTypeName);
94                 }
95 
96                 if (DEBUG)
97                 {
98                     System.out.println("EnumFieldReferenceInitializer: ["+referencedEnumClass.getName()+"."+enumConstantName+"] -> "+referencedEnumField);
99                 }
100 
101                 enumConstantElementValue.referencedField = referencedEnumField;
102             }
103         }
104     }
105 
106 
107     // Implementations for InstructionVisitor.
108 
visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)109     public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
110 
111 
visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)112     public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
113     {
114         switch (constantInstruction.opcode)
115         {
116             case InstructionConstants.OP_LDC:
117             case InstructionConstants.OP_LDC_W:
118             case InstructionConstants.OP_PUTSTATIC:
119                 clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
120                 break;
121         }
122     }
123 
124 
125     // Implementations for ConstantVisitor.
126 
visitAnyConstant(Clazz clazz, Constant constant)127     public void visitAnyConstant(Clazz clazz, Constant constant) {}
128 
129 
visitStringConstant(Clazz clazz, StringConstant stringConstant)130     public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
131     {
132         enumConstantNameFound =
133             enumConstantName.equals(stringConstant.getString(clazz));
134     }
135 
136 
visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)137     public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
138     {
139         if (enumConstantNameFound)
140         {
141             if (enumTypeName.equals(fieldrefConstant.getType(clazz)))
142             {
143                 referencedEnumField = (Field)fieldrefConstant.referencedMember;
144             }
145 
146             enumConstantNameFound = false;
147         }
148     }
149 }