2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.codeInsight.completion;
18 import com.intellij.codeInsight.*;
19 import com.intellij.codeInsight.lookup.*;
20 import com.intellij.openapi.util.Key;
21 import com.intellij.openapi.util.Pair;
22 import com.intellij.patterns.ElementPattern;
23 import com.intellij.patterns.PsiJavaPatterns;
24 import com.intellij.psi.*;
25 import com.intellij.psi.filters.ElementExtractorFilter;
26 import com.intellij.psi.filters.ElementFilter;
27 import com.intellij.psi.filters.GeneratorFilter;
28 import com.intellij.psi.filters.OrFilter;
29 import com.intellij.psi.filters.getters.*;
30 import com.intellij.psi.filters.types.AssignableFromFilter;
31 import com.intellij.psi.filters.types.AssignableGroupFilter;
32 import com.intellij.psi.filters.types.AssignableToFilter;
33 import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
34 import com.intellij.psi.infos.CandidateInfo;
35 import com.intellij.psi.javadoc.PsiDocTag;
36 import com.intellij.psi.util.InheritanceUtil;
37 import com.intellij.psi.util.PsiTreeUtil;
38 import com.intellij.psi.util.PsiUtil;
39 import com.intellij.psi.util.TypeConversionUtil;
40 import com.intellij.util.Consumer;
41 import com.intellij.util.ProcessingContext;
42 import com.intellij.util.ReflectionCache;
43 import com.intellij.util.SmartList;
44 import com.intellij.util.containers.ContainerUtil;
45 import gnu.trove.THashSet;
46 import gnu.trove.TObjectHashingStrategy;
47 import org.jetbrains.annotations.NonNls;
48 import org.jetbrains.annotations.NotNull;
49 import org.jetbrains.annotations.Nullable;
53 import static com.intellij.patterns.PlatformPatterns.psiElement;
54 import static com.intellij.patterns.PsiJavaPatterns.psiMethod;
55 import static com.intellij.patterns.StandardPatterns.*;
60 public class JavaSmartCompletionContributor extends CompletionContributor {
61 private static final TObjectHashingStrategy<ExpectedTypeInfo> EXPECTED_TYPE_INFO_STRATEGY = new TObjectHashingStrategy<ExpectedTypeInfo>() {
62 public int computeHashCode(final ExpectedTypeInfo object) {
63 return object.getType().hashCode();
66 public boolean equals(final ExpectedTypeInfo o1, final ExpectedTypeInfo o2) {
67 return o1.getType().equals(o2.getType());
71 private static final ElementExtractorFilter THROWABLES_FILTER = new ElementExtractorFilter(new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE));
72 @NonNls private static final String EXCEPTION_TAG = "exception";
73 static final ElementPattern<PsiElement> AFTER_NEW =
74 psiElement().afterLeaf(
75 psiElement().withText(PsiKeyword.NEW).andNot(
76 psiElement().afterLeaf(
77 psiElement().withText(PsiKeyword.THROW))));
78 static final ElementPattern<PsiElement> AFTER_THROW_NEW = psiElement().afterLeaf(psiElement().withText(PsiKeyword.NEW).afterLeaf(PsiKeyword.THROW));
79 private static final OrFilter THROWABLE_TYPE_FILTER = new OrFilter(
80 new GeneratorFilter(AssignableGroupFilter.class, new ThrowsListGetter()),
81 new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE));
82 public static final ElementPattern<PsiElement> INSIDE_EXPRESSION = or(
83 psiElement().withParent(PsiExpression.class).andNot(psiElement().withParent(PsiLiteralExpression.class)),
84 psiElement().inside(PsiClassObjectAccessExpression.class),
85 psiElement().inside(PsiThisExpression.class),
86 psiElement().inside(PsiSuperExpression.class)
88 static final ElementPattern<PsiElement> INSIDE_TYPECAST_EXPRESSION = psiElement().withParent(
89 psiElement(PsiReferenceExpression.class).afterLeaf(
90 psiElement().withText(")").withParent(PsiTypeCastExpression.class)));
93 private static ElementFilter getReferenceFilter(PsiElement element) {
95 if (AFTER_THROW_NEW.accepts(element)) {
96 return new ElementExtractorFilter(THROWABLE_TYPE_FILTER);
100 if (psiElement().afterLeaf(psiElement().withText(".")).withSuperParent(2, psiElement(PsiNewExpression.class)).accepts(element)) {
101 if (((PsiNewExpression)element.getParent().getParent()).getClassReference() == element.getParent()) {
102 return new GeneratorFilter(AssignableGroupFilter.class, new ExpectedTypesGetter());
111 public JavaSmartCompletionContributor() {
112 extend(CompletionType.SMART, SmartCastProvider.INSIDE_TYPECAST_TYPE, new SmartCastProvider());
114 extend(CompletionType.SMART,
115 psiElement().beforeLeaf(psiElement(JavaTokenType.RPARENTH)).afterLeaf("(").withParent(
116 psiElement(PsiReferenceExpression.class).withParent(
117 psiElement(PsiExpressionList.class).withParent(PsiCall.class))), new SameSignatureCallParametersProvider());
119 extend(CompletionType.SMART, psiElement().afterLeaf(PsiKeyword.INSTANCEOF), new CompletionProvider<CompletionParameters>() {
120 protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
121 final PsiElement position = parameters.getPosition();
122 final PsiType[] leftTypes = InstanceOfLeftPartTypeGetter.getLeftTypes(position);
123 final Set<PsiClassType> expectedClassTypes = new LinkedHashSet<PsiClassType>();
124 final Set<PsiClass> parameterizedTypes = new THashSet<PsiClass>();
125 for (final PsiType type : leftTypes) {
126 if (type instanceof PsiClassType) {
127 final PsiClassType classType = (PsiClassType)type;
128 if (!classType.isRaw()) {
129 ContainerUtil.addIfNotNull(classType.resolve(), parameterizedTypes);
132 expectedClassTypes.add(classType.rawType());
137 .processInheritors(parameters, expectedClassTypes, result.getPrefixMatcher(), new Consumer<PsiType>() {
138 public void consume(PsiType type) {
139 final PsiClass psiClass = PsiUtil.resolveClassInType(type);
140 if (psiClass == null) return;
142 if (expectedClassTypes.contains(type)) return;
144 result.addElement(createInstanceofLookupElement(psiClass, parameterizedTypes));
150 extend(CompletionType.SMART, psiElement(), new CompletionProvider<CompletionParameters>() {
151 protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
152 final PsiElement element = parameters.getPosition();
153 final PsiReference reference = element.getContainingFile().findReferenceAt(parameters.getOffset());
154 if (reference != null) {
155 final ElementFilter filter = getReferenceFilter(element);
156 if (filter != null) {
157 final List<ExpectedTypeInfo> infos = Arrays.asList(getExpectedTypes(parameters));
158 for (final LookupElement item : completeReference(element, reference, filter, true, parameters)) {
159 if (item.getObject() instanceof PsiClass) {
160 result.addElement(decorate(LookupElementDecorator.withInsertHandler((LookupItem)item, ConstructorInsertHandler.SMART_INSTANCE), infos));
164 else if (INSIDE_TYPECAST_EXPRESSION.accepts(element)) {
165 for (final LookupElement item : completeReference(element, reference, new GeneratorFilter(AssignableToFilter.class, new CastTypeGetter()), false, parameters)) {
166 result.addElement(item);
174 //method throws clause
175 extend(CompletionType.SMART, psiElement().inside(
176 psiElement(PsiReferenceList.class).save("refList").withParent(
177 psiMethod().withThrowsList(get("refList")))), new CompletionProvider<CompletionParameters>() {
179 protected void addCompletions(@NotNull CompletionParameters parameters,
180 ProcessingContext context,
181 @NotNull CompletionResultSet result) {
182 final PsiElement element = parameters.getPosition();
183 final PsiReference reference = element.getContainingFile().findReferenceAt(parameters.getOffset());
184 assert reference != null;
185 for (final LookupElement item : completeReference(element, reference, THROWABLES_FILTER, true, parameters)) {
186 result.addElement(item);
191 extend(CompletionType.SMART, INSIDE_EXPRESSION, new ExpectedTypeBasedCompletionProvider() {
192 protected void addCompletions(final CompletionParameters params, final CompletionResultSet result, final Collection<ExpectedTypeInfo> _infos) {
193 Consumer<LookupElement> noTypeCheck = new Consumer<LookupElement>() {
194 public void consume(final LookupElement lookupElement) {
195 result.addElement(decorate(lookupElement, _infos));
199 THashSet<ExpectedTypeInfo> mergedInfos = new THashSet<ExpectedTypeInfo>(_infos, EXPECTED_TYPE_INFO_STRATEGY);
200 List<Runnable> chainedEtc = new ArrayList<Runnable>();
201 for (final ExpectedTypeInfo info : mergedInfos) {
202 Runnable slowContinuation =
203 ReferenceExpressionCompletionContributor.fillCompletionVariants(new JavaSmartCompletionParameters(params, info), noTypeCheck);
204 ContainerUtil.addIfNotNull(chainedEtc, slowContinuation);
206 addExpectedTypeMembers(params, mergedInfos, true, noTypeCheck);
208 for (final ExpectedTypeInfo info : mergedInfos) {
209 BasicExpressionCompletionContributor.fillCompletionVariants(new JavaSmartCompletionParameters(params, info), new Consumer<LookupElement>() {
211 public void consume(LookupElement lookupElement) {
212 final TypedLookupItem typed = lookupElement.as(TypedLookupItem.CLASS_CONDITION_KEY);
214 final PsiType psiType = typed.getType();
215 if (psiType != null && info.getType().isAssignableFrom(psiType)) {
216 result.addElement(decorate(lookupElement, _infos));
220 }, result.getPrefixMatcher());
224 for (Runnable runnable : chainedEtc) {
229 final boolean searchInheritors = params.getInvocationCount() > 1;
230 if (searchInheritors) {
231 addExpectedTypeMembers(params, mergedInfos, false, noTypeCheck);
236 extend(CompletionType.SMART, or(
237 PsiJavaPatterns.psiElement().withParent(PsiNameValuePair.class),
238 PsiJavaPatterns.psiElement().withSuperParent(2, PsiNameValuePair.class)), new CompletionProvider<CompletionParameters>() {
239 public void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
240 final PsiElement element = parameters.getPosition();
241 final ElementPattern<? extends PsiElement> leftNeighbor = PsiJavaPatterns.psiElement().afterLeaf(PsiJavaPatterns.psiElement().withText("."));
242 final boolean needQualify = leftNeighbor.accepts(element);
244 for (final PsiType type : ExpectedTypesGetter.getExpectedTypes(element, false)) {
245 final PsiClass psiClass = PsiUtil.resolveClassInType(type);
246 if (psiClass != null && psiClass.isAnnotationType()) {
247 final LookupItem item = JavaClassNameCompletionContributor.createClassLookupItem(psiClass, true);
248 if (needQualify) JavaCompletionUtil.qualify(item);
249 result.addElement(item);
256 extend(CompletionType.SMART, psiElement().inside(
257 psiElement(PsiDocTag.class).withName(
258 string().oneOf(PsiKeyword.THROWS, EXCEPTION_TAG))), new CompletionProvider<CompletionParameters>() {
259 public void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
260 final PsiElement element = parameters.getPosition();
261 final Set<PsiClass> throwsSet = new HashSet<PsiClass>();
262 final PsiMethod method = PsiTreeUtil.getContextOfType(element, PsiMethod.class, true);
264 for (PsiClassType ref : method.getThrowsList().getReferencedTypes()) {
265 final PsiClass exception = ref.resolve();
266 if (exception != null && throwsSet.add(exception)) {
267 result.addElement(TailTypeDecorator.withTail(new JavaPsiClassReferenceElement(exception), TailType.HUMBLE_SPACE));
275 final Key<PsiTryStatement> tryKey = Key.create("try");
276 extend(CompletionType.SMART, psiElement().afterLeaf(
277 psiElement().withText("("))
278 .withSuperParent(3, psiElement(PsiCatchSection.class).withParent(
279 psiElement(PsiTryStatement.class).save(tryKey))), new CompletionProvider<CompletionParameters>() {
280 protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
281 final PsiCodeBlock tryBlock = context.get(tryKey).getTryBlock();
282 if (tryBlock == null) return;
284 for (final PsiClassType type : ExceptionUtil.getThrownExceptions(tryBlock.getStatements())) {
285 result.addElement(TailTypeDecorator.withTail(PsiTypeLookupItem.createLookupItem(type, tryBlock).setInsertHandler(new DefaultInsertHandler()), TailType.HUMBLE_SPACE));
290 extend(CompletionType.SMART, psiElement().inside(psiElement(PsiReferenceParameterList.class)),
291 new CompletionProvider<CompletionParameters>() {
293 protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext processingContext, @NotNull final CompletionResultSet resultSet) {
294 final PsiElement context = parameters.getPosition();
296 final Pair<PsiClass, Integer> pair = getTypeParameterInfo(context);
297 if (pair == null) return;
299 final PsiClass referencedClass = pair.first;
300 final int parameterIndex = pair.second.intValue();
301 final PsiTypeParameter[] typeParameters = referencedClass.getTypeParameters();
302 final PsiTypeParameter targetParameter = typeParameters[parameterIndex];
304 boolean isLast = parameterIndex == typeParameters.length - 1;
305 final TailType tail = isLast ? new CharTailType('>') : TailType.COMMA;
307 PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper();
308 final PsiType[] psiTypes = ExpectedTypesGetter.getExpectedTypes(context, false);
309 if (psiTypes.length > 0) {
310 for (PsiType type : psiTypes) {
311 if (!(type instanceof PsiClassType)) continue;
312 final PsiClassType.ClassResolveResult result = ((PsiClassType)type).resolveGenerics();
313 final PsiClass typeClass = result.getElement();
314 final PsiSubstitutor substitutor = result.getSubstitutor();
316 if (!InheritanceUtil.isInheritorOrSelf(referencedClass, typeClass, true)) continue;
318 final PsiSubstitutor currentSubstitutor =
319 TypeConversionUtil.getClassSubstitutor(typeClass, referencedClass, PsiSubstitutor.EMPTY);
320 for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(typeClass)) {
321 final PsiType argSubstitution = substitutor.substitute(parameter);
322 final PsiType paramSubstitution = currentSubstitutor.substitute(parameter);
323 final PsiType substitution = resolveHelper
324 .getSubstitutionForTypeParameter(targetParameter, paramSubstitution, argSubstitution, false,
325 PsiUtil.getLanguageLevel(context));
326 if (substitution != null && substitution != PsiType.NULL) {
327 final LookupItem item = PsiTypeLookupItem.createLookupItem(substitution, context);
328 resultSet.addElement(TailTypeDecorator.withTail(item.setInsertHandler(new DefaultInsertHandler()), tail));
333 final List<PsiClassType> typeList = Collections.singletonList((PsiClassType)TypeConversionUtil.typeParameterErasure(targetParameter));
335 .processInheritors(parameters, typeList, resultSet.getPrefixMatcher(), new Consumer<PsiType>() {
336 public void consume(final PsiType type) {
337 final PsiClass psiClass = PsiUtil.resolveClassInType(type);
338 if (psiClass == null) return;
340 resultSet.addElement(TailTypeDecorator.withTail(new JavaPsiClassReferenceElement(psiClass), tail));
349 extend(CompletionType.SMART, AFTER_NEW, new JavaInheritorsGetter(ConstructorInsertHandler.SMART_INSTANCE));
352 private static void addExpectedTypeMembers(CompletionParameters params,
353 THashSet<ExpectedTypeInfo> mergedInfos,
355 Consumer<LookupElement> consumer) {
356 PsiElement position = params.getPosition();
357 if (!BasicExpressionCompletionContributor.AFTER_DOT.accepts(position)) {
358 for (ExpectedTypeInfo info : mergedInfos) {
359 new JavaMembersGetter(info.getType(), position).addMembers(params, !quick, consumer);
360 if (!info.getDefaultType().equals(info.getType())) {
361 new JavaMembersGetter(info.getDefaultType(), position).addMembers(params, !quick, consumer);
368 public void fillCompletionVariants(CompletionParameters parameters, CompletionResultSet result) {
369 super.fillCompletionVariants(parameters, JavaCompletionSorting.addJavaSorting(parameters, result));
372 public static SmartCompletionDecorator decorate(LookupElement lookupElement, Collection<ExpectedTypeInfo> infos) {
373 LookupItem item = lookupElement.as(LookupItem.CLASS_CONDITION_KEY);
374 if (item != null && item.getInsertHandler() == null) {
375 item.setInsertHandler(DefaultInsertHandler.NO_TAIL_HANDLER);
378 return new SmartCompletionDecorator(lookupElement, infos);
381 private static LookupElement createInstanceofLookupElement(PsiClass psiClass, Set<PsiClass> toWildcardInheritors) {
382 final PsiTypeParameter[] typeParameters = psiClass.getTypeParameters();
383 if (typeParameters.length > 0) {
384 for (final PsiClass parameterizedType : toWildcardInheritors) {
385 if (psiClass.isInheritor(parameterizedType, true)) {
386 PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
387 final PsiWildcardType wildcard = PsiWildcardType.createUnbounded(psiClass.getManager());
388 for (final PsiTypeParameter typeParameter : typeParameters) {
389 substitutor = substitutor.put(typeParameter, wildcard);
391 final PsiElementFactory factory = JavaPsiFacade.getElementFactory(psiClass.getProject());
392 return PsiTypeLookupItem.createLookupItem(factory.createType(psiClass, substitutor), psiClass);
398 return new JavaPsiClassReferenceElement(psiClass);
402 public static Pair<PsiClass, Integer> getTypeParameterInfo(PsiElement context) {
403 final PsiReferenceParameterList parameterList = PsiTreeUtil.getContextOfType(context, PsiReferenceParameterList.class, true);
404 if (parameterList == null) return null;
406 PsiElement parent = parameterList.getParent();
407 if (!(parent instanceof PsiJavaCodeReferenceElement)) return null;
409 final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)parent;
410 final int parameterIndex;
413 final PsiTypeElement typeElement = PsiTreeUtil.getContextOfType(context, PsiTypeElement.class, true);
414 if(typeElement != null){
415 final PsiTypeElement[] elements = referenceElement.getParameterList().getTypeParameterElements();
416 while (index < elements.length) {
417 final PsiTypeElement element = elements[index++];
418 if(element == typeElement) break;
421 parameterIndex = index - 1;
423 if(parameterIndex < 0) return null;
424 final PsiElement target = referenceElement.resolve();
425 if(!(target instanceof PsiClass)) return null;
427 final PsiClass referencedClass = (PsiClass)target;
428 final PsiTypeParameter[] typeParameters = referencedClass.getTypeParameters();
429 if(typeParameters.length <= parameterIndex) return null;
431 return Pair.create(referencedClass, parameterIndex);
436 public static ExpectedTypeInfo[] getExpectedTypes(final CompletionParameters parameters) {
437 final PsiElement position = parameters.getPosition();
438 if (psiElement().withParent(psiElement(PsiReferenceExpression.class).withParent(PsiThrowStatement.class)).accepts(position)) {
439 final PsiElementFactory factory = JavaPsiFacade.getInstance(position.getProject()).getElementFactory();
440 final PsiClassType classType = factory
441 .createTypeByFQClassName(CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION, position.getResolveScope());
442 final List<ExpectedTypeInfo> result = new SmartList<ExpectedTypeInfo>();
443 result.add(new ExpectedTypeInfoImpl(classType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, 0, classType, TailType.SEMICOLON));
444 final PsiMethod method = PsiTreeUtil.getContextOfType(position, PsiMethod.class, true);
445 if (method != null) {
446 for (final PsiClassType type : method.getThrowsList().getReferencedTypes()) {
447 result.add(new ExpectedTypeInfoImpl(type, ExpectedTypeInfo.TYPE_OR_SUBTYPE, 0, type, TailType.SEMICOLON));
450 return result.toArray(new ExpectedTypeInfo[result.size()]);
453 PsiExpression expression = PsiTreeUtil.getContextOfType(position, PsiExpression.class, true);
454 if (expression == null) return ExpectedTypeInfo.EMPTY_ARRAY;
456 return ExpectedTypesProvider.getExpectedTypes(expression, true, parameters.getCompletionType() == CompletionType.SMART, false);
459 static Set<LookupElement> completeReference(final PsiElement element, PsiReference reference, final ElementFilter filter, final boolean acceptClasses, CompletionParameters parameters) {
460 if (reference instanceof PsiMultiReference) {
461 reference = ContainerUtil.findInstance(((PsiMultiReference) reference).getReferences(), PsiJavaReference.class);
464 if (reference instanceof PsiJavaReference) {
465 final PsiJavaReference javaReference = (PsiJavaReference)reference;
467 return JavaCompletionUtil.processJavaReference(element, javaReference, new ElementFilter() {
468 public boolean isAcceptable(Object element, PsiElement context) {
469 return filter.isAcceptable(element, context);
472 public boolean isClassAcceptable(Class hintClass) {
474 return ReflectionCache.isAssignable(PsiClass.class, hintClass);
477 return ReflectionCache.isAssignable(PsiVariable.class, hintClass) ||
478 ReflectionCache.isAssignable(PsiMethod.class, hintClass) ||
479 ReflectionCache.isAssignable(CandidateInfo.class, hintClass);
481 }, true, parameters.getInvocationCount() <= 1, null, parameters);
484 return Collections.emptySet();
488 public void beforeCompletion(@NotNull CompletionInitializationContext context) {
489 if (context.getCompletionType() != CompletionType.SMART) {
493 if (!context.getEditor().getSelectionModel().hasSelection()) {
494 final PsiFile file = context.getFile();
495 PsiElement element = file.findElementAt(context.getStartOffset());
496 if (element instanceof PsiIdentifier) {
497 element = element.getParent();
498 while (element instanceof PsiJavaCodeReferenceElement || element instanceof PsiCall ||
499 element instanceof PsiThisExpression || element instanceof PsiSuperExpression ||
500 element instanceof PsiTypeElement ||
501 element instanceof PsiClassObjectAccessExpression) {
502 int newEnd = element.getTextRange().getEndOffset();
503 if (element instanceof PsiMethodCallExpression) {
504 newEnd = ((PsiMethodCallExpression)element).getMethodExpression().getTextRange().getEndOffset();
506 else if (element instanceof PsiNewExpression) {
507 final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)element).getClassReference();
508 if (classReference != null) {
509 newEnd = classReference.getTextRange().getEndOffset();
512 context.setReplacementOffset(newEnd);
513 element = element.getParent();
518 PsiElement lastElement = context.getFile().findElementAt(context.getStartOffset() - 1);
519 if (lastElement != null && lastElement.getText().equals("(")) {
520 final PsiElement parent = lastElement.getParent();
521 if (parent instanceof PsiTypeCastExpression) {
522 context.setDummyIdentifier("");
525 if (parent instanceof PsiParenthesizedExpression) {
526 context.setDummyIdentifier("xxx)yyy "); // to handle type cast
530 context.setDummyIdentifier("xxx");