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