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.Constructor;
023: import recoder.java.CompilationUnit;
024: import recoder.java.Expression;
025: import recoder.java.Statement;
026: import recoder.java.StatementBlock;
027: import recoder.java.declaration.*;
028: import recoder.java.declaration.modifier.Private;
029: import recoder.java.declaration.modifier.Public;
030: import recoder.java.expression.operator.CopyAssignment;
031: import recoder.java.reference.*;
032: import recoder.kit.ProblemReport;
033: import recoder.list.*;
034: import de.uka.ilkd.key.util.Debug;
035:
036: /**
037: * Transforms the constructors of the given class to their
038: * normalform. The constructor normalform can then be accessed via a
039: * methodcall <code><init><cons_args)</code>. The visibility of
040: * the normalform is the same as for the original constructor.
041: */
042: public class ConstructorNormalformBuilder extends
043: RecoderModelTransformer {
044:
045: public static final String CONSTRUCTOR_NORMALFORM_IDENTIFIER = "<init>";
046:
047: public static final String OBJECT_INITIALIZER_IDENTIFIER = "<objectInitializer>";
048:
049: private HashMap class2constructors;
050: private HashMap class2initializers;
051: private HashMap class2methodDeclaration;
052:
053: private ClassType javaLangObject;
054:
055: /** creates the constructor normalform builder */
056: public ConstructorNormalformBuilder(
057: CrossReferenceServiceConfiguration services,
058: CompilationUnitMutableList units) {
059: super (services, units);
060: class2constructors = new HashMap(4 * units.size());
061: class2initializers = new HashMap(10 * units.size());
062: class2methodDeclaration = new HashMap(10 * units.size());
063: }
064:
065: /**
066: * The list of statements is the smallest list that contains a copy
067: * assignment for each instance field initializer of class cd,
068: * e.g. <code> i = 0; </code> for <code> public int i = 0; </code> or
069: * a reference to the private method
070: * <code><objectInitializer><i>i</i> refering to the i-th object
071: * initializer of cd. These private declared methods are created on
072: * the fly. Example for
073: * <code>
074: * class C {
075: * int i = 0;
076: * {
077: * int j = 3;
078: * i = j + 5;
079: * }
080: *
081: * public C () {} ...
082: * }
083: * </code> the following list of size two is returned
084: * <code>
085: * [ i = 0;, <objectInitializer>0(); ]
086: * </code>
087: * where <code>
088: * private <objectInitializer>0() {
089: * int j = 3;
090: * i = j + 5;
091: * }
092: * </code>
093: * @param cd the ClassDeclaration of which the initilizers have to
094: * be collected
095: * @return the list of copy assignments and method references
096: * realising the initializers.
097: */
098: private StatementList collectInitializers(ClassDeclaration cd) {
099: StatementMutableList result = new StatementArrayList(20);
100: MethodDeclarationMutableList mdl = new MethodDeclarationArrayList(
101: 5);
102: int childCount = cd.getChildCount();
103: for (int i = 0; i < childCount; i++) {
104: if (cd.getChildAt(i) instanceof ClassInitializer
105: && !((ClassInitializer) cd.getChildAt(i))
106: .isStatic()) {
107:
108: ModifierMutableList mods = new ModifierArrayList(1);
109: mods.add(new Private());
110: String name = OBJECT_INITIALIZER_IDENTIFIER
111: + mdl.size();
112: MethodDeclaration initializerMethod = new MethodDeclaration(
113: mods,
114: null, //return type is void
115: new ImplicitIdentifier(name),
116: new ParameterDeclarationArrayList(0), null,
117: (StatementBlock) ((ClassInitializer) cd
118: .getChildAt(i)).getBody().deepClone());
119: initializerMethod.makeAllParentRolesValid();
120: mdl.add(initializerMethod);
121: result.add(new MethodReference(null,
122: new ImplicitIdentifier(name)));
123: } else if (cd.getChildAt(i) instanceof FieldDeclaration
124: && !((FieldDeclaration) cd.getChildAt(i))
125: .isStatic()) {
126: FieldSpecificationList specs = ((FieldDeclaration) cd
127: .getChildAt(i)).getFieldSpecifications();
128: for (int j = 0; j < specs.size(); j++) {
129: Expression fieldInit = null;
130: if ((fieldInit = specs.getFieldSpecification(j)
131: .getInitializer()) != null) {
132: CopyAssignment fieldCopy = new CopyAssignment(
133: new FieldReference(new ThisReference(),
134: specs.getFieldSpecification(j)
135: .getIdentifier()),
136: (Expression) fieldInit.deepClone());
137: result.add(fieldCopy);
138: }
139: }
140: }
141: }
142: class2methodDeclaration.put(cd, mdl);
143: return result;
144: }
145:
146: /**
147: * Two-pass transformation have to be strictly divided up into two
148: * parts. the first part analyzes the model and collects all
149: * necessary information. In this case all class declarations are
150: * examined and initializers as well as constructors are collected.
151: * All actions, which may cause a recoder model update have to be
152: * done here.
153: * @return status report if analyze encountered problems or not
154: */
155: public ProblemReport analyze() {
156: javaLangObject = services.getNameInfo().getJavaLangObject();
157: if (!(javaLangObject instanceof ClassDeclaration)) {
158: Debug
159: .fail("Could not find class java.lang.Object or only as bytecode");
160: }
161: for (int unit = 0; unit < units.size(); unit++) {
162: CompilationUnit cu = units.getCompilationUnit(unit);
163: int typeCount = cu.getTypeDeclarationCount();
164:
165: for (int i = 0; i < typeCount; i++) {
166: if (cu.getTypeDeclarationAt(i) instanceof ClassDeclaration) {
167: ClassDeclaration cd = (ClassDeclaration) cu
168: .getTypeDeclarationAt(i);
169: if (cd.getTypeDeclarationCount() > 0) {
170: Debug
171: .out("consNFBuilder: Inner Class detected."
172: + "No constructor normalform will be built"
173: + "for the inner classes of "
174: + cd.getIdentifier());
175: }
176:
177: // collect constructors for transformation phase
178: ConstructorMutableList constructors = new ConstructorArrayList(
179: 10);
180: constructors.add(services.getSourceInfo()
181: .getConstructors(cd));
182: class2constructors.put(cd, constructors);
183:
184: // collect initializers for transformation phase
185: class2initializers.put(cd, collectInitializers(cd));
186: }
187: }
188: }
189: setProblemReport(NO_PROBLEM);
190: return NO_PROBLEM;
191: }
192:
193: /**
194: * Creates the normalform of the given constructor, that is declared
195: * in class cd. For a detailed description of the normalform to be
196: * built see the KeY Manual.
197: * @param cd the ClassDeclaration where the cons is declared
198: * @param cons the Constructor to be transformed
199: * @return the constructor normalform
200: */
201: private MethodDeclaration normalform(ClassDeclaration cd,
202: Constructor cons) {
203:
204: ModifierMutableList mods = new ModifierArrayList(5);
205: ParameterDeclarationMutableList parameters;
206: Throws recThrows;
207: StatementBlock body;
208:
209: if (!(cons instanceof ConstructorDeclaration)) {
210: mods.add(new Public());
211: parameters = new ParameterDeclarationArrayList(0);
212: recThrows = null;
213: body = new StatementBlock();
214: } else {
215: ConstructorDeclaration consDecl = (ConstructorDeclaration) cons;
216: mods = (ModifierMutableList) (consDecl.getModifiers() == null ? null
217: : consDecl.getModifiers().deepClone());
218: parameters = (ParameterDeclarationMutableList) consDecl
219: .getParameters().deepClone();
220: recThrows = (Throws) (consDecl.getThrown() == null ? null
221: : consDecl.getThrown().deepClone());
222: body = (StatementBlock) consDecl.getBody().deepClone();
223: }
224:
225: if (cd != javaLangObject) {
226: // remember original first statement
227: Statement first = body.getStatementCount() > 0 ? body
228: .getStatementAt(0) : null;
229:
230: // first statement has to be a this or super constructor call
231: if (!(first instanceof SpecialConstructorReference)) {
232: if (body.getBody() == null) {
233: body.setBody(new StatementArrayList());
234: }
235: attach(new MethodReference(new SuperReference(),
236: new ImplicitIdentifier(
237: CONSTRUCTOR_NORMALFORM_IDENTIFIER)),
238: body, 0);
239: } else {
240: body.getBody().remove(0);
241: ReferencePrefix referencePrefix;
242: referencePrefix = first instanceof ThisConstructorReference ? (ReferencePrefix) new ThisReference()
243: : (ReferencePrefix) new SuperReference();
244: attach(new MethodReference(referencePrefix,
245: new ImplicitIdentifier(
246: CONSTRUCTOR_NORMALFORM_IDENTIFIER),
247: ((SpecialConstructorReference) first)
248: .getArguments()), body, 0);
249: }
250: // if the first statement is not a this constructor reference
251: // the instance initializers have to be added in source code
252: // order
253: if (!(first instanceof ThisConstructorReference)) {
254: StatementMutableList initializers = (StatementMutableList) class2initializers
255: .get(cd);
256: for (int i = 0; i < initializers.size(); i++) {
257: attach((Statement) initializers.getStatement(i)
258: .deepClone(), body, i + 1);
259: }
260: }
261: }
262:
263: MethodDeclaration nf = new MethodDeclaration(mods,
264: new TypeReference(cd.getIdentifier()),
265: new ImplicitIdentifier(
266: CONSTRUCTOR_NORMALFORM_IDENTIFIER), parameters,
267: recThrows, body);
268: nf.makeAllParentRolesValid();
269: return nf;
270: }
271:
272: /**
273: * entry method for the constructor normalform builder
274: * @param td the TypeDeclaration
275: */
276: protected void makeExplicit(TypeDeclaration td) {
277: if (td instanceof ClassDeclaration) {
278: ConstructorMutableList constructors = (ConstructorMutableList) class2constructors
279: .get(td);
280: for (int i = 0; i < constructors.size(); i++) {
281: attach(normalform((ClassDeclaration) td, constructors
282: .getConstructor(i)), td, 0);
283: }
284:
285: MethodDeclarationList mdl = (MethodDeclarationList) class2methodDeclaration
286: .get(td);
287: for (int i = 0; i < mdl.size(); i++) {
288: attach(mdl.getMethodDeclaration(i), td, 0);
289: }
290:
291: /* java.io.StringWriter sw = new java.io.StringWriter();
292: // //services.getProgramFactory().getPrettyPrinter(sw).visitMethodDeclaration(nf);
293: services.getProgramFactory().getPrettyPrinter(sw).visitClassDeclaration((ClassDeclaration)td);
294: System.out.println(sw.toString());
295: try { sw.close(); } catch (Exception e) {} */
296: }
297:
298: }
299:
300: }
|