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 }