Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 604f51fe72be99a2f9ca70a9620f0216f99419ac (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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
/*******************************************************************************
 * Copyright (c) 2000, 2022 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
 *******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.BranchLabel;
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.impl.IntConstant;
import org.eclipse.jdt.internal.compiler.impl.JavaFeature;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;

public class CaseStatement extends Statement {

	static final int CASE_CONSTANT = 1;
	static final int CASE_PATTERN  = 2;

	public BranchLabel targetLabel;
	public Expression[] constantExpressions; // case with multiple expressions
	public BranchLabel[] targetLabels; // for multiple expressions
	public boolean isExpr = false;
	/* package */ int patternIndex = -1; // points to first pattern var index [only one pattern variable allowed now - should be 0]

public CaseStatement(Expression constantExpression, int sourceEnd, int sourceStart) {
	this(sourceEnd, sourceStart, constantExpression != null ? new Expression[] {constantExpression} : null);
}

public CaseStatement(int sourceEnd, int sourceStart, Expression[] constantExpressions) {
	this.constantExpressions = constantExpressions;
	this.sourceEnd = sourceEnd;
	this.sourceStart = sourceStart;
	initPatterns();
}

private void initPatterns() {
	int l = this.constantExpressions == null ? 0 : this.constantExpressions.length;
	for (int i = 0; i < l; ++i) {
		Expression e = this.constantExpressions[i];
		if (e instanceof Pattern) {
			this.patternIndex = i;
			break;
		}
	}
}

@Override
public FlowInfo analyseCode(
	BlockScope currentScope,
	FlowContext flowContext,
	FlowInfo flowInfo) {
	if (this.constantExpressions != null) {
		int nullPatternCount = 0;
		for(int i=0; i < this.constantExpressions.length; i++) {
			Expression e = this.constantExpressions[i];
			nullPatternCount +=  e instanceof NullLiteral ? 1 : 0;
			if (i > 0 && (e instanceof Pattern)) {
				if (!(i == nullPatternCount && e instanceof TypePattern))
					currentScope.problemReporter().IllegalFallThroughToPattern(e);
			}
			flowInfo = analyseConstantExpression(currentScope, flowContext, flowInfo, e);
			if (nullPatternCount > 0 && e instanceof TypePattern) {
				LocalVariableBinding binding = ((TypePattern) e).local.binding;
				if (binding != null)
					flowInfo.markNullStatus(binding, FlowInfo.POTENTIALLY_NULL);
			}
		}
	}
	return flowInfo;
}
private FlowInfo analyseConstantExpression(
		BlockScope currentScope,
		FlowContext flowContext,
		FlowInfo flowInfo,
		Expression e) {
	if (e.constant == Constant.NotAConstant
			&& !e.resolvedType.isEnum()) {
		boolean caseNullorDefaultAllowed =
				JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(currentScope.compilerOptions())
				&& (e instanceof NullLiteral || e instanceof FakeDefaultLiteral);
		if (!caseNullorDefaultAllowed)
			currentScope.problemReporter().caseExpressionMustBeConstant(e);
		if (e instanceof NullLiteral && flowContext.associatedNode instanceof SwitchStatement) {
			Expression switchValue = ((SwitchStatement) flowContext.associatedNode).expression;
			if (switchValue != null && switchValue.nullStatus(flowInfo, flowContext) == FlowInfo.NON_NULL) {
				currentScope.problemReporter().unnecessaryNullCaseInSwitchOverNonNull(this);
			}
		}
	}
	return e.analyseCode(currentScope, flowContext, flowInfo);
}

@Override
public boolean containsPatternVariable() {
	return this.patternIndex != -1;
}
@Override
public StringBuffer printStatement(int tab, StringBuffer output) {
	printIndent(tab, output);
	if (this.constantExpressions == null) {
		output.append("default "); //$NON-NLS-1$
		output.append(this.isExpr ? "->" : ":"); //$NON-NLS-1$ //$NON-NLS-2$
	} else {
		output.append("case "); //$NON-NLS-1$
		for (int i = 0, l = this.constantExpressions.length; i < l; ++i) {
			this.constantExpressions[i].printExpression(0, output);
			if (i < l -1) output.append(',');
		}
		output.append(this.isExpr ? " ->" : " :"); //$NON-NLS-1$ //$NON-NLS-2$
	}
	return output;
}

/**
 * Case code generation
 *
 */
@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream) {
	if ((this.bits & ASTNode.IsReachable) == 0) {
		return;
	}
	int pc = codeStream.position;
	if (this.targetLabels != null) {
		for (int i = 0, l = this.targetLabels.length; i < l; ++i) {
			this.targetLabels[i].place();
		}
	}
	if (this.targetLabel != null)
		this.targetLabel.place();
	casePatternExpressionGenerateCode(currentScope, codeStream);
	codeStream.recordPositionsFrom(pc, this.sourceStart);
}

