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; 018 019import com.google.common.collect.Sets; 020import com.intellij.openapi.util.Pair; 021import com.intellij.util.containers.MultiMap; 022import org.jetbrains.annotations.NotNull; 023import org.jetbrains.jet.lang.descriptors.*; 024import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor; 025import org.jetbrains.jet.lang.diagnostics.Errors; 026import org.jetbrains.jet.lang.psi.JetClass; 027import org.jetbrains.jet.lang.psi.JetClassOrObject; 028import org.jetbrains.jet.lang.psi.JetDeclaration; 029import org.jetbrains.jet.lang.psi.JetObjectDeclaration; 030import org.jetbrains.jet.lang.resolve.name.Name; 031 032import javax.inject.Inject; 033import java.util.Collection; 034import java.util.Map; 035import java.util.Set; 036 037public 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}