001: // This file is part of KeY - Integrated Deductive Software Design
002: // Copyright (C) 2001-2007 Universitaet Karlsruhe, Germany
003: // Universitaet Koblenz-Landau, Germany
004: // Chalmers University of Technology, Sweden
005: //
006: // The KeY system is protected by the GNU General Public License.
007: // See LICENSE.TXT for details.
008: //
009: // This file is part of KeY - Integrated Deductive Software Design
010: // Copyright (C) 2001-2004 Universitaet Karlsruhe, Germany
011: // Universitaet Koblenz-Landau, Germany
012: // Chalmers University of Technology, Sweden
013: //
014: // The KeY system is protected by the GNU General Public License.
015: // See LICENSE.TXT for details.
016: package de.uka.ilkd.key.java.recoderext;
017:
018: import java.util.HashMap;
019:
020: import recoder.CrossReferenceServiceConfiguration;
021: import recoder.abstraction.ClassType;
022: import recoder.abstraction.Field;
023: import recoder.java.CompilationUnit;
024: import recoder.java.Identifier;
025: import recoder.java.StatementBlock;
026: import recoder.java.declaration.ClassDeclaration;
027: import recoder.java.declaration.FieldDeclaration;
028: import recoder.java.declaration.MethodDeclaration;
029: import recoder.java.declaration.TypeDeclaration;
030: import recoder.java.declaration.modifier.Private;
031: import recoder.java.declaration.modifier.Protected;
032: import recoder.java.reference.MethodReference;
033: import recoder.java.reference.ReferencePrefix;
034: import recoder.java.reference.SuperReference;
035: import recoder.java.reference.ThisReference;
036: import recoder.kit.ProblemReport;
037: import recoder.list.*;
038: import de.uka.ilkd.key.util.Debug;
039:
040: /**
041: * Creates the preparation method for pre-initilizing the object fields
042: * with their default settings.
043: */
044: public class PrepareObjectBuilder extends RecoderModelTransformer {
045:
046: public static final String IMPLICIT_OBJECT_PREPARE = "<prepare>";
047:
048: public static final String IMPLICIT_OBJECT_PREPARE_ENTER = "<prepareEnter>";
049:
050: private HashMap class2fields;
051:
052: private ClassType javaLangObject;
053:
054: public PrepareObjectBuilder(
055: CrossReferenceServiceConfiguration services,
056: CompilationUnitMutableList units) {
057: super (services, units);
058: class2fields = new HashMap(units.size());
059: }
060:
061: /**
062: * returns all fields of the class cd in source code order. The
063: * method is a work around for a bug in recoder 0.70 as there source
064: * code order is not respected. May become obsolete if newer recoder
065: * versions are used.
066: */
067: private FieldList getFields(ClassDeclaration cd) {
068: FieldMutableList result = new FieldArrayList(cd.getChildCount());
069: for (int i = 0; i < cd.getChildCount(); i++) {
070: if (cd.getChildAt(i) instanceof FieldDeclaration) {
071: FieldSpecificationList fields = ((FieldDeclaration) cd
072: .getChildAt(i)).getFieldSpecifications();
073: for (int j = 0; j < fields.size(); j++) {
074: result.add(fields.getFieldSpecification(j));
075: }
076: }
077: }
078: return result;
079: }
080:
081: /**
082: * Two-pass transformation have to be strictly divided up into two
083: * parts. the first part analyzes the model and collects all
084: * necessary information. In this case all class declarations are
085: * examined and for each found field a copy assignment to its
086: * default value is added to the map "class2fields".
087: * All actions, which may cause a recoder model update have to be
088: * done here.
089: * @return status report if analyze encountered problems or not
090: */
091: public ProblemReport analyze() {
092: javaLangObject = services.getNameInfo().getJavaLangObject();
093: if (!(javaLangObject instanceof ClassDeclaration)) {
094: Debug
095: .fail("Could not find class java.lang.Object or only as bytecode");
096: }
097: for (int unit = 0; unit < units.size(); unit++) {
098: CompilationUnit cu = units.getCompilationUnit(unit);
099: int typeCount = cu.getTypeDeclarationCount();
100:
101: for (int i = 0; i < typeCount; i++) {
102: if (cu.getTypeDeclarationAt(i) instanceof ClassDeclaration) {
103: ClassDeclaration cd = (ClassDeclaration) cu
104: .getTypeDeclarationAt(i);
105: if (cd.getTypeDeclarationCount() > 0) {
106: Debug
107: .out("prepare object builder: Inner Class detected."
108: + "No class preparation method will be built"
109: + "for inner classes of "
110: + cd.getIdentifier());
111: }
112:
113: // collect fields for transformation phase
114:
115: class2fields
116: .put(cd, defaultSettings(getFields(cd)));
117: //would be nice but in Recoder0.70 the source order is not respected
118: // class2fields.put(cd, defaultSettings(cd.getFields()));
119: }
120: }
121: }
122: setProblemReport(NO_PROBLEM);
123: return NO_PROBLEM;
124: }
125:
126: /**
127: * creates the assignments of the field variables to their default values
128: * and inserts them to the given body list
129: * @return the same list body that has been handed over as parameter
130: */
131: private StatementMutableList defaultSettings(FieldList fields) {
132:
133: if (fields == null) {
134: return new StatementArrayList(0);
135: }
136: StatementMutableList result = new StatementArrayList(fields
137: .size());
138: for (int i = 0; i < fields.size(); i++) {
139: Field field = fields.getField(i);
140: if (!field.isStatic()) {
141: Identifier fieldId;
142: if (field.getName().charAt(0) != '<') {
143: fieldId = new Identifier(field.getName());
144: result.add(assign((attribute(new ThisReference(),
145: fieldId)), getDefaultValue(services
146: .getCrossReferenceSourceInfo().getType(
147: field))));
148: }
149: }
150: }
151:
152: return result;
153: }
154:
155: /**
156: * creates an implicit method called 'prepare', that sets all
157: * attributes to their default values
158: */
159: protected StatementBlock createPrepareBody(ReferencePrefix prefix,
160: TypeDeclaration classType) {
161:
162: StatementMutableList body = new StatementArrayList(15);
163:
164: if (classType != javaLangObject) {
165: // we can access the implementation
166: body.add((new MethodReference(new SuperReference(),
167: new ImplicitIdentifier(IMPLICIT_OBJECT_PREPARE))));
168: }
169: body.add((StatementMutableList) class2fields.get(classType));
170: return new StatementBlock(body);
171: }
172:
173: /**
174: * creates the implicit <code><prepare></code> method that
175: * sets the fields of the given type to its default values
176: * @param type the TypeDeclaration for which the
177: * <code><prepare></code> is created
178: * @return the implicit <code><prepare></code> method
179: */
180: public MethodDeclaration createMethod(TypeDeclaration type) {
181: ModifierMutableList modifiers = new ModifierArrayList(1);
182: modifiers.add(new Protected());
183: MethodDeclaration md = new MethodDeclaration(modifiers, null,
184: new ImplicitIdentifier(IMPLICIT_OBJECT_PREPARE),
185: new ParameterDeclarationArrayList(0), null,
186: createPrepareBody(new ThisReference(), type));
187: md.makeAllParentRolesValid();
188: return md;
189: }
190:
191: /**
192: * creates the implicit <code><prepareEnter></code> method that
193: * sets the fields of the given type to its default values
194: * @param type the TypeDeclaration for which the
195: * <code><prepare></code> is created
196: * @return the implicit <code><prepare></code> method
197: */
198: public MethodDeclaration createMethodPrepareEnter(
199: TypeDeclaration type) {
200: ModifierMutableList modifiers = new ModifierArrayList(1);
201: modifiers.add(new Private());
202: MethodDeclaration md = new MethodDeclaration(modifiers, null,
203: new ImplicitIdentifier(IMPLICIT_OBJECT_PREPARE_ENTER),
204: new ParameterDeclarationArrayList(0), null,
205: createPrepareBody(new ThisReference(), type));
206: md.makeAllParentRolesValid();
207: return md;
208: }
209:
210: /**
211: * entry method for the constructor normalform builder
212: * @param td the TypeDeclaration
213: */
214: protected void makeExplicit(TypeDeclaration td) {
215: if (td instanceof ClassDeclaration) {
216: attach(createMethod(td), td, td.getMembers().size());
217: attach(createMethodPrepareEnter(td), td, td.getMembers()
218: .size());
219: // java.io.StringWriter sw = new java.io.StringWriter();
220: // services.getProgramFactory().getPrettyPrinter(sw).visitClassDeclaration((ClassDeclaration)td);
221: // System.out.println(sw.toString());
222: // try { sw.close(); } catch (Exception e) {}
223: }
224: }
225:
226: }
|