private void casePatternExpressionGenerateCode(BlockScope currentScope, CodeStream codeStream) {
	if (this.patternIndex != -1) {
		LocalVariableBinding local = currentScope.findVariable(SwitchStatement.SecretPatternVariableName, null);
		codeStream.load(local);
		Pattern patternExpression = ((Pattern) this.constantExpressions[this.patternIndex]);
		patternExpression.generateCode(currentScope, codeStream);
	}
}

/**
 * No-op : should use resolveCase(...) instead.
 */
@Override
public void resolve(BlockScope scope) {
	// no-op : should use resolveCase(...) instead.
}
public static class ResolvedCase {
	static final ResolvedCase[] UnresolvedCase = new ResolvedCase[0];
	public Constant c;
	public Expression e;
	public TypeBinding t; // For ease of access. This.e contains the type binding anyway.
	public int index;
	private int intValue;
	private boolean isPattern;
	ResolvedCase(Constant c, Expression e, TypeBinding t, int index) {
		this.c = c;
		this.e = e;
		this.t= t;
		this.index = index;
		if (c.typeID() == TypeIds.T_JavaLangString) {
			c.stringValue().hashCode();
		} else {
			this.intValue = c.intValue();
		}
		this.isPattern = e instanceof Pattern;
	}
	public int intValue() {
		return this.intValue;
	}
	public boolean isPattern() {
		return this.isPattern;
	}
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("case "); //$NON-NLS-1$
		builder.append(this.e);
		builder.append(" [CONSTANT="); //$NON-NLS-1$
		builder.append(this.c);
		builder.append("]"); //$NON-NLS-1$
		return builder.toString();
	}
}
/**
 * Returns the constant intValue or ordinal for enum constants. If constant is NotAConstant, then answers Float.MIN_VALUE
 */
