| /******************************************************************************* |
| * Copyright (c) 2000, 2014 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Stephan Herrmann - Contribution for |
| * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.compiler.lookup; |
| |
| import org.eclipse.jdt.internal.compiler.ast.*; |
| import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
| import org.eclipse.jdt.internal.compiler.impl.Constant; |
| |
| public class ElementValuePair { |
| char[] name; |
| public Object value; |
| public MethodBinding binding; |
| |
| /** |
| * We want to avoid eagerly resolving of all enums that are used in annotations. |
| * This class encapsulates an unresolved enum constant as referenced in an ElementValuePair. |
| * The enum constant will be resolved when asking getValue() |
| */ |
| public static class UnresolvedEnumConstant { |
| ReferenceBinding enumType; |
| LookupEnvironment environment; |
| char[] enumConstantName; |
| UnresolvedEnumConstant(ReferenceBinding enumType, LookupEnvironment environment, char[] enumConstantName) { |
| this.enumType = enumType; |
| this.environment = environment; |
| this.enumConstantName = enumConstantName; |
| } |
| FieldBinding getResolved() { |
| if (this.enumType.isUnresolvedType()) |
| this.enumType = (ReferenceBinding) BinaryTypeBinding.resolveType(this.enumType, this.environment, false /* no raw conversion */); |
| return this.enumType.getField(this.enumConstantName, false); |
| } |
| public char[] getEnumConstantName() { |
| return this.enumConstantName; |
| } |
| } |
| |
| public static Object getValue(Expression expression) { |
| if (expression == null) |
| return null; |
| Constant constant = expression.constant; |
| // literals would hit this case. |
| if (constant != null && constant != Constant.NotAConstant) |
| return constant; |
| |
| if (expression instanceof Annotation) |
| return ((Annotation) expression).getCompilerAnnotation(); |
| if (expression instanceof ArrayInitializer) { |
| Expression[] exprs = ((ArrayInitializer) expression).expressions; |
| int length = exprs == null ? 0 : exprs.length; |
| Object[] values = new Object[length]; |
| for (int i = 0; i < length; i++) |
| values[i] = getValue(exprs[i]); |
| return values; |
| } |
| if (expression instanceof ClassLiteralAccess) |
| return ((ClassLiteralAccess) expression).targetType; |
| if (expression instanceof Reference) { |
| FieldBinding fieldBinding = null; |
| if (expression instanceof FieldReference) { |
| fieldBinding = ((FieldReference) expression).fieldBinding(); |
| } else if (expression instanceof NameReference) { |
| Binding binding = ((NameReference) expression).binding; |
| if (binding != null && binding.kind() == Binding.FIELD) |
| fieldBinding = (FieldBinding) binding; |
| } |
| if (fieldBinding != null && (fieldBinding.modifiers & ClassFileConstants.AccEnum) > 0) |
| return fieldBinding; |
| } |
| // something that isn't a compile time constant. |
| return null; |
| } |
| |
| public ElementValuePair(char[] name, Expression expression, MethodBinding binding) { |
| this(name, ElementValuePair.getValue(expression), binding); |
| } |
| |
| public ElementValuePair(char[] name, Object value, MethodBinding binding) { |
| this.name = name; |
| this.value = value; |
| this.binding = binding; |
| } |
| |
| /** |
| * @return the name of the element value pair. |
| */ |
| public char[] getName() { |
| return this.name; |
| } |
| |
| /** |
| * @return the method binding that defined this member value pair or null if no such binding exists. |
| */ |
| public MethodBinding getMethodBinding() { |
| return this.binding; |
| } |
| |
| /** |
| * Return {@link TypeBinding} for member value of type {@link java.lang.Class} |
| * Return {@link org.eclipse.jdt.internal.compiler.impl.Constant} for member of primitive type or String |
| * Return {@link FieldBinding} for enum constant |
| * Return {@link AnnotationBinding} for annotation instance |
| * Return <code>Object[]</code> for member value of array type. |
| * @return the value of this member value pair or null if the value is missing or is not a compile-time constant |
| */ |
| public Object getValue() { |
| if (this.value instanceof UnresolvedEnumConstant) |
| this.value = ((UnresolvedEnumConstant)this.value).getResolved(); |
| else if (this.value instanceof Object[]) { |
| Object[] valueArray = (Object[]) this.value; |
| for(int i = 0; i < valueArray.length; i++) { |
| Object object = valueArray[i]; |
| if (object instanceof UnresolvedEnumConstant) |
| valueArray[i] = ((UnresolvedEnumConstant) object).getResolved(); |
| } |
| } |
| return this.value; |
| } |
| |
| void setMethodBinding(MethodBinding binding) { |
| // lazily set after annotation type was resolved |
| this.binding = binding; |
| } |
| |
| void setValue(Object value) { |
| // can be modified after the initialization if holding an unresolved ref |
| this.value = value; |
| } |
| |
| @Override |
| public String toString() { |
| StringBuffer buffer = new StringBuffer(5); |
| buffer.append(this.name).append(" = "); //$NON-NLS-1$ |
| buffer.append(this.value); |
| return buffer.toString(); |
| } |
| } |