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.diagnostics.Errors;
025 import org.jetbrains.jet.lang.psi.JetClassOrObject;
026 import org.jetbrains.jet.lang.psi.JetDeclaration;
027 import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
028 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
029 import org.jetbrains.jet.lang.resolve.name.Name;
030
031 import javax.inject.Inject;
032 import java.util.Collection;
033 import java.util.Map;
034 import java.util.Set;
035
036 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFqName;
037
038 public class OverloadResolver {
039 private BindingTrace trace;
040
041 @Inject
042 public void setTrace(BindingTrace trace) {
043 this.trace = trace;
044 }
045
046
047
048 public void process(@NotNull BodiesResolveContext c) {
049 checkOverloads(c);
050 }
051
052 private void checkOverloads(@NotNull BodiesResolveContext c) {
053 MultiMap<ClassDescriptor, ConstructorDescriptor> inClasses = MultiMap.create();
054 MultiMap<FqNameUnsafe, ConstructorDescriptor> inPackages = MultiMap.create();
055 fillGroupedConstructors(c, inClasses, inPackages);
056
057 for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getClasses().entrySet()) {
058 checkOverloadsInAClass(entry.getValue(), entry.getKey(), inClasses.get(entry.getValue()));
059 }
060 checkOverloadsInPackages(c, inPackages);
061 }
062
063 private void fillGroupedConstructors(
064 @NotNull BodiesResolveContext c,
065 @NotNull MultiMap<ClassDescriptor, ConstructorDescriptor> inClasses,
066 @NotNull MultiMap<FqNameUnsafe, ConstructorDescriptor> inPackages
067 ) {
068 for (ClassDescriptorWithResolutionScopes klass : c.getClasses().values()) {
069 if (klass.getKind().isSingleton()) {
070 // Constructors of singletons aren't callable from the code, so they shouldn't participate in overload name checking
071 continue;
072 }
073 DeclarationDescriptor containingDeclaration = klass.getContainingDeclaration();
074 if (containingDeclaration instanceof ClassDescriptor) {
075 ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
076 inClasses.put(classDescriptor, klass.getConstructors());
077 }
078 else if (containingDeclaration instanceof PackageFragmentDescriptor) {
079 inPackages.put(getFqName(klass), klass.getConstructors());
080 }
081 else if (!(containingDeclaration instanceof FunctionDescriptor)) {
082 throw new IllegalStateException();
083 }
084 }
085 }
086
087 private void checkOverloadsInPackages(
088 @NotNull BodiesResolveContext c,
089 @NotNull MultiMap<FqNameUnsafe, ConstructorDescriptor> inPackages
090 ) {
091
092 MultiMap<FqNameUnsafe, CallableMemberDescriptor> functionsByName = MultiMap.create();
093
094 for (SimpleFunctionDescriptor function : c.getFunctions().values()) {
095 if (function.getContainingDeclaration() instanceof PackageFragmentDescriptor) {
096 functionsByName.putValue(getFqName(function), function);
097 }
098 }
099
100 for (PropertyDescriptor property : c.getProperties().values()) {
101 if (property.getContainingDeclaration() instanceof PackageFragmentDescriptor) {
102 functionsByName.putValue(getFqName(property), property);
103 }
104 }
105
106 for (Map.Entry<FqNameUnsafe, Collection<ConstructorDescriptor>> entry : inPackages.entrySet()) {
107 functionsByName.putValues(entry.getKey(), entry.getValue());
108 }
109
110 for (Map.Entry<FqNameUnsafe, Collection<CallableMemberDescriptor>> e : functionsByName.entrySet()) {
111 checkOverloadsWithSameName(e.getValue(), e.getKey().parent().asString());
112 }
113 }
114
115 private static String nameForErrorMessage(ClassDescriptor classDescriptor, JetClassOrObject jetClass) {
116 String name = jetClass.getName();
117 if (name != null) {
118 return name;
119 }
120 if (jetClass instanceof JetObjectDeclaration) {
121 // must be class object
122 name = classDescriptor.getContainingDeclaration().getName().asString();
123 return "class object " + name;
124 }
125 // safe
126 return "<unknown>";
127 }
128
129 private void checkOverloadsInAClass(
130 ClassDescriptorWithResolutionScopes classDescriptor, JetClassOrObject klass,
131 Collection<ConstructorDescriptor> nestedClassConstructors
132 ) {
133 MultiMap<Name, CallableMemberDescriptor> functionsByName = MultiMap.create();
134
135 if (classDescriptor.getKind() == ClassKind.ENUM_CLASS) {
136 ClassDescriptorWithResolutionScopes classObjectDescriptor = (ClassDescriptorWithResolutionScopes) classDescriptor.getClassObjectDescriptor();
137 assert classObjectDescriptor != null;
138 for (CallableMemberDescriptor memberDescriptor : classObjectDescriptor.getDeclaredCallableMembers()) {
139 functionsByName.putValue(memberDescriptor.getName(), memberDescriptor);
140 }
141 }
142
143 for (CallableMemberDescriptor function : classDescriptor.getDeclaredCallableMembers()) {
144 functionsByName.putValue(function.getName(), function);
145 }
146
147 for (ConstructorDescriptor nestedClassConstructor : nestedClassConstructors) {
148 functionsByName.putValue(nestedClassConstructor.getContainingDeclaration().getName(), nestedClassConstructor);
149 }
150
151 for (Map.Entry<Name, Collection<CallableMemberDescriptor>> e : functionsByName.entrySet()) {
152 checkOverloadsWithSameName(e.getValue(), nameForErrorMessage(classDescriptor, klass));
153 }
154
155 // Kotlin has no secondary constructors at this time
156
157 }
158
159 private void checkOverloadsWithSameName(
160 Collection<CallableMemberDescriptor> functions,
161 @NotNull String functionContainer
162 ) {
163 if (functions.size() == 1) {
164 // micro-optimization
165 return;
166 }
167 Set<Pair<JetDeclaration, CallableMemberDescriptor>> redeclarations = findRedeclarations(functions);
168 reportRedeclarations(functionContainer, redeclarations);
169 }
170
171 @NotNull
172 private Set<Pair<JetDeclaration, CallableMemberDescriptor>> findRedeclarations(@NotNull Collection<CallableMemberDescriptor> functions) {
173 Set<Pair<JetDeclaration, CallableMemberDescriptor>> redeclarations = Sets.newHashSet();
174 for (CallableMemberDescriptor member : functions) {
175 for (CallableMemberDescriptor member2 : functions) {
176 if (member == member2) {
177 continue;
178 }
179
180 OverloadUtil.OverloadCompatibilityInfo overloadable = OverloadUtil.isOverloadable(member, member2);
181 if (!overloadable.isSuccess()) {
182 JetDeclaration jetDeclaration = (JetDeclaration) BindingContextUtils
183 .descriptorToDeclaration(trace.getBindingContext(), member);
184 if (jetDeclaration != null) {
185 redeclarations.add(Pair.create(jetDeclaration, member));
186 }
187 }
188 }
189 }
190 return redeclarations;
191 }
192
193 private void reportRedeclarations(@NotNull String functionContainer,
194 @NotNull Set<Pair<JetDeclaration, CallableMemberDescriptor>> redeclarations) {
195 for (Pair<JetDeclaration, CallableMemberDescriptor> redeclaration : redeclarations) {
196 CallableMemberDescriptor memberDescriptor = redeclaration.getSecond();
197 JetDeclaration jetDeclaration = redeclaration.getFirst();
198 if (memberDescriptor instanceof PropertyDescriptor) {
199 trace.report(Errors.REDECLARATION.on(jetDeclaration, memberDescriptor.getName().asString()));
200 }
201 else {
202 trace.report(Errors.CONFLICTING_OVERLOADS.on(jetDeclaration, memberDescriptor, functionContainer));
203 }
204 }
205 }
206 }