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.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.google.common.collect.Sets;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.annotations.TestOnly;
026    import org.jetbrains.jet.lang.descriptors.*;
027    import org.jetbrains.jet.lang.resolve.BindingTrace;
028    import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler;
029    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
030    import org.jetbrains.jet.utils.Printer;
031    
032    import java.util.Collection;
033    import java.util.List;
034    import java.util.Set;
035    
036    public final class JetScopeUtils {
037        private JetScopeUtils() {}
038    
039        public static List<ReceiverValue> getImplicitReceiversHierarchyValues(@NotNull JetScope scope) {
040            Collection<ReceiverParameterDescriptor> hierarchy = scope.getImplicitReceiversHierarchy();
041    
042            return Lists.newArrayList(
043                    Collections2.transform(hierarchy,
044                           new Function<ReceiverParameterDescriptor, ReceiverValue>() {
045                               @Override
046                               public ReceiverValue apply(ReceiverParameterDescriptor receiverParameterDescriptor) {
047                                   return receiverParameterDescriptor.getValue();
048                               }
049                           })
050            );
051        }
052    
053        /**
054         * Get all extension descriptors among visible descriptors for current scope.
055         *
056         * @param scope Scope for query extensions.
057         * @return extension descriptors.
058         */
059        public static Collection<CallableDescriptor> getAllExtensions(@NotNull JetScope scope) {
060            Set<CallableDescriptor> result = Sets.newHashSet();
061    
062            for (DeclarationDescriptor descriptor : scope.getAllDescriptors()) {
063                if (descriptor instanceof CallableDescriptor) {
064                    CallableDescriptor callDescriptor = (CallableDescriptor) descriptor;
065                    if (callDescriptor.getReceiverParameter() != null) {
066                        result.add(callDescriptor);
067                    }
068                }
069            }
070    
071            return result;
072        }
073    
074        public static JetScope makeScopeForPropertyAccessor(
075                @NotNull PropertyDescriptor propertyDescriptor,
076                @NotNull JetScope parentScope,
077                @NotNull BindingTrace trace
078        ) {
079            JetScope propertyDeclarationInnerScope =
080                    getPropertyDeclarationInnerScope(propertyDescriptor, parentScope,
081                                                     propertyDescriptor.getTypeParameters(),
082                                                     propertyDescriptor.getReceiverParameter(), trace);
083            WritableScope accessorScope = new WritableScopeImpl(propertyDeclarationInnerScope, parentScope.getContainingDeclaration(),
084                                                                new TraceBasedRedeclarationHandler(trace), "Accessor Scope");
085            accessorScope.changeLockLevel(WritableScope.LockLevel.READING);
086    
087            return accessorScope;
088        }
089    
090        public static JetScope getPropertyDeclarationInnerScope(
091                @NotNull PropertyDescriptor propertyDescriptor,
092                @NotNull JetScope outerScope,
093                @NotNull List<? extends TypeParameterDescriptor> typeParameters,
094                @Nullable ReceiverParameterDescriptor receiver,
095                BindingTrace trace
096        ) {
097            return getPropertyDeclarationInnerScope(propertyDescriptor, outerScope, typeParameters, receiver, trace, true);
098        }
099    
100        public static JetScope getPropertyDeclarationInnerScopeForInitializer(
101                @NotNull JetScope outerScope,
102                @NotNull List<? extends TypeParameterDescriptor> typeParameters,
103                @Nullable ReceiverParameterDescriptor receiver,
104                BindingTrace trace
105        ) {
106            return getPropertyDeclarationInnerScope(null, outerScope, typeParameters, receiver, trace, false);
107        }
108    
109        private static JetScope getPropertyDeclarationInnerScope(
110                @Nullable PropertyDescriptor propertyDescriptor,
111                // PropertyDescriptor can be null for property scope which hasn't label to property (in this case addLabelForProperty parameter must be false
112                @NotNull JetScope outerScope,
113                @NotNull List<? extends TypeParameterDescriptor> typeParameters,
114                @Nullable ReceiverParameterDescriptor receiver,
115                BindingTrace trace,
116                boolean addLabelForProperty
117        ) {
118            WritableScopeImpl result = new WritableScopeImpl(
119                    outerScope, outerScope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(trace),
120                    "Property declaration inner scope");
121            if (addLabelForProperty) {
122                assert propertyDescriptor != null : "PropertyDescriptor can be null for property scope which hasn't label to property";
123                result.addLabeledDeclaration(propertyDescriptor);
124            }
125            for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
126                result.addTypeParameterDescriptor(typeParameterDescriptor);
127            }
128            if (receiver != null) {
129                result.setImplicitReceiver(receiver);
130            }
131            result.changeLockLevel(WritableScope.LockLevel.READING);
132            return result;
133        }
134    
135        @TestOnly
136        @NotNull
137        public static String printStructure(@Nullable JetScope scope) {
138            StringBuilder out = new StringBuilder();
139            Printer p = new Printer(out);
140            if (scope == null) {
141                p.println("null");
142            }
143            else {
144                scope.printScopeStructure(p);
145            }
146            return out.toString();
147        }
148    }