public ResolvedCase[] resolveCase(BlockScope scope, TypeBinding switchExpressionType, SwitchStatement switchStatement) {
	if (containsPatternVariable()) {
		return resolveWithPatternVariablesInScope(this.patternVarsWhenTrue, scope, switchExpressionType, switchStatement);
	}
	return resolveCasePrivate(scope, switchExpressionType, switchStatement);
}
public ResolvedCase[] resolveWithPatternVariablesInScope(LocalVariableBinding[] patternVariablesInScope,
		BlockScope scope,
		TypeBinding switchExpressionType,
		SwitchStatement switchStatement) {
	if (patternVariablesInScope != null) {
		for (LocalVariableBinding binding : patternVariablesInScope) {
			binding.modifiers &= ~ExtraCompilerModifiers.AccPatternVariable;
		}
		ResolvedCase[] cases = resolveCasePrivate(scope, switchExpressionType, switchStatement);
		for (LocalVariableBinding binding : patternVariablesInScope) {
			binding.modifiers |= ExtraCompilerModifiers.AccPatternVariable;
		}
		return cases;
	} else {
		return resolveCasePrivate(scope, switchExpressionType, switchStatement);
	}
}
private Expression getFirstValidExpression(BlockScope scope, SwitchStatement switchStatement) {
	assert this.constantExpressions != null;
	Expression ret = null;
	int patternCaseLabelCount = 0;
	int typePatternCount = 0;
	int defaultCaseLabelCount = 0;
	int nullCaseLabelCount = 0;

	boolean patternSwitchAllowed = JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(scope.compilerOptions());
	if (patternSwitchAllowed) {
		for (Expression e : this.constantExpressions) {
			 if (e instanceof FakeDefaultLiteral) {
				 scope.problemReporter().validateJavaFeatureSupport(JavaFeature.PATTERN_MATCHING_IN_SWITCH,
							e.sourceStart, e.sourceEnd);
				 flagDuplicateDefault(scope, switchStatement,
						 this.constantExpressions.length > 1 ? e : this);
				 if (patternCaseLabelCount > 0) {
					 scope.problemReporter().switchPatternBothPatternAndDefaultCaseLabelsNotAllowed(e);
				 }
				 ++defaultCaseLabelCount;
				 continue;
			}
			if (e instanceof Pattern) {
				scope.problemReporter().validateJavaFeatureSupport(JavaFeature.PATTERN_MATCHING_IN_SWITCH,
						e.sourceStart, e.sourceEnd);
				if (patternCaseLabelCount++ > 0) {
					scope.problemReporter().switchPatternOnlyOnePatternCaseLabelAllowed(e);
					return e; // Return and avoid secondary errors
				} else if (defaultCaseLabelCount > 0) {
					scope.problemReporter().switchPatternBothPatternAndDefaultCaseLabelsNotAllowed(e);
					return e; // Return and avoid secondary errors
				}
				if (e instanceof TypePattern) {
					++typePatternCount;
				} else if (nullCaseLabelCount > 0 ) {
					scope.problemReporter().switchPatternBothNullAndNonTypePatternNotAllowed(e);
					return e; // Return and avoid secondary errors
				}
			} else if (e instanceof NullLiteral) {
				scope.problemReporter().validateJavaFeatureSupport(JavaFeature.PATTERN_MATCHING_IN_SWITCH,
						e.sourceStart, e.sourceEnd);
				if (switchStatement.nullCase == null) {
					switchStatement.nullCase = this;
					if ((switchStatement.switchBits & SwitchStatement.TotalPattern) != 0) {
						scope.problemReporter().patternDominatedByAnother(this.constantExpressions[0]);
						return e; // Return and avoid secondary errors
					}
				}

				if (nullCaseLabelCount++ > 0) {
					// TODO: Decide whether we need to have a more fine-grain element level error flagging for null specifically
//					continue;
				}
				if ((patternCaseLabelCount - typePatternCount) > 0) {
					scope.problemReporter().switchPatternBothNullAndNonTypePatternNotAllowed(e);
					return e; // Return and avoid secondary errors
				}
			}
			if (ret == null) ret = e;
		}
	} else {
		for (Expression e : this.constantExpressions) {
			if (e instanceof Pattern
					|| e instanceof NullLiteral
					|| e instanceof FakeDefaultLiteral) {
				scope.problemReporter().validateJavaFeatureSupport(JavaFeature.PATTERN_MATCHING_IN_SWITCH,
						e.sourceStart, e.sourceEnd);
				continue;
			}
			if (ret == null) ret = e;
		}
	}
	return ret;
}
private ResolvedCase[] resolveCasePrivate(BlockScope scope, TypeBinding switchExpressionType, SwitchStatement switchStatement) {
	// switchExpressionType maybe null in error case
	scope.enclosingCase = this; // record entering in a switch case block
	if (this.constantExpressions == null) {
		flagDuplicateDefault(scope, switchStatement, this);
		return ResolvedCase.UnresolvedCase;
	}
	Expression constExpr = getFirstValidExpression(scope, switchStatement);
	if (constExpr == null) {
		return ResolvedCase.UnresolvedCase;
	}

	// add into the collection of cases of the associated switch statement
	switchStatement.cases[switchStatement.caseCount++] = this;
	if (switchExpressionType != null && switchExpressionType.isEnum() && (constExpr instanceof SingleNameReference)) {
		((SingleNameReference) constExpr).setActualReceiverType((ReferenceBinding)switchExpressionType);
	}

	TypeBinding caseType = constExpr.resolveType(scope);
	if (caseType == null || switchExpressionType == null) return ResolvedCase.UnresolvedCase;
	// tag constant name with enum type for privileged access to its members

	List<ResolvedCase> cases = new ArrayList<>();
	for (Expression e : this.constantExpressions) {
		if (e != constExpr) {
			if (switchExpressionType.isEnum() && (e instanceof SingleNameReference)) {
				((SingleNameReference) e).setActualReceiverType((ReferenceBinding)switchExpressionType);
			} else if (e instanceof FakeDefaultLiteral) {
				continue; // already processed
			}
			caseType = e.resolveType(scope);
		}
		if (caseType == null)
			return ResolvedCase.UnresolvedCase;
		 // Avoid further resolution and secondary errors
		if (caseType.isValidBinding()) {
			Constant con = resolveConstantExpression(scope, caseType, switchExpressionType, switchStatement, e);
			if (con != Constant.NotAConstant) {
				int index = this == switchStatement.nullCase && e instanceof NullLiteral ?
						-1 : switchStatement.constantIndex++;
				cases.add(new ResolvedCase(con, e, caseType, index));
			}
		}
	}
	this.resolveWithPatternVariablesInScope(this.getPatternVariablesWhenTrue(), scope);
	if (cases.size() > 0) {
		return cases.toArray(new ResolvedCase[cases.size()]);
	}

	return ResolvedCase.UnresolvedCase;
}

private void flagDuplicateDefault(BlockScope scope, SwitchStatement switchStatement, ASTNode node) {
	// remember the default case into the associated switch statement
	if (switchStatement.defaultCase != null)
		scope.problemReporter().duplicateDefaultCase(node);

	// on error the last default will be the selected one ...
	switchStatement.defaultCase = this;
	if ((switchStatement.switchBits & SwitchStatement.TotalPattern) != 0) {
		scope.problemReporter().illegalTotalPatternWithDefault(this);
	}
}
public void collectPatternVariablesToScope(LocalVariableBinding[] variables, BlockScope scope) {
	if (!containsPatternVariable()) {
		return;
	}
	for (Expression e : this.constantExpressions) {
		e.collectPatternVariablesToScope(variables, scope);
		LocalVariableBinding[] patternVariables = e.getPatternVariablesWhenTrue();
		addPatternVariablesWhenTrue(patternVariables);
	}
}
public Constant resolveConstantExpression(BlockScope scope,
											TypeBinding caseType,
											TypeBinding switchType,
											SwitchStatement switchStatement,
											Expression expression) {

	boolean patternSwitchAllowed = JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(scope.compilerOptions());
	if (patternSwitchAllowed) {
		if (expression instanceof Pattern) {
			return resolveConstantExpression(scope, caseType, switchType,
					switchStatement,(Pattern) expression);
		} else if (expression instanceof NullLiteral) {
			if (!(switchType instanceof ReferenceBinding)) {
				scope.problemReporter().typeMismatchError(TypeBinding.NULL, switchType, expression, null);
			}
			switchStatement.switchBits |= SwitchStatement.NullCase;
			return IntConstant.fromValue(-1);
		} else if (expression instanceof FakeDefaultLiteral) {
			// do nothing
		} else {
			if (switchStatement.isNonTraditional) {
				if (switchType.isBaseType() && !expression.isConstantValueOfTypeAssignableToType(caseType, switchType)) {
					scope.problemReporter().typeMismatchError(caseType, switchType, expression, null);
					return Constant.NotAConstant;
				}
			}
		}
	}
	boolean boxing = !patternSwitchAllowed ||
			switchStatement.isAllowedType(switchType);

	if (expression.isConstantValueOfTypeAssignableToType(caseType, switchType)
			||(caseType.isCompatibleWith(switchType)
				&& !(expression instanceof StringLiteral))) {
		if (caseType.isEnum()) {
			if (((expression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) != 0) {
				scope.problemReporter().enumConstantsCannotBeSurroundedByParenthesis(expression);
			}

			if (expression instanceof NameReference
					&& (expression.bits & ASTNode.RestrictiveFlagMASK) == Binding.FIELD) {
				NameReference reference = (NameReference) expression;
				FieldBinding field = reference.fieldBinding();
				if ((field.modifiers & ClassFileConstants.AccEnum) == 0) {
					 scope.problemReporter().enumSwitchCannotTargetField(reference, field);
				} else 	if (reference instanceof QualifiedNameReference) {
					 scope.problemReporter().cannotUseQualifiedEnumConstantInCaseLabel(reference, field);
				}
				return IntConstant.fromValue(field.original().id + 1); // (ordinal value + 1) zero should not be returned see bug 141810
			}
		} else {
			return expression.constant;
		}
	} else if (boxing && isBoxingCompatible(caseType, switchType, expression, scope)) {
		// constantExpression.computeConversion(scope, caseType, switchExpressionType); - do not report boxing/unboxing conversion
		return expression.constant;
	}
	scope.problemReporter().typeMismatchError(expression.resolvedType, switchType, expression, switchStatement.expression);
	return Constant.NotAConstant;
}

private Constant resolveConstantExpression(BlockScope scope,
		TypeBinding caseType,
		TypeBinding switchExpressionType,
		SwitchStatement switchStatement,
		Pattern e) {
	Constant constant = Constant.NotAConstant;
	TypeBinding type = e.resolveType(scope);
	if (type != null) {
		constant = IntConstant.fromValue(switchStatement.constantIndex);
		switchStatement.caseLabelElements.add(e);
		if (e.resolvedType != null) {
			// 14.30.2 at compile-time we "resolve" the pattern with respect to the (compile-time) type
			// of the expression being pattern matched
			TypeBinding pb = e.resolveAtType(scope, switchStatement.expression.resolvedType);
			if (pb != null) switchStatement.caseLabelElementTypes.add(pb);
			TypeBinding expressionType = switchStatement.expression.resolvedType;
			LocalDeclaration patternVar = e.getPatternVariableIntroduced();
			if (patternVar != null && !patternVar.type.isTypeNameVar(scope)) {
				// The following code is copied from InstanceOfExpression#resolve()
				// But there are enough differences to warrant a copy
				if (!pb.isReifiable()) {
					if (expressionType != TypeBinding.NULL) {
						boolean isLegal = e.checkCastTypesCompatibility(scope, pb, expressionType, e, false);
						if (!isLegal || (e.bits & ASTNode.UnsafeCast) != 0) {
							scope.problemReporter().unsafeCastInInstanceof(e, pb, expressionType);
						}
					}
				} else if (pb.isValidBinding()) {
					// if not a valid binding, an error has already been reported for unresolved type
					if (pb.isPrimitiveType()) {
						scope.problemReporter().unexpectedTypeinSwitchPattern(pb, e);
						return Constant.NotAConstant;
					}
					if (pb.isBaseType()
							|| !e.checkCastTypesCompatibility(scope, pb, expressionType, null, false)) {
						scope.problemReporter().typeMismatchError(expressionType, pb, e, null);
						return Constant.NotAConstant;
					}
				}
			}
			if (e.isTotalForType(expressionType)) {
				if ((switchStatement.switchBits & SwitchStatement.TotalPattern) != 0) {
					scope.problemReporter().duplicateTotalPattern(e);
					return IntConstant.fromValue(-1);
				}
				switchStatement.switchBits |= (SwitchStatement.TotalPattern | SwitchStatement.Exhaustive);
				if (switchStatement.defaultCase != null)
					scope.problemReporter().illegalTotalPatternWithDefault(this);
				switchStatement.totalPattern = e;
				e.isTotalTypeNode = true;
				if (switchStatement.nullCase == null)
					constant = IntConstant.fromValue(-1);
			}
		}

	}
 	return constant;
}

/* package */ void patternCaseRemovePatternLocals(CodeStream codeStream) {
	for (Expression e : this.constantExpressions) {
		if (e instanceof Pattern) {
			e.traverse(new ASTVisitor() {
				@Override
				public boolean visit(TypePattern typePattern, BlockScope scope) {
					LocalDeclaration local = typePattern.getPatternVariableIntroduced();
					if (local != null && local.binding != null)
						codeStream.removeVariable(local.binding);
					return false; // No deeper than this on this node
				}
			}, (BlockScope) null);
		}
	}
}
@Override
public void traverse(ASTVisitor visitor, 	BlockScope blockScope) {
	if (visitor.visit(this, blockScope)) {
		if (this.constantExpressions != null) {
			for (Expression e : this.constantExpressions) {
				e.traverse(visitor, blockScope);
			}
		}

	}
	visitor.endVisit(this, blockScope);
}
/**
 * @noreference This method is not intended to be referenced by clients.
 * To be used in SelectionParser/AssistParser only if containsPatternVariable is positive
 * @return local declaration in the type pattern if any else null
 */
public LocalDeclaration getLocalDeclaration() {
	Expression cexp = this.constantExpressions[this.patternIndex];
	LocalDeclaration patternVariableIntroduced = cexp.getPatternVariableIntroduced();
	return patternVariableIntroduced;
}

}

Back to the top