/*
* This file is part of the X10 project (http://x10-lang.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* This file was originally derived from the Polyglot extensible compiler framework.
*
* (C) Copyright 2000-2007 Polyglot project group, Cornell University
* (C) Copyright IBM Corporation 2007-2012.
*/
package polyglot.visit;
import java.util.Set;
import polyglot.ast.*;
import polyglot.frontend.Job;
import polyglot.types.*;
import x10.errors.Errors;
import x10.util.CollectionFactory;
/** Visitor which ensures that field intializers and initializers do not
* make illegal forward references to fields.
* This is an implementation of the rules of the Java Language Spec, 2nd
* Edition, Section 8.3.2.3
*
* Yoav: It now only checks for illegal forward ref of static fields.
*/
public class FwdReferenceChecker extends ContextVisitor
{
public FwdReferenceChecker(Job job, TypeSystem ts, NodeFactory nf) {
super(job, ts, nf);
}
private boolean inInitialization = false;
private Set<FieldDef> declaredFields = CollectionFactory.newHashSet();
protected NodeVisitor enterCall(Node n) {
if (n instanceof FieldDecl) {
FieldDecl fd = (FieldDecl)n;
if (fd.flags().flags().isStatic()) {
FwdReferenceChecker frc = (FwdReferenceChecker)this.shallowCopy();
frc.declaredFields = CollectionFactory.newHashSet(declaredFields);
declaredFields.add(fd.fieldDef());
frc.inInitialization = true;
return frc;
}
}
else if (n instanceof Initializer && ((Initializer)n).flags().flags().isStatic()) {
FwdReferenceChecker frc = (FwdReferenceChecker)this.shallowCopy();
frc.inInitialization = true;
return frc;
}
else if (n instanceof Field) {
if (inInitialization) {
// we need to check if this is an illegal fwd reference.
Field f = (Field)n;
// an illegal fwd reference if a usage of an instance
// (resp. static) field occurs in an instance (resp. static)
// initialization, and the innermost enclosing class or
// interface of the usage is the same as the container of
// the field, and we have not yet seen the field declaration.
//
ClassType currentClass = context().currentClass();
ContainerType fContainer = f.fieldInstance().container();
if (f.fieldInstance().flags().isStatic() &&
currentClass.typeEquals(fContainer, context) &&
!declaredFields.contains(f.fieldInstance().def()))
{
Errors.issue(job(), new SemanticException("Illegal forward reference", f.position()));
}
}
}
return this;
}
}