com.redhat.ceylon.compiler.java.codegen.InterfaceVisitor Maven / Gradle / Ivy
/*
* 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