/******************************************************************************* * Copyright (c) 2008, 2013 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 *******************************************************************************/ package org.eclipse.jdt.internal.compiler; import java.util.ArrayList; import java.util.Map; 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.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; @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; 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; Argument[] arguments = methodDeclaration.arguments; 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(); } 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; methodInfo.name = methodDeclaration.selector; methodInfo.nameSourceStart = methodDeclaration.sourceStart; methodInfo.nameSourceEnd = selectorSourceEnd; methodInfo.parameterTypes = argumentTypes; methodInfo.parameterNames = argumentNames; 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; currentModifiers &= ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccDeprecated | ClassFileConstants.AccAnnotationDefault | ExtraCompilerModifiers.AccDefaultMethod; 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; 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; 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); } } /* * 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) { 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; int fieldCounter = fields == null ? 0 : fields.length; int methodCounter = methods == null ? 0 : methods.length; int memberTypeCounter = memberTypes == null ? 0 : memberTypes.length; int fieldIndex = 0; int methodIndex = 0; int memberTypeIndex = 0; if (notifyTypePresence){ char[][] interfaceNames = getInterfaceNames(typeDeclaration); 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; } typeInfo.modifiers = deprecated ? (currentModifiers & ExtraCompilerModifiers.AccJustFlag) | ClassFileConstants.AccDeprecated : currentModifiers & ExtraCompilerModifiers.AccJustFlag; typeInfo.name = typeDeclaration.name; 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; 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)) { FieldDeclaration nextFieldDeclaration = null; AbstractMethodDeclaration nextMethodDeclaration = null; TypeDeclaration nextMemberDeclaration = null; 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 } } switch (nextDeclarationType) { case 0 : fieldIndex++; notifySourceElementRequestor(nextFieldDeclaration, typeDeclaration); break; case 1 : methodIndex++; notifySourceElementRequestor(nextMethodDeclaration, typeDeclaration, currentPackage); break; case 2 : memberTypeIndex++; notifySourceElementRequestor(nextMemberDeclaration, true, null, currentPackage); } } 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); } } } }