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 org.apache.log4j.Logger;
021:
022: import recoder.CrossReferenceServiceConfiguration;
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.FieldSpecification;
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.Static;
032: import recoder.java.expression.literal.BooleanLiteral;
033: import recoder.java.expression.operator.CopyAssignment;
034: import recoder.java.reference.FieldReference;
035: import recoder.kit.ProblemReport;
036: import recoder.list.*;
037: import de.uka.ilkd.key.util.Debug;
038:
039: /**
040: * Each class is prepared before it is initialised. The preparation of
041: * a class consists of pre-initialising the class fields with their
042: * default values. This class creates the implicit method
043: * <code><clprepare></code> responsible for the class
044: * preparation.
045: */
046: public class ClassPreparationMethodBuilder extends
047: RecoderModelTransformer {
048:
049: static Logger logger = Logger
050: .getLogger(ClassPreparationMethodBuilder.class.getName());
051:
052: public static final String CLASS_PREPARE_IDENTIFIER = "<clprepare>";
053:
054: /** maps a class to its static NON CONSTANT fields */
055: private HashMap class2staticFields;
056:
057: /**
058: * Creates an instance of the class preparation method model
059: * transformer. Information about the current recoder model can be
060: * accessed via the given service configuration. The implicit
061: * preparation method is created and added for all classes,
062: * which are declared in one of the given compilation units.
063: * @param services the CrossReferenceServiceConfiguration with the
064: * information about the recoder model
065: * @param units the CompilationUnitMutableList with the classes to
066: * be transformed
067: */
068: public ClassPreparationMethodBuilder(
069: CrossReferenceServiceConfiguration services,
070: CompilationUnitMutableList units) {
071: super (services, units);
072: class2staticFields = new HashMap(10 * units.size());
073: }
074:
075: /**
076: * returns true if the given fieldspecification denotes a constant
077: * field. A constant field is declared as final and static and
078: * initialised with a time constant, which is not prepared or
079: * initialised here. ATTENTION: this is a derivation from the JLS
080: * but the obtained behaviour is equivalent as we only consider
081: * completely compiled programs and not partial compilations. The
082: * reason for preparation and initialisation of comnpile time
083: * constant fields is due to binary compatibility reasons.
084: */
085: private boolean isConstantField(FieldSpecification spec) {
086: if (logger.isDebugEnabled()) {
087: logger.debug("now at " + spec.getFullName());
088: }
089: boolean result = spec.isStatic() && spec.isFinal();
090: if (!result) {
091: return result;
092: }
093: recoder.service.ConstantEvaluator ce = services
094: .getConstantEvaluator();
095: result = ce.isCompileTimeConstant(spec.getInitializer());
096: return result;
097: }
098:
099: /**
100: * retrieves all static non constant fields and returns a list of
101: * copy assignment pre-initialising them with their default values
102: *
103: * some special settings for implicit fields are performed here as well
104: * @param typeDeclaration the ClassDeclaration whose fields have to be prepared
105: * @return the list of copy assignments
106: */
107: private StatementList prepareFields(TypeDeclaration typeDeclaration) {
108:
109: StatementMutableList result = new StatementArrayList(20);
110:
111: FieldSpecificationList fields = typeDeclaration
112: .getFieldsInScope();
113:
114: for (int i = 0; i < fields.size(); i++) {
115: FieldSpecification spec = fields.getFieldSpecification(i);
116: if (spec.isStatic() && !isConstantField(spec)) {
117: Identifier ident = spec.getIdentifier();
118: if (ident instanceof ImplicitIdentifier) {
119: result.add(new CopyAssignment(
120: new PassiveExpression(new FieldReference(
121: (ImplicitIdentifier) ident
122: .deepClone())),
123: getDefaultValue(spec.getType())));
124: } else {
125: result.add(new CopyAssignment(
126: new PassiveExpression(new FieldReference(
127: (Identifier) ident.deepClone())),
128: getDefaultValue(spec.getType())));
129: }
130: }
131: }
132:
133: result.add(new CopyAssignment(new PassiveExpression(
134: new FieldReference(new ImplicitIdentifier(
135: ImplicitFieldAdder.IMPLICIT_CLASS_PREPARED))),
136: new BooleanLiteral(true)));
137:
138: return result;
139: }
140:
141: public ProblemReport analyze() {
142: for (int unit = 0; unit < units.size(); unit++) {
143: CompilationUnit cu = units.getCompilationUnit(unit);
144: int typeCount = cu.getTypeDeclarationCount();
145:
146: for (int i = 0; i < typeCount; i++) {
147: if (cu.getTypeDeclarationAt(i) instanceof ClassDeclaration) {
148: ClassDeclaration cd = (ClassDeclaration) cu
149: .getTypeDeclarationAt(i);
150: if (cd.getTypeDeclarationCount() > 0) {
151: Debug
152: .out("clPrepBuilder: Inner Class detected. "
153: + "Reject building class initialisation methods.");
154: }
155:
156: // collect initializers for transformation phase
157: class2staticFields.put(cd, prepareFields(cd));
158: }
159: }
160: }
161: setProblemReport(NO_PROBLEM);
162: return NO_PROBLEM;
163: }
164:
165: /**
166: * creates the static method <code><clprepare></code> for the
167: * given type declaration
168: * @param td the TypeDeclaration to which the new created method
169: * will be attached
170: * @return the created class preparation method
171: */
172: private MethodDeclaration createPrepareMethod(TypeDeclaration td) {
173: ModifierMutableList modifiers = new ModifierArrayList(2);
174: modifiers.add(new Static());
175: modifiers.add(new Private());
176: return new MethodDeclaration(modifiers,
177: null, // return type is void
178: new ImplicitIdentifier(CLASS_PREPARE_IDENTIFIER),
179: new ParameterDeclarationArrayList(0), null, // no throws
180: new StatementBlock(
181: (StatementMutableList) class2staticFields
182: .get(td)));
183: }
184:
185: /**
186: * entry method for the constructor normalform builder
187: * @param td the TypeDeclaration
188: */
189: protected void makeExplicit(TypeDeclaration td) {
190: attach(createPrepareMethod(td), td, 0);
191: // for debug
192: // java.io.StringWriter sw = new java.io.StringWriter();
193: // // services.getProgramFactory().getPrettyPrinter(sw).visitMethodDeclaration(nf);
194: // services.getProgramFactory().getPrettyPrinter(sw).visitTypeDeclaration((TypeDeclaration)td);
195: // System.out.println(sw.toString());
196: // try { sw.close(); } catch (Exception e) {}
197: }
198:
199: }
|