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