/** * Determine if we are interested in this field on the basis of the target of the field. To wit, * if the field is static, then the target of the field must be the current class; if the field is * not static then the target must be "this". */ protected boolean isFieldsTargetAppropriate(Field f) { if (f.fieldInstance().flags().isStatic()) { ClassType containingClass = (ClassType) currCBI.currCodeDecl.codeInstance().container(); return containingClass.equals(f.fieldInstance().container()); } else { return (f.target() instanceof Special && Special.THIS.equals(((Special) f.target()).kind())); } }
/** Check that the assignment to a field is correct. */ protected void checkFieldAssign( FlowGraph graph, FieldAssign a, DataFlowItem dfIn, DataFlowItem dfOut) throws SemanticException { Field f = (Field) a.left(); FieldInstance fi = f.fieldInstance(); if (fi.flags().isFinal()) { if ((currCBI.currCodeDecl instanceof ConstructorDecl || currCBI.currCodeDecl instanceof Initializer) && isFieldsTargetAppropriate(f)) { // we are in a constructor or initializer block and // if the field is static then the target is the class // at hand, and if it is not static then the // target of the field is this. // So a final field in this situation can be // assigned to at most once. MinMaxInitCount initCount = (MinMaxInitCount) dfOut.initStatus.get(fi); if (InitCount.MANY.equals(initCount.getMax())) { throw new SemanticException( "field \"" + fi.name() + "\" might already have been assigned to", a.position()); } } else { // not in a constructor or intializer, or the target is // not appropriate. So we cannot assign // to a final field at all. throw new SemanticException( "Cannot assign a value " + "to final field \"" + fi.name() + "\"", a.position()); } } }
/** Perform the appropriate flow operations for assignment to a field */ protected Map flowFieldAssign( DataFlowItem inItem, FlowGraph graph, FieldAssign a, Set succEdgeKeys) { Field f = (Field) a.left(); FieldInstance fi = f.fieldInstance(); if (fi.flags().isFinal() && isFieldsTargetAppropriate(f)) { // this field is final and the target for this field is // appropriate for what we are interested in. Map m = new HashMap(inItem.initStatus); MinMaxInitCount initCount = (MinMaxInitCount) m.get(fi); // initCount may be null if the field is defined in an // outer class. if (initCount != null) { initCount = new MinMaxInitCount(initCount.getMin().increment(), initCount.getMax().increment()); m.put(fi, initCount); return itemToMap(new DataFlowItem(m), succEdgeKeys); } } return null; }