| /******************************************************************************* |
| * Copyright (c) 2008, 2017 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.aspectj.org.eclipse.jdt.internal.compiler; |
| |
| import java.util.ArrayList; |
| import java.util.Map; |
| |
| import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ISourceElementRequestor.ParameterInfo; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ISourceElementRequestor.TypeParameterInfo; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ASTNode; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AllocationExpression; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ArrayReference; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Assignment; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ExportsStatement; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Expression; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ImportReference; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Initializer; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MessageSend; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.OpensStatement; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ThisReference; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeParameter; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeConstants; |
| import org.aspectj.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); |
| } |
| @Override |
| 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(...) |
| } |
| @Override |
| 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<ASTNode,char[][]> 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.typeAnnotated = ((typeParameter.bits & ASTNode.HasTypeAnnotations) != 0); |
| 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 = 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 = 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); |
| } |
| } |
| |
| /* |
| * 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) |
| + (parsedUnit.moduleDeclaration == null ? 0 : 1); |
| 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]; |
| } |
| } |
| |
| if (parsedUnit.moduleDeclaration != null) |
| nodes[index++] = parsedUnit.moduleDeclaration; |
| |
| // 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 if (node instanceof TypeDeclaration) { |
| notifySourceElementRequestor((TypeDeclaration)node, true, null, currentPackage); |
| } else if (node instanceof ModuleDeclaration) { |
| notifySourceElementRequestor(parsedUnit.moduleDeclaration); |
| } |
| } |
| } |
| |
| 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 = 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(ModuleDeclaration moduleDeclaration) { |
| boolean isInRange = |
| this.initialPosition <= moduleDeclaration.declarationSourceStart |
| && this.eofPosition >= moduleDeclaration.declarationSourceEnd; |
| ISourceElementRequestor.ModuleInfo info = new ISourceElementRequestor.ModuleInfo(); |
| if (isInRange) { |
| |
| int currentModifiers = moduleDeclaration.modifiers; |
| |
| // remember deprecation so as to not lose it below |
| boolean deprecated = (currentModifiers & ClassFileConstants.AccDeprecated) != 0 || hasDeprecatedAnnotation(moduleDeclaration.annotations); |
| |
| info.declarationStart = moduleDeclaration.declarationSourceStart; |
| info.modifiers = deprecated ? (currentModifiers & ExtraCompilerModifiers.AccJustFlag) | ClassFileConstants.AccDeprecated : currentModifiers & ExtraCompilerModifiers.AccJustFlag; |
| info.name = TypeConstants.MODULE_INFO_NAME; |
| info.nameSourceStart = moduleDeclaration.sourceStart; |
| info.nameSourceEnd = moduleDeclaration.sourceEnd; |
| info.moduleName = moduleDeclaration.moduleName; |
| info.annotations = moduleDeclaration.annotations; |
| info.node = moduleDeclaration; |
| info.categories = this.nodesToCategories.get(moduleDeclaration); |
| fillModuleInfo(moduleDeclaration, info); |
| this.requestor.enterModule(info); |
| this.requestor.exitModule(moduleDeclaration.declarationSourceEnd); |
| } |
| } |
| 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 = 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--; |
| } |
| } |
| private void fillModuleInfo(ModuleDeclaration mod, ISourceElementRequestor.ModuleInfo modInfo) { |
| if (mod.requiresCount > 0) { |
| ISourceElementRequestor.RequiresInfo reqs[] = new ISourceElementRequestor.RequiresInfo[mod.requiresCount]; |
| for (int i = 0; i < mod.requiresCount; i++) { |
| ISourceElementRequestor.RequiresInfo req = new ISourceElementRequestor.RequiresInfo(); |
| req.moduleName = CharOperation.concatWith(mod.requires[i].module.tokens, '.'); |
| req.modifiers = mod.requires[i].modifiers; |
| reqs[i] = req; |
| } |
| modInfo.requires = reqs; |
| } |
| if (mod.exportsCount > 0) { |
| ISourceElementRequestor.PackageExportInfo exps[] = new ISourceElementRequestor.PackageExportInfo[mod.exportsCount]; |
| for (int i = 0; i < mod.exportsCount; i++) { |
| ISourceElementRequestor.PackageExportInfo exp = new ISourceElementRequestor.PackageExportInfo(); |
| ExportsStatement exportsStatement = mod.exports[i]; |
| exp.pkgName = exportsStatement.pkgName; |
| if (exportsStatement.targets == null) { |
| exp.targets = CharOperation.NO_CHAR_CHAR; |
| } else { |
| exp.targets = new char[exportsStatement.targets.length][]; |
| for(int j = 0; j < exp.targets.length; j++) { |
| exp.targets[j] = CharOperation.concatWith(exportsStatement.targets[j].tokens, '.'); |
| } |
| } |
| exps[i] = exp; |
| } |
| modInfo.exports = exps; |
| } |
| if (mod.servicesCount > 0) { |
| ISourceElementRequestor.ServicesInfo[] services = new ISourceElementRequestor.ServicesInfo[mod.servicesCount]; |
| for (int i = 0; i < services.length; i++) { |
| ISourceElementRequestor.ServicesInfo ser = new ISourceElementRequestor.ServicesInfo(); |
| ser.serviceName = CharOperation.concatWith(mod.services[i].serviceInterface.getParameterizedTypeName(), '.'); |
| ser.implNames = new char[mod.services[i].implementations.length][]; |
| for (int j = 0; j < ser.implNames.length; j++) { |
| ser.implNames[j] = CharOperation.concatWith(mod.services[i].implementations[j].getParameterizedTypeName(), '.'); |
| } |
| services[i] = ser; |
| } |
| modInfo.services = services; |
| } |
| if (mod.usesCount > 0) { |
| char[][] uses = new char[mod.usesCount][]; |
| for (int i = 0; i < uses.length; i++) { |
| uses[i] = CharOperation.concatWith(mod.uses[i].serviceInterface.getParameterizedTypeName(), '.'); |
| } |
| modInfo.usedServices = uses; |
| } |
| if (mod.opensCount > 0) { |
| ISourceElementRequestor.PackageExportInfo opens[] = new ISourceElementRequestor.PackageExportInfo[mod.opensCount]; |
| for (int i = 0; i < mod.opensCount; i++) { |
| ISourceElementRequestor.PackageExportInfo op = new ISourceElementRequestor.PackageExportInfo(); |
| OpensStatement openStmt = mod.opens[i]; |
| op.pkgName = openStmt.pkgName; |
| if (openStmt.targets == null) { |
| op.targets = CharOperation.NO_CHAR_CHAR; |
| } else { |
| op.targets = new char[openStmt.targets.length][]; |
| for(int j = 0; j < op.targets.length; j++) { |
| op.targets[j] = CharOperation.concatWith(openStmt.targets[j].tokens, '.'); |
| } |
| } |
| opens[i] = op; |
| } |
| modInfo.opens = opens; |
| } |
| } |
| /* |
| * 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); |
| } |
| } |
| } |
| } |