001: /* FieldAnalyzer Copyright (C) 1998-2002 Jochen Hoenicke.
002: *
003: * This program is free software; you can redistribute it and/or modify
004: * it under the terms of the GNU Lesser General Public License as published by
005: * the Free Software Foundation; either version 2, or (at your option)
006: * any later version.
007: *
008: * This program is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: * GNU General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public License
014: * along with this program; see the file COPYING.LESSER. If not, write to
015: * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
016: *
017: * $Id: FieldAnalyzer.java.in,v 4.3.2.3 2002/05/28 17:34:03 hoenicke Exp $
018: */
019:
020: package jode.decompiler;
021:
022: import jode.type.Type;
023: import jode.bytecode.FieldInfo;
024: import jode.expr.Expression;
025: import jode.expr.ThisOperator;
026: import jode.expr.LocalLoadOperator;
027: import jode.expr.ConstOperator;
028: import jode.expr.OuterLocalOperator;
029:
030: import java.lang.reflect.Modifier;
031: import java.io.IOException;
032:
033: import java.util.Set;
034:
035: public class FieldAnalyzer implements Analyzer {
036: ClassAnalyzer clazz;
037: ImportHandler imports;
038: int modifiers;
039: Type type;
040: String fieldName;
041: Expression constant;
042: boolean isSynthetic;
043: boolean isDeprecated;
044: boolean analyzedSynthetic = false;
045:
046: public FieldAnalyzer(ClassAnalyzer cla, FieldInfo fd,
047: ImportHandler i) {
048: clazz = cla;
049: imports = i;
050:
051: modifiers = fd.getModifiers();
052: type = Type.tType(fd.getType());
053: fieldName = fd.getName();
054: constant = null;
055: this .isSynthetic = fd.isSynthetic();
056: this .isDeprecated = fd.isDeprecated();
057: if (fd.getConstant() != null) {
058: constant = new ConstOperator(fd.getConstant());
059: constant.setType(type);
060: constant.makeInitializer(type);
061: }
062: }
063:
064: public String getName() {
065: return fieldName;
066: }
067:
068: public Type getType() {
069: return type;
070: }
071:
072: public ClassAnalyzer getClassAnalyzer() {
073: return clazz;
074: }
075:
076: public Expression getConstant() {
077: return constant;
078: }
079:
080: public boolean isSynthetic() {
081: return isSynthetic;
082: }
083:
084: public boolean isFinal() {
085: return Modifier.isFinal(modifiers);
086: }
087:
088: public void analyzedSynthetic() {
089: analyzedSynthetic = true;
090: }
091:
092: public boolean setInitializer(Expression expr) {
093: if (constant != null)
094: return constant.equals(expr);
095:
096: /* This should check for isFinal(), but sadly, sometimes jikes
097: * doesn't make a val$ field final. I don't know when, or why,
098: * so I currently ignore isFinal.
099: */
100: if (isSynthetic
101: && (fieldName.startsWith("this$") || fieldName
102: .startsWith("val$"))) {
103: if (fieldName.startsWith("val$") && fieldName.length() > 4
104: && expr instanceof OuterLocalOperator) {
105: LocalInfo li = ((OuterLocalOperator) expr)
106: .getLocalInfo();
107: li.addHint(fieldName.substring(4), type);
108: }
109: analyzedSynthetic();
110: } else
111: expr.makeInitializer(type);
112:
113: constant = expr;
114: return true;
115: }
116:
117: public boolean setClassConstant(String clazzName) {
118: if (constant != null)
119: return false;
120: if (clazzName.charAt(0) == '[') {
121: if (clazzName.charAt(clazzName.length() - 1) == ';')
122: clazzName = clazzName.substring(0,
123: clazzName.length() - 1);
124:
125: if (fieldName.equals("array"
126: + (clazzName.replace('[', '$').replace('.', '$')))) {
127: analyzedSynthetic();
128: return true;
129: }
130: } else {
131: if (fieldName
132: .equals("class$" + clazzName.replace('.', '$'))
133: || fieldName.equals("class$L"
134: + clazzName.replace('.', '$'))) {
135: analyzedSynthetic();
136: return true;
137: }
138: }
139: return false;
140: }
141:
142: public void analyze() {
143: imports.useType(type);
144: }
145:
146: public void makeDeclaration(Set done) {
147: if (constant != null) {
148: constant.makeDeclaration(done);
149: constant = constant.simplify();
150: }
151: }
152:
153: public boolean skipWriting() {
154: return analyzedSynthetic;
155: }
156:
157: public void dumpSource(TabbedPrintWriter writer) throws IOException {
158: if (isDeprecated) {
159: writer.println("/**");
160: writer.println(" * @deprecated");
161: writer.println(" */");
162: }
163: if (isSynthetic)
164: writer.print("/*synthetic*/ ");
165: int modifiedModifiers = modifiers;
166: /*
167: * JLS-1.0, section 9.3:
168: *
169: * Every field declaration in the body of an interface is
170: * implicitly public, static, and final. It is permitted, but
171: * strongly discouraged as a matter of style, to redundantly
172: * specify any or all of these modifiers for such fields.
173: *
174: * But I personally don't like this style..., move the
175: * comment mark if you think different.
176:
177: if (clazz.getClazz().isInterface())
178: modifiedModifiers &= ~(Modifier.PUBLIC
179: | Modifier.STATIC
180: | Modifier.FINAL);
181: */
182: writer.startOp(writer.NO_PAREN, 0);
183: String modif = Modifier.toString(modifiedModifiers);
184: if (modif.length() > 0)
185: writer.print(modif + " ");
186:
187: writer.printType(type);
188: writer.print(" " + fieldName);
189: if (constant != null) {
190: writer.breakOp();
191: writer.print(" = ");
192: constant.dumpExpression(writer.IMPL_PAREN, writer);
193: }
194: writer.endOp();
195: writer.println(";");
196: }
197:
198: public String toString() {
199: return getClass().getName() + "[" + clazz.getClazz() + "."
200: + getName() + "]";
201: }
202: }
|