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 }