/******************************************************************************* * Copyright (c) 2000, 2011 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.core; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Stack; import org.eclipse.core.runtime.Assert; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.IAnnotation; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMemberValuePair; import org.eclipse.jdt.core.ITypeParameter; import org.eclipse.jdt.core.Signature; import org.eclipse.jdt.core.compiler.CategorizedProblem; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.internal.compiler.ISourceElementRequestor; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.ImportReference; import org.eclipse.jdt.internal.compiler.ast.Literal; import org.eclipse.jdt.internal.compiler.ast.MemberValuePair; import org.eclipse.jdt.internal.compiler.ast.NullLiteral; import org.eclipse.jdt.internal.compiler.ast.OperatorIds; import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.UnaryExpression; import org.eclipse.jdt.internal.compiler.parser.Parser; import org.eclipse.jdt.internal.compiler.parser.RecoveryScanner; import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt; import org.eclipse.jdt.internal.core.util.ReferenceInfoAdapter; import org.eclipse.jdt.internal.core.util.Util; /** * A requestor for the fuzzy parser, used to compute the children of an ICompilationUnit. */ public class CompilationUnitStructureRequestor extends ReferenceInfoAdapter implements ISourceElementRequestor { /** * The handle to the compilation unit being parsed */ protected ICompilationUnit unit; /** * The info object for the compilation unit being parsed */ protected CompilationUnitElementInfo unitInfo; /** * The import container info - null until created */ protected ImportContainerInfo importContainerInfo = null; protected ImportContainer importContainer; /** * Hashtable of children elements of the compilation unit. * Children are added to the table as they are found by * the parser. Keys are handles, values are corresponding * info objects. */ protected Map newElements; /* * A table from a handle (with occurenceCount == 1) to the current occurence count for this handle */ private HashtableOfObjectToInt occurenceCounts; /** * Stack of parent scope info objects. The info on the * top of the stack is the parent of the next element found. * For example, when we locate a method, the parent info object * will be the type the method is contained in. */ protected Stack infoStack; /* * Map from info to of ArrayList of IJavaElement representing the children * of the given info. */ protected HashMap children; /** * Stack of parent handles, corresponding to the info stack. We * keep both, since info objects do not have back pointers to * handles. */ protected Stack handleStack; /** * The number of references reported thus far. Used to * expand the arrays of reference kinds and names. */ protected int referenceCount= 0; /** * Problem requestor which will get notified of discovered problems */ protected boolean hasSyntaxErrors = false; /* * The parser this requestor is using. */ protected Parser parser; protected HashtableOfObject fieldRefCache; protected HashtableOfObject messageRefCache; protected HashtableOfObject typeRefCache; protected HashtableOfObject unknownRefCache; protected CompilationUnitStructureRequestor(ICompilationUnit unit, CompilationUnitElementInfo unitInfo, Map newElements) { this.unit = unit; this.unitInfo = unitInfo; this.newElements = newElements; this.occurenceCounts = new HashtableOfObjectToInt(); } /** * @see ISourceElementRequestor */ public void acceptImport(int declarationStart, int declarationEnd, int nameSourceStart, int nameSourceEnd, char[][] tokens, boolean onDemand, int modifiers) { JavaElement parentHandle= (JavaElement) this.handleStack.peek(); if (!(parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT)) { Assert.isTrue(false); // Should not happen } ICompilationUnit parentCU= (ICompilationUnit)parentHandle; //create the import container and its info if (this.importContainer == null) { this.importContainer = createImportContainer(parentCU); this.importContainerInfo = new ImportContainerInfo(); Object parentInfo = this.infoStack.peek(); addToChildren(parentInfo, this.importContainer); this.newElements.put(this.importContainer, this.importContainerInfo); } String elementName = JavaModelManager.getJavaModelManager().intern(new String(CharOperation.concatWith(tokens, '.'))); ImportDeclaration handle = createImportDeclaration(this.importContainer, elementName, onDemand); resolveDuplicates(handle); ImportDeclarationElementInfo info = new ImportDeclarationElementInfo(); info.setSourceRangeStart(declarationStart); info.setSourceRangeEnd(declarationEnd); info.setNameSourceStart(nameSourceStart); info.setNameSourceEnd(nameSourceEnd); info.setFlags(modifiers); addToChildren(this.importContainerInfo, handle); this.newElements.put(handle, info); } /* * Table of line separator position. This table is passed once at the end * of the parse action, so as to allow computation of normalized ranges. * * A line separator might corresponds to several characters in the source, * */ public void acceptLineSeparatorPositions(int[] positions) { // ignore line separator positions } /** * @see ISourceElementRequestor */ public void acceptPackage(ImportReference importReference) { Object parentInfo = this.infoStack.peek(); JavaElement parentHandle= (JavaElement) this.handleStack.peek(); PackageDeclaration handle = null; if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) { char[] name = CharOperation.concatWith(importReference.getImportName(), '.'); handle = createPackageDeclaration(parentHandle, new String(name)); } else { Assert.isTrue(false); // Should not happen } resolveDuplicates(handle); AnnotatableInfo info = new AnnotatableInfo(); info.setSourceRangeStart(importReference.declarationSourceStart); info.setSourceRangeEnd(importReference.declarationSourceEnd); info.setNameSourceStart(importReference.sourceStart); info.setNameSourceEnd(importReference.sourceEnd); addToChildren(parentInfo, handle); this.newElements.put(handle, info); if (importReference.annotations != null) { for (int i = 0, length = importReference.annotations.length; i < length; i++) { org.eclipse.jdt.internal.compiler.ast.Annotation annotation = importReference.annotations[i]; acceptAnnotation(annotation, info, handle); } } } public void acceptProblem(CategorizedProblem problem) { if ((problem.getID() & IProblem.Syntax) != 0){ this.hasSyntaxErrors = true; } } private void addToChildren(Object parentInfo, JavaElement handle) { ArrayList childrenList = (ArrayList) this.children.get(parentInfo); if (childrenList == null) this.children.put(parentInfo, childrenList = new ArrayList()); childrenList.add(handle); } protected Annotation createAnnotation(JavaElement parent, String name) { return new Annotation(parent, name); } protected SourceField createField(JavaElement parent, FieldInfo fieldInfo) { String fieldName = JavaModelManager.getJavaModelManager().intern(new String(fieldInfo.name)); return new SourceField(parent, fieldName); } protected ImportContainer createImportContainer(ICompilationUnit parent) { return (ImportContainer)parent.getImportContainer(); } protected ImportDeclaration createImportDeclaration(ImportContainer parent, String name, boolean onDemand) { return new ImportDeclaration(parent, name, onDemand); } protected Initializer createInitializer(JavaElement parent) { return new Initializer(parent, 1); } protected SourceMethod createMethodHandle(JavaElement parent, MethodInfo methodInfo) { String selector = JavaModelManager.getJavaModelManager().intern(new String(methodInfo.name)); String[] parameterTypeSigs = convertTypeNamesToSigs(methodInfo.parameterTypes); return new SourceMethod(parent, selector, parameterTypeSigs); } protected PackageDeclaration createPackageDeclaration(JavaElement parent, String name) { return new PackageDeclaration((CompilationUnit) parent, name); } protected SourceType createTypeHandle(JavaElement parent, TypeInfo typeInfo) { String nameString= new String(typeInfo.name); return new SourceType(parent, nameString); } protected TypeParameter createTypeParameter(JavaElement parent, String name) { return new TypeParameter(parent, name); } /** * Convert these type names to signatures. * @see Signature */ protected static String[] convertTypeNamesToSigs(char[][] typeNames) { if (typeNames == null) return CharOperation.NO_STRINGS; int n = typeNames.length; if (n == 0) return CharOperation.NO_STRINGS; JavaModelManager manager = JavaModelManager.getJavaModelManager(); String[] typeSigs = new String[n]; for (int i = 0; i < n; ++i) { typeSigs[i] = manager.intern(Signature.createTypeSignature(typeNames[i], false)); } return typeSigs; } protected IAnnotation acceptAnnotation(org.eclipse.jdt.internal.compiler.ast.Annotation annotation, AnnotatableInfo parentInfo, JavaElement parentHandle) { String nameString = new String(CharOperation.concatWith(annotation.type.getTypeName(), '.')); Annotation handle = createAnnotation(parentHandle, nameString); //NB: occurenceCount is computed in resolveDuplicates resolveDuplicates(handle); AnnotationInfo info = new AnnotationInfo(); // populate the maps here as getValue(...) below may need them this.newElements.put(handle, info); this.handleStack.push(handle); info.setSourceRangeStart(annotation.sourceStart()); info.nameStart = annotation.type.sourceStart(); info.nameEnd = annotation.type.sourceEnd(); MemberValuePair[] memberValuePairs = annotation.memberValuePairs(); int membersLength = memberValuePairs.length; if (membersLength == 0) { info.members = Annotation.NO_MEMBER_VALUE_PAIRS; } else { info.members = getMemberValuePairs(memberValuePairs); } if (parentInfo != null) { IAnnotation[] annotations = parentInfo.annotations; int length = annotations.length; System.arraycopy(annotations, 0, annotations = new IAnnotation[length+1], 0, length); annotations[length] = handle; parentInfo.annotations = annotations; } info.setSourceRangeEnd(annotation.declarationSourceEnd); this.handleStack.pop(); return handle; } /** * @see ISourceElementRequestor */ public void enterCompilationUnit() { this.infoStack = new Stack(); this.children = new HashMap(); this.handleStack= new Stack(); this.infoStack.push(this.unitInfo); this.handleStack.push(this.unit); } /** * @see ISourceElementRequestor */ public void enterConstructor(MethodInfo methodInfo) { enterMethod(methodInfo); } /** * @see ISourceElementRequestor */ public void enterField(FieldInfo fieldInfo) { TypeInfo parentInfo = (TypeInfo) this.infoStack.peek(); JavaElement parentHandle= (JavaElement) this.handleStack.peek(); SourceField handle = null; if (parentHandle.getElementType() == IJavaElement.TYPE) { handle = createField(parentHandle, fieldInfo); } else { Assert.isTrue(false); // Should not happen } resolveDuplicates(handle); addToChildren(parentInfo, handle); parentInfo.childrenCategories.put(handle, fieldInfo.categories); this.infoStack.push(fieldInfo); this.handleStack.push(handle); } /** * @see ISourceElementRequestor */ public void enterInitializer(int declarationSourceStart, int modifiers) { Object parentInfo = this.infoStack.peek(); JavaElement parentHandle= (JavaElement) this.handleStack.peek(); Initializer handle = null; if (parentHandle.getElementType() == IJavaElement.TYPE) { handle = createInitializer(parentHandle); } else { Assert.isTrue(false); // Should not happen } resolveDuplicates(handle); addToChildren(parentInfo, handle); this.infoStack.push(new int[] {declarationSourceStart, modifiers}); this.handleStack.push(handle); } /** * @see ISourceElementRequestor */ public void enterMethod(MethodInfo methodInfo) { TypeInfo parentInfo = (TypeInfo) this.infoStack.peek(); JavaElement parentHandle= (JavaElement) this.handleStack.peek(); SourceMethod handle = null; // translate nulls to empty arrays if (methodInfo.parameterTypes == null) { methodInfo.parameterTypes= CharOperation.NO_CHAR_CHAR; } if (methodInfo.parameterNames == null) { methodInfo.parameterNames= CharOperation.NO_CHAR_CHAR; } if (methodInfo.exceptionTypes == null) { methodInfo.exceptionTypes= CharOperation.NO_CHAR_CHAR; } if (parentHandle.getElementType() == IJavaElement.TYPE) { handle = createMethodHandle(parentHandle, methodInfo); } else { Assert.isTrue(false); // Should not happen } resolveDuplicates(handle); this.infoStack.push(methodInfo); this.handleStack.push(handle); addToChildren(parentInfo, handle); parentInfo.childrenCategories.put(handle, methodInfo.categories); } private SourceMethodElementInfo createMethodInfo(MethodInfo methodInfo, SourceMethod handle) { IJavaElement[] elements = getChildren(methodInfo); SourceMethodElementInfo info; if (methodInfo.isConstructor) { info = elements.length == 0 ? new SourceConstructorInfo() : new SourceConstructorWithChildrenInfo(elements); } else if (methodInfo.isAnnotation) { info = new SourceAnnotationMethodInfo(); } else { info = elements.length == 0 ? new SourceMethodInfo() : new SourceMethodWithChildrenInfo(elements); } info.setSourceRangeStart(methodInfo.declarationStart); int flags = methodInfo.modifiers; info.setNameSourceStart(methodInfo.nameSourceStart); info.setNameSourceEnd(methodInfo.nameSourceEnd); info.setFlags(flags); JavaModelManager manager = JavaModelManager.getJavaModelManager(); char[][] parameterNames = methodInfo.parameterNames; for (int i = 0, length = parameterNames.length; i < length; i++) parameterNames[i] = manager.intern(parameterNames[i]); info.setArgumentNames(parameterNames); char[] returnType = methodInfo.returnType == null ? new char[]{'v', 'o','i', 'd'} : methodInfo.returnType; info.setReturnType(manager.intern(returnType)); char[][] exceptionTypes = methodInfo.exceptionTypes; info.setExceptionTypeNames(exceptionTypes); for (int i = 0, length = exceptionTypes.length; i < length; i++) exceptionTypes[i] = manager.intern(exceptionTypes[i]); this.newElements.put(handle, info); if (methodInfo.typeParameters != null) { for (int i = 0, length = methodInfo.typeParameters.length; i < length; i++) { TypeParameterInfo typeParameterInfo = methodInfo.typeParameters[i]; acceptTypeParameter(typeParameterInfo, info); } } if (methodInfo.annotations != null) { int length = methodInfo.annotations.length; this.unitInfo.annotationNumber += length; for (int i = 0; i < length; i++) { org.eclipse.jdt.internal.compiler.ast.Annotation annotation = methodInfo.annotations[i]; acceptAnnotation(annotation, info, handle); } } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=334783 // Process the parameter annotations from the arguments if (methodInfo.node != null && methodInfo.node.arguments != null) { info.arguments = acceptMethodParameters(methodInfo.node.arguments, handle, methodInfo); } return info; } private LocalVariable[] acceptMethodParameters(Argument[] arguments, JavaElement methodHandle, MethodInfo methodInfo) { if (arguments == null) return null; LocalVariable[] result = new LocalVariable[arguments.length]; Annotation[][] paramAnnotations = new Annotation[arguments.length][]; for(int i = 0; i < arguments.length; i++) { Argument argument = arguments[i]; AnnotatableInfo localVarInfo = new AnnotatableInfo(); localVarInfo.setSourceRangeStart(argument.declarationSourceStart); localVarInfo.setSourceRangeEnd(argument.declarationSourceStart); localVarInfo.setNameSourceStart(argument.sourceStart); localVarInfo.setNameSourceEnd(argument.sourceEnd); String paramTypeSig = JavaModelManager.getJavaModelManager().intern(Signature.createTypeSignature(methodInfo.parameterTypes[i], false)); result[i] = new LocalVariable( methodHandle, new String(argument.name), argument.declarationSourceStart, argument.declarationSourceEnd, argument.sourceStart, argument.sourceEnd, paramTypeSig, argument.annotations, argument.modifiers, true); this.newElements.put(result[i], localVarInfo); this.infoStack.push(localVarInfo); this.handleStack.push(result[i]); if (argument.annotations != null) { paramAnnotations[i] = new Annotation[argument.annotations.length]; for (int j = 0; j < argument.annotations.length; j++ ) { org.eclipse.jdt.internal.compiler.ast.Annotation annotation = argument.annotations[j]; acceptAnnotation(annotation, localVarInfo, result[i]); } } this.infoStack.pop(); this.handleStack.pop(); } return result; } /** * @see ISourceElementRequestor */ public void enterType(TypeInfo typeInfo) { Object parentInfo = this.infoStack.peek(); JavaElement parentHandle= (JavaElement) this.handleStack.peek(); SourceType handle = createTypeHandle(parentHandle, typeInfo); //NB: occurenceCount is computed in resolveDuplicates resolveDuplicates(handle); this.infoStack.push(typeInfo); this.handleStack.push(handle); if (parentHandle.getElementType() == IJavaElement.TYPE) ((TypeInfo) parentInfo).childrenCategories.put(handle, typeInfo.categories); addToChildren(parentInfo, handle); } private SourceTypeElementInfo createTypeInfo(TypeInfo typeInfo, SourceType handle) { SourceTypeElementInfo info = typeInfo.anonymousMember ? new SourceTypeElementInfo() { public boolean isAnonymousMember() { return true; } } : new SourceTypeElementInfo(); info.setHandle(handle); info.setSourceRangeStart(typeInfo.declarationStart); info.setFlags(typeInfo.modifiers); info.setNameSourceStart(typeInfo.nameSourceStart); info.setNameSourceEnd(typeInfo.nameSourceEnd); JavaModelManager manager = JavaModelManager.getJavaModelManager(); char[] superclass = typeInfo.superclass; info.setSuperclassName(superclass == null ? null : manager.intern(superclass)); char[][] superinterfaces = typeInfo.superinterfaces; for (int i = 0, length = superinterfaces == null ? 0 : superinterfaces.length; i < length; i++) superinterfaces[i] = manager.intern(superinterfaces[i]); info.setSuperInterfaceNames(superinterfaces); info.addCategories(handle, typeInfo.categories); this.newElements.put(handle, info); if (typeInfo.typeParameters != null) { for (int i = 0, length = typeInfo.typeParameters.length; i < length; i++) { TypeParameterInfo typeParameterInfo = typeInfo.typeParameters[i]; acceptTypeParameter(typeParameterInfo, info); } } if (typeInfo.annotations != null) { int length = typeInfo.annotations.length; this.unitInfo.annotationNumber += length; for (int i = 0; i < length; i++) { org.eclipse.jdt.internal.compiler.ast.Annotation annotation = typeInfo.annotations[i]; acceptAnnotation(annotation, info, handle); } } if (typeInfo.childrenCategories != null) { Iterator iterator = typeInfo.childrenCategories.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); info.addCategories((IJavaElement) entry.getKey(), (char[][]) entry.getValue()); } } return info; } protected void acceptTypeParameter(TypeParameterInfo typeParameterInfo, JavaElementInfo parentInfo) { JavaElement parentHandle = (JavaElement) this.handleStack.peek(); String nameString = new String(typeParameterInfo.name); TypeParameter handle = createTypeParameter(parentHandle, nameString); //NB: occurenceCount is computed in resolveDuplicates resolveDuplicates(handle); TypeParameterElementInfo info = new TypeParameterElementInfo(); info.setSourceRangeStart(typeParameterInfo.declarationStart); info.nameStart = typeParameterInfo.nameSourceStart; info.nameEnd = typeParameterInfo.nameSourceEnd; info.bounds = typeParameterInfo.bounds; if (parentInfo instanceof SourceTypeElementInfo) { SourceTypeElementInfo elementInfo = (SourceTypeElementInfo) parentInfo; ITypeParameter[] typeParameters = elementInfo.typeParameters; int length = typeParameters.length; System.arraycopy(typeParameters, 0, typeParameters = new ITypeParameter[length+1], 0, length); typeParameters[length] = handle; elementInfo.typeParameters = typeParameters; } else { SourceMethodElementInfo elementInfo = (SourceMethodElementInfo) parentInfo; ITypeParameter[] typeParameters = elementInfo.typeParameters; int length = typeParameters.length; System.arraycopy(typeParameters, 0, typeParameters = new ITypeParameter[length+1], 0, length); typeParameters[length] = handle; elementInfo.typeParameters = typeParameters; } this.newElements.put(handle, info); info.setSourceRangeEnd(typeParameterInfo.declarationEnd); } /** * @see ISourceElementRequestor */ public void exitCompilationUnit(int declarationEnd) { // set import container children if (this.importContainerInfo != null) { this.importContainerInfo.children = getChildren(this.importContainerInfo); } this.unitInfo.children = getChildren(this.unitInfo); this.unitInfo.setSourceLength(declarationEnd + 1); // determine if there were any parsing errors this.unitInfo.setIsStructureKnown(!this.hasSyntaxErrors); } /** * @see ISourceElementRequestor */ public void exitConstructor(int declarationEnd) { exitMethod(declarationEnd, null); } /** * @see ISourceElementRequestor */ public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) { JavaElement handle = (JavaElement) this.handleStack.peek(); FieldInfo fieldInfo = (FieldInfo) this.infoStack.peek(); IJavaElement[] elements = getChildren(fieldInfo); SourceFieldElementInfo info = elements.length == 0 ? new SourceFieldElementInfo() : new SourceFieldWithChildrenInfo(elements); info.setNameSourceStart(fieldInfo.nameSourceStart); info.setNameSourceEnd(fieldInfo.nameSourceEnd); info.setSourceRangeStart(fieldInfo.declarationStart); info.setFlags(fieldInfo.modifiers); char[] typeName = JavaModelManager.getJavaModelManager().intern(fieldInfo.type); info.setTypeName(typeName); this.newElements.put(handle, info); if (fieldInfo.annotations != null) { int length = fieldInfo.annotations.length; this.unitInfo.annotationNumber += length; for (int i = 0; i < length; i++) { org.eclipse.jdt.internal.compiler.ast.Annotation annotation = fieldInfo.annotations[i]; acceptAnnotation(annotation, info, handle); } } info.setSourceRangeEnd(declarationSourceEnd); this.handleStack.pop(); this.infoStack.pop(); // remember initializer source if field is a constant if (initializationStart != -1) { int flags = info.flags; Object typeInfo; if (Flags.isStatic(flags) && Flags.isFinal(flags) || ((typeInfo = this.infoStack.peek()) instanceof TypeInfo && (Flags.isInterface(((TypeInfo)typeInfo).modifiers)))) { int length = declarationEnd - initializationStart; if (length > 0) { char[] initializer = new char[length]; System.arraycopy(this.parser.scanner.source, initializationStart, initializer, 0, length); info.initializationSource = initializer; } } } } /** * @see ISourceElementRequestor */ public void exitInitializer(int declarationEnd) { JavaElement handle = (JavaElement) this.handleStack.peek(); int[] initializerInfo = (int[]) this.infoStack.peek(); IJavaElement[] elements = getChildren(initializerInfo); InitializerElementInfo info = elements.length == 0 ? new InitializerElementInfo() : new InitializerWithChildrenInfo(elements); info.setSourceRangeStart(initializerInfo[0]); info.setFlags(initializerInfo[1]); info.setSourceRangeEnd(declarationEnd); this.newElements.put(handle, info); this.handleStack.pop(); this.infoStack.pop(); } /** * @see ISourceElementRequestor */ public void exitMethod(int declarationEnd, Expression defaultValue) { SourceMethod handle = (SourceMethod) this.handleStack.peek(); MethodInfo methodInfo = (MethodInfo) this.infoStack.peek(); SourceMethodElementInfo info = createMethodInfo(methodInfo, handle); info.setSourceRangeEnd(declarationEnd); // remember default value of annotation method if (info.isAnnotationMethod() && defaultValue != null) { SourceAnnotationMethodInfo annotationMethodInfo = (SourceAnnotationMethodInfo) info; annotationMethodInfo.defaultValueStart = defaultValue.sourceStart; annotationMethodInfo.defaultValueEnd = defaultValue.sourceEnd; JavaElement element = (JavaElement) this.handleStack.peek(); org.eclipse.jdt.internal.core.MemberValuePair defaultMemberValuePair = new org.eclipse.jdt.internal.core.MemberValuePair(element.getElementName()); defaultMemberValuePair.value = getMemberValue(defaultMemberValuePair, defaultValue); annotationMethodInfo.defaultValue = defaultMemberValuePair; } this.handleStack.pop(); this.infoStack.pop(); } /** * @see ISourceElementRequestor */ public void exitType(int declarationEnd) { SourceType handle = (SourceType) this.handleStack.peek(); TypeInfo typeInfo = (TypeInfo) this.infoStack.peek(); SourceTypeElementInfo info = createTypeInfo(typeInfo, handle); info.setSourceRangeEnd(declarationEnd); info.children = getChildren(typeInfo); this.handleStack.pop(); this.infoStack.pop(); } /** * Resolves duplicate handles by incrementing the occurrence count * of the handle being created. */ protected void resolveDuplicates(SourceRefElement handle) { int occurenceCount = this.occurenceCounts.get(handle); if (occurenceCount == -1) this.occurenceCounts.put(handle, 1); else { this.occurenceCounts.put(handle, ++occurenceCount); handle.occurrenceCount = occurenceCount; } } protected IMemberValuePair getMemberValuePair(MemberValuePair memberValuePair) { String memberName = new String(memberValuePair.name); org.eclipse.jdt.internal.core.MemberValuePair result = new org.eclipse.jdt.internal.core.MemberValuePair(memberName); result.value = getMemberValue(result, memberValuePair.value); return result; } protected IMemberValuePair[] getMemberValuePairs(MemberValuePair[] memberValuePairs) { int membersLength = memberValuePairs.length; IMemberValuePair[] members = new IMemberValuePair[membersLength]; for (int j = 0; j < membersLength; j++) { members[j] = getMemberValuePair(memberValuePairs[j]); } return members; } private IJavaElement[] getChildren(Object info) { ArrayList childrenList = (ArrayList) this.children.get(info); if (childrenList != null) { return (IJavaElement[]) childrenList.toArray(new IJavaElement[childrenList.size()]); } return JavaElement.NO_ELEMENTS; } /* * Creates the value from the given expression, and sets the valueKind on the given memberValuePair */ protected Object getMemberValue(org.eclipse.jdt.internal.core.MemberValuePair memberValuePair, Expression expression) { if (expression instanceof NullLiteral) { return null; } else if (expression instanceof Literal) { ((Literal) expression).computeConstant(); return Util.getAnnotationMemberValue(memberValuePair, expression.constant); } else if (expression instanceof org.eclipse.jdt.internal.compiler.ast.Annotation) { org.eclipse.jdt.internal.compiler.ast.Annotation annotation = (org.eclipse.jdt.internal.compiler.ast.Annotation) expression; Object handle = acceptAnnotation(annotation, null, (JavaElement) this.handleStack.peek()); memberValuePair.valueKind = IMemberValuePair.K_ANNOTATION; return handle; } else if (expression instanceof ClassLiteralAccess) { ClassLiteralAccess classLiteral = (ClassLiteralAccess) expression; char[] name = CharOperation.concatWith(classLiteral.type.getTypeName(), '.'); memberValuePair.valueKind = IMemberValuePair.K_CLASS; return new String(name); } else if (expression instanceof QualifiedNameReference) { char[] qualifiedName = CharOperation.concatWith(((QualifiedNameReference) expression).tokens, '.'); memberValuePair.valueKind = IMemberValuePair.K_QUALIFIED_NAME; return new String(qualifiedName); } else if (expression instanceof SingleNameReference) { char[] simpleName = ((SingleNameReference) expression).token; if (simpleName == RecoveryScanner.FAKE_IDENTIFIER) { memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN; return null; } memberValuePair.valueKind = IMemberValuePair.K_SIMPLE_NAME; return new String(simpleName); } else if (expression instanceof ArrayInitializer) { memberValuePair.valueKind = -1; // modified below by the first call to getMemberValue(...) Expression[] expressions = ((ArrayInitializer) expression).expressions; int length = expressions == null ? 0 : expressions.length; Object[] values = new Object[length]; for (int i = 0; i < length; i++) { int previousValueKind = memberValuePair.valueKind; Object value = getMemberValue(memberValuePair, expressions[i]); if (previousValueKind != -1 && memberValuePair.valueKind != previousValueKind) { // values are heterogeneous, value kind is thus unknown memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN; } values[i] = value; } if (memberValuePair.valueKind == -1) memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN; return values; } else if (expression instanceof UnaryExpression) { // to deal with negative numerals (see bug - 248312) UnaryExpression unaryExpression = (UnaryExpression) expression; if ((unaryExpression.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT == OperatorIds.MINUS) { if (unaryExpression.expression instanceof Literal) { Literal subExpression = (Literal) unaryExpression.expression; subExpression.computeConstant(); return Util.getNegativeAnnotationMemberValue(memberValuePair, subExpression.constant); } } memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN; return null; } else { memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN; return null; } } }