1 /*******************************************************************************
2 * Copyright (c) 2000, 2013 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.parser;
12
13 /**
14 * Internal local variable structure for parsing recovery
15 */
16 import java.util.HashSet;
17 import java.util.Set;
18
19 import org.eclipse.jdt.internal.compiler.ast.Annotation;
20 import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference;
21 import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
22 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
23 import org.eclipse.jdt.internal.compiler.ast.Expression;
24 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
25 import org.eclipse.jdt.internal.compiler.ast.Statement;
26
27 @SuppressWarnings("rawtypes")
28 public class RecoveredLocalVariable extends RecoveredStatement {
29
30 public RecoveredAnnotation[] annotations;
31 public int annotationCount;
32 public int modifiers;
33 public int modifiersStart;
34
35 public LocalDeclaration localDeclaration;
36 public boolean alreadyCompletedLocalInitialization;
RecoveredLocalVariable(LocalDeclaration localDeclaration, RecoveredElement parent, int bracketBalance)37 public RecoveredLocalVariable(LocalDeclaration localDeclaration, RecoveredElement parent, int bracketBalance){
38 super(localDeclaration, parent, bracketBalance);
39 this.localDeclaration = localDeclaration;
40 this.alreadyCompletedLocalInitialization = localDeclaration.initialization != null;
41 }
42 /*
43 * Record an expression statement if local variable is expecting an initialization expression.
44 */
add(Statement stmt, int bracketBalanceValue)45 public RecoveredElement add(Statement stmt, int bracketBalanceValue) {
46
47 if (this.alreadyCompletedLocalInitialization || !(stmt instanceof Expression)) {
48 return super.add(stmt, bracketBalanceValue);
49 } else {
50 this.alreadyCompletedLocalInitialization = true;
51 this.localDeclaration.initialization = (Expression)stmt;
52 this.localDeclaration.declarationSourceEnd = stmt.sourceEnd;
53 this.localDeclaration.declarationEnd = stmt.sourceEnd;
54 return this;
55 }
56 }
attach(RecoveredAnnotation[] annots, int annotCount, int mods, int modsSourceStart)57 public void attach(RecoveredAnnotation[] annots, int annotCount, int mods, int modsSourceStart) {
58 if (annotCount > 0) {
59 Annotation[] existingAnnotations = this.localDeclaration.annotations;
60 if (existingAnnotations != null) {
61 this.annotations = new RecoveredAnnotation[annotCount];
62 this.annotationCount = 0;
63 next : for (int i = 0; i < annotCount; i++) {
64 for (int j = 0; j < existingAnnotations.length; j++) {
65 if (annots[i].annotation == existingAnnotations[j]) continue next;
66 }
67 this.annotations[this.annotationCount++] = annots[i];
68 }
69 } else {
70 this.annotations = annots;
71 this.annotationCount = annotCount;
72 }
73 }
74
75 if (mods != 0) {
76 this.modifiers = mods;
77 this.modifiersStart = modsSourceStart;
78 }
79 }
80 /*
81 * Answer the associated parsed structure
82 */
parseTree()83 public ASTNode parseTree(){
84 return this.localDeclaration;
85 }
86 /*
87 * Answer the very source end of the corresponding parse node
88 */
sourceEnd()89 public int sourceEnd(){
90 return this.localDeclaration.declarationSourceEnd;
91 }
toString(int tab)92 public String toString(int tab) {
93 return tabString(tab) + "Recovered local variable:\n" + this.localDeclaration.print(tab + 1, new StringBuffer(10)); //$NON-NLS-1$
94 }
updatedStatement(int depth, Set knownTypes)95 public Statement updatedStatement(int depth, Set knownTypes){
96 /* update annotations */
97 if (this.modifiers != 0) {
98 this.localDeclaration.modifiers |= this.modifiers;
99 if (this.modifiersStart < this.localDeclaration.declarationSourceStart) {
100 this.localDeclaration.declarationSourceStart = this.modifiersStart;
101 }
102 }
103 /* update annotations */
104 if (this.annotationCount > 0){
105 int existingCount = this.localDeclaration.annotations == null ? 0 : this.localDeclaration.annotations.length;
106 Annotation[] annotationReferences = new Annotation[existingCount + this.annotationCount];
107 if (existingCount > 0){
108 System.arraycopy(this.localDeclaration.annotations, 0, annotationReferences, this.annotationCount, existingCount);
109 }
110 for (int i = 0; i < this.annotationCount; i++){
111 annotationReferences[i] = this.annotations[i].updatedAnnotationReference();
112 }
113 this.localDeclaration.annotations = annotationReferences;
114
115 int start = this.annotations[0].annotation.sourceStart;
116 if (start < this.localDeclaration.declarationSourceStart) {
117 this.localDeclaration.declarationSourceStart = start;
118 }
119 }
120 return this.localDeclaration;
121 }
122 /*
123 * A closing brace got consumed, might have closed the current element,
124 * in which case both the currentElement is exited.
125 *
126 * Fields have no associated braces, thus if matches, then update parent.
127 */
updateOnClosingBrace(int braceStart, int braceEnd)128 public RecoveredElement updateOnClosingBrace(int braceStart, int braceEnd){
129 if (this.bracketBalance > 0){ // was an array initializer
130 this.bracketBalance--;
131 if (this.bracketBalance == 0) this.alreadyCompletedLocalInitialization = true;
132 return this;
133 }
134 if (this.parent != null){
135 return this.parent.updateOnClosingBrace(braceStart, braceEnd);
136 }
137 return this;
138 }
139 /*
140 * An opening brace got consumed, might be the expected opening one of the current element,
141 * in which case the bodyStart is updated.
142 */
updateOnOpeningBrace(int braceStart, int braceEnd)143 public RecoveredElement updateOnOpeningBrace(int braceStart, int braceEnd){
144 if (this.localDeclaration.declarationSourceEnd == 0
145 && (this.localDeclaration.type instanceof ArrayTypeReference || this.localDeclaration.type instanceof ArrayQualifiedTypeReference)
146 && !this.alreadyCompletedLocalInitialization){
147 this.bracketBalance++;
148 return null; // no update is necessary (array initializer)
149 }
150 // might be an array initializer
151 this.updateSourceEndIfNecessary(braceStart - 1, braceEnd - 1);
152 return this.parent.updateOnOpeningBrace(braceStart, braceEnd);
153 }
updateParseTree()154 public void updateParseTree(){
155 updatedStatement(0, new HashSet());
156 }
157 /*
158 * Update the declarationSourceEnd of the corresponding parse node
159 */
updateSourceEndIfNecessary(int bodyStart, int bodyEnd)160 public void updateSourceEndIfNecessary(int bodyStart, int bodyEnd){
161 if (this.localDeclaration.declarationSourceEnd == 0) {
162 this.localDeclaration.declarationSourceEnd = bodyEnd;
163 this.localDeclaration.declarationEnd = bodyEnd;
164 }
165 }
166 }
167