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.scopes;
018    
019    import com.google.common.base.Function;
020    import com.google.common.collect.Collections2;
021    import com.google.common.collect.Lists;
022    import com.intellij.psi.PsiElement;
023    import com.intellij.psi.util.PsiTreeUtil;
024    import org.jetbrains.annotations.NotNull;
025    import org.jetbrains.annotations.Nullable;
026    import org.jetbrains.annotations.TestOnly;
027    import org.jetbrains.kotlin.descriptors.*;
028    import org.jetbrains.kotlin.psi.*;
029    import org.jetbrains.kotlin.resolve.BindingContext;
030    import org.jetbrains.kotlin.resolve.BindingTrace;
031    import org.jetbrains.kotlin.resolve.TraceBasedRedeclarationHandler;
032    import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
033    import org.jetbrains.kotlin.utils.Printer;
034    
035    import java.util.Collection;
036    import java.util.List;
037    
038    public final class JetScopeUtils {
039        private JetScopeUtils() {}
040    
041        @NotNull
042        public static List<ReceiverValue> getImplicitReceiversHierarchyValues(@NotNull JetScope scope) {
043            Collection<ReceiverParameterDescriptor> hierarchy = scope.getImplicitReceiversHierarchy();
044    
045            return Lists.newArrayList(
046                    Collections2.transform(hierarchy,
047                           new Function<ReceiverParameterDescriptor, ReceiverValue>() {
048                               @Override
049                               public ReceiverValue apply(ReceiverParameterDescriptor receiverParameterDescriptor) {
050                                   return receiverParameterDescriptor.getValue();
051                               }
052                           })
053            );
054        }
055    
056        public static JetScope makeScopeForPropertyAccessor(
057                @NotNull PropertyDescriptor propertyDescriptor,
058                @NotNull JetScope parentScope,
059                @NotNull BindingTrace trace
060        ) {
061            JetScope propertyDeclarationInnerScope =
062                    getPropertyDeclarationInnerScope(propertyDescriptor, parentScope,
063                                                     propertyDescriptor.getTypeParameters(),
064                                                     propertyDescriptor.getExtensionReceiverParameter(), trace);
065            WritableScope accessorScope = new WritableScopeImpl(propertyDeclarationInnerScope, parentScope.getContainingDeclaration(),
066                                                                new TraceBasedRedeclarationHandler(trace), "Accessor Scope");
067            accessorScope.changeLockLevel(WritableScope.LockLevel.READING);
068    
069            return accessorScope;
070        }
071    
072        public static JetScope getPropertyDeclarationInnerScope(
073                @NotNull PropertyDescriptor propertyDescriptor,
074                @NotNull JetScope outerScope,
075                @NotNull RedeclarationHandler redeclarationHandler
076        ) {
077            return getPropertyDeclarationInnerScope(propertyDescriptor,
078                                                    outerScope,
079                                                    propertyDescriptor.getTypeParameters(),
080                                                    propertyDescriptor.getExtensionReceiverParameter(),
081                                                    redeclarationHandler,
082                                                    true);
083        }
084    
085        public static JetScope getPropertyDeclarationInnerScope(
086                @NotNull PropertyDescriptor propertyDescriptor,
087                @NotNull JetScope outerScope,
088                @NotNull List<? extends TypeParameterDescriptor> typeParameters,
089                @Nullable ReceiverParameterDescriptor receiver,
090                BindingTrace trace
091        ) {
092            return getPropertyDeclarationInnerScope(propertyDescriptor, outerScope, typeParameters, receiver, trace, true);
093        }
094    
095        public static JetScope getPropertyDeclarationInnerScopeForInitializer(
096                @NotNull PropertyDescriptor propertyDescriptor,
097                @NotNull JetScope outerScope,
098                @NotNull List<? extends TypeParameterDescriptor> typeParameters,
099                @Nullable ReceiverParameterDescriptor receiver,
100                BindingTrace trace
101        ) {
102            return getPropertyDeclarationInnerScope(propertyDescriptor, outerScope, typeParameters, receiver, trace, false);
103        }
104    
105        private static JetScope getPropertyDeclarationInnerScope(
106                @NotNull PropertyDescriptor propertyDescriptor,
107                @NotNull JetScope outerScope,
108                @NotNull List<? extends TypeParameterDescriptor> typeParameters,
109                @Nullable ReceiverParameterDescriptor receiver,
110                BindingTrace trace,
111                boolean addLabelForProperty
112        ) {
113            TraceBasedRedeclarationHandler redeclarationHandler = new TraceBasedRedeclarationHandler(trace);
114            return getPropertyDeclarationInnerScope(propertyDescriptor, outerScope, typeParameters, receiver, redeclarationHandler,
115                                                    addLabelForProperty);
116        }
117    
118        @NotNull
119        private static JetScope getPropertyDeclarationInnerScope(
120                @NotNull PropertyDescriptor propertyDescriptor,
121                @NotNull JetScope outerScope,
122                @NotNull List<? extends TypeParameterDescriptor> typeParameters,
123                @Nullable ReceiverParameterDescriptor receiver,
124                @NotNull RedeclarationHandler redeclarationHandler,
125                boolean addLabelForProperty
126        ) {
127            WritableScopeImpl result = new WritableScopeImpl(
128                    outerScope, propertyDescriptor, redeclarationHandler,
129                    "Property declaration inner scope");
130            if (addLabelForProperty) {
131                result.addLabeledDeclaration(propertyDescriptor);
132            }
133            for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
134                result.addClassifierDescriptor(typeParameterDescriptor);
135            }
136            if (receiver != null) {
137                result.setImplicitReceiver(receiver);
138            }
139            result.changeLockLevel(WritableScope.LockLevel.READING);
140            return result;
141        }
142    
143        @TestOnly
144        @NotNull
145        public static String printStructure(@Nullable JetScope scope) {
146            StringBuilder out = new StringBuilder();
147            Printer p = new Printer(out);
148            if (scope == null) {
149                p.println("null");
150            }
151            else {
152                scope.printScopeStructure(p);
153            }
154            return out.toString();
155        }
156    
157        @Nullable
158        public static JetScope getResolutionScope(@NotNull PsiElement element, @NotNull BindingContext context) {
159            PsiElement parent = element.getParent();
160    
161            if (parent instanceof JetClassBody) {
162                JetClassOrObject classOrObject = (JetClassOrObject) parent.getParent();
163                ClassDescriptor classDescriptor = context.get(BindingContext.CLASS, classOrObject);
164                if (classDescriptor instanceof ClassDescriptorWithResolutionScopes) {
165                    return ((ClassDescriptorWithResolutionScopes) classDescriptor).getScopeForMemberDeclarationResolution();
166                }
167                return null;
168            }
169    
170            if (parent instanceof JetFile) {
171                PackageFragmentDescriptor packageFragment = context.get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, (JetFile) parent);
172                if (packageFragment == null) return null;
173    
174                PackageViewDescriptor packageView = packageFragment.getContainingDeclaration().getPackage(((JetFile) parent).getPackageFqName());
175                return packageView != null ? packageView.getMemberScope() : null;
176            }
177    
178            JetExpression expression = PsiTreeUtil.getParentOfType(element, JetExpression.class, false);
179            return expression != null ? context.get(BindingContext.RESOLUTION_SCOPE, expression) : null;
180        }
181    }