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