blob: bcde841f88f10707c99a2f0e12ecca7ee34fd50d [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2003, 2006 Fraunhofer Gesellschaft, Munich, Germany,
* for its Fraunhofer Institute for Computer Architecture and Software
* Technology (FIRST), Berlin, Germany and Technical University Berlin,
* Germany.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
* $Id: CallinCalloutBinding.java 23416 2010-02-03 19:59:31Z stephan $
*
* Please visit http://www.eclipse.org/objectteams for updates and contact.
*
* Contributors:
* Fraunhofer FIRST - Initial API and implementation
* Technical University Berlin - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.otdt.internal.core.compiler.lookup;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.eclipse.objectteams.otdt.core.compiler.InferenceKind;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CallinMappingDeclaration;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.TypeAnalyzer;
/**
* NEW for OTDT
*
*
* @author mac
* @version $Id: CallinCalloutBinding.java 23416 2010-02-03 19:59:31Z stephan $
*/
public class CallinCalloutBinding extends Binding
{
//TODO(mkr) resolve mix of local constants and TerminalTokens
public static final int CALLIN = 1;
public static final int CALLOUT = 2;
public static final int CALLOUT_OVERRIDE = 3;
public static final int REPLACE = 1;
public static final int AFTER = 2;
public static final int BEFORE = 3;
public TypeVariableBinding[] typeVariables;
public MethodBinding _roleMethodBinding;
public ReferenceBinding _declaringRoleClass;
public MethodBinding[] _baseMethods = Binding.NO_METHODS;
public FieldBinding _baseField;
public int type;
public int callinModifier; // TerminalTokens: before,after,replace
public int calloutModifier; // TerminalTokens: get or set
public int declaredModifiers; // for callout: explicit visibility modifiers
public char[] name;
public InferenceKind inferred = InferenceKind.NONE;
// currently only use: TagBits.AnnotationResolved
public long tagBits = 0L;
// link to the original if copy-inherited:
public CallinCalloutBinding copyInheritanceSrc;
//{OTDyn: management of callin ids across team inheritance:
public int callinIdMax = -1;
// SH}
//@param CALLOUT
public CallinCalloutBinding(boolean isCalloutOverride,
MethodBinding roleMethodBinding,
ReferenceBinding declaringRoleClass,
int calloutModifier,
int declaredModifiers)
{
this._declaringRoleClass = declaringRoleClass;
this._roleMethodBinding = roleMethodBinding;
if(isCalloutOverride){
this.type = CALLOUT_OVERRIDE;
} else {
this.type = CALLOUT;
}
this.calloutModifier = calloutModifier;
this.declaredModifiers = declaredModifiers;
}
//@param type CALLIN
public CallinCalloutBinding(
ReferenceBinding declaringRoleClass, CallinMappingDeclaration mappingDecl)
{
this.type = CALLIN;
this._declaringRoleClass = declaringRoleClass;
this.name = mappingDecl.name;
this.callinModifier = mappingDecl.callinModifier;
this._roleMethodBinding = mappingDecl.getRoleMethod();
//this._baseMethods = null; // set during resolve of mapping declaration
// but beware: not in all cases this resolve is called at all (e.g., no baseclass declared).
}
/**
* @param declaringRole
* @param name
* @param callinModifier
*/
public CallinCalloutBinding(ReferenceBinding declaringRole, char[] name, int callinModifier) {
this.type = CALLIN;
this._declaringRoleClass = declaringRole;
this.name = name;
this.callinModifier = callinModifier;
}
/**
* Create an unresolved callin binding.
* (details to be filled by by CallinMethodMappingsAttribute.merge->createBinding())
*
* @param declaringRole
* @param name
*/
public CallinCalloutBinding(ReferenceBinding declaringRole, char[] name) {
this.type = CALLIN;
this._declaringRoleClass = declaringRole;
this.name = name;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.internal.compiler.lookup.Binding#bindingType()
*/
@Override
public int kind()
{
return BINDING;
}
public CallinCalloutBinding getOrigin() {
if (this.copyInheritanceSrc != null)
return this.copyInheritanceSrc.getOrigin();
return this;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.internal.compiler.lookup.Binding#readableName()
*/
@Override
public char[] readableName()
{
StringBuffer buffer = new StringBuffer();
buffer.append(toString());
return buffer.toString().toCharArray();
}
/**
* @return true if Binding is CallinBinding
*/
public boolean isCallin()
{
return this.type == CALLIN;
}
public boolean isReplaceCallin() {
return this.type == CALLIN && this.callinModifier == REPLACE;
}
/**
* @return true if Binding is CalloutOverrideBinding
*/
private boolean isCalloutOverride()
{
return this.type == CALLOUT_OVERRIDE;
}
/**
* @return true if Binding is Callout or CalloutOverride
*/
public boolean isCallout()
{
return this.type == CALLOUT || this.type == CALLOUT_OVERRIDE;
}
public boolean hasValidBaseMethods() {
if ( this._baseMethods == null
|| this._baseMethods.length == 0)
return false;
for (int i = 0; i < this._baseMethods.length; i++) {
if (!this._baseMethods[i].isValidBinding())
return false;
}
return true;
}
public boolean hasValidRoleMethod() {
return
this._roleMethodBinding != null
&& this._roleMethodBinding.isValidBinding();
}
/** Get the problemId of the first erroneous method binding or NoError. */
@Override
public int problemId() {
if (this._roleMethodBinding != null && !this._roleMethodBinding.isValidBinding())
return this._roleMethodBinding.problemId();
if (this._baseMethods != null)
for (MethodBinding method : this._baseMethods)
if (!method.isValidBinding())
return method.problemId();
if (this._baseField != null)
return this._baseField.problemId();
return ProblemReasons.NoError;
}
public boolean isRoleMethodOverriddenIn(ReferenceBinding subRole) {
if (!hasValidRoleMethod()) return false;
for (MethodBinding subMethod : subRole.getMethods(this._roleMethodBinding.selector)) {
if (TypeAnalyzer.isEqualMethodSignature(
this._roleMethodBinding.declaringClass.enclosingType(), this._roleMethodBinding,
subRole.enclosingType(), subMethod,
TypeAnalyzer.ANY_MATCH))
return true;
}
return false;
}
// copied from MethodBinding.getTypeVariable()
public TypeVariableBinding getTypeVariable(char[] variableName) {
for (int i = this.typeVariables.length; --i >= 0;)
if (CharOperation.equals(this.typeVariables[i].sourceName, variableName))
return this.typeVariables[i];
return null;
}
@Override
@SuppressWarnings("nls")
public char[] computeUniqueKey(boolean isLeaf) {
// callin mappings have a name:
if (this.name != null)
return this.name;
// fail safe for erroneous bindings (see CallinCalloutScope.createBinding())
if (this._roleMethodBinding == null)
return new char[0]; // like to call new String() on the result, => must not be null!
// callout mappings assemble a key from elements:
if (this._baseMethods != Binding.NO_METHODS)
return CharOperation.concat(
this._roleMethodBinding.computeUniqueKey(isLeaf),
"->".toCharArray(),
this._baseMethods[0].computeUniqueKey(isLeaf));
// fail safe for callout without base methods:
return CharOperation.concat(
this._roleMethodBinding.computeUniqueKey(isLeaf),
"->".toCharArray());
}
@Override
public void setAnnotations(AnnotationBinding[] annotations, boolean forceStore) {
this._declaringRoleClass.storeAnnotations(this, annotations, forceStore);
}
@Override
public AnnotationBinding[] getAnnotations() {
return this._declaringRoleClass.retrieveAnnotations(this);
}
@Override
@SuppressWarnings("nls")
public String toString()
{
String result = (this.name == null) ? "" : new String(this.name)+": ";
result +=
(this._roleMethodBinding != null)
? this._roleMethodBinding.toString(false) // no modifiers
: "NULL ROLE METHODS";
if (isCallin())
{
result += "<- "+CallinMappingDeclaration.callinModifier(this.callinModifier)+" ";
}
else if(isCallout())
{
if(isCalloutOverride())
result += "=> ";
else
result += "-> ";
}
if (this._baseMethods != null)
for (int i = 0; i < this._baseMethods.length; i++) {
result += this._baseMethods[i].toString(false); // no modifiers
if (i<this._baseMethods.length-1)
result += ", ";
}
result += ';';
return result;
}
/** Answer the name of this callin qualified with the declaring class's name. */
public char[] getQualifiedName() {
char[] theName = this.name;
if (theName[0] == '<')
return theName; // synthetic name is already unique.
ReferenceBinding currentType = this._declaringRoleClass;
return CharOperation.concat(theName, currentType.readableName(), '$');
}
/**
* Answer the name of the role that introduced this callin mapping
* (support for overriding in otredyn).
*/
public ReferenceBinding introducingRoleClass() {
ReferenceBinding declaringRole = this._declaringRoleClass;
if (this.name == null)
return declaringRole;
if (this.name[0] != '<') {
ReferenceBinding currentRole = declaringRole;
while (currentRole != null && currentRole.isRole()) {
for (CallinCalloutBinding mapping : currentRole.callinCallouts) {
if (CharOperation.equals(this.name, mapping.name)) {
declaringRole = currentRole;
}
}
currentRole = currentRole.superclass();
}
}
return declaringRole;
}
}