001    /*
002     * Copyright 2010-2013 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.jet.lang.types.expressions;
018    
019    import com.google.common.collect.Lists;
020    import com.google.common.collect.Maps;
021    import com.intellij.openapi.project.Project;
022    import com.intellij.openapi.util.Pair;
023    import com.intellij.psi.PsiElement;
024    import com.intellij.psi.tree.IElementType;
025    import com.intellij.psi.util.PsiTreeUtil;
026    import org.jetbrains.annotations.NotNull;
027    import org.jetbrains.annotations.Nullable;
028    import org.jetbrains.jet.JetNodeTypes;
029    import org.jetbrains.jet.lang.descriptors.*;
030    import org.jetbrains.jet.lang.diagnostics.Diagnostic;
031    import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory;
032    import org.jetbrains.jet.lang.diagnostics.Errors;
033    import org.jetbrains.jet.lang.psi.*;
034    import org.jetbrains.jet.lang.resolve.*;
035    import org.jetbrains.jet.lang.resolve.calls.CallResolver;
036    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
037    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
038    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
039    import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil;
040    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
041    import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
042    import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
043    import org.jetbrains.jet.lang.resolve.name.FqName;
044    import org.jetbrains.jet.lang.resolve.name.Name;
045    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
046    import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
047    import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
048    import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
049    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
050    import org.jetbrains.jet.lang.types.*;
051    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
052    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
053    import org.jetbrains.jet.lexer.JetTokens;
054    import org.jetbrains.jet.util.slicedmap.WritableSlice;
055    
056    import java.util.*;
057    
058    import static org.jetbrains.jet.lang.diagnostics.Errors.*;
059    import static org.jetbrains.jet.lang.resolve.BindingContext.*;
060    import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType;
061    
062    public class ExpressionTypingUtils {
063    
064        private final ExpressionTypingServices expressionTypingServices;
065        private final CallResolver callResolver;
066    
067        public ExpressionTypingUtils(@NotNull ExpressionTypingServices expressionTypingServices, @NotNull CallResolver resolver) {
068            this.expressionTypingServices = expressionTypingServices;
069            callResolver = resolver;
070        }
071    
072        @Nullable
073        protected static ExpressionReceiver getExpressionReceiver(@NotNull JetExpression expression, @Nullable JetType type) {
074            if (type == null) return null;
075            return new ExpressionReceiver(expression, type);
076        }
077    
078        @Nullable
079        protected static ExpressionReceiver getExpressionReceiver(@NotNull ExpressionTypingFacade facade, @NotNull JetExpression expression, ExpressionTypingContext context) {
080            return getExpressionReceiver(expression, facade.getTypeInfo(expression, context).getType());
081        }
082    
083        @NotNull
084        protected static ExpressionReceiver safeGetExpressionReceiver(@NotNull ExpressionTypingFacade facade, @NotNull JetExpression expression, ExpressionTypingContext context) {
085            JetType type = facade.safeGetTypeInfo(expression, context).getType();
086            assert type != null : "safeGetTypeInfo should return @NotNull type";
087            return new ExpressionReceiver(expression, type);
088        }
089    
090        @NotNull
091        public static WritableScopeImpl newWritableScopeImpl(ExpressionTypingContext context, @NotNull String scopeDebugName) {
092            WritableScopeImpl scope = new WritableScopeImpl(
093                    context.scope, context.scope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(context.trace), scopeDebugName);
094            scope.changeLockLevel(WritableScope.LockLevel.BOTH);
095            return scope;
096        }
097    
098        public static boolean isBoolean(@NotNull JetType type) {
099            return JetTypeChecker.DEFAULT.isSubtypeOf(type, KotlinBuiltIns.getInstance().getBooleanType());
100        }
101    
102        public static boolean ensureBooleanResult(JetExpression operationSign, Name name, JetType resultType, ExpressionTypingContext context) {
103            return ensureBooleanResultWithCustomSubject(operationSign, resultType, "'" + name + "'", context);
104        }
105    
106        public static boolean ensureBooleanResultWithCustomSubject(JetExpression operationSign, JetType resultType, String subjectName, ExpressionTypingContext context) {
107            if (resultType != null) {
108                // TODO : Relax?
109                if (!isBoolean(resultType)) {
110                    context.trace.report(RESULT_TYPE_MISMATCH.on(operationSign, subjectName, KotlinBuiltIns.getInstance().getBooleanType(), resultType));
111                    return false;
112                }
113            }
114            return true;
115        }
116    
117        @NotNull
118        public static JetType getDefaultType(IElementType constantType) {
119            if (constantType == JetNodeTypes.INTEGER_CONSTANT) {
120                return KotlinBuiltIns.getInstance().getIntType();
121            }
122            else if (constantType == JetNodeTypes.FLOAT_CONSTANT) {
123                return KotlinBuiltIns.getInstance().getDoubleType();
124            }
125            else if (constantType == JetNodeTypes.BOOLEAN_CONSTANT) {
126                return KotlinBuiltIns.getInstance().getBooleanType();
127            }
128            else if (constantType == JetNodeTypes.CHARACTER_CONSTANT) {
129                return KotlinBuiltIns.getInstance().getCharType();
130            }
131            else if (constantType == JetNodeTypes.NULL) {
132                return KotlinBuiltIns.getInstance().getNullableNothingType();
133            }
134            else {
135                throw new IllegalArgumentException("Unsupported constant type: " + constantType);
136            }
137        }
138    
139        private static boolean isCapturedInInline(
140                @NotNull BindingContext context,
141                @NotNull DeclarationDescriptor scopeContainer,
142                @NotNull DeclarationDescriptor variableParent
143        ) {
144            PsiElement scopeDeclaration = BindingContextUtils.descriptorToDeclaration(context, scopeContainer);
145            if (!(scopeDeclaration instanceof JetFunctionLiteral)) {
146                return false;
147            }
148    
149            PsiElement parent = scopeDeclaration.getParent();
150            assert parent instanceof JetFunctionLiteralExpression : "parent of JetFunctionLiteral is " + parent;
151            JetCallExpression callExpression = getCallExpression((JetFunctionLiteralExpression) parent);
152            if (callExpression == null) {
153                return false;
154            }
155    
156            ResolvedCall<?> resolvedCall = context.get(BindingContext.RESOLVED_CALL, callExpression.getCalleeExpression());
157            if (resolvedCall == null) {
158                return false;
159            }
160    
161            CallableDescriptor callable = resolvedCall.getResultingDescriptor();
162            if (callable instanceof SimpleFunctionDescriptor && ((SimpleFunctionDescriptor) callable).getInlineStrategy().isInline()) {
163                DeclarationDescriptor scopeContainerParent = scopeContainer.getContainingDeclaration();
164                assert scopeContainerParent != null : "parent is null for " + scopeContainer;
165                return scopeContainerParent == variableParent || isCapturedInInline(context, scopeContainerParent, variableParent);
166            }
167            else {
168                return false;
169            }
170        }
171    
172        @Nullable
173        private static JetCallExpression getCallExpression(@NotNull JetFunctionLiteralExpression functionLiteralExpression) {
174            PsiElement parent = functionLiteralExpression.getParent();
175            if (parent instanceof JetValueArgument) {
176                // foo({ ... })    or     foo(f = { ... })
177    
178                PsiElement valueArgumentList = parent.getParent();
179                assert valueArgumentList instanceof JetValueArgumentList : "parent of value argument is " + valueArgumentList;
180    
181                if (valueArgumentList.getParent() instanceof JetCallExpression) { // may be argument list of annotation
182                    return (JetCallExpression) valueArgumentList.getParent();
183                }
184            }
185            else if (parent instanceof JetCallExpression) {
186                // foo { ... }
187    
188                return  (JetCallExpression) parent;
189            }
190            return null;
191        }
192        public static void checkCapturingInClosure(JetSimpleNameExpression expression, BindingTrace trace, JetScope scope) {
193            VariableDescriptor variable = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), expression, true);
194            if (variable != null) {
195                DeclarationDescriptor variableParent = variable.getContainingDeclaration();
196                DeclarationDescriptor scopeContainer = scope.getContainingDeclaration();
197                if (scopeContainer != variableParent && variableParent instanceof CallableDescriptor) {
198                    if (trace.get(CAPTURED_IN_CLOSURE, variable) != CaptureKind.NOT_INLINE) {
199                        boolean inline = isCapturedInInline(trace.getBindingContext(), scopeContainer, variableParent);
200                        trace.record(CAPTURED_IN_CLOSURE, variable, inline ? CaptureKind.INLINE_ONLY : CaptureKind.NOT_INLINE);
201                    }
202                }
203            }
204        }
205    
206        /**
207         * Check that function or property with the given qualified name can be resolved in given scope and called on given receiver
208         *
209         * @param callableFQN
210         * @param project
211         * @param scope
212         * @return
213         */
214        public static List<CallableDescriptor> canFindSuitableCall(
215                @NotNull FqName callableFQN,
216                @NotNull Project project,
217                @NotNull JetExpression receiverExpression,
218                @NotNull JetType receiverType,
219                @NotNull JetScope scope,
220                @NotNull ModuleDescriptor module
221        ) {
222            JetImportDirective importDirective = JetPsiFactory.createImportDirective(project, callableFQN.asString());
223    
224            Collection<? extends DeclarationDescriptor> declarationDescriptors = new QualifiedExpressionResolver()
225                    .analyseImportReference(importDirective, scope, new BindingTraceContext(), module);
226    
227            List<CallableDescriptor> callableExtensionDescriptors = new ArrayList<CallableDescriptor>();
228            ReceiverValue receiverValue = new ExpressionReceiver(receiverExpression, receiverType);
229    
230            for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) {
231                if (declarationDescriptor instanceof CallableDescriptor) {
232                    CallableDescriptor callableDescriptor = (CallableDescriptor) declarationDescriptor;
233    
234                    if (checkIsExtensionCallable(receiverValue, callableDescriptor)) {
235                        callableExtensionDescriptors.add(callableDescriptor);
236                    }
237                }
238            }
239    
240            return callableExtensionDescriptors;
241        }
242    
243        /*
244        * Checks if receiver declaration could be resolved to call expected receiver.
245        */
246        public static boolean checkIsExtensionCallable (
247                @NotNull ReceiverValue receiverArgument,
248                @NotNull CallableDescriptor callableDescriptor
249        ) {
250            JetType type = receiverArgument.getType();
251    
252            if (type instanceof PackageType) {
253                // This fake class ruins standard algorithms
254                return false;
255            }
256    
257            if (checkReceiverResolution(receiverArgument, type, callableDescriptor)) return true;
258            if (type.isNullable()) {
259                JetType notNullableType = TypeUtils.makeNotNullable(type);
260                if (checkReceiverResolution(receiverArgument, notNullableType, callableDescriptor)) return true;
261            }
262            return false;
263        }
264    
265        private static boolean checkReceiverResolution (
266                @NotNull ReceiverValue receiverArgument,
267                @NotNull JetType receiverType,
268                @NotNull CallableDescriptor callableDescriptor
269        ) {
270            ReceiverParameterDescriptor receiverParameter = callableDescriptor.getReceiverParameter();
271    
272            if (!receiverArgument.exists() && receiverParameter == null) {
273                // Both receivers do not exist
274                return true;
275            }
276    
277            if (!(receiverArgument.exists() && receiverParameter != null)) {
278                return false;
279            }
280    
281            Set<Name> typeNamesInReceiver = collectUsedTypeNames(receiverParameter.getType());
282    
283            ConstraintSystem constraintSystem = new ConstraintSystemImpl();
284            Map<TypeParameterDescriptor, Variance> typeVariables = Maps.newLinkedHashMap();
285            for (TypeParameterDescriptor typeParameterDescriptor : callableDescriptor.getTypeParameters()) {
286                if (typeNamesInReceiver.contains(typeParameterDescriptor.getName())) {
287                    typeVariables.put(typeParameterDescriptor, Variance.INVARIANT);
288                }
289            }
290            constraintSystem.registerTypeVariables(typeVariables);
291    
292            constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), ConstraintPosition.RECEIVER_POSITION);
293            return constraintSystem.getStatus().isSuccessful() && ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, true);
294        }
295    
296        private static Set<Name> collectUsedTypeNames(@NotNull JetType jetType) {
297            Set<Name> typeNames = new HashSet<Name>();
298    
299            ClassifierDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
300            if (descriptor != null) {
301                typeNames.add(descriptor.getName());
302            }
303    
304            for (TypeProjection argument : jetType.getArguments()) {
305                typeNames.addAll(collectUsedTypeNames(argument.getType()));
306            }
307    
308            return typeNames;
309        }
310    
311        @NotNull
312        public OverloadResolutionResults<FunctionDescriptor> resolveFakeCall(
313                @NotNull ExpressionTypingContext context,
314                @NotNull ReceiverValue receiver,
315                @NotNull Name name,
316                @NotNull JetType... argumentTypes
317        ) {
318            TemporaryBindingTrace traceWithFakeArgumentInfo = TemporaryBindingTrace.create(context.trace, "trace to store fake argument for",
319                                                                                           name);
320            List<JetExpression> fakeArguments = Lists.newArrayList();
321            for (JetType type : argumentTypes) {
322                fakeArguments.add(createFakeExpressionOfType(expressionTypingServices.getProject(), traceWithFakeArgumentInfo,
323                                                             "fakeArgument" + fakeArguments.size(), type));
324            }
325            return makeAndResolveFakeCall(receiver, context.replaceBindingTrace(traceWithFakeArgumentInfo), fakeArguments, name).getSecond();
326        }
327    
328        public static JetExpression createFakeExpressionOfType(
329                @NotNull Project project,
330                @NotNull BindingTrace trace,
331                @NotNull String argumentName,
332                @NotNull JetType argumentType
333        ) {
334            JetExpression fakeExpression = JetPsiFactory.createExpression(project, argumentName);
335            trace.record(EXPRESSION_TYPE, fakeExpression, argumentType);
336            trace.record(PROCESSED, fakeExpression);
337            return fakeExpression;
338        }
339    
340        @NotNull
341        public OverloadResolutionResults<FunctionDescriptor> resolveFakeCall(
342                @NotNull ExpressionTypingContext context,
343                @NotNull ReceiverValue receiver,
344                @NotNull Name name
345        ) {
346            return resolveFakeCall(receiver, context, Collections.<JetExpression>emptyList(), name);
347        }
348    
349        @NotNull
350        public OverloadResolutionResults<FunctionDescriptor> resolveFakeCall(
351                @NotNull ReceiverValue receiver,
352                @NotNull ExpressionTypingContext context,
353                @NotNull List<JetExpression> valueArguments,
354                @NotNull Name name
355        ) {
356            return makeAndResolveFakeCall(receiver, context, valueArguments, name).getSecond();
357        }
358    
359        @NotNull
360        public Pair<Call, OverloadResolutionResults<FunctionDescriptor>> makeAndResolveFakeCall(
361                @NotNull ReceiverValue receiver,
362                @NotNull ExpressionTypingContext context,
363                @NotNull List<JetExpression> valueArguments,
364                @NotNull Name name
365        ) {
366            final JetReferenceExpression fake = JetPsiFactory.createSimpleName(expressionTypingServices.getProject(), "fake");
367            TemporaryBindingTrace fakeTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve fake call for", name);
368            Call call = CallMaker.makeCallWithExpressions(fake, receiver, null, fake, valueArguments);
369            OverloadResolutionResults<FunctionDescriptor> results =
370                    callResolver.resolveCallWithGivenName(context.replaceBindingTrace(fakeTrace), call, fake, name);
371            if (results.isSuccess()) {
372                fakeTrace.commit(new TraceEntryFilter() {
373                    @Override
374                    public boolean accept(@Nullable WritableSlice<?, ?> slice, Object key) {
375                        // excluding all entries related to fake expression
376                        return key != fake;
377                    }
378                }, true);
379            }
380            return Pair.create(call, results);
381        }
382    
383        public void defineLocalVariablesFromMultiDeclaration(
384                @NotNull WritableScope writableScope,
385                @NotNull JetMultiDeclaration multiDeclaration,
386                @NotNull ReceiverValue receiver,
387                @NotNull JetExpression reportErrorsOn,
388                @NotNull ExpressionTypingContext context
389        ) {
390            int componentIndex = 1;
391            for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) {
392                Name componentName = Name.identifier(DescriptorResolver.COMPONENT_FUNCTION_NAME_PREFIX + componentIndex);
393                componentIndex++;
394    
395                JetType expectedType = getExpectedTypeForComponent(context, entry);
396                OverloadResolutionResults<FunctionDescriptor> results =
397                        resolveFakeCall(context.replaceExpectedType(expectedType), receiver, componentName);
398    
399                JetType componentType = null;
400                if (results.isSuccess()) {
401                    context.trace.record(COMPONENT_RESOLVED_CALL, entry, results.getResultingCall());
402                    componentType = results.getResultingDescriptor().getReturnType();
403                    if (componentType != null && !noExpectedType(expectedType)
404                           && !JetTypeChecker.DEFAULT.isSubtypeOf(componentType, expectedType)) {
405    
406                        context.trace.report(
407                                COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH.on(reportErrorsOn, componentName, componentType, expectedType));
408                    }
409                }
410                else if (results.isAmbiguity()) {
411                    context.trace.report(COMPONENT_FUNCTION_AMBIGUITY.on(reportErrorsOn, componentName, results.getResultingCalls()));
412                }
413                else {
414                    context.trace.report(COMPONENT_FUNCTION_MISSING.on(reportErrorsOn, componentName, receiver.getType()));
415                }
416                if (componentType == null) {
417                    componentType = ErrorUtils.createErrorType(componentName + "() return type");
418                }
419                VariableDescriptor variableDescriptor = expressionTypingServices.getDescriptorResolver().
420                    resolveLocalVariableDescriptorWithType(writableScope, entry, componentType, context.trace);
421    
422                VariableDescriptor olderVariable = writableScope.getLocalVariable(variableDescriptor.getName());
423                checkVariableShadowing(context, variableDescriptor, olderVariable);
424    
425                writableScope.addVariableDescriptor(variableDescriptor);
426            }
427        }
428    
429        public static void checkVariableShadowing(@NotNull ExpressionTypingContext context, @NotNull VariableDescriptor variableDescriptor, VariableDescriptor oldDescriptor) {
430            if (oldDescriptor != null && isLocal(variableDescriptor.getContainingDeclaration(), oldDescriptor)) {
431                PsiElement declaration = BindingContextUtils.descriptorToDeclaration(context.trace.getBindingContext(), variableDescriptor);
432                if (declaration != null) {
433                    context.trace.report(Errors.NAME_SHADOWING.on(declaration, variableDescriptor.getName().asString()));
434                }
435            }
436        }
437    
438        @NotNull
439        private JetType getExpectedTypeForComponent(ExpressionTypingContext context, JetMultiDeclarationEntry entry) {
440            JetTypeReference entryTypeRef = entry.getTypeRef();
441            if (entryTypeRef != null) {
442                return expressionTypingServices.getTypeResolver().resolveType(context.scope, entryTypeRef, context.trace, true);
443            }
444            else {
445                return TypeUtils.NO_EXPECTED_TYPE;
446            }
447        }
448    
449        public static ObservableBindingTrace makeTraceInterceptingTypeMismatch(@NotNull BindingTrace trace, @NotNull final JetElement expressionToWatch, @NotNull final boolean[] mismatchFound) {
450            return new ObservableBindingTrace(trace) {
451    
452                @Override
453                public void report(@NotNull Diagnostic diagnostic) {
454                    DiagnosticFactory<?> factory = diagnostic.getFactory();
455                    if ((factory == TYPE_MISMATCH || factory == CONSTANT_EXPECTED_TYPE_MISMATCH || factory == NULL_FOR_NONNULL_TYPE)
456                            && diagnostic.getPsiElement() == expressionToWatch) {
457                        mismatchFound[0] = true;
458                    }
459                    if (TYPE_INFERENCE_ERRORS.contains(factory) &&
460                        PsiTreeUtil.isAncestor(expressionToWatch, diagnostic.getPsiElement(), false)) {
461                        mismatchFound[0] = true;
462                    }
463                    super.report(diagnostic);
464                }
465            };
466        }
467    
468        @NotNull
469        public static JetTypeInfo getTypeInfoOrNullType(
470                @Nullable JetExpression expression,
471                @NotNull ExpressionTypingContext context,
472                @NotNull ExpressionTypingInternals facade
473        ) {
474            return expression != null
475                   ? facade.getTypeInfo(expression, context)
476                   : JetTypeInfo.create(null, context.dataFlowInfo);
477        }
478    
479        @SuppressWarnings("SuspiciousMethodCalls")
480        public static boolean isBinaryExpressionDependentOnExpectedType(@NotNull JetBinaryExpression expression) {
481            IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
482            return (operationType == JetTokens.IDENTIFIER || OperatorConventions.BINARY_OPERATION_NAMES.containsKey(operationType)
483                    || operationType == JetTokens.ELVIS);
484        }
485    
486        public static boolean isUnaryExpressionDependentOnExpectedType(@NotNull JetUnaryExpression expression) {
487            return expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL;
488        }
489    
490        @NotNull
491        public static List<JetType> getValueParametersTypes(@NotNull List<ValueParameterDescriptor> valueParameters) {
492            List<JetType> parameterTypes = new ArrayList<JetType>(valueParameters.size());
493            for (ValueParameterDescriptor parameter : valueParameters) {
494                parameterTypes.add(parameter.getType());
495            }
496            return parameterTypes;
497        }
498    
499        /**
500         * The primary case for local extensions is the following:
501         *
502         * I had a locally declared extension function or a local variable of function type called foo
503         * And I called it on my x
504         * Now, someone added function foo() to the class of x
505         * My code should not change
506         *
507         * thus
508         *
509         * local extension prevail over members (and members prevail over all non-local extensions)
510         */
511        public static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) {
512            if (candidate instanceof ValueParameterDescriptor) {
513                return true;
514            }
515            DeclarationDescriptor parent = candidate.getContainingDeclaration();
516            if (!(parent instanceof FunctionDescriptor)) {
517                return false;
518            }
519            FunctionDescriptor functionDescriptor = (FunctionDescriptor) parent;
520            DeclarationDescriptor current = containerOfTheCurrentLocality;
521            while (current != null) {
522                if (current == functionDescriptor) {
523                    return true;
524                }
525                current = current.getContainingDeclaration();
526            }
527            return false;
528        }
529    }