blob: 6c8dd149765a2e7d4bca49fa55d3106bb3eca743 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2015 IBM Corporation and others.
* 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*
* Fraunhofer FIRST - extended API and implementation
* Technical University Berlin - extended API and implementation *
*******************************************************************************/
package org.eclipse.jdt.internal.compiler;
import java.util.ArrayList;
import java.util.Map;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ISourceElementRequestor.ParameterInfo;
import org.eclipse.jdt.internal.compiler.ISourceElementRequestor.TypeParameterInfo;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
import org.eclipse.jdt.internal.compiler.ast.ArrayReference;
import org.eclipse.jdt.internal.compiler.ast.Assignment;
import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.Initializer;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.AbstractMethodMappingDeclaration;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CallinMappingDeclaration;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.GuardPredicateDeclaration;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.LiftingTypeReference;
import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec;
import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.MethodSignatureEnhancer;
@SuppressWarnings({"rawtypes", "unchecked"})
public class SourceElementNotifier {
/**
* An ast visitor that visits local type declarations.
*/
public class LocalDeclarationVisitor extends ASTVisitor {
public ImportReference currentPackage;
ArrayList declaringTypes;
public void pushDeclaringType(TypeDeclaration declaringType) {
if (this.declaringTypes == null) {
this.declaringTypes = new ArrayList();
}
this.declaringTypes.add(declaringType);
}
public void popDeclaringType() {
this.declaringTypes.remove(this.declaringTypes.size()-1);
}
public TypeDeclaration peekDeclaringType() {
if (this.declaringTypes == null) return null;
int size = this.declaringTypes.size();
if (size == 0) return null;
return (TypeDeclaration) this.declaringTypes.get(size-1);
}
public boolean visit(TypeDeclaration typeDeclaration, BlockScope scope) {
notifySourceElementRequestor(typeDeclaration, true, peekDeclaringType(), this.currentPackage);
return false; // don't visit members as this was done during notifySourceElementRequestor(...)
}
public boolean visit(TypeDeclaration typeDeclaration, ClassScope scope) {
notifySourceElementRequestor(typeDeclaration, true, peekDeclaringType(), this.currentPackage);
return false; // don't visit members as this was done during notifySourceElementRequestor(...)
}
}
ISourceElementRequestor requestor;
boolean reportReferenceInfo;
char[][] typeNames;
char[][] superTypeNames;
int nestedTypeIndex;
LocalDeclarationVisitor localDeclarationVisitor = null;
HashtableOfObjectToInt sourceEnds;
Map nodesToCategories;
int initialPosition;
int eofPosition;
public SourceElementNotifier(ISourceElementRequestor requestor, boolean reportLocalDeclarations) {
this.requestor = requestor;
if (reportLocalDeclarations) {
this.localDeclarationVisitor = new LocalDeclarationVisitor();
}
this.typeNames = new char[4][];
this.superTypeNames = new char[4][];
this.nestedTypeIndex = 0;
}
protected Object[][] getArgumentInfos(Argument[] arguments) {
int argumentLength = arguments.length;
char[][] argumentTypes = new char[argumentLength][];
char[][] argumentNames = new char[argumentLength][];
ParameterInfo[] parameterInfos = new ParameterInfo[argumentLength];
for (int i = 0; i < argumentLength; i++) {
Argument argument = arguments[i];
argumentTypes[i] = CharOperation.concatWith(argument.type.getParameterizedTypeName(), '.');
char[] name = argument.name;
argumentNames[i] = name;
ParameterInfo parameterInfo = new ParameterInfo();
parameterInfo.declarationStart = argument.declarationSourceStart;
parameterInfo.declarationEnd = argument.declarationSourceEnd;
parameterInfo.nameSourceStart = argument.sourceStart;
parameterInfo.nameSourceEnd = argument.sourceEnd;
parameterInfo.modifiers = argument.modifiers;
parameterInfo.name = name;
parameterInfos[i] = parameterInfo;
}
return new Object[][] { parameterInfos, new char[][][] { argumentTypes, argumentNames } };
}
protected char[][] getInterfaceNames(TypeDeclaration typeDeclaration) {
char[][] interfaceNames = null;
int superInterfacesLength = 0;
TypeReference[] superInterfaces = typeDeclaration.superInterfaces;
if (superInterfaces != null) {
superInterfacesLength = superInterfaces.length;
interfaceNames = new char[superInterfacesLength][];
} else {
if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
// see PR 3442
QualifiedAllocationExpression alloc = typeDeclaration.allocation;
if (alloc != null && alloc.type != null) {
superInterfaces = new TypeReference[] { alloc.type};
superInterfacesLength = 1;
interfaceNames = new char[1][];
}
}
}
if (superInterfaces != null) {
for (int i = 0; i < superInterfacesLength; i++) {
interfaceNames[i] =
CharOperation.concatWith(superInterfaces[i].getParameterizedTypeName(), '.');
}
}
return interfaceNames;
}
protected char[] getSuperclassName(TypeDeclaration typeDeclaration) {
TypeReference superclass = typeDeclaration.superclass;
return superclass != null ? CharOperation.concatWith(superclass.getParameterizedTypeName(), '.') : null;
}
protected char[][] getThrownExceptions(AbstractMethodDeclaration methodDeclaration) {
char[][] thrownExceptionTypes = null;
TypeReference[] thrownExceptions = methodDeclaration.thrownExceptions;
if (thrownExceptions != null) {
int thrownExceptionLength = thrownExceptions.length;
thrownExceptionTypes = new char[thrownExceptionLength][];
for (int i = 0; i < thrownExceptionLength; i++) {
thrownExceptionTypes[i] =
CharOperation.concatWith(thrownExceptions[i].getParameterizedTypeName(), '.');
}
}
return thrownExceptionTypes;
}
protected char[][] getTypeParameterBounds(TypeParameter typeParameter) {
TypeReference firstBound = typeParameter.type;
TypeReference[] otherBounds = typeParameter.bounds;
char[][] typeParameterBounds = null;
if (firstBound != null) {
if (otherBounds != null) {
int otherBoundsLength = otherBounds.length;
char[][] boundNames = new char[otherBoundsLength+1][];
boundNames[0] = CharOperation.concatWith(firstBound.getParameterizedTypeName(), '.');
for (int j = 0; j < otherBoundsLength; j++) {
boundNames[j+1] =
CharOperation.concatWith(otherBounds[j].getParameterizedTypeName(), '.');
}
typeParameterBounds = boundNames;
} else {
typeParameterBounds = new char[][] { CharOperation.concatWith(firstBound.getParameterizedTypeName(), '.')};
}
} else {
typeParameterBounds = CharOperation.NO_CHAR_CHAR;
}
return typeParameterBounds;
}
private TypeParameterInfo[] getTypeParameterInfos(TypeParameter[] typeParameters) {
if (typeParameters == null) return null;
int typeParametersLength = typeParameters.length;
TypeParameterInfo[] result = new TypeParameterInfo[typeParametersLength];
for (int i = 0; i < typeParametersLength; i++) {
TypeParameter typeParameter = typeParameters[i];
char[][] typeParameterBounds = getTypeParameterBounds(typeParameter);
ISourceElementRequestor.TypeParameterInfo typeParameterInfo = new ISourceElementRequestor.TypeParameterInfo();
typeParameterInfo.declarationStart = typeParameter.declarationSourceStart;
typeParameterInfo.declarationEnd = typeParameter.declarationSourceEnd;
typeParameterInfo.name = typeParameter.name;
typeParameterInfo.nameSourceStart = typeParameter.sourceStart;
typeParameterInfo.nameSourceEnd = typeParameter.sourceEnd;
typeParameterInfo.bounds = typeParameterBounds;
//{ObjectTeams: value parameter / <B base R> ?
if (typeParameter.getKind() == AbstractVariableDeclaration.TYPE_VALUE_PARAMETER)
typeParameterInfo.isValueParameter= true;
if (typeParameter.hasBaseBound())
typeParameterInfo.hasBaseBound= true;
// SH}
result[i] = typeParameterInfo;
}
return result;
}
/*
* Checks whether one of the annotations is the @Deprecated annotation
* (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=89807)
*/
private boolean hasDeprecatedAnnotation(Annotation[] annotations) {
if (annotations != null) {
for (int i = 0, length = annotations.length; i < length; i++) {
Annotation annotation = annotations[i];
if (CharOperation.equals(annotation.type.getLastToken(), TypeConstants.JAVA_LANG_DEPRECATED[2])) {
return true;
}
}
}
return false;
}
/*
* Update the bodyStart of the corresponding parse node
*/
protected void notifySourceElementRequestor(AbstractMethodDeclaration methodDeclaration, TypeDeclaration declaringType, ImportReference currentPackage) {
// range check
boolean isInRange =
this.initialPosition <= methodDeclaration.declarationSourceStart
&& this.eofPosition >= methodDeclaration.declarationSourceEnd;
if (methodDeclaration.isClinit()) {
this.visitIfNeeded(methodDeclaration);
return;
}
if (methodDeclaration.isDefaultConstructor()) {
if (this.reportReferenceInfo) {
ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) methodDeclaration;
ExplicitConstructorCall constructorCall = constructorDeclaration.constructorCall;
if (constructorCall != null) {
switch(constructorCall.accessMode) {
case ExplicitConstructorCall.This :
this.requestor.acceptConstructorReference(
this.typeNames[this.nestedTypeIndex-1],
constructorCall.arguments == null ? 0 : constructorCall.arguments.length,
constructorCall.sourceStart);
break;
case ExplicitConstructorCall.Super :
case ExplicitConstructorCall.ImplicitSuper :
this.requestor.acceptConstructorReference(
this.superTypeNames[this.nestedTypeIndex-1],
constructorCall.arguments == null ? 0 : constructorCall.arguments.length,
constructorCall.sourceStart);
break;
}
}
}
return;
}
char[][] argumentTypes = null;
char[][] argumentNames = null;
boolean isVarArgs = false;
//{ObjectTeams: retrench signature of callin method:
/* orig:
Argument[] arguments = methodDeclaration.arguments;
:giro */
Argument[] arguments = MethodSignatureEnhancer.getSourceArguments(methodDeclaration);
boolean [] baseclassFlags = null;
// SH}
ParameterInfo[] parameterInfos = null;
ISourceElementRequestor.MethodInfo methodInfo = new ISourceElementRequestor.MethodInfo();
methodInfo.typeAnnotated = ((methodDeclaration.bits & ASTNode.HasTypeAnnotations) != 0);
if (arguments != null) {
Object[][] argumentInfos = getArgumentInfos(arguments);
parameterInfos = (ParameterInfo[]) argumentInfos[0];
argumentTypes = (char[][]) argumentInfos[1][0];
argumentNames = (char[][]) argumentInfos[1][1];
isVarArgs = arguments[arguments.length-1].isVarArgs();
//{ObjectTeams: compute flag array
baseclassFlags = new boolean[arguments.length];
for (int i = 0; i < arguments.length; i++)
// LTRs resolve in base-import scope, if present.
baseclassFlags[i] = (arguments[i].type instanceof LiftingTypeReference);
// SH}
}
char[][] thrownExceptionTypes = getThrownExceptions(methodDeclaration);
// by default no selector end position
int selectorSourceEnd = -1;
if (methodDeclaration.isConstructor()) {
selectorSourceEnd = this.sourceEnds.get(methodDeclaration);
if (isInRange){
int currentModifiers = methodDeclaration.modifiers;
currentModifiers &= ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccDeprecated;
if (isVarArgs)
currentModifiers |= ClassFileConstants.AccVarargs;
if (hasDeprecatedAnnotation(methodDeclaration.annotations))
currentModifiers |= ClassFileConstants.AccDeprecated;
methodInfo.isConstructor = true;
methodInfo.declarationStart = methodDeclaration.declarationSourceStart;
methodInfo.modifiers = currentModifiers;
// Note(SH): OT: no callin flag in constructor ;-)
methodInfo.name = methodDeclaration.selector;
methodInfo.nameSourceStart = methodDeclaration.sourceStart;
methodInfo.nameSourceEnd = selectorSourceEnd;
methodInfo.parameterTypes = argumentTypes;
methodInfo.parameterNames = argumentNames;
//{ObjectTeams: store additional array
methodInfo.parameterBaseclassFlags = baseclassFlags;
// SH}
methodInfo.exceptionTypes = thrownExceptionTypes;
methodInfo.typeParameters = getTypeParameterInfos(methodDeclaration.typeParameters());
methodInfo.parameterInfos = parameterInfos;
methodInfo.categories = (char[][]) this.nodesToCategories.get(methodDeclaration);
methodInfo.annotations = methodDeclaration.annotations;
methodInfo.declaringPackageName = currentPackage == null ? CharOperation.NO_CHAR : CharOperation.concatWith(currentPackage.tokens, '.');
methodInfo.declaringTypeModifiers = declaringType.modifiers;
methodInfo.extraFlags = ExtraFlags.getExtraFlags(declaringType);
methodInfo.node = methodDeclaration;
this.requestor.enterConstructor(methodInfo);
}
if (this.reportReferenceInfo) {
ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) methodDeclaration;
ExplicitConstructorCall constructorCall = constructorDeclaration.constructorCall;
if (constructorCall != null) {
switch(constructorCall.accessMode) {
case ExplicitConstructorCall.This :
this.requestor.acceptConstructorReference(
this.typeNames[this.nestedTypeIndex-1],
constructorCall.arguments == null ? 0 : constructorCall.arguments.length,
constructorCall.sourceStart);
break;
case ExplicitConstructorCall.Super :
case ExplicitConstructorCall.ImplicitSuper :
this.requestor.acceptConstructorReference(
this.superTypeNames[this.nestedTypeIndex-1],
constructorCall.arguments == null ? 0 : constructorCall.arguments.length,
constructorCall.sourceStart);
break;
}
}
}
this.visitIfNeeded(methodDeclaration);
if (isInRange){
this.requestor.exitConstructor(methodDeclaration.declarationSourceEnd);
}
return;
}
selectorSourceEnd = this.sourceEnds.get(methodDeclaration);
if (isInRange) {
int currentModifiers = methodDeclaration.modifiers;
//{ObjectTeams: additionally pass AccCallin:
/* orig:
currentModifiers &= ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccDeprecated | ClassFileConstants.AccAnnotationDefault | ExtraCompilerModifiers.AccDefaultMethod;
:giro */
currentModifiers &= ExtraCompilerModifiers.AccJustFlag | ExtraCompilerModifiers.AccCallin | ClassFileConstants.AccDeprecated | ClassFileConstants.AccAnnotationDefault | ExtraCompilerModifiers.AccDefaultMethod;
// SH}
if (isVarArgs)
currentModifiers |= ClassFileConstants.AccVarargs;
if (hasDeprecatedAnnotation(methodDeclaration.annotations))
currentModifiers |= ClassFileConstants.AccDeprecated;
TypeReference returnType = methodDeclaration instanceof MethodDeclaration
? ((MethodDeclaration) methodDeclaration).returnType
: null;
methodInfo.isAnnotation = methodDeclaration instanceof AnnotationMethodDeclaration;
methodInfo.declarationStart = methodDeclaration.declarationSourceStart;
methodInfo.modifiers = currentModifiers;
methodInfo.returnType = returnType == null ? null : CharOperation.concatWith(returnType.getParameterizedTypeName(), '.');
methodInfo.name = methodDeclaration.selector;
methodInfo.nameSourceStart = methodDeclaration.sourceStart;
methodInfo.nameSourceEnd = selectorSourceEnd;
methodInfo.parameterTypes = argumentTypes;
methodInfo.parameterNames = argumentNames;
//{ObjectTeams: store additional array
methodInfo.parameterBaseclassFlags = baseclassFlags;
// SH}
methodInfo.exceptionTypes = thrownExceptionTypes;
methodInfo.typeParameters = getTypeParameterInfos(methodDeclaration.typeParameters());
methodInfo.parameterInfos = parameterInfos;
methodInfo.categories = (char[][]) this.nodesToCategories.get(methodDeclaration);
methodInfo.annotations = methodDeclaration.annotations;
methodInfo.node = methodDeclaration;
methodInfo.enclosingType = declaringType;
methodInfo.declaringPackageName = currentPackage == null ? CharOperation.NO_CHAR : CharOperation.concatWith(currentPackage.tokens, '.');
this.requestor.enterMethod(methodInfo);
}
this.visitIfNeeded(methodDeclaration);
if (isInRange) {
if (methodDeclaration instanceof AnnotationMethodDeclaration) {
AnnotationMethodDeclaration annotationMethodDeclaration = (AnnotationMethodDeclaration) methodDeclaration;
Expression expression = annotationMethodDeclaration.defaultValue;
if (expression != null) {
this.requestor.exitMethod(methodDeclaration.declarationSourceEnd, expression);
return;
}
}
this.requestor.exitMethod(methodDeclaration.declarationSourceEnd, null);
}
}
//{OTDTUI: needed for method mappings
private char[] returnTypeName(MethodSpec spec) {
return (!spec.hasSignature || spec.returnType == null) ?
null : CharOperation.concatWith(spec.returnType.getParameterizedTypeName(), '.');
}
public void notifySourceElementRequestor(AbstractMethodMappingDeclaration mapping)
{
// range check
boolean isInRange =
this.initialPosition <= mapping.sourceStart
&& this.eofPosition >= mapping.sourceEnd;
if (isInRange)
{
if (mapping instanceof CalloutMappingDeclaration)
{
CalloutMappingDeclaration callout = (CalloutMappingDeclaration)mapping;
// role method spec:
ISourceElementRequestor.MethodSpecInfo roleInfo= new ISourceElementRequestor.MethodSpecInfo();
boolean isDeclaration = false;
if (callout.roleMethodSpec != null) {
roleInfo.node = callout.roleMethodSpec;
roleInfo.parameterTypes= argumentTypes(callout.roleMethodSpec);
roleInfo.parameterNames= argumentNames(callout.roleMethodSpec);
roleInfo.selector= callout.roleMethodSpec.selector;
roleInfo.returnType= returnTypeName(callout.roleMethodSpec);
isDeclaration= callout.roleMethodSpec.isDeclaration;
}
// prepare base side:
char[] baseReturnTypeName = null;
char[] baseSelector = null;
if (callout.baseMethodSpec != null) {
baseReturnTypeName= returnTypeName(callout.baseMethodSpec);
baseSelector= callout.baseMethodSpec.selector;
}
if (callout.isCalloutToField())
{
ISourceElementRequestor.CalloutToFieldInfo info= new ISourceElementRequestor.CalloutToFieldInfo();
info.isSetter= ((FieldAccessSpec)callout.baseMethodSpec).isSetter();
info.declarationSourceStart= mapping.declarationSourceStart;
info.sourceStart= mapping.sourceStart;
info.hasSignature= callout.hasSignature;
info.isDeclaration= isDeclaration;
info.isOverride= mapping.isCalloutOverride();
info.declaredModifiers= callout.declaredModifiers;
info.left= roleInfo;
// base field spec:
info.rightSelector= baseSelector;
info.rightReturnType= baseReturnTypeName;
info.annotations = mapping.annotations;
this.requestor.enterCalloutToFieldMapping(info);
visitIfNeeded(callout);
} else {
ISourceElementRequestor.CalloutInfo info= new ISourceElementRequestor.CalloutInfo();
info.declarationSourceStart= mapping.declarationSourceStart;
info.sourceStart= mapping.sourceStart;
info.hasSignature= callout.hasSignature;
info.isDeclaration= isDeclaration;
info.isOverride= mapping.isCalloutOverride();
info.declaredModifiers= callout.declaredModifiers;
info.left= roleInfo;
// base method spec:
ISourceElementRequestor.MethodSpecInfo baseInfo= new ISourceElementRequestor.MethodSpecInfo();
baseInfo.node = callout.baseMethodSpec;
baseInfo.selector= baseSelector;
baseInfo.returnType= baseReturnTypeName;
baseInfo.parameterTypes= argumentTypes(callout.baseMethodSpec);
baseInfo.parameterNames= argumentNames(callout.baseMethodSpec);
info.right= baseInfo;
info.annotations = mapping.annotations;
this.requestor.enterCalloutMapping(info);
visitIfNeeded(callout);
}
} else {
CallinMappingDeclaration callinDecl = (CallinMappingDeclaration)mapping;
ISourceElementRequestor.CallinInfo info= new ISourceElementRequestor.CallinInfo();
info.declarationSourceStart= mapping.declarationSourceStart;
info.sourceStart= mapping.sourceStart;
info.callinName= callinDecl.name;
info.callinKind= callinDecl.callinModifier;
info.hasSignature= callinDecl.hasSignature;
ISourceElementRequestor.MethodSpecInfo roleInfo= new ISourceElementRequestor.MethodSpecInfo();
roleInfo.node = callinDecl.roleMethodSpec;
roleInfo.selector= callinDecl.roleMethodSpec.selector;
roleInfo.returnType= returnTypeName(callinDecl.roleMethodSpec);
roleInfo.parameterTypes= argumentTypes(callinDecl.roleMethodSpec);
roleInfo.parameterNames= argumentNames(callinDecl.roleMethodSpec);
roleInfo.typeParameters = getTypeParameterInfos(callinDecl.roleMethodSpec.typeParameters);
info.left= roleInfo;
int baseSpecsLength = (callinDecl.baseMethodSpecs == null) ? 0 : callinDecl.baseMethodSpecs.length;
ISourceElementRequestor.MethodSpecInfo[] baseInfos= new ISourceElementRequestor.MethodSpecInfo[baseSpecsLength];
for (int idx=0; idx < baseSpecsLength; idx++)
{
MethodSpec spec = callinDecl.baseMethodSpecs[idx];
baseInfos[idx]= new ISourceElementRequestor.MethodSpecInfo();
baseInfos[idx].node = spec;
baseInfos[idx].selector= spec.selector;
if (callinDecl.hasSignature) {
int argListLength = spec.arguments == null ? 0: spec.arguments.length;
char[][] baseArgTypes= new char[argListLength][];
char[][] baseArgNames= new char[argListLength][];
for(int argIdx = 0; argIdx < argListLength; argIdx++)
{
char[] argType = Signature.toQualifiedName(spec.arguments[argIdx].type.getParameterizedTypeName());
baseArgTypes[argIdx] = argType;
baseArgNames[argIdx] = spec.arguments[argIdx].name;
}
baseInfos[idx].parameterNames= baseArgNames;
baseInfos[idx].parameterTypes= baseArgTypes;
if (spec.returnType != null)
baseInfos[idx].returnType = Signature.toQualifiedName(spec.returnType.getParameterizedTypeName());
}
}
info.right= baseInfos;
info.covariantReturn= callinDecl.hasCovariantReturn();
info.annotations = mapping.annotations;
this.requestor.enterCallinMapping(info);
visitIfNeeded(callinDecl);
}
}
if (isInRange)
{
if (mapping instanceof CalloutMappingDeclaration)
{
CalloutMappingDeclaration callout = (CalloutMappingDeclaration)mapping;
if (callout.isCalloutToField())
this.requestor.exitCalloutToFieldMapping(callout.sourceEnd, callout.declarationSourceEnd);
else
this.requestor.exitCalloutMapping(mapping.sourceEnd, mapping.declarationSourceEnd);
}
else
{
this.requestor.exitCallinMapping(mapping.sourceEnd, mapping.declarationSourceEnd);
}
}
}
private void visitIfNeeded(CalloutMappingDeclaration callout)
{
if (this.localDeclarationVisitor != null && (callout.bits & ASTNode.HasLocalType) != 0) {
if (callout.mappings != null)
{
for (int i = 0; i < callout.mappings.length; i++)
{
callout.mappings[i].traverse(this.localDeclarationVisitor, callout.scope);
}
}
}
}
private void visitIfNeeded(CallinMappingDeclaration callinDecl)
{
if (this.localDeclarationVisitor != null && (callinDecl.bits & ASTNode.HasLocalType) != 0) {
if (callinDecl.mappings != null)
{
for (int i = 0; i < callinDecl.mappings.length; i++)
{
callinDecl.mappings[i].traverse(this.localDeclarationVisitor, callinDecl.scope);
}
}
}
}
private char[][] argumentNames(MethodSpec methodSpec)
{
if (methodSpec == null)
return null;
char[][] argumentNames = null;
Argument[] arguments = methodSpec.arguments;
if (methodSpec.hasSignature && arguments != null)
{
int argumentLength = arguments.length;
argumentNames = new char[argumentLength][];
for (int idx = 0; idx < argumentLength; idx++)
{
argumentNames[idx] = arguments[idx].name;
}
}
return argumentNames;
}
private char[][] argumentTypes(MethodSpec methodSpec)
{
if (methodSpec == null)
return null;
char[][] argumentTypes = null;
Argument[] arguments = methodSpec.arguments;
if (methodSpec.hasSignature && arguments != null)
{
int argumentLength = arguments.length;
argumentTypes = new char[argumentLength][];
for (int idx = 0; idx < argumentLength; idx++)
{
argumentTypes[idx] = CharOperation.concatWith(arguments[idx].type.getParameterizedTypeName(), '.');
}
}
return argumentTypes;
}
//ak}
/*
* Update the bodyStart of the corresponding parse node
*/
public void notifySourceElementRequestor(
CompilationUnitDeclaration parsedUnit,
int sourceStart,
int sourceEnd,
boolean reportReference,
HashtableOfObjectToInt sourceEndsMap,
Map nodesToCategoriesMap) {
this.initialPosition = sourceStart;
this.eofPosition = sourceEnd;
this.reportReferenceInfo = reportReference;
this.sourceEnds = sourceEndsMap;
this.nodesToCategories = nodesToCategoriesMap;
try {
// range check
boolean isInRange =
this.initialPosition <= parsedUnit.sourceStart
&& this.eofPosition >= parsedUnit.sourceEnd;
// collect the top level ast nodes
int length = 0;
ASTNode[] nodes = null;
if (isInRange) {
this.requestor.enterCompilationUnit();
}
ImportReference currentPackage = parsedUnit.currentPackage;
if (this.localDeclarationVisitor != null) {
this.localDeclarationVisitor.currentPackage = currentPackage;
}
ImportReference[] imports = parsedUnit.imports;
TypeDeclaration[] types = parsedUnit.types;
length =
(currentPackage == null ? 0 : 1)
+ (imports == null ? 0 : imports.length)
+ (types == null ? 0 : types.length);
nodes = new ASTNode[length];
int index = 0;
if (currentPackage != null) {
nodes[index++] = currentPackage;
}
if (imports != null) {
for (int i = 0, max = imports.length; i < max; i++) {
nodes[index++] = imports[i];
}
}
if (types != null) {
for (int i = 0, max = types.length; i < max; i++) {
nodes[index++] = types[i];
}
}
// notify the nodes in the syntactical order
if (length > 0) {
quickSort(nodes, 0, length-1);
for (int i=0;i<length;i++) {
ASTNode node = nodes[i];
if (node instanceof ImportReference) {
ImportReference importRef = (ImportReference)node;
if (node == parsedUnit.currentPackage) {
notifySourceElementRequestor(importRef, true);
} else {
notifySourceElementRequestor(importRef, false);
}
} else { // instanceof TypeDeclaration
notifySourceElementRequestor((TypeDeclaration)node, true, null, currentPackage);
}
}
}
if (isInRange) {
this.requestor.exitCompilationUnit(parsedUnit.sourceEnd);
}
} finally {
reset();
}
}
/*
* Update the bodyStart of the corresponding parse node
*/
protected void notifySourceElementRequestor(FieldDeclaration fieldDeclaration, TypeDeclaration declaringType) {
// range check
boolean isInRange =
this.initialPosition <= fieldDeclaration.declarationSourceStart
&& this.eofPosition >= fieldDeclaration.declarationSourceEnd;
switch(fieldDeclaration.getKind()) {
case AbstractVariableDeclaration.ENUM_CONSTANT:
if (this.reportReferenceInfo) {
// accept constructor reference for enum constant
if (fieldDeclaration.initialization instanceof AllocationExpression) {
AllocationExpression alloc = (AllocationExpression) fieldDeclaration.initialization;
this.requestor.acceptConstructorReference(
declaringType.name,
alloc.arguments == null ? 0 : alloc.arguments.length,
alloc.sourceStart);
}
}
// $FALL-THROUGH$
case AbstractVariableDeclaration.FIELD:
int fieldEndPosition = this.sourceEnds.get(fieldDeclaration);
if (fieldEndPosition == -1) {
// use the declaration source end by default
fieldEndPosition = fieldDeclaration.declarationSourceEnd;
}
if (isInRange) {
int currentModifiers = fieldDeclaration.modifiers;
// remember deprecation so as to not lose it below
boolean deprecated = (currentModifiers & ClassFileConstants.AccDeprecated) != 0 || hasDeprecatedAnnotation(fieldDeclaration.annotations);
char[] typeName = null;
if (fieldDeclaration.type == null) {
// enum constant
typeName = declaringType.name;
currentModifiers |= ClassFileConstants.AccEnum;
} else {
// regular field
typeName = CharOperation.concatWith(fieldDeclaration.type.getParameterizedTypeName(), '.');
}
ISourceElementRequestor.FieldInfo fieldInfo = new ISourceElementRequestor.FieldInfo();
fieldInfo.typeAnnotated = ((fieldDeclaration.bits & ASTNode.HasTypeAnnotations) != 0);
fieldInfo.declarationStart = fieldDeclaration.declarationSourceStart;
fieldInfo.name = fieldDeclaration.name;
fieldInfo.modifiers = deprecated ? (currentModifiers & ExtraCompilerModifiers.AccJustFlag) | ClassFileConstants.AccDeprecated : currentModifiers & ExtraCompilerModifiers.AccJustFlag;
fieldInfo.type = typeName;
fieldInfo.nameSourceStart = fieldDeclaration.sourceStart;
fieldInfo.nameSourceEnd = fieldDeclaration.sourceEnd;
fieldInfo.categories = (char[][]) this.nodesToCategories.get(fieldDeclaration);
fieldInfo.annotations = fieldDeclaration.annotations;
fieldInfo.node = fieldDeclaration;
this.requestor.enterField(fieldInfo);
}
this.visitIfNeeded(fieldDeclaration, declaringType);
if (isInRange){
this.requestor.exitField(
// filter out initializations that are not a constant (simple check)
(fieldDeclaration.initialization == null
|| fieldDeclaration.initialization instanceof ArrayInitializer
|| fieldDeclaration.initialization instanceof AllocationExpression
|| fieldDeclaration.initialization instanceof ArrayAllocationExpression
|| fieldDeclaration.initialization instanceof Assignment
|| fieldDeclaration.initialization instanceof ClassLiteralAccess
|| fieldDeclaration.initialization instanceof MessageSend
|| fieldDeclaration.initialization instanceof ArrayReference
|| fieldDeclaration.initialization instanceof ThisReference) ?
-1 :
fieldDeclaration.initialization.sourceStart,
fieldEndPosition,
fieldDeclaration.declarationSourceEnd);
}
break;
case AbstractVariableDeclaration.INITIALIZER:
if (isInRange){
this.requestor.enterInitializer(
fieldDeclaration.declarationSourceStart,
fieldDeclaration.modifiers);
}
this.visitIfNeeded((Initializer)fieldDeclaration);
if (isInRange){
this.requestor.exitInitializer(fieldDeclaration.declarationSourceEnd);
}
break;
}
}
protected void notifySourceElementRequestor(
ImportReference importReference,
boolean isPackage) {
if (isPackage) {
this.requestor.acceptPackage(importReference);
} else {
final boolean onDemand = (importReference.bits & ASTNode.OnDemand) != 0;
this.requestor.acceptImport(
importReference.declarationSourceStart,
importReference.declarationSourceEnd,
importReference.sourceStart,
onDemand ? importReference.trailingStarPosition : importReference.sourceEnd,
importReference.tokens,
onDemand,
importReference.modifiers);
}
}
protected void notifySourceElementRequestor(TypeDeclaration typeDeclaration, boolean notifyTypePresence, TypeDeclaration declaringType, ImportReference currentPackage) {
//{ObjectTeams: don't convert generated types (role ifc part):
if (typeDeclaration.isGenerated) return;
// SH}
if (CharOperation.equals(TypeConstants.PACKAGE_INFO_NAME, typeDeclaration.name)) return;
// range check
boolean isInRange =
this.initialPosition <= typeDeclaration.declarationSourceStart
&& this.eofPosition >= typeDeclaration.declarationSourceEnd;
FieldDeclaration[] fields = typeDeclaration.fields;
AbstractMethodDeclaration[] methods = typeDeclaration.methods;
TypeDeclaration[] memberTypes = typeDeclaration.memberTypes;
//{ObjectTeams: treatment for method mappings
AbstractMethodMappingDeclaration[] bindings = typeDeclaration.callinCallouts;
//ak}
int fieldCounter = fields == null ? 0 : fields.length;
int methodCounter = methods == null ? 0 : methods.length;
int memberTypeCounter = memberTypes == null ? 0 : memberTypes.length;
//{ObjectTeams: treatment for method mappings
int bindingCount = (bindings == null) ? 0 : bindings.length;
//ak}
int fieldIndex = 0;
int methodIndex = 0;
int memberTypeIndex = 0;
//ObjectTeams: treatment for method mappings
int bindingIndex = 0;
//ak}
if (notifyTypePresence){
char[][] interfaceNames = getInterfaceNames(typeDeclaration);
//{ObjectTeams: construction of baseclass's name
char[] baseclassName = null;
char[] baseclassAnchor= null;
if (typeDeclaration.baseclass != null)
{
baseclassName = CharOperation.concatWith(
typeDeclaration.baseclass.getTypeName(),
'.');
char[][] anchorNames= ParameterizedSingleTypeReference.getTypeAnchor(typeDeclaration.baseclass);
if (anchorNames != null)
baseclassAnchor = CharOperation.concatWith(anchorNames, '.');
}
//ak}
int kind = TypeDeclaration.kind(typeDeclaration.modifiers);
char[] implicitSuperclassName = TypeConstants.CharArray_JAVA_LANG_OBJECT;
ISourceElementRequestor.TypeInfo typeInfo = new ISourceElementRequestor.TypeInfo();
typeInfo.typeAnnotated = ((typeDeclaration.bits & ASTNode.HasTypeAnnotations) != 0);
if (isInRange) {
int currentModifiers = typeDeclaration.modifiers;
// remember deprecation so as to not lose it below
boolean deprecated = (currentModifiers & ClassFileConstants.AccDeprecated) != 0 || hasDeprecatedAnnotation(typeDeclaration.annotations);
boolean isEnumInit = typeDeclaration.allocation != null && typeDeclaration.allocation.enumConstant != null;
char[] superclassName;
if (isEnumInit) {
currentModifiers |= ClassFileConstants.AccEnum;
superclassName = declaringType.name;
} else {
superclassName = getSuperclassName(typeDeclaration);
}
if (typeDeclaration.allocation == null) {
typeInfo.declarationStart = typeDeclaration.declarationSourceStart;
} else if (isEnumInit) {
typeInfo.declarationStart = typeDeclaration.allocation.enumConstant.sourceStart;
} else {
typeInfo.declarationStart = typeDeclaration.allocation.sourceStart;
}
//{ObjectTeams: let Role/Team flags pass through, strip __OT__ prefix
/* orig:
typeInfo.modifiers = deprecated ? (currentModifiers & ExtraCompilerModifiers.AccJustFlag) | ClassFileConstants.AccDeprecated : currentModifiers & ExtraCompilerModifiers.AccJustFlag;
typeInfo.name = typeDeclaration.name;
:giro */
typeInfo.modifiers = deprecated ? (currentModifiers & ExtraCompilerModifiers.AccOTTypeJustFlag) | ClassFileConstants.AccDeprecated : currentModifiers & ExtraCompilerModifiers.AccOTTypeJustFlag;
typeInfo.name = typeDeclaration.name;
// existing __OT__ prefix and special treatment for o.o.Team.Confined:
if (CharOperation.prefixEquals(IOTConstants.OT_DELIM_NAME, typeInfo.name)) {
typeInfo.name = CharOperation.subarray(typeInfo.name, IOTConstants.OT_DELIM_LEN, -1);
if (CharOperation.equals(IOTConstants.CONFINED, typeInfo.name) && CharOperation.equals(new char[][]{IOTConstants.CONFINED}, interfaceNames)) {
// avoid Confined implements Confined (revert manual role splitting)
superclassName = null;
interfaceNames = null;
}
// filtering interface o.o.T.Confined is already done at the call site.
}
// SH}
typeInfo.nameSourceStart = isEnumInit ? typeDeclaration.allocation.enumConstant.sourceStart : typeDeclaration.sourceStart;
typeInfo.nameSourceEnd = sourceEnd(typeDeclaration);
typeInfo.superclass = superclassName;
typeInfo.superinterfaces = interfaceNames;
typeInfo.typeParameters = getTypeParameterInfos(typeDeclaration.typeParameters);
typeInfo.categories = (char[][]) this.nodesToCategories.get(typeDeclaration);
typeInfo.secondary = typeDeclaration.isSecondary();
typeInfo.anonymousMember = typeDeclaration.allocation != null && typeDeclaration.allocation.enclosingInstance != null;
typeInfo.annotations = typeDeclaration.annotations;
typeInfo.extraFlags = ExtraFlags.getExtraFlags(typeDeclaration);
typeInfo.node = typeDeclaration;
//{ObjectTeams: added baseclass reference, isRoleFile:
typeInfo.baseclassName = baseclassName; // yes, interfaces will have a baseclass, too. (Current compiler limitation though).
typeInfo.baseclassAnchor = baseclassAnchor;
typeInfo.isRoleFile = typeDeclaration.isRoleFile();
//haebor,km});
this.requestor.enterType(typeInfo);
switch (kind) {
case TypeDeclaration.CLASS_DECL :
if (superclassName != null)
implicitSuperclassName = superclassName;
break;
case TypeDeclaration.INTERFACE_DECL :
implicitSuperclassName = TypeConstants.CharArray_JAVA_LANG_OBJECT;
break;
case TypeDeclaration.ENUM_DECL :
implicitSuperclassName = TypeConstants.CharArray_JAVA_LANG_ENUM;
break;
case TypeDeclaration.ANNOTATION_TYPE_DECL :
implicitSuperclassName = TypeConstants.CharArray_JAVA_LANG_ANNOTATION_ANNOTATION;
break;
}
}
if (this.nestedTypeIndex == this.typeNames.length) {
// need a resize
System.arraycopy(this.typeNames, 0, (this.typeNames = new char[this.nestedTypeIndex * 2][]), 0, this.nestedTypeIndex);
System.arraycopy(this.superTypeNames, 0, (this.superTypeNames = new char[this.nestedTypeIndex * 2][]), 0, this.nestedTypeIndex);
}
this.typeNames[this.nestedTypeIndex] = typeDeclaration.name;
this.superTypeNames[this.nestedTypeIndex++] = implicitSuperclassName;
}
while ((fieldIndex < fieldCounter)
|| (memberTypeIndex < memberTypeCounter)
|| (methodIndex < methodCounter)
// {ObjectTeams: treatment for method mappings
|| (bindingIndex < bindingCount))
// orig:
{
FieldDeclaration nextFieldDeclaration = null;
AbstractMethodDeclaration nextMethodDeclaration = null;
TypeDeclaration nextMemberDeclaration = null;
// :giro
AbstractMethodMappingDeclaration nextBindingDeclaration = null;
//ak}
int position = Integer.MAX_VALUE;
int nextDeclarationType = -1;
if (fieldIndex < fieldCounter) {
nextFieldDeclaration = fields[fieldIndex];
if (nextFieldDeclaration.declarationSourceStart < position) {
position = nextFieldDeclaration.declarationSourceStart;
nextDeclarationType = 0; // FIELD
}
}
if (methodIndex < methodCounter) {
nextMethodDeclaration = methods[methodIndex];
if (nextMethodDeclaration.declarationSourceStart < position) {
position = nextMethodDeclaration.declarationSourceStart;
nextDeclarationType = 1; // METHOD
}
}
if (memberTypeIndex < memberTypeCounter) {
nextMemberDeclaration = memberTypes[memberTypeIndex];
if (nextMemberDeclaration.declarationSourceStart < position) {
position = nextMemberDeclaration.declarationSourceStart;
nextDeclarationType = 2; // MEMBER
}
}
//{ObjectTeams: treatment for method mappings
if (bindingIndex < bindingCount)
{
nextBindingDeclaration = bindings[bindingIndex];
if (nextBindingDeclaration.sourceStart < position)
{
position = nextBindingDeclaration.sourceStart;
nextDeclarationType = 3; // BINDING
}
}
//ak}
switch (nextDeclarationType) {
case 0 :
fieldIndex++;
//{ObjectTeams: don't convert _OT$.. fields:
if ( nextFieldDeclaration.name != null
&& CharOperation.prefixEquals(IOTConstants.OT_DOLLAR_NAME, nextFieldDeclaration.name))
break;
// SH}
notifySourceElementRequestor(nextFieldDeclaration, typeDeclaration);
break;
case 1 :
methodIndex++;
//{ObjectTeams: don't convert generated methods:
if (nextMethodDeclaration.isGenerated && !(nextMethodDeclaration instanceof GuardPredicateDeclaration))
break;
// SH}
notifySourceElementRequestor(nextMethodDeclaration, typeDeclaration, currentPackage);
break;
case 2 :
memberTypeIndex++;
//{ObjectTeams: don't convert interface o.o.T.Confined:
if ( currentPackage != null && CharOperation.equals(IOTConstants.ORG_OBJECTTEAMS, currentPackage.tokens)
&& CharOperation.equals(IOTConstants.TEAM, typeDeclaration.name)
&& CharOperation.equals(IOTConstants.CONFINED, nextMemberDeclaration.name))
break;
notifySourceElementRequestor(nextMemberDeclaration, true, null, currentPackage);
//{ObjectTeams: treatment for method mappings
break;
case 3:
bindingIndex++;
notifySourceElementRequestor(nextBindingDeclaration);
break;
//ak}
}
}
if (notifyTypePresence){
if (isInRange){
this.requestor.exitType(typeDeclaration.declarationSourceEnd);
}
this.nestedTypeIndex--;
}
}
/*
* Sort the given ast nodes by their positions.
*/
private static void quickSort(ASTNode[] sortedCollection, int left, int right) {
int original_left = left;
int original_right = right;
ASTNode mid = sortedCollection[left + (right - left) / 2];
do {
while (sortedCollection[left].sourceStart < mid.sourceStart) {
left++;
}
while (mid.sourceStart < sortedCollection[right].sourceStart) {
right--;
}
if (left <= right) {
ASTNode tmp = sortedCollection[left];
sortedCollection[left] = sortedCollection[right];
sortedCollection[right] = tmp;
left++;
right--;
}
} while (left <= right);
if (original_left < right) {
quickSort(sortedCollection, original_left, right);
}
if (left < original_right) {
quickSort(sortedCollection, left, original_right);
}
}
private void reset() {
this.typeNames = new char[4][];
this.superTypeNames = new char[4][];
this.nestedTypeIndex = 0;
this.sourceEnds = null;
}
private int sourceEnd(TypeDeclaration typeDeclaration) {
if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
QualifiedAllocationExpression allocation = typeDeclaration.allocation;
if (allocation.enumConstant != null) // case of enum constant body
return allocation.enumConstant.sourceEnd;
return allocation.type.sourceEnd;
} else {
return typeDeclaration.sourceEnd;
}
}
private void visitIfNeeded(AbstractMethodDeclaration method) {
if (this.localDeclarationVisitor != null
&& (method.bits & ASTNode.HasLocalType) != 0) {
if (method instanceof ConstructorDeclaration) {
ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) method;
if (constructorDeclaration.constructorCall != null) {
constructorDeclaration.constructorCall.traverse(this.localDeclarationVisitor, method.scope);
}
}
if (method.statements != null) {
int statementsLength = method.statements.length;
for (int i = 0; i < statementsLength; i++)
method.statements[i].traverse(this.localDeclarationVisitor, method.scope);
}
}
}
private void visitIfNeeded(FieldDeclaration field, TypeDeclaration declaringType) {
if (this.localDeclarationVisitor != null
&& (field.bits & ASTNode.HasLocalType) != 0) {
if (field.initialization != null) {
try {
this.localDeclarationVisitor.pushDeclaringType(declaringType);
field.initialization.traverse(this.localDeclarationVisitor, (MethodScope) null);
} finally {
this.localDeclarationVisitor.popDeclaringType();
}
}
}
}
private void visitIfNeeded(Initializer initializer) {
if (this.localDeclarationVisitor != null
&& (initializer.bits & ASTNode.HasLocalType) != 0) {
if (initializer.block != null) {
initializer.block.traverse(this.localDeclarationVisitor, null);
}
}
}
}