Skip to main content
summaryrefslogtreecommitdiffstats
blob: ff19f339a67e77b1cbb93b766c9d9d700780b429 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*******************************************************************************
 * 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();
}
}

Back to the top