001    /*
002     * Copyright 2010-2015 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.kotlin.resolve.lazy;
018    
019    import com.intellij.psi.PsiElement;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
022    import org.jetbrains.kotlin.psi.*;
023    import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
024    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
025    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory;
026    import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor;
027    import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor;
028    import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
029    
030    public class DeclarationScopeProviderImpl implements DeclarationScopeProvider {
031    
032        private final LazyDeclarationResolver lazyDeclarationResolver;
033    
034        private final FileScopeProvider fileScopeProvider;
035    
036        public DeclarationScopeProviderImpl(
037                @NotNull LazyDeclarationResolver lazyDeclarationResolver,
038                @NotNull FileScopeProvider fileScopeProvider
039        ) {
040            this.lazyDeclarationResolver = lazyDeclarationResolver;
041            this.fileScopeProvider = fileScopeProvider;
042        }
043    
044        @Override
045        @NotNull
046        public LexicalScope getResolutionScopeForDeclaration(@NotNull PsiElement elementOfDeclaration) {
047            KtDeclaration ktDeclaration = KtStubbedPsiUtil.getPsiOrStubParent(elementOfDeclaration, KtDeclaration.class, false);
048    
049            assert !(elementOfDeclaration instanceof KtDeclaration) || ktDeclaration == elementOfDeclaration :
050                    "For JetDeclaration element getParentOfType() should return itself.";
051            assert ktDeclaration != null : "Should be contained inside declaration.";
052    
053            KtDeclaration parentDeclaration = KtStubbedPsiUtil.getContainingDeclaration(ktDeclaration);
054    
055            if (ktDeclaration instanceof KtPropertyAccessor) {
056                parentDeclaration = KtStubbedPsiUtil.getContainingDeclaration(parentDeclaration, KtDeclaration.class);
057            }
058    
059            if (parentDeclaration == null) {
060                return fileScopeProvider.getFileResolutionScope((KtFile) elementOfDeclaration.getContainingFile());
061            }
062    
063            if (parentDeclaration instanceof KtClassOrObject) {
064                KtClassOrObject parentClassOrObject = (KtClassOrObject) parentDeclaration;
065                LazyClassDescriptor parentClassDescriptor = (LazyClassDescriptor) lazyDeclarationResolver.getClassDescriptor(parentClassOrObject, NoLookupLocation.WHEN_GET_DECLARATION_SCOPE);
066    
067                if (ktDeclaration instanceof KtAnonymousInitializer || ktDeclaration instanceof KtProperty) {
068                    return parentClassDescriptor.getScopeForInitializerResolution();
069                }
070    
071                if (ktDeclaration instanceof KtObjectDeclaration && ((KtObjectDeclaration) ktDeclaration).isCompanion()) {
072                    return parentClassDescriptor.getScopeForCompanionObjectHeaderResolution();
073                }
074    
075                if (ktDeclaration instanceof KtObjectDeclaration ||
076                    ktDeclaration instanceof KtClass && !((KtClass) ktDeclaration).isInner()) {
077                    return parentClassDescriptor.getScopeForStaticMemberDeclarationResolution();
078                }
079    
080                return parentClassDescriptor.getScopeForMemberDeclarationResolution();
081            }
082            //TODO: this is not how it works for classes and for exact parity we can try to use the code above
083            if (parentDeclaration instanceof KtScript) {
084                LazyScriptDescriptor scriptDescriptor = (LazyScriptDescriptor) lazyDeclarationResolver.resolveToDescriptor(parentDeclaration);
085                return scriptDescriptor.getScopeForInitializerResolution();
086            }
087    
088            throw new IllegalStateException("Don't call this method for local declarations: " + ktDeclaration + "\n" +
089                                            PsiUtilsKt.getElementTextWithContext(ktDeclaration));
090        }
091    
092        @NotNull
093        @Override
094        public DataFlowInfo getOuterDataFlowInfoForDeclaration(@NotNull PsiElement elementOfDeclaration) {
095            return DataFlowInfoFactory.EMPTY;
096        }
097    }