/*
* 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.HashSet;
import java.util.Set;
import polyglot.ast.*;
import polyglot.frontend.Job;
import polyglot.types.LocalDef;
import polyglot.types.TypeSystem;
import polyglot.util.CollectionUtil; import x10.util.CollectionFactory;
/**
* This visitor converts non-final local variables into final local variables.
* This improves the precision of some analyses.
*
* @author nystrom
*/
public class FinalLocalExtractor extends NodeVisitor {
/** Set of LocalInstances declared final; these should not be made non-final. */
protected Set<LocalDef> isFinal;
/**
* @param job
* @param ts
* @param nf
*/
public FinalLocalExtractor(Job job, TypeSystem ts, NodeFactory nf) {
super();
}
public NodeVisitor begin() {
isFinal = CollectionFactory.newHashSet();
return super.begin();
}
public void finish() {
isFinal = null;
}
// TODO: handle locals that are not initialized when declared
//
// TODO: handle anonymous classes: this visitor assumes all LocalInstances
// are set correctly, which is true after disambiguation, except for anonymous
// classes.
//
// TODO: convert to pseudo-SSA form: generate a new local decl when a local
// is assigned, rather than marking the original as final. If a local
// requires a phi-function, just mark it non-final rather than generating
// the phi.
public NodeVisitor enter(Node parent, Node n) {
if (n instanceof Formal) {
Formal d = (Formal) n;
LocalDef li = d.localDef();
if (! li.flags().isFinal()) {
li.setFlags(li.flags().Final());
}
else {
isFinal.add(li);
}
}
if (n instanceof LocalDecl) {
LocalDecl d = (LocalDecl) n;
LocalDef li = d.localDef();
if (! li.flags().isFinal()) {
li.setFlags(li.flags().Final());
}
else {
isFinal.add(li);
}
}
if (n instanceof Unary) {
Unary u = (Unary) n;
if (u.expr() instanceof Local) {
Local l = (Local) u.expr();
LocalDef li = l.localInstance().def();
if (u.operator() == Unary.PRE_DEC || u.operator() == Unary.POST_DEC ||
u.operator() == Unary.PRE_INC || u.operator() == Unary.POST_INC) {
if (! isFinal.contains(li)) {
li.setFlags(li.flags().clearFinal());
}
}
}
}
if (n instanceof LocalAssign) {
LocalAssign a = (LocalAssign) n;
if (a.local() instanceof Local) {
LocalDef li = ((Local) a.local()).localInstance().def();
if (! isFinal.contains(li)) {
li.setFlags(li.flags().clearFinal());
}
}
}
return super.enter(parent, n);
}
protected static class LocalDeclFixer extends NodeVisitor {
public Node leave(Node old, Node n, NodeVisitor v) {
if (n instanceof Formal) {
Formal d = (Formal) n;
FlagsNode f = d.flags();
f = f.flags(d.localDef().flags());
}
if (n instanceof LocalDecl) {
LocalDecl d = (LocalDecl) n;
FlagsNode f = d.flags();
f = f.flags(d.localDef().flags());
return d.flags(f);
}
return n;
}
}
public Node leave(Node old, Node n, NodeVisitor v) {
// Revisit everything to ensure the local decls' flags agree with
// their local instance's.
if (n instanceof SourceFile) {
return n.visit(new LocalDeclFixer());
}
return n;
}
}