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