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
017package org.jetbrains.jet.lang.resolve.calls.tasks;
018
019import com.google.common.collect.Lists;
020import com.google.common.collect.Sets;
021import org.jetbrains.annotations.NotNull;
022import org.jetbrains.jet.lang.descriptors.*;
023import org.jetbrains.jet.lang.resolve.DescriptorUtils;
024import org.jetbrains.jet.lang.resolve.name.Name;
025import org.jetbrains.jet.lang.resolve.scopes.JetScope;
026import org.jetbrains.jet.lang.types.ErrorUtils;
027import org.jetbrains.jet.lang.types.JetType;
028
029import java.util.*;
030
031public class CallableDescriptorCollectors {
032    public static CallableDescriptorCollector<FunctionDescriptor> FUNCTIONS = new FunctionCollector();
033    public static CallableDescriptorCollector<VariableDescriptor> VARIABLES = new VariableCollector();
034    public static CallableDescriptorCollector<VariableDescriptor> PROPERTIES = new PropertyCollector();
035    public static List<CallableDescriptorCollector<? extends CallableDescriptor>> FUNCTIONS_AND_VARIABLES =
036            Lists.newArrayList(FUNCTIONS, VARIABLES);
037
038    private static class FunctionCollector implements CallableDescriptorCollector<FunctionDescriptor> {
039
040        @NotNull
041        @Override
042        public Collection<FunctionDescriptor> getNonExtensionsByName(JetScope scope, Name name) {
043            Set<FunctionDescriptor> functions = Sets.newLinkedHashSet(scope.getFunctions(name));
044            for (Iterator<FunctionDescriptor> iterator = functions.iterator(); iterator.hasNext(); ) {
045                FunctionDescriptor functionDescriptor = iterator.next();
046                if (functionDescriptor.getReceiverParameter() != null) {
047                    iterator.remove();
048                }
049            }
050            addConstructors(scope, name, functions);
051            return functions;
052        }
053
054        @NotNull
055        @Override
056        public Collection<FunctionDescriptor> getMembersByName(@NotNull JetType receiverType, Name name) {
057            JetScope receiverScope = receiverType.getMemberScope();
058            Set<FunctionDescriptor> members = Sets.newHashSet(receiverScope.getFunctions(name));
059            addConstructors(receiverScope, name, members);
060            return members;
061        }
062
063        @NotNull
064        @Override
065        public Collection<FunctionDescriptor> getNonMembersByName(JetScope scope, Name name) {
066            return scope.getFunctions(name);
067        }
068
069        private static void addConstructors(JetScope scope, Name name, Collection<FunctionDescriptor> functions) {
070            ClassifierDescriptor classifier = scope.getClassifier(name);
071            if (classifier instanceof ClassDescriptor && !ErrorUtils.isError(classifier.getTypeConstructor())) {
072                ClassDescriptor classDescriptor = (ClassDescriptor) classifier;
073                functions.addAll(classDescriptor.getConstructors());
074            }
075        }
076
077        @Override
078        public String toString() {
079            return "FUNCTIONS";
080        }
081    }
082
083    private static class VariableCollector implements CallableDescriptorCollector<VariableDescriptor> {
084
085        @NotNull
086        @Override
087        public Collection<VariableDescriptor> getNonExtensionsByName(JetScope scope, Name name) {
088            VariableDescriptor descriptor = scope.getLocalVariable(name);
089            if (descriptor == null) {
090                descriptor = DescriptorUtils.filterNonExtensionProperty(scope.getProperties(name));
091            }
092            if (descriptor == null) return Collections.emptyList();
093            return Collections.singleton(descriptor);
094        }
095
096        @NotNull
097        @Override
098        public Collection<VariableDescriptor> getMembersByName(@NotNull JetType receiverType, Name name) {
099            return receiverType.getMemberScope().getProperties(name);
100        }
101
102        @NotNull
103        @Override
104        public Collection<VariableDescriptor> getNonMembersByName(JetScope scope, Name name) {
105            Collection<VariableDescriptor> result = Sets.newLinkedHashSet();
106
107            VariableDescriptor localVariable = scope.getLocalVariable(name);
108            if (localVariable != null) {
109                result.add(localVariable);
110            }
111            result.addAll(scope.getProperties(name));
112            return result;
113        }
114
115        @Override
116        public String toString() {
117            return "VARIABLES";
118        }
119    }
120
121    private static class PropertyCollector implements CallableDescriptorCollector<VariableDescriptor> {
122        private static Collection<VariableDescriptor> filterProperties(Collection<? extends VariableDescriptor> variableDescriptors) {
123            ArrayList<VariableDescriptor> properties = Lists.newArrayList();
124            for (VariableDescriptor descriptor : variableDescriptors) {
125                if (descriptor instanceof PropertyDescriptor) {
126                    properties.add(descriptor);
127                }
128            }
129            return properties;
130        }
131
132        @NotNull
133        @Override
134        public Collection<VariableDescriptor> getNonExtensionsByName(JetScope scope, Name name) {
135            return filterProperties(VARIABLES.getNonExtensionsByName(scope, name));
136        }
137
138        @NotNull
139        @Override
140        public Collection<VariableDescriptor> getMembersByName(@NotNull JetType receiver, Name name) {
141            return filterProperties(VARIABLES.getMembersByName(receiver, name));
142        }
143
144        @NotNull
145        @Override
146        public Collection<VariableDescriptor> getNonMembersByName(JetScope scope, Name name) {
147            return filterProperties(VARIABLES.getNonMembersByName(scope, name));
148        }
149
150        @Override
151        public String toString() {
152            return "PROPERTIES";
153        }
154    }
155
156    private CallableDescriptorCollectors() {
157    }
158}