| /********************************************************************** |
| * This file is part of "Object Teams Development Tooling"-Software |
| * |
| * Copyright 2004, 2010 Fraunhofer Gesellschaft, Munich, Germany, |
| * for its Fraunhofer Institute for Computer Architecture and Software |
| * Technology (FIRST), Berlin, Germany and Technical University Berlin, |
| * Germany. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * 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.bytecode; |
| |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.LinkedList; |
| |
| import org.eclipse.jdt.core.compiler.CharOperation; |
| import org.eclipse.jdt.internal.compiler.ClassFile; |
| import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; |
| import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; |
| import org.eclipse.jdt.internal.compiler.classfmt.ClassFileStruct; |
| import org.eclipse.jdt.internal.compiler.impl.CompilerOptions.WeavingScheme; |
| import org.eclipse.jdt.internal.compiler.lookup.Binding; |
| import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; |
| import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; |
| import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; |
| import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding; |
| import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; |
| import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; |
| import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; |
| import org.eclipse.jdt.internal.compiler.util.Util; |
| import org.eclipse.objectteams.otdt.core.compiler.IOTConstants; |
| import org.eclipse.objectteams.otdt.core.exceptions.InternalCompilerError; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CallinMappingDeclaration; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.control.ITranslationStates; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.model.ModelElement; |
| import org.eclipse.objectteams.otdt.internal.core.compiler.model.TypeModel; |
| |
| /** |
| * Represents the "CallinMethodMappings" attribute |
| * |
| * Location: |
| * A bound role class with a callin binding. |
| * |
| * Content: |
| * A list of method bindings, for structure see inner classes Mapping and BaseMethod. |
| * |
| * Purpose: |
| * The OTRE uses this attribute to determine |
| * a) which callins (callin wrapper calls) have to be woven into which base methods |
| * b) which base method has to be called while generating a base-call in a callin role method |
| * |
| * |
| * The value of this attribute is a nested list, therefor everything |
| * is handcoded here. |
| * |
| * @author stephan |
| */ |
| public class CallinMethodMappingsAttribute extends AbstractAttribute { |
| |
| // bits in 'flags' |
| public static final short STATIC_ROLE_METHOD = 1; |
| public static final short INHERITED = 4; |
| public static final short COVARIANT_BASE_RETURN = 8; |
| |
| public static final int CONSTANT_PART_LENGTH = 20; // 3 short (linepos) + 7 names, : 1 filename, 1 name, 2 selectors, 2 signatures; 1 modifier |
| public static final int BASE_METHOD_PART_LENGTH = 13; // 4 names (2 selectors, 2 signatures) + 1 + 4 bytes (flags) |
| /** |
| * Local structure to store values when read from byte code. |
| */ |
| public class Mapping { |
| public CallinCalloutBinding _binding; |
| // for JSR-045: |
| short _lineNumber, _lineOffset, _flags; |
| char[] |
| _fileName, |
| // generally used fields: |
| _mappingName, _roleSelector, _roleSignature, _liftMethodName, _liftMethodSignature, _callinModifier; |
| |
| BaseMethod[] _baseMethods; |
| Mapping(char[] name, char[] selector, char[] signature, short flags, char[] liftMethodName, char[] liftMethodSignature, char[] modifier) |
| { |
| this._mappingName = name; |
| this._roleSelector = selector; |
| this._roleSignature = signature; |
| this._flags = flags; |
| this._liftMethodName = liftMethodName; |
| this._liftMethodSignature = liftMethodSignature; |
| this._callinModifier = modifier; |
| } |
| |
| Mapping(char[] fileName, short lineNumber, short lineOffset, |
| char[] name, char[] selector, char[] signature, short flags, char[] liftMethodName, char[] liftMethodSignature, char[] modifier) |
| { |
| this(name, selector, signature, flags, liftMethodName, liftMethodSignature, modifier); |
| this._fileName = fileName; |
| this._lineNumber = lineNumber; |
| this._lineOffset = lineOffset; |
| } |
| |
| int getSize() { |
| return |
| CONSTANT_PART_LENGTH |
| + 2 // count |
| +(this._baseMethods.length |
| * BASE_METHOD_PART_LENGTH); |
| } |
| @Override |
| @SuppressWarnings("nls") |
| public String toString() { |
| String result = |
| new String(this._mappingName)+":\n"+ |
| new String(this._roleSelector) + new String(this._roleSignature)+ |
| " <- " + new String(this._callinModifier) + " "; |
| for (int i = 0; i < this._baseMethods.length; i++) { |
| result += new String(this._baseMethods[i]._selector)+new String(this._baseMethods[i]._signature); |
| if ((this._flags & COVARIANT_BASE_RETURN) != 0) |
| result += "+"; |
| } |
| if (this._liftMethodName.length > 0) |
| result += "\nlift by: "+new String(this._liftMethodName)+new String(this._liftMethodSignature); |
| return result; |
| } |
| |
| /** |
| * Compute from 'decl' and store info as needed for SMAP (JSR-045). |
| */ |
| void setSMAPinfo(CallinMappingDeclaration decl) { |
| this._fileName = getFileName(decl); |
| int[] lineEnds = decl.scope.referenceCompilationUnit().compilationResult().getLineSeparatorPositions(); |
| this._lineNumber = |
| (short)Util.getLineNumber(decl.sourceStart, lineEnds, 0, lineEnds.length-1); |
| short lineEnd = |
| (short)Util.getLineNumber(decl.declarationSourceEnd, lineEnds, 0, lineEnds.length-1); |
| this._lineOffset = (short)(lineEnd - this._lineNumber); |
| } |
| |
| /** Compute the name of the file containing the given callin mapping. |
| * Do consider packages but no projects or source folders. |
| * @param decl the declaration who's declaring file is being requested |
| * @return non-null source-folder relative file name |
| */ |
| private char[] getFileName(CallinMappingDeclaration decl) { |
| CompilationUnitDeclaration compilationUnit = decl.scope.referenceCompilationUnit(); |
| char[] fullName = compilationUnit.getFileName(); |
| char[][] packageName = null; |
| if ( compilationUnit.currentPackage == null |
| || compilationUnit.currentPackage.tokens.length == 0) |
| { // default package, use last path component only |
| int pos = CharOperation.lastIndexOf('/', fullName); |
| if (pos == -1) // no '/' |
| return fullName; |
| return CharOperation.subarray(fullName, pos+1, -1); |
| } |
| packageName = compilationUnit.currentPackage.tokens; |
| char[][] components = CharOperation.splitOn('/', fullName); |
| |
| // sometimes fullname (ie., compilationUnit.getFileName()) does not contain any path, just sourceunitname, |
| // which is due to the many different contexts calling new CompilationResult(fileName..) |
| int pos = CharOperation.lastIndexOf('/', fullName); |
| if (pos == -1) |
| { |
| return CharOperation.concatWith (packageName, fullName, '/'); |
| } |
| |
| //check whether components contains packageName: |
| if (components.length <= packageName.length) |
| throw new InternalCompilerError("too few path elements"); //$NON-NLS-1$ |
| int start = components.length - (packageName.length + 1); |
| int end = components.length; |
| if (!CharOperation.equals(packageName, |
| CharOperation.subarray(components, start, end - 1))) |
| decl.scope.problemReporter().packageIsNotExpectedPackage(compilationUnit); |
| return CharOperation.concatWith(CharOperation.subarray(components, start, end), '/'); |
| } |
| |
| // == below: support for copying wrappers for callin-to-private |
| |
| public boolean roleMethodIsPrivate() { |
| if (this._binding == null) |
| return false; |
| return this._binding._roleMethodBinding.isPrivate(); |
| } |
| |
| public char[][] getWrapperNames() { |
| if (this._baseMethods == null) |
| return null; |
| char[][] names = new char[this._baseMethods.length][]; |
| for (int i = 0; i < this._baseMethods.length; i++) |
| names[i] = this._baseMethods[i]._wrapperName; |
| return names; |
| } |
| |
| public char[][] getWrapperSignatures() { |
| if (this._baseMethods == null) |
| return null; |
| char[][] signatures = new char[this._baseMethods.length][]; |
| for (int i = 0; i < this._baseMethods.length; i++) |
| signatures[i] = this._baseMethods[i]._wrapperSign; |
| return signatures; |
| } |
| |
| public Mapping cloneForSubrole() { |
| Mapping other = new Mapping(this._fileName, this._lineNumber, this._lineOffset, |
| this._mappingName, this._roleSelector, this._roleSignature, |
| this._flags, this._liftMethodName, this._liftMethodSignature, |
| this._callinModifier); |
| other._flags |= INHERITED; |
| other._baseMethods = this._baseMethods; // shared, not modified |
| return other; |
| } |
| } |
| /** |
| * Local structure to store values when read from byte code. |
| */ |
| private class BaseMethod { |
| static final int CALLIN = 1; |
| static final int STATIC = 2; |
| char[] _selector, _signature, _wrapperName, _wrapperSign; |
| boolean _isCallin, _isStatic; |
| int _translationFlags; |
| MethodSpec _methodSpec = null; |
| BaseMethod (char[] sel, char[] sig, char[] wrapName, char[] wrapSign, int flags, int translationFlags) |
| { |
| this(sel, sig, wrapName, wrapSign, (flags & CALLIN)!=0, (flags & STATIC)!=0, translationFlags); |
| } |
| BaseMethod (char[] sel, char[] sig, char[] wrapName, char[] wrapSign, |
| boolean isCallin, boolean isStatic, int translationFlags) |
| { |
| this._selector = sel; |
| this._signature = sig; |
| this._wrapperName = wrapName; |
| this._wrapperSign = wrapSign; |
| this._isCallin = isCallin; |
| this._isStatic = isStatic; |
| this._translationFlags = translationFlags; |
| } |
| @Override |
| @SuppressWarnings("nls") |
| public String toString() { |
| return (this._isCallin ? "callin " : "") + (this._isStatic ? "static " : "") + new String(this._selector)+new String(this._signature); |
| } |
| public void fetchTranslationFlags() { |
| this._translationFlags = this._methodSpec.getTranslationFlags(); |
| this._methodSpec = null; |
| } |
| |
| } |
| public Mapping[] _mappings; // this holds the data read from byte code |
| private int _size; // attribute size in bytes |
| |
| /** |
| * @param decls the mapping declarations to encode and store in this attribute. |
| */ |
| public CallinMethodMappingsAttribute(CallinMappingDeclaration[] decls) |
| { |
| super(IOTConstants.CALLIN_METHOD_MAPPINGS); |
| |
| // lengths/counts: |
| this._size = 0; |
| int len = decls.length; |
| // subtract errors: |
| for (int i = 0; i < decls.length; i++) { |
| if (decls[i].ignoreFurtherInvestigation) |
| len--; |
| } |
| |
| this._mappings = new Mapping[len]; |
| int idx = 0; |
| for (int i = 0; i < decls.length; i++) { |
| CallinMappingDeclaration decl = decls[i]; |
| if (decl.ignoreFurtherInvestigation) |
| continue; |
| |
| this._size += CONSTANT_PART_LENGTH; |
| |
| short flags = 0; |
| if (decl.roleMethodSpec.resolvedMethod.isStatic()) |
| flags |= STATIC_ROLE_METHOD; |
| if (decl.hasCovariantReturn()) |
| flags |= COVARIANT_BASE_RETURN; |
| |
| |
| Mapping currentMapping = |
| this._mappings[idx++] = new Mapping( |
| decl.name, |
| decl.roleMethodSpec.selector, |
| decl.roleMethodSpec.signature(WeavingScheme.OTRE), |
| flags, |
| decl.liftMethod != null ? |
| decl.liftMethod.selector : new char[0], |
| decl.liftMethod != null ? |
| decl.liftMethod.signature() : new char[0], |
| decl.getCallinModifier()); |
| currentMapping.setSMAPinfo(decl); |
| |
| MethodSpec[] baseMethods = decl.baseMethodSpecs; |
| currentMapping._baseMethods = new BaseMethod[baseMethods.length]; |
| this._size += 2; // 1 count |
| for (int j = 0; j < baseMethods.length; j++) { |
| MethodSpec bm = baseMethods[j]; |
| MethodDeclaration wrapper = decl.getWrapper(bm); |
| |
| this._size += BASE_METHOD_PART_LENGTH; |
| currentMapping._baseMethods[j] = new BaseMethod( |
| bm.codegenSeletor(), |
| bm.resolvedMethod.signature(), |
| wrapper.selector, |
| wrapper.binding.signature(), |
| bm.isCallin(), |
| bm.resolvedMethod.isStatic(), |
| bm.getTranslationFlags()); |
| // callins with param mappings compute the need for translation only during resolve() |
| // (see PotentialLiftExpression.rememberMethodSpec().) |
| if (decl.mappings != null) |
| currentMapping._baseMethods[j]._methodSpec = bm; |
| } |
| } |
| } |
| |
| /** |
| * Read the attribute from byte code. |
| * |
| * @param reader this reader holds the bytes to read |
| * @param readOffset offset where to start reading |
| * @param constantPoolOffsets constant pool offset to be used during reading |
| */ |
| public CallinMethodMappingsAttribute(ClassFileStruct reader, int readOffset, int[] constantPoolOffsets) { |
| super(IOTConstants.CALLIN_METHOD_MAPPINGS); |
| this._reader = reader; |
| this._readOffset = readOffset; |
| this._constantPoolOffsets = constantPoolOffsets; |
| |
| this._size = 0; |
| int numMappings = consumeShort(); |
| this._mappings = new Mapping[numMappings]; |
| for (int i=0; i<numMappings; i++) |
| this._mappings[i] = readMapping(); |
| } |
| |
| @Override |
| public void merge(ModelElement model, AbstractAttribute other) |
| { |
| assert other instanceof CallinMethodMappingsAttribute; |
| assert model instanceof TypeModel; |
| ReferenceBinding typeBinding = ((TypeModel)model).getBinding(); |
| |
| CallinMethodMappingsAttribute otherCMMA = (CallinMethodMappingsAttribute)other; |
| HashMap<String,Mapping> set = new HashMap<String,Mapping>(); |
| LinkedList<CallinCalloutBinding> newBindings = new LinkedList<CallinCalloutBinding>(); |
| for (int i = 0; i < this._mappings.length; i++) { |
| set.put(new String(this._mappings[i]._mappingName), this._mappings[i]); |
| } |
| for (int i = 0; i < otherCMMA._mappings.length; i++) { |
| Mapping mapping = otherCMMA._mappings[i]; |
| if (set.containsKey(new String(mapping._mappingName))) { |
| continue; |
| } |
| set.put(new String(mapping._mappingName), mapping.cloneForSubrole()); |
| this._size += mapping.getSize(); |
| |
| newBindings.add(createBinding(typeBinding, mapping)); |
| } |
| |
| // store combined array: |
| Collection<Mapping> values = set.values(); |
| this._mappings = new Mapping[values.size()]; |
| values.toArray(this._mappings); |
| |
| // add new mappings to the binding: |
| if (newBindings.size() > 0) { |
| CallinCalloutBinding[] callins = new CallinCalloutBinding[newBindings.size()]; |
| newBindings.toArray(callins); |
| typeBinding.addCallinCallouts(callins); |
| } |
| } |
| /** |
| * Read one method mapping |
| */ |
| private Mapping readMapping() { |
| this._size += CONSTANT_PART_LENGTH; |
| Mapping map = new Mapping( |
| consumeName(), (short)consumeShort(), (short)consumeShort(), |
| consumeName(), consumeName(), consumeName(), (short)consumeShort(), |
| consumeName(), consumeName(), consumeName()); |
| this._size += 2; |
| int numBaseMethods = consumeShort(); |
| map._baseMethods = new BaseMethod[numBaseMethods]; |
| for (int i=0; i<numBaseMethods; i++) { |
| map._baseMethods[i] = readBaseMethod(); |
| } |
| return map; |
| } |
| |
| /** |
| * Read data for one bound base method. |
| */ |
| private BaseMethod readBaseMethod() { |
| this._size += BASE_METHOD_PART_LENGTH; |
| return new BaseMethod(consumeName(), |
| consumeName(), |
| consumeName(), |
| consumeName(), |
| consumeByte(), |
| consumeInt()); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.AbstractAttribute#write(org.eclipse.jdt.internal.compiler.ClassFile) |
| */ |
| @Override |
| public void write(ClassFile classFile) { |
| super.write(classFile); |
| |
| writeValues(classFile); |
| |
| writeBack(classFile); |
| } |
| |
| /** |
| * Write the contents from values stored in _mappings |
| * @param classFile |
| */ |
| private void writeValues(ClassFile classFile) { |
| if (this._contentsOffset + 8 + this._size >= this._contents.length) { // 8: name(2) + size(4) + elementCount(2) |
| this._contents = classFile.getResizedContents(8 + this._size); |
| } |
| writeName (this._name); |
| writeInt (this._size + 2); // + elementCount |
| writeUnsignedShort(this._mappings.length); |
| for (int i=0; i<this._mappings.length; i++) { |
| Mapping map = this._mappings[i]; |
| writeName(map._fileName); |
| writeUnsignedShort(map._lineNumber); |
| writeUnsignedShort(map._lineOffset); |
| writeName(map._mappingName); |
| writeName(map._roleSelector); |
| writeName(map._roleSignature); |
| writeUnsignedShort(map._flags); |
| writeName(map._liftMethodName); |
| writeName(map._liftMethodSignature); |
| writeName(map._callinModifier); |
| writeBaseMethods(this._mappings[i]._baseMethods); |
| } |
| } |
| |
| |
| private void writeBaseMethods(BaseMethod[] methods) { |
| writeUnsignedShort(methods.length); |
| for (int i = 0; i < methods.length; i++) { |
| writeName(methods[i]._selector); |
| writeName(methods[i]._signature); |
| writeName(methods[i]._wrapperName); |
| writeName(methods[i]._wrapperSign); |
| int flags = 0; |
| if (methods[i]._isCallin) flags |= BaseMethod.CALLIN; |
| if (methods[i]._isStatic) flags |= BaseMethod.STATIC; |
| writeByte((byte)flags); |
| if (methods[i]._methodSpec != null) |
| methods[i].fetchTranslationFlags(); |
| writeInt(methods[i]._translationFlags); |
| } |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.AbstractAttribute#evaluate(org.eclipse.jdt.internal.compiler.lookup.Binding, org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment) |
| */ |
| @Override |
| public void evaluate(Binding binding, LookupEnvironment environment, char[][][] missingTypeNames) { |
| checkBindingMismatch(binding, ExtraCompilerModifiers.AccRole); |
| if (((ReferenceBinding)binding).isRole()) |
| ((ReferenceBinding)binding).roleModel.addAttribute(this); |
| } |
| // Evaluate CallinMethodMappingAttribute late, because we need our methods to be in place. |
| @Override |
| public void evaluateLateAttribute(ReferenceBinding roleBinding, int state) |
| { |
| if (state != ITranslationStates.STATE_FAULT_IN_TYPES) |
| return; |
| CallinCalloutBinding[] callins = new CallinCalloutBinding[this._mappings.length]; |
| for (int i = 0; i < this._mappings.length; i++) { |
| callins[i] = createBinding(roleBinding, this._mappings[i]); |
| } |
| if (callins.length > 0) |
| roleBinding.addCallinCallouts(callins); |
| } |
| |
| /** |
| * @param roleBinding |
| * @param mapping |
| * @throws InternalCompilerError |
| */ |
| private CallinCalloutBinding createBinding(ReferenceBinding roleBinding, Mapping mapping) |
| { |
| CallinCalloutBinding result = null; |
| CallinCalloutBinding[] callinCallouts = roleBinding.callinCallouts; |
| if (callinCallouts != null) { |
| for (int i = 0; i < callinCallouts.length; i++) { |
| if (CharOperation.equals(mapping._mappingName, callinCallouts[i].name)) |
| { |
| // fill in details to existing binding: |
| result = callinCallouts[i]; |
| result.callinModifier = encodeCallinModifier(mapping._callinModifier); |
| break; |
| } |
| } |
| } |
| if (result == null) |
| result = new CallinCalloutBinding(roleBinding, |
| mapping._mappingName, |
| encodeCallinModifier(mapping._callinModifier)); |
| BaseMethod[] mappingBaseMethods = mapping._baseMethods; |
| MethodBinding[] baseMethods = new MethodBinding[mappingBaseMethods.length]; |
| |
| ReferenceBinding currentType = roleBinding; |
| char[] roleSignature = mapping._roleSignature; |
| if (result.callinModifier == TerminalTokens.TokenNamereplace) { |
| // ignore generalized return by truncating the signature: |
| int closePos = CharOperation.indexOf(')', roleSignature); |
| if (closePos > -1) |
| roleSignature = CharOperation.subarray(roleSignature, 0, closePos+1); |
| } |
| |
| roleMethod: |
| while (currentType != null) { |
| ReferenceBinding currentType2 = currentType; |
| while (currentType2 != null) { |
| MethodBinding[] methods = currentType2.getMethods(mapping._roleSelector); |
| for (int j = 0; j < methods.length; j++) { |
| if (CharOperation.prefixEquals(roleSignature, MethodSpec.signature(methods[j], WeavingScheme.OTRE))) |
| { |
| result._roleMethodBinding = methods[j]; |
| break roleMethod; |
| } |
| } |
| currentType2 = currentType2.superclass(); |
| } |
| currentType = currentType.enclosingType(); |
| } |
| if (result._roleMethodBinding == null) |
| throw new InternalCompilerError("role method specified in callin mapping does not exist "+mapping); //$NON-NLS-1$ |
| |
| |
| mappingBaseMethods: |
| for (int i = 0; i < mappingBaseMethods.length; i++) { |
| BaseMethod bm = mappingBaseMethods[i]; |
| currentType = roleBinding.baseclass(); |
| while (currentType != null) { |
| MethodBinding[] methods = currentType.getMethods(bm._selector); |
| for (int j = 0; j < methods.length; j++) { |
| if (CharOperation.equals(bm._signature, methods[j].signature())) // TODO(SH): enhancing? / _isCallin? |
| { |
| baseMethods[i] = methods[j]; |
| continue mappingBaseMethods; |
| } |
| } |
| currentType = currentType.superclass(); |
| } |
| baseMethods[i]= new ProblemMethodBinding(bm._selector, null, roleBinding.baseclass(), ProblemReasons.NotFound); |
| } |
| result._baseMethods = baseMethods; |
| mapping._binding = result; |
| |
| result.copyInheritanceSrc = findTSuperBinding(mapping._mappingName, roleBinding); |
| return result; |
| } |
| |
| private CallinCalloutBinding findTSuperBinding(char[] name, ReferenceBinding roleType) { |
| ReferenceBinding[] tsuperRoles = roleType.roleModel.getTSuperRoleBindings(); |
| for (int i = tsuperRoles.length-1; i >= 0; i--) { // check highest prio first (which comes last in the array) |
| if (tsuperRoles[i].callinCallouts != null) |
| for (CallinCalloutBinding mapping : tsuperRoles[i].callinCallouts) |
| if (CharOperation.equals(mapping.name, name)) |
| return mapping.copyInheritanceSrc != null ? |
| mapping.copyInheritanceSrc : |
| mapping; |
| } |
| return null; |
| } |
| |
| private int encodeCallinModifier(char[] modifierName) { |
| if (CharOperation.equals(modifierName, IOTConstants.NAME_REPLACE)) |
| return TerminalTokens.TokenNamereplace; |
| if (CharOperation.equals(modifierName, IOTConstants.NAME_AFTER)) |
| return TerminalTokens.TokenNameafter; |
| if (CharOperation.equals(modifierName, IOTConstants.NAME_BEFORE)) |
| return TerminalTokens.TokenNamebefore; |
| throw new InternalCompilerError("invalid callin modifier in byte code"); //$NON-NLS-1$ |
| } |
| |
| |
| // ==== public accessors for use by org.eclipse.jdt.internal.core.ClassFileInfo ==== |
| public int getLength() { |
| return this._mappings.length; |
| } |
| public char[] getCallinNameAt(int i) { |
| return this._mappings[i]._mappingName; |
| } |
| public String getRoleMethodNameAt(int i) { |
| return new String(this._mappings[i]._roleSelector); |
| } |
| public String getRoleMethodSignatureAt(int i) { |
| return new String(this._mappings[i]._roleSignature); |
| } |
| public String[] getBaseMethodNamesAt(int i) { |
| BaseMethod[] baseMethods = this._mappings[i]._baseMethods; |
| String[] names = new String[baseMethods.length]; |
| for (int j = 0; j < baseMethods.length; j++) { |
| names[j] = new String(baseMethods[j]._selector); |
| } |
| return names; |
| } |
| public String[] getBaseMethodSignaturesAt(int i) { |
| BaseMethod[] baseMethods = this._mappings[i]._baseMethods; |
| String[] signatures = new String[baseMethods.length]; |
| for (int j = 0; j < baseMethods.length; j++) { |
| signatures[j] = new String(baseMethods[j]._signature); |
| } |
| return signatures; |
| } |
| |
| /** |
| * translate modifier name of the ith mapping to token (TerminalTokens.TokenNameXXX). |
| */ |
| public int getCallinModifierAt(int i) { |
| char[] modifierName = this._mappings[i]._callinModifier; |
| if (CharOperation.equals(modifierName, IOTConstants.NAME_BEFORE)) |
| return TerminalTokens.TokenNamebefore; |
| if (CharOperation.equals(modifierName, IOTConstants.NAME_REPLACE)) |
| return TerminalTokens.TokenNamereplace; |
| if (CharOperation.equals(modifierName, IOTConstants.NAME_AFTER)) |
| return TerminalTokens.TokenNameafter; |
| return -1; |
| } |
| |
| /** Does mapping `i' declare covariant return types ('+')? */ |
| public boolean getCovariantReturnAt(int i) { |
| return (this._mappings[i]._flags & COVARIANT_BASE_RETURN) != 0; |
| } |
| |
| @Override |
| public String toString() { |
| String result = new String(this._name); |
| for (int i = 0; i < this._mappings.length; i++) { |
| result += "\n"+this._mappings[i]; //$NON-NLS-1$ |
| } |
| return result; |
| } |
| |
| public boolean isInherited() { |
| for (Mapping mapping : this._mappings) { |
| if ((mapping._flags & INHERITED) == 0) |
| return false; |
| } |
| return true; // only if all mappings are inherited. |
| } |
| } |