1 | /******************************************************************************* |
---|---|
2 | * Copyright (c) 2000, 2021 IBM Corporation and others. |
3 | * |
4 | * This program and the accompanying materials |
5 | * are made available under the terms of the Eclipse Public License 2.0 |
6 | * which accompanies this distribution, and is available at |
7 | * https://www.eclipse.org/legal/epl-2.0/ |
8 | * |
9 | * SPDX-License-Identifier: EPL-2.0 |
10 | * |
11 | * Contributors: |
12 | * IBM Corporation - initial API and implementation |
13 | * Stephan Herrmann - Contribution for |
14 | * Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda |
15 | * Bug 466308 - [hovering] Javadoc header for parameter is wrong with annotation-based null analysis |
16 | *******************************************************************************/ |
17 | |
18 | package org.eclipse.jdt.core.dom; |
19 | |
20 | import org.eclipse.jdt.core.IJavaElement; |
21 | import org.eclipse.jdt.core.JavaCore; |
22 | import org.eclipse.jdt.core.util.IModifierConstants; |
23 | import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; |
24 | import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
25 | import org.eclipse.jdt.internal.compiler.impl.Constant; |
26 | import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; |
27 | import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; |
28 | import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; |
29 | import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding; |
30 | import org.eclipse.jdt.internal.compiler.lookup.TagBits; |
31 | import org.eclipse.jdt.internal.compiler.lookup.TypeIds; |
32 | import org.eclipse.jdt.internal.core.JavaElement; |
33 | import org.eclipse.jdt.internal.core.LocalVariable; |
34 | import org.eclipse.jdt.internal.core.util.Util; |
35 | |
36 | /** |
37 | * Internal implementation of variable bindings. |
38 | */ |
39 | class VariableBinding implements IVariableBinding { |
40 | |
41 | private static final int VALID_MODIFIERS = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | |
42 | Modifier.STATIC | Modifier.FINAL | Modifier.TRANSIENT | Modifier.VOLATILE; |
43 | |
44 | private org.eclipse.jdt.internal.compiler.lookup.VariableBinding binding; |
45 | private ITypeBinding declaringClass; |
46 | private String key; |
47 | private String name; |
48 | private BindingResolver resolver; |
49 | private ITypeBinding type; |
50 | private IAnnotationBinding[] annotations; |
51 | |
52 | VariableBinding(BindingResolver resolver, org.eclipse.jdt.internal.compiler.lookup.VariableBinding binding) { |
53 | this.resolver = resolver; |
54 | this.binding = binding; |
55 | } |
56 | |
57 | @Override |
58 | public IAnnotationBinding[] getAnnotations() { |
59 | if (this.annotations != null) { |
60 | return this.annotations; |
61 | } |
62 | org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] internalAnnotations = this.binding.getAnnotations(); |
63 | int length = internalAnnotations == null ? 0 : internalAnnotations.length; |
64 | if (length != 0) { |
65 | IAnnotationBinding[] tempAnnotations = new IAnnotationBinding[length]; |
66 | int convertedAnnotationCount = 0; |
67 | for (int i = 0; i < length; i++) { |
68 | org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding internalAnnotation = internalAnnotations[i]; |
69 | final IAnnotationBinding annotationInstance = this.resolver.getAnnotationInstance(internalAnnotation); |
70 | if (annotationInstance == null) { |
71 | continue; |
72 | } |
73 | tempAnnotations[convertedAnnotationCount++] = annotationInstance; |
74 | } |
75 | if (convertedAnnotationCount != length) { |
76 | if (convertedAnnotationCount == 0) { |
77 | return this.annotations = AnnotationBinding.NoAnnotations; |
78 | } |
79 | System.arraycopy(tempAnnotations, 0, (tempAnnotations = new IAnnotationBinding[convertedAnnotationCount]), 0, convertedAnnotationCount); |
80 | } |
81 | return this.annotations = tempAnnotations; |
82 | } |
83 | return this.annotations = AnnotationBinding.NoAnnotations; |
84 | } |
85 | |
86 | @Override |
87 | public Object getConstantValue() { |
88 | Constant c = this.binding.constant(); |
89 | if (c == null || c == Constant.NotAConstant) return null; |
90 | switch (c.typeID()) { |
91 | case TypeIds.T_boolean: |
92 | return Boolean.valueOf(c.booleanValue()); |
93 | case TypeIds.T_byte: |
94 | return Byte.valueOf(c.byteValue()); |
95 | case TypeIds.T_char: |
96 | return Character.valueOf(c.charValue()); |
97 | case TypeIds.T_double: |
98 | return Double.valueOf(c.doubleValue()); |
99 | case TypeIds.T_float: |
100 | return Float.valueOf(c.floatValue()); |
101 | case TypeIds.T_int: |
102 | return Integer.valueOf(c.intValue()); |
103 | case TypeIds.T_long: |
104 | return Long.valueOf(c.longValue()); |
105 | case TypeIds.T_short: |
106 | return Short.valueOf(c.shortValue()); |
107 | case TypeIds.T_JavaLangString: |
108 | return c.stringValue(); |
109 | } |
110 | return null; |
111 | } |
112 | |
113 | @Override |
114 | public ITypeBinding getDeclaringClass() { |
115 | if (isField()) { |
116 | if (this.declaringClass == null) { |
117 | FieldBinding fieldBinding = (FieldBinding) this.binding; |
118 | this.declaringClass = this.resolver.getTypeBinding(fieldBinding.declaringClass); |
119 | } |
120 | return this.declaringClass; |
121 | } else { |
122 | return null; |
123 | } |
124 | } |
125 | |
126 | @Override |
127 | public IMethodBinding getDeclaringMethod() { |
128 | if (!isField()) { |
129 | ASTNode node = this.resolver.findDeclaringNode(this); |
130 | while (true) { |
131 | if (node == null) { |
132 | if (this.binding instanceof LocalVariableBinding) { |
133 | LocalVariableBinding localVariableBinding = (LocalVariableBinding) this.binding; |
134 | org.eclipse.jdt.internal.compiler.lookup.MethodBinding enclosingMethod = localVariableBinding.getEnclosingMethod(); |
135 | if (enclosingMethod != null) |
136 | return this.resolver.getMethodBinding(enclosingMethod); |
137 | } |
138 | return null; |
139 | } |
140 | switch(node.getNodeType()) { |
141 | case ASTNode.INITIALIZER : |
142 | return null; |
143 | case ASTNode.METHOD_DECLARATION : |
144 | MethodDeclaration methodDeclaration = (MethodDeclaration) node; |
145 | return methodDeclaration.resolveBinding(); |
146 | case ASTNode.LAMBDA_EXPRESSION : |
147 | LambdaExpression lambdaExpression = (LambdaExpression) node; |
148 | return lambdaExpression.resolveMethodBinding(); |
149 | default: |
150 | node = node.getParent(); |
151 | } |
152 | } |
153 | } |
154 | return null; |
155 | } |
156 | |
157 | @Override |
158 | public IJavaElement getJavaElement() { |
159 | JavaElement element = getUnresolvedJavaElement(); |
160 | if (element == null) |
161 | return null; |
162 | return element.resolved(this.binding); |
163 | } |
164 | |
165 | @Override |
166 | public String getKey() { |
167 | if (this.key == null) { |
168 | this.key = new String(this.binding.computeUniqueKey()); |
169 | } |
170 | return this.key; |
171 | } |
172 | |
173 | @Override |
174 | public int getKind() { |
175 | return IBinding.VARIABLE; |
176 | } |
177 | |
178 | @Override |
179 | public int getModifiers() { |
180 | if (isField()) { |
181 | return ((FieldBinding) this.binding).getAccessFlags() & VALID_MODIFIERS; |
182 | } |
183 | if (this.binding.isFinal()) { |
184 | return IModifierConstants.ACC_FINAL; |
185 | } |
186 | return Modifier.NONE; |
187 | } |
188 | |
189 | @Override |
190 | public String getName() { |
191 | if (this.name == null) { |
192 | this.name = new String(this.binding.name); |
193 | } |
194 | return this.name; |
195 | } |
196 | |
197 | @Override |
198 | public ITypeBinding getType() { |
199 | if (this.type == null) { |
200 | this.type = this.resolver.getTypeBinding(this.binding.type); |
201 | } |
202 | return this.type; |
203 | } |
204 | |
205 | private JavaElement getUnresolvedJavaElement() { |
206 | if (JavaCore.getPlugin() == null) { |
207 | return null; |
208 | } |
209 | if (isField()) { |
210 | if (this.resolver instanceof DefaultBindingResolver) { |
211 | DefaultBindingResolver defaultBindingResolver = (DefaultBindingResolver) this.resolver; |
212 | if (!defaultBindingResolver.fromJavaProject) return null; |
213 | return Util.getUnresolvedJavaElement( |
214 | (FieldBinding) this.binding, |
215 | defaultBindingResolver.workingCopyOwner, |
216 | defaultBindingResolver.getBindingsToNodesMap()); |
217 | } |
218 | return null; |
219 | }else if (isRecordComponent()) { |
220 | if (this.resolver instanceof DefaultBindingResolver) { |
221 | DefaultBindingResolver defaultBindingResolver = (DefaultBindingResolver) this.resolver; |
222 | if (!defaultBindingResolver.fromJavaProject) return null; |
223 | return Util.getUnresolvedJavaElement( |
224 | (RecordComponentBinding) this.binding, |
225 | defaultBindingResolver.workingCopyOwner, |
226 | defaultBindingResolver.getBindingsToNodesMap()); |
227 | } |
228 | return null; |
229 | } |
230 | // local variable |
231 | if (!(this.resolver instanceof DefaultBindingResolver)) return null; |
232 | DefaultBindingResolver defaultBindingResolver = (DefaultBindingResolver) this.resolver; |
233 | if (!defaultBindingResolver.fromJavaProject) return null; |
234 | VariableDeclaration localVar = (VariableDeclaration) defaultBindingResolver.bindingsToAstNodes.get(this); |
235 | if (localVar == null) return null; |
236 | SimpleName localName = localVar.getName(); |
237 | int nameStart = localName.getStartPosition(); |
238 | int nameLength = localName.getLength(); |
239 | int sourceStart; |
240 | int sourceLength; |
241 | int modifiers = 0; |
242 | if (localVar instanceof SingleVariableDeclaration) { |
243 | sourceStart = localVar.getStartPosition(); |
244 | sourceLength = localVar.getLength(); |
245 | final SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration) localVar; |
246 | modifiers = singleVariableDeclaration.getModifiers(); |
247 | } else { |
248 | ASTNode node = localVar.getParent(); |
249 | sourceStart = node.getStartPosition(); |
250 | sourceLength = node.getLength(); |
251 | VariableDeclarationFragment fragment = (VariableDeclarationFragment) localVar; |
252 | final ASTNode parent = fragment.getParent(); |
253 | switch (parent.getNodeType()) { |
254 | case ASTNode.VARIABLE_DECLARATION_EXPRESSION : |
255 | VariableDeclarationExpression expression = (VariableDeclarationExpression) parent; |
256 | modifiers = expression.getModifiers(); |
257 | break; |
258 | case ASTNode.VARIABLE_DECLARATION_STATEMENT : |
259 | VariableDeclarationStatement statement = (VariableDeclarationStatement) parent; |
260 | modifiers = statement.getModifiers(); |
261 | break; |
262 | case ASTNode.FIELD_DECLARATION : |
263 | FieldDeclaration fieldDeclaration = (FieldDeclaration) parent; |
264 | modifiers = fieldDeclaration.getModifiers(); |
265 | break; |
266 | } |
267 | } |
268 | int sourceEnd = sourceStart+sourceLength-1; |
269 | char[] typeSig = this.binding.type.genericTypeSignature(); |
270 | JavaElement parent = null; |
271 | IMethodBinding declaringMethod = getDeclaringMethod(); |
272 | if (this.binding instanceof RecordComponentBinding) { |
273 | return null; // TODO : SEE Bug 562736/ BUG 562637 |
274 | } |
275 | final LocalVariableBinding localVariableBinding = (LocalVariableBinding) this.binding; |
276 | if (declaringMethod == null) { |
277 | ReferenceContext referenceContext = localVariableBinding.declaringScope.referenceContext(); |
278 | if (referenceContext instanceof TypeDeclaration){ |
279 | // Local variable is declared inside an initializer |
280 | TypeDeclaration typeDeclaration = (TypeDeclaration) referenceContext; |
281 | JavaElement typeHandle = null; |
282 | typeHandle = Util.getUnresolvedJavaElement( |
283 | typeDeclaration.binding, |
284 | defaultBindingResolver.workingCopyOwner, |
285 | defaultBindingResolver.getBindingsToNodesMap()); |
286 | parent = Util.getUnresolvedJavaElement(sourceStart, sourceEnd, typeHandle); |
287 | } else { |
288 | return null; |
289 | } |
290 | } else { |
291 | parent = (JavaElement) declaringMethod.getJavaElement(); |
292 | } |
293 | if (parent == null) return null; |
294 | return new LocalVariable( |
295 | parent, |
296 | localName.getIdentifier(), |
297 | sourceStart, |
298 | sourceEnd, |
299 | nameStart, |
300 | nameStart+nameLength-1, |
301 | new String(typeSig), |
302 | localVariableBinding.declaration.annotations, |
303 | modifiers, |
304 | (localVariableBinding.tagBits & TagBits.IsArgument) != 0); |
305 | } |
306 | |
307 | @Override |
308 | public IVariableBinding getVariableDeclaration() { |
309 | if (isField()) { |
310 | FieldBinding fieldBinding = (FieldBinding) this.binding; |
311 | return this.resolver.getVariableBinding(fieldBinding.original()); |
312 | } |
313 | return this; |
314 | } |
315 | |
316 | @Override |
317 | public int getVariableId() { |
318 | return this.binding.id; |
319 | } |
320 | |
321 | @Override |
322 | public boolean isParameter() { |
323 | return (this.binding.tagBits & TagBits.IsArgument) != 0; |
324 | } |
325 | |
326 | @Override |
327 | public boolean isDeprecated() { |
328 | if (isField()) { |
329 | return ((FieldBinding) this.binding).isDeprecated(); |
330 | } |
331 | return false; |
332 | } |
333 | |
334 | @Override |
335 | public boolean isEnumConstant() { |
336 | return (this.binding.modifiers & ClassFileConstants.AccEnum) != 0; |
337 | } |
338 | |
339 | @Override |
340 | public boolean isEqualTo(IBinding other) { |
341 | if (other == this) { |
342 | // identical binding - equal (key or no key) |
343 | return true; |
344 | } |
345 | if (other == null) { |
346 | // other binding missing |
347 | return false; |
348 | } |
349 | if (!(other instanceof VariableBinding)) { |
350 | return false; |
351 | } |
352 | org.eclipse.jdt.internal.compiler.lookup.VariableBinding otherBinding = ((VariableBinding) other).binding; |
353 | if (this.binding instanceof FieldBinding) { |
354 | if (otherBinding instanceof FieldBinding) { |
355 | return BindingComparator.isEqual((FieldBinding) this.binding, (FieldBinding) otherBinding); |
356 | } else { |
357 | return false; |
358 | } |
359 | } else { |
360 | if (BindingComparator.isEqual(this.binding, otherBinding)) { |
361 | IMethodBinding declaringMethod = getDeclaringMethod(); |
362 | IMethodBinding otherDeclaringMethod = ((VariableBinding) other).getDeclaringMethod(); |
363 | if (declaringMethod == null) { |
364 | if (otherDeclaringMethod != null) { |
365 | return false; |
366 | } |
367 | return true; |
368 | } |
369 | return declaringMethod.isEqualTo(otherDeclaringMethod); |
370 | } |
371 | return false; |
372 | } |
373 | } |
374 | |
375 | @Override |
376 | public boolean isField() { |
377 | return this.binding instanceof FieldBinding; |
378 | } |
379 | |
380 | @Override |
381 | public boolean isSynthetic() { |
382 | if (isField()) { |
383 | return ((FieldBinding) this.binding).isSynthetic(); |
384 | } |
385 | return false; |
386 | } |
387 | |
388 | @Override |
389 | public boolean isRecovered() { |
390 | return false; |
391 | } |
392 | |
393 | @Override |
394 | public boolean isEffectivelyFinal() { |
395 | return (!this.binding.isFinal() && this.binding.isEffectivelyFinal()); |
396 | } |
397 | |
398 | @Override |
399 | public boolean isRecordComponent() { |
400 | return this.binding instanceof RecordComponentBinding; |
401 | } |
402 | |
403 | /* |
404 | * For debugging purpose only. |
405 | * @see java.lang.Object#toString() |
406 | */ |
407 | @Override |
408 | public String toString() { |
409 | return this.binding.toString(); |
410 | } |
411 | |
412 | } |
413 |
Members