All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redhat.ceylon.compiler.java.codegen.InterfaceVisitor Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
/*
 * Copyright Red Hat Inc. and/or its affiliates and other contributors
 * as indicated by the authors tag. All rights reserved.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License version 2.
 * 
 * This particular file is subject to the "Classpath" exception as provided in the 
 * LICENSE file that accompanied this code.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License,
 * along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 */

package com.redhat.ceylon.compiler.java.codegen;

import java.util.HashSet;
import java.util.Set;

import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;
import com.redhat.ceylon.model.typechecker.model.ClassOrInterface;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.Functional;
import com.redhat.ceylon.model.typechecker.model.Interface;
import com.redhat.ceylon.model.typechecker.model.Function;
import com.redhat.ceylon.model.typechecker.model.Parameter;
import com.redhat.ceylon.model.typechecker.model.ParameterList;
import com.redhat.ceylon.model.typechecker.model.Setter;
import com.redhat.ceylon.model.typechecker.model.TypeParameter;
import com.redhat.ceylon.model.typechecker.model.Value;

/**
 * Visits every local interface and computes their Java companion class name.
 * Also visits every interface and calculates if they need a companion class. 
 * 
 * @author Stéphane Épardaud 
 */
public class InterfaceVisitor extends Visitor {

    private Set localCompanionClasses = new HashSet();
    
    private void collect(Node that, Interface model) {
        if(model != null && !model.isMember()){
            String name = Naming.suffixName(Naming.Suffix.$impl, model.getName());
            // find an unused name
            int i;
            String prefixedName;
            for(i=1;localCompanionClasses.contains(prefixedName = i+name);i++){}
            // add it
            localCompanionClasses.add(prefixedName);
            model.setJavaCompanionClassName(prefixedName);
        }
    }

    @Override
    public void visit(Tree.AnyMethod that){
        Function model = that.getDeclarationModel();
        // locals and toplevels get a type generated for them
        if(!model.isMember() && !model.isToplevel()){
            Set old = localCompanionClasses;
            localCompanionClasses = new HashSet();
            super.visit(that);
            localCompanionClasses = old;
        }else{
            super.visit(that);
        }
    }

    @Override
    public void visit(Tree.AttributeGetterDefinition that){
        Value model = that.getDeclarationModel();
        // locals and toplevels get a type generated for them
        if(!model.isMember() && !model.isToplevel()){
            Set old = localCompanionClasses;
            localCompanionClasses = new HashSet();
            super.visit(that);
            localCompanionClasses = old;
        }else{
            super.visit(that);
        }
    }
    
    @Override
    public void visit(Tree.AttributeSetterDefinition that){
        Setter model = that.getDeclarationModel();
        // locals and toplevels get a type generated for them
        if(!model.isMember() && !model.isToplevel()){
            Set old = localCompanionClasses;
            localCompanionClasses = new HashSet();
            super.visit(that);
            localCompanionClasses = old;
        }else{
            super.visit(that);
        }
    }

    @Override
    public void visit(Tree.TypeAliasDeclaration that){
        // stop at aliases, do not collect them since we can never create any instance of them
        // and they are useless at runtime
    }

    @Override
    public void visit(Tree.ClassOrInterface that){
        ClassOrInterface model = that.getDeclarationModel();
        // stop at aliases, do not collect them since we can never create any instance of them
        // and they are useless at runtime
        if(!model.isAlias()){
            // we never need to collect other local declaration names since only interfaces compete in the $impl name range
            if(model instanceof Interface)
                collect(that, (Interface) model);

            Set old = localCompanionClasses;
            localCompanionClasses = new HashSet();
            super.visit(that);
            localCompanionClasses = old;
        }
        if(model instanceof Interface){
            ((Interface)model).setCompanionClassNeeded(isInterfaceWithCode(model));
        }
    }

    private boolean isInterfaceWithCode(ClassOrInterface model) {
        for (Declaration member : model.getMembers()) {
            if (member instanceof TypeParameter) {
                continue;
            }
            if (member instanceof Functional) {
                for (ParameterList pl : ((Functional)member).getParameterLists()) {
                    for (Parameter p : pl.getParameters()) {
                        if (p.isDefaulted()) {
                            return true;
                        }
                    }
                }
            }
            // formal classes contain code
            if (!member.isFormal() || member instanceof com.redhat.ceylon.model.typechecker.model.Class) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void visit(Tree.ObjectDefinition that){
        Value model = that.getDeclarationModel();
        // locals and toplevels get a type generated for them
        if(!model.isMember() && !model.isToplevel()){
            Set old = localCompanionClasses;
            localCompanionClasses = new HashSet();
            super.visit(that);
            localCompanionClasses = old;
        }else{
            super.visit(that);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy