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;
018
019 import com.google.common.collect.Sets;
020 import com.intellij.openapi.util.Pair;
021 import com.intellij.util.containers.MultiMap;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.jet.lang.descriptors.*;
024 import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
025 import org.jetbrains.jet.lang.diagnostics.Errors;
026 import org.jetbrains.jet.lang.psi.JetClass;
027 import org.jetbrains.jet.lang.psi.JetClassOrObject;
028 import org.jetbrains.jet.lang.psi.JetDeclaration;
029 import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
030 import org.jetbrains.jet.lang.resolve.name.Name;
031
032 import javax.inject.Inject;
033 import java.util.Collection;
034 import java.util.Map;
035 import java.util.Set;
036
037 public class OverloadResolver {
038 private TopDownAnalysisContext context;
039 private BindingTrace trace;
040
041
042 @Inject
043 public void setContext(TopDownAnalysisContext context) {
044 this.context = context;
045 }
046
047 @Inject
048 public void setTrace(BindingTrace trace) {
049 this.trace = trace;
050 }
051
052
053
054 public void process() {
055 checkOverloads();
056 }
057
058 private void checkOverloads() {
059 Pair<MultiMap<ClassDescriptor, ConstructorDescriptor>, MultiMap<Key, ConstructorDescriptor>> pair = constructorsGrouped();
060 MultiMap<ClassDescriptor, ConstructorDescriptor> inClasses = pair.first;
061 MultiMap<Key, ConstructorDescriptor> inNamespaces = pair.second;
062
063 for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
064 checkOverloadsInAClass(entry.getValue(), entry.getKey(), inClasses.get(entry.getValue()));
065 }
066 for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
067 checkOverloadsInAClass(entry.getValue(), entry.getKey(), inClasses.get(entry.getValue()));
068 }
069 checkOverloadsInANamespace(inNamespaces);
070 }
071
072 private static class Key extends Pair<String, Name> {
073 Key(String namespace, Name name) {
074 super(namespace, name);
075 }
076
077 Key(NamespaceDescriptor namespaceDescriptor, Name name) {
078 this(DescriptorUtils.getFQName(namespaceDescriptor).asString(), name);
079 }
080
081 public String getNamespace() {
082 return first;
083 }
084
085 public Name getFunctionName() {
086 return second;
087 }
088 }
089
090
091 private Pair<MultiMap<ClassDescriptor, ConstructorDescriptor>, MultiMap<Key, ConstructorDescriptor>>
092 constructorsGrouped()
093 {
094 MultiMap<ClassDescriptor, ConstructorDescriptor> inClasses = MultiMap.create();
095 MultiMap<Key, ConstructorDescriptor> inNamespaces = MultiMap.create();
096
097 for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
098 MutableClassDescriptor klass = entry.getValue();
099 DeclarationDescriptor containingDeclaration = klass.getContainingDeclaration();
100 if (containingDeclaration instanceof NamespaceDescriptor) {
101 NamespaceDescriptor namespaceDescriptor = (NamespaceDescriptor) containingDeclaration;
102 inNamespaces.put(new Key(namespaceDescriptor, klass.getName()), klass.getConstructors());
103 }
104 else if (containingDeclaration instanceof ClassDescriptor) {
105 ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
106 inClasses.put(classDescriptor, klass.getConstructors());
107 }
108 else if (!(containingDeclaration instanceof FunctionDescriptor)) {
109 throw new IllegalStateException();
110 }
111 }
112
113 return Pair.create(inClasses, inNamespaces);
114 }
115
116 private void checkOverloadsInANamespace(MultiMap<Key, ConstructorDescriptor> inNamespaces) {
117
118 MultiMap<Key, CallableMemberDescriptor> functionsByName = MultiMap.create();
119
120 for (SimpleFunctionDescriptor function : context.getFunctions().values()) {
121 DeclarationDescriptor containingDeclaration = function.getContainingDeclaration();
122 if (containingDeclaration instanceof NamespaceDescriptor) {
123 NamespaceDescriptor namespaceDescriptor = (NamespaceDescriptor) containingDeclaration;
124 functionsByName.putValue(new Key(namespaceDescriptor, function.getName()), function);
125 }
126 }
127
128 for (PropertyDescriptor property : context.getProperties().values()) {
129 DeclarationDescriptor containingDeclaration = property.getContainingDeclaration();
130 if (containingDeclaration instanceof NamespaceDescriptor) {
131 NamespaceDescriptor namespaceDescriptor = (NamespaceDescriptor) containingDeclaration;
132 functionsByName.putValue(new Key(namespaceDescriptor, property.getName()), property);
133 }
134 }
135
136 for (Map.Entry<Key, Collection<ConstructorDescriptor>> entry : inNamespaces.entrySet()) {
137 functionsByName.putValues(entry.getKey(), entry.getValue());
138 }
139
140 for (Map.Entry<Key, Collection<CallableMemberDescriptor>> e : functionsByName.entrySet()) {
141 checkOverloadsWithSameName(e.getKey().getFunctionName(), e.getValue(), e.getKey().getNamespace());
142 }
143 }
144
145 private String nameForErrorMessage(ClassDescriptor classDescriptor, JetClassOrObject jetClass) {
146 String name = jetClass.getName();
147 if (name != null) {
148 return name;
149 }
150 if (jetClass instanceof JetObjectDeclaration) {
151 // must be class object
152 name = classDescriptor.getContainingDeclaration().getName().asString();
153 return "class object " + name;
154 }
155 // safe
156 return "<unknown>";
157 }
158
159 private void checkOverloadsInAClass(
160 MutableClassDescriptor classDescriptor, JetClassOrObject klass,
161 Collection<ConstructorDescriptor> nestedClassConstructors
162 ) {
163 MultiMap<Name, CallableMemberDescriptor> functionsByName = MultiMap.create();
164
165 if (classDescriptor.getKind() == ClassKind.ENUM_CLASS) {
166 MutableClassDescriptor classObjectDescriptor = (MutableClassDescriptor) classDescriptor.getClassObjectDescriptor();
167 assert classObjectDescriptor != null;
168 for (CallableMemberDescriptor memberDescriptor : classObjectDescriptor.getDeclaredCallableMembers()) {
169 functionsByName.putValue(memberDescriptor.getName(), memberDescriptor);
170 }
171 }
172
173 for (CallableMemberDescriptor function : classDescriptor.getDeclaredCallableMembers()) {
174 functionsByName.putValue(function.getName(), function);
175 }
176
177 for (ConstructorDescriptor nestedClassConstructor : nestedClassConstructors) {
178 functionsByName.putValue(nestedClassConstructor.getContainingDeclaration().getName(), nestedClassConstructor);
179 }
180
181 for (Map.Entry<Name, Collection<CallableMemberDescriptor>> e : functionsByName.entrySet()) {
182 checkOverloadsWithSameName(e.getKey(), e.getValue(), nameForErrorMessage(classDescriptor, klass));
183 }
184
185 // Kotlin has no secondary constructors at this time
186
187 }
188
189 private void checkOverloadsWithSameName(@NotNull Name name, Collection<CallableMemberDescriptor> functions, @NotNull String functionContainer) {
190 if (functions.size() == 1) {
191 // microoptimization
192 return;
193 }
194 Set<Pair<JetDeclaration, CallableMemberDescriptor>> redeclarations = findRedeclarations(functions);
195 reportRedeclarations(functionContainer, redeclarations);
196 }
197
198 @NotNull
199 private Set<Pair<JetDeclaration, CallableMemberDescriptor>> findRedeclarations(@NotNull Collection<CallableMemberDescriptor> functions) {
200 Set<Pair<JetDeclaration, CallableMemberDescriptor>> redeclarations = Sets.newHashSet();
201 for (CallableMemberDescriptor member : functions) {
202 for (CallableMemberDescriptor member2 : functions) {
203 if (member == member2) {
204 continue;
205 }
206
207 OverloadUtil.OverloadCompatibilityInfo overloadable = OverloadUtil.isOverloadable(member, member2);
208 if (!overloadable.isSuccess()) {
209 JetDeclaration jetDeclaration = (JetDeclaration) BindingContextUtils
210 .descriptorToDeclaration(trace.getBindingContext(), member);
211 if (jetDeclaration != null) {
212 redeclarations.add(Pair.create(jetDeclaration, member));
213 }
214 }
215 }
216 }
217 return redeclarations;
218 }
219
220 private void reportRedeclarations(@NotNull String functionContainer,
221 @NotNull Set<Pair<JetDeclaration, CallableMemberDescriptor>> redeclarations) {
222 for (Pair<JetDeclaration, CallableMemberDescriptor> redeclaration : redeclarations) {
223 CallableMemberDescriptor memberDescriptor = redeclaration.getSecond();
224 JetDeclaration jetDeclaration = redeclaration.getFirst();
225 if (memberDescriptor instanceof PropertyDescriptor) {
226 trace.report(Errors.REDECLARATION.on(jetDeclaration, memberDescriptor.getName().asString()));
227 }
228 else {
229 trace.report(Errors.CONFLICTING_OVERLOADS.on(jetDeclaration, memberDescriptor, functionContainer));
230 }
231 }
232 }
233 }