001: /* FieldOperator 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: FieldOperator.java.in,v 4.4.2.2 2002/05/28 17:34:06 hoenicke Exp $
018: */
019:
020: package jode.expr;
021:
022: import jode.type.Type;
023: import jode.type.NullType;
024: import jode.type.ClassInterfacesType;
025: import jode.bytecode.FieldInfo;
026: import jode.bytecode.ClassInfo;
027: import jode.bytecode.Reference;
028: import jode.bytecode.InnerClassInfo;
029: import jode.bytecode.TypeSignature;
030: import jode.decompiler.MethodAnalyzer;
031: import jode.decompiler.ClassAnalyzer;
032: import jode.decompiler.MethodAnalyzer;
033: import jode.decompiler.FieldAnalyzer;
034: import jode.decompiler.Options;
035: import jode.decompiler.TabbedPrintWriter;
036: import jode.decompiler.Scope;
037:
038: import java.lang.reflect.Modifier;
039: import java.util.Collection;
040:
041: /**
042: * This class contains everything shared between PutFieldOperator and
043: * GetFieldOperator
044: */
045: public abstract class FieldOperator extends Operator {
046: MethodAnalyzer methodAnalyzer;
047: boolean staticFlag;
048: Reference ref;
049: Type classType;
050:
051: public FieldOperator(MethodAnalyzer methodAnalyzer,
052: boolean staticFlag, Reference ref) {
053: super (Type.tType(ref.getType()));
054: this .methodAnalyzer = methodAnalyzer;
055: this .staticFlag = staticFlag;
056: this .classType = Type.tType(ref.getClazz());
057: this .ref = ref;
058: if (staticFlag)
059: methodAnalyzer.useType(classType);
060: initOperands(staticFlag ? 0 : 1);
061: }
062:
063: public int getPriority() {
064: return 950;
065: }
066:
067: public void updateSubTypes() {
068: if (!staticFlag)
069: subExpressions[0].setType(Type.tSubType(classType));
070: }
071:
072: public void updateType() {
073: updateParentType(getFieldType());
074: }
075:
076: public boolean isStatic() {
077: return staticFlag;
078: }
079:
080: public ClassInfo getClassInfo() {
081: if (classType instanceof ClassInterfacesType)
082: return ((ClassInterfacesType) classType).getClassInfo();
083: return null;
084: }
085:
086: /**
087: * Returns the field analyzer for the field, if the field is
088: * declared in the same class or some outer class as the method
089: * containing this instruction. Otherwise it returns null.
090: * @return see above.
091: */
092: public FieldAnalyzer getField() {
093: ClassInfo clazz = getClassInfo();
094: if (clazz != null) {
095: ClassAnalyzer ana = methodAnalyzer.getClassAnalyzer();
096: while (true) {
097: if (clazz == ana.getClazz()) {
098: int field = ana.getFieldIndex(ref.getName(), Type
099: .tType(ref.getType()));
100: if (field >= 0)
101: return ana.getField(field);
102: return null;
103: }
104: if (ana.getParent() == null)
105: return null;
106: if (ana.getParent() instanceof MethodAnalyzer)
107: ana = ((MethodAnalyzer) ana.getParent())
108: .getClassAnalyzer();
109: else if (ana.getParent() instanceof ClassAnalyzer)
110: ana = (ClassAnalyzer) ana.getParent();
111: else
112: throw new jode.AssertError("Unknown parent");
113: }
114: }
115: return null;
116: }
117:
118: public String getFieldName() {
119: return ref.getName();
120: }
121:
122: public Type getFieldType() {
123: return Type.tType(ref.getType());
124: }
125:
126: private static FieldInfo getFieldInfo(ClassInfo clazz, String name,
127: String type) {
128: while (clazz != null) {
129: FieldInfo field = clazz.findField(name, type);
130: if (field != null)
131: return field;
132:
133: ClassInfo[] ifaces = clazz.getInterfaces();
134: for (int i = 0; i < ifaces.length; i++) {
135: field = getFieldInfo(ifaces[i], name, type);
136: if (field != null)
137: return field;
138: }
139:
140: clazz = clazz.getSuperclass();
141: }
142: return null;
143: }
144:
145: public FieldInfo getFieldInfo() {
146: ClassInfo clazz;
147: if (ref.getClazz().charAt(0) == '[')
148: clazz = ClassInfo.javaLangObject;
149: else
150: clazz = TypeSignature.getClassInfo(ref.getClazz());
151: return getFieldInfo(clazz, ref.getName(), ref.getType());
152: }
153:
154: public boolean needsCast(Type type) {
155: if (type instanceof NullType)
156: return true;
157: if (!(type instanceof ClassInterfacesType && classType instanceof ClassInterfacesType))
158: return false;
159:
160: ClassInfo clazz = ((ClassInterfacesType) classType)
161: .getClassInfo();
162: ClassInfo parClazz = ((ClassInterfacesType) type)
163: .getClassInfo();
164: FieldInfo field = clazz.findField(ref.getName(), ref.getType());
165:
166: find_field: while (field == null) {
167: ClassInfo ifaces[] = clazz.getInterfaces();
168: for (int i = 0; i < ifaces.length; i++) {
169: field = ifaces[i].findField(ref.getName(), ref
170: .getType());
171: if (field != null)
172: break find_field;
173: }
174: clazz = clazz.getSuperclass();
175: if (clazz == null)
176: /* Weird, field not existing? */
177: return false;
178: field = clazz.findField(ref.getName(), ref.getType());
179: }
180: if (Modifier.isPrivate(field.getModifiers()))
181: return parClazz != clazz;
182: else if ((field.getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) == 0) {
183: /* Field is protected. We need a cast if parClazz is in
184: * other package than clazz.
185: */
186: int lastDot = clazz.getName().lastIndexOf('.');
187: if (lastDot == -1
188: || lastDot != parClazz.getName().lastIndexOf('.')
189: || !(parClazz.getName().startsWith(clazz.getName()
190: .substring(0, lastDot))))
191: return true;
192: }
193:
194: while (clazz != parClazz && clazz != null) {
195: FieldInfo[] fields = parClazz.getFields();
196: for (int i = 0; i < fields.length; i++) {
197: if (fields[i].getName().equals(ref.getName()))
198: return true;
199: }
200: parClazz = parClazz.getSuperclass();
201: }
202: return false;
203: }
204:
205: public InnerClassInfo getOuterClassInfo(ClassInfo ci) {
206: if (ci != null) {
207: InnerClassInfo[] outers = ci.getOuterClasses();
208: if (outers != null)
209: return outers[0];
210: }
211: return null;
212: }
213:
214: /**
215: * We add the named method scoped classes to the declarables.
216: */
217: public void fillDeclarables(Collection used) {
218: ClassInfo clazz = getClassInfo();
219: InnerClassInfo outer = getOuterClassInfo(clazz);
220: ClassAnalyzer clazzAna = methodAnalyzer.getClassAnalyzer(clazz);
221:
222: if ((Options.options & Options.OPTION_ANON) != 0
223: && outer != null && outer.outer == null
224: && outer.name != null && clazzAna != null
225: && clazzAna.getParent() == methodAnalyzer) {
226:
227: /* This is a named method scope class, declare it.
228: * But first declare all method scoped classes,
229: * that are used inside; order does matter.
230: */
231: clazzAna.fillDeclarables(used);
232: used.add(clazzAna);
233: }
234: super .fillDeclarables(used);
235: }
236:
237: public void dumpExpression(TabbedPrintWriter writer)
238: throws java.io.IOException {
239: boolean opIsThis = !staticFlag
240: && subExpressions[0] instanceof ThisOperator;
241: String fieldName = ref.getName();
242: if (staticFlag) {
243: if (!classType.equals(Type
244: .tClass(methodAnalyzer.getClazz()))
245: || methodAnalyzer.findLocal(fieldName) != null) {
246: writer.printType(classType);
247: writer.breakOp();
248: writer.print(".");
249: }
250: writer.print(fieldName);
251: } else if (needsCast(subExpressions[0].getType().getCanonic())) {
252: writer.print("(");
253: writer.startOp(writer.EXPL_PAREN, 1);
254: writer.print("(");
255: writer.printType(classType);
256: writer.print(") ");
257: writer.breakOp();
258: subExpressions[0].dumpExpression(writer, 700);
259: writer.endOp();
260: writer.print(")");
261: writer.breakOp();
262: writer.print(".");
263: writer.print(fieldName);
264: } else {
265: if (opIsThis) {
266: ThisOperator this Op = (ThisOperator) subExpressions[0];
267: Scope scope = writer.getScope(this Op.getClassInfo(),
268: Scope.CLASSSCOPE);
269:
270: if (scope == null
271: || writer.conflicts(fieldName, scope,
272: Scope.FIELDNAME)) {
273: this Op.dumpExpression(writer, 950);
274: writer.breakOp();
275: writer.print(".");
276: } else if (writer.conflicts(fieldName, scope,
277: Scope.AMBIGUOUSNAME)
278: || (/* This is a inherited field conflicting
279: * with a field name in some outer class.
280: */
281: getField() == null && writer
282: .conflicts(fieldName, null,
283: Scope.NOSUPERFIELDNAME))) {
284: this Op.dumpExpression(writer, 950);
285: writer.breakOp();
286: writer.print(".");
287: }
288: } else {
289: subExpressions[0].dumpExpression(writer, 950);
290: writer.breakOp();
291: writer.print(".");
292: }
293: writer.print(fieldName);
294: }
295: }
296: }
|