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.calls.tasks;
018    
019    import com.google.common.collect.Lists;
020    import com.google.common.collect.Sets;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.jet.lang.descriptors.*;
023    import org.jetbrains.jet.lang.resolve.BindingTrace;
024    import org.jetbrains.jet.lang.resolve.name.Name;
025    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
026    import org.jetbrains.jet.lang.types.ErrorUtils;
027    import org.jetbrains.jet.lang.types.JetType;
028    
029    import java.util.*;
030    
031    import static org.jetbrains.jet.lang.resolve.LibrarySourceHacks.filterOutMembersFromLibrarySource;
032    
033    @SuppressWarnings("unchecked")
034    public class CallableDescriptorCollectors<D extends CallableDescriptor> implements Iterable<CallableDescriptorCollector<D>> {
035        private static final CallableDescriptorCollector<FunctionDescriptor> FUNCTIONS_COLLECTOR =
036                new FilteredCollector<FunctionDescriptor>(new FunctionCollector());
037        private static final CallableDescriptorCollector<VariableDescriptor> VARIABLES_COLLECTOR =
038                new FilteredCollector<VariableDescriptor>(new VariableCollector());
039        private static final CallableDescriptorCollector<VariableDescriptor> PROPERTIES_COLLECTOR =
040                new FilteredCollector<VariableDescriptor>(new PropertyCollector());
041    
042        public static final CallableDescriptorCollectors<CallableDescriptor> FUNCTIONS_AND_VARIABLES =
043                new CallableDescriptorCollectors(FUNCTIONS_COLLECTOR, VARIABLES_COLLECTOR);
044        public static final CallableDescriptorCollectors<CallableDescriptor> FUNCTIONS =
045                new CallableDescriptorCollectors(FUNCTIONS_COLLECTOR);
046        public static final CallableDescriptorCollectors<VariableDescriptor> VARIABLES =
047                new CallableDescriptorCollectors(VARIABLES_COLLECTOR);
048        public static final CallableDescriptorCollectors<VariableDescriptor> PROPERTIES =
049                new CallableDescriptorCollectors(PROPERTIES_COLLECTOR);
050    
051        private static class FunctionCollector implements CallableDescriptorCollector<FunctionDescriptor> {
052    
053            @NotNull
054            @Override
055            public Collection<FunctionDescriptor> getNonExtensionsByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
056                Set<FunctionDescriptor> functions = Sets.newLinkedHashSet();
057                for (FunctionDescriptor function : scope.getFunctions(name)) {
058                    if (function.getReceiverParameter() == null) {
059                        functions.add(function);
060                    }
061                }
062                addConstructors(scope, name, functions);
063                return functions;
064            }
065    
066            @NotNull
067            @Override
068            public Collection<FunctionDescriptor> getMembersByName(@NotNull JetType receiverType, Name name, @NotNull BindingTrace bindingTrace) {
069                JetScope receiverScope = receiverType.getMemberScope();
070                Set<FunctionDescriptor> members = Sets.newHashSet(receiverScope.getFunctions(name));
071                addConstructors(receiverScope, name, members);
072                return members;
073            }
074    
075            @NotNull
076            @Override
077            public Collection<FunctionDescriptor> getNonMembersByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
078                return scope.getFunctions(name);
079            }
080    
081            private static void addConstructors(JetScope scope, Name name, Collection<FunctionDescriptor> functions) {
082                ClassifierDescriptor classifier = scope.getClassifier(name);
083                if (!(classifier instanceof ClassDescriptor) || ErrorUtils.isError(classifier)) return;
084                ClassDescriptor classDescriptor = (ClassDescriptor) classifier;
085                if (classDescriptor.getKind().isSingleton()) {
086                    // Constructors of singletons shouldn't be callable from the code
087                    return;
088                }
089                functions.addAll(classDescriptor.getConstructors());
090            }
091    
092            @Override
093            public String toString() {
094                return "FUNCTIONS";
095            }
096        }
097    
098        private static class VariableCollector implements CallableDescriptorCollector<VariableDescriptor> {
099    
100            @NotNull
101            @Override
102            public Collection<VariableDescriptor> getNonExtensionsByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
103                VariableDescriptor localVariable = scope.getLocalVariable(name);
104                if (localVariable != null) {
105                    return Collections.singleton(localVariable);
106                }
107    
108                LinkedHashSet<VariableDescriptor> variables = Sets.newLinkedHashSet();
109                for (VariableDescriptor variable : scope.getProperties(name)) {
110                    if (variable.getReceiverParameter() == null) {
111                        variables.add(variable);
112                    }
113                }
114                return variables;
115            }
116    
117            @NotNull
118            @Override
119            public Collection<VariableDescriptor> getMembersByName(@NotNull JetType receiverType, Name name, @NotNull BindingTrace bindingTrace) {
120                return receiverType.getMemberScope().getProperties(name);
121            }
122    
123            @NotNull
124            @Override
125            public Collection<VariableDescriptor> getNonMembersByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
126                Collection<VariableDescriptor> result = Sets.newLinkedHashSet();
127    
128                VariableDescriptor localVariable = scope.getLocalVariable(name);
129                if (localVariable != null) {
130                    result.add(localVariable);
131                }
132                result.addAll(scope.getProperties(name));
133                return result;
134            }
135    
136            @Override
137            public String toString() {
138                return "VARIABLES";
139            }
140        }
141    
142        private static class PropertyCollector implements CallableDescriptorCollector<VariableDescriptor> {
143            private static Collection<VariableDescriptor> filterProperties(Collection<? extends VariableDescriptor> variableDescriptors) {
144                ArrayList<VariableDescriptor> properties = Lists.newArrayList();
145                for (VariableDescriptor descriptor : variableDescriptors) {
146                    if (descriptor instanceof PropertyDescriptor) {
147                        properties.add(descriptor);
148                    }
149                }
150                return properties;
151            }
152    
153            @NotNull
154            @Override
155            public Collection<VariableDescriptor> getNonExtensionsByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
156                return filterProperties(VARIABLES_COLLECTOR.getNonExtensionsByName(scope, name, bindingTrace));
157            }
158    
159            @NotNull
160            @Override
161            public Collection<VariableDescriptor> getMembersByName(@NotNull JetType receiver, Name name, @NotNull BindingTrace bindingTrace) {
162                return filterProperties(VARIABLES_COLLECTOR.getMembersByName(receiver, name, bindingTrace));
163            }
164    
165            @NotNull
166            @Override
167            public Collection<VariableDescriptor> getNonMembersByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
168                return filterProperties(VARIABLES_COLLECTOR.getNonMembersByName(scope, name, bindingTrace));
169            }
170    
171            @Override
172            public String toString() {
173                return "PROPERTIES";
174            }
175        }
176        
177        private static class FilteredCollector<D extends CallableDescriptor> implements CallableDescriptorCollector<D> {
178            private final CallableDescriptorCollector<D> delegate;
179    
180            private FilteredCollector(CallableDescriptorCollector<D> delegate) {
181                this.delegate = delegate;
182            }
183    
184            @NotNull
185            @Override
186            public Collection<D> getNonExtensionsByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
187                return filterOutMembersFromLibrarySource(delegate.getNonExtensionsByName(scope, name, bindingTrace), bindingTrace);
188            }
189    
190            @NotNull
191            @Override
192            public Collection<D> getMembersByName(@NotNull JetType receiver, Name name, @NotNull BindingTrace bindingTrace) {
193                return filterOutMembersFromLibrarySource(delegate.getMembersByName(receiver, name, bindingTrace), bindingTrace);
194            }
195    
196            @NotNull
197            @Override
198            public Collection<D> getNonMembersByName(JetScope scope, Name name, @NotNull BindingTrace bindingTrace) {
199                return filterOutMembersFromLibrarySource(delegate.getNonMembersByName(scope, name, bindingTrace), bindingTrace);
200            }
201    
202            @Override
203            public String toString() {
204                return delegate.toString();
205            }
206        }
207    
208        private final Collection<CallableDescriptorCollector<D>> collectors;
209    
210        private CallableDescriptorCollectors(CallableDescriptorCollector<D>... collectors) {
211            this.collectors = Lists.newArrayList(collectors);
212        }
213    
214        @NotNull
215        @Override
216        public Iterator<CallableDescriptorCollector<D>> iterator() {
217            return collectors.iterator();
218        }
219    }