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.java.resolver;
018
019 import kotlin.Function1;
020 import kotlin.Unit;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.*;
024 import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
025 import org.jetbrains.jet.lang.resolve.OverridingUtil;
026 import org.jetbrains.jet.lang.resolve.java.structure.*;
027 import org.jetbrains.jet.lang.resolve.name.FqName;
028 import org.jetbrains.jet.lang.resolve.name.Name;
029 import org.jetbrains.jet.lang.types.TypeConstructor;
030 import org.jetbrains.jet.lang.types.TypeProjection;
031 import org.jetbrains.jet.lang.types.TypeProjectionImpl;
032 import org.jetbrains.jet.lang.types.TypeSubstitutor;
033
034 import java.util.*;
035
036 public final class DescriptorResolverUtils {
037 private DescriptorResolverUtils() {
038 }
039
040 @NotNull
041 public static <D extends CallableMemberDescriptor> Collection<D> resolveOverrides(
042 @NotNull Name name,
043 @NotNull Collection<D> membersFromSupertypes,
044 @NotNull Collection<D> membersFromCurrent,
045 @NotNull ClassDescriptor classDescriptor,
046 @NotNull final ErrorReporter errorReporter
047 ) {
048 final Set<D> result = new HashSet<D>();
049
050 OverridingUtil.generateOverridesInFunctionGroup(
051 name, membersFromSupertypes, membersFromCurrent, classDescriptor,
052 new OverridingUtil.DescriptorSink() {
053 @Override
054 @SuppressWarnings("unchecked")
055 public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) {
056 OverridingUtil.resolveUnknownVisibilityForMember(fakeOverride, new Function1<CallableMemberDescriptor, Unit>() {
057 @Override
058 public Unit invoke(@NotNull CallableMemberDescriptor descriptor) {
059 errorReporter.reportCannotInferVisibility(descriptor);
060 return Unit.INSTANCE$;
061 }
062 });
063 result.add((D) fakeOverride);
064 }
065
066 @Override
067 public void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent) {
068 // nop
069 }
070 }
071 );
072
073 return result;
074 }
075
076 @Nullable
077 public static ValueParameterDescriptor getAnnotationParameterByName(@NotNull Name name, @NotNull ClassDescriptor annotationClass) {
078 Collection<ConstructorDescriptor> constructors = annotationClass.getConstructors();
079 assert constructors.size() == 1 : "Annotation class descriptor must have only one constructor";
080
081 for (ValueParameterDescriptor parameter : constructors.iterator().next().getValueParameters()) {
082 if (parameter.getName().equals(name)) {
083 return parameter;
084 }
085 }
086
087 return null;
088 }
089
090 public static boolean isObjectMethodInInterface(@NotNull JavaMember member) {
091 return member.getContainingClass().isInterface() && member instanceof JavaMethod && isObjectMethod((JavaMethod) member);
092 }
093
094 public static boolean isObjectMethod(@NotNull JavaMethod method) {
095 String name = method.getName().asString();
096 if (name.equals("toString") || name.equals("hashCode")) {
097 return method.getValueParameters().isEmpty();
098 }
099 else if (name.equals("equals")) {
100 return isMethodWithOneParameterWithFqName(method, "java.lang.Object");
101 }
102 return false;
103 }
104
105 private static boolean isMethodWithOneParameterWithFqName(@NotNull JavaMethod method, @NotNull String fqName) {
106 List<JavaValueParameter> parameters = method.getValueParameters();
107 if (parameters.size() == 1) {
108 JavaType type = parameters.get(0).getType();
109 if (type instanceof JavaClassifierType) {
110 JavaClassifier classifier = ((JavaClassifierType) type).getClassifier();
111 if (classifier instanceof JavaClass) {
112 FqName classFqName = ((JavaClass) classifier).getFqName();
113 return classFqName != null && classFqName.asString().equals(fqName);
114 }
115 }
116 }
117 return false;
118 }
119
120 @NotNull
121 public static Collection<JavaClass> getClassesInPackage(@NotNull JavaPackage javaPackage) {
122 Collection<JavaClass> classes = javaPackage.getClasses();
123 Set<FqName> addedQualifiedNames = new HashSet<FqName>(classes.size());
124 List<JavaClass> result = new ArrayList<JavaClass>(classes.size());
125
126 for (JavaClass javaClass : classes) {
127 FqName fqName = javaClass.getFqName();
128 if (fqName != null && addedQualifiedNames.add(fqName)) {
129 result.add(javaClass);
130 }
131 }
132
133 return result;
134 }
135
136 /**
137 * @see com.intellij.psi.util.TypeConversionUtil#erasure(com.intellij.psi.PsiType)
138 */
139 @Nullable
140 public static JavaType erasure(@NotNull JavaType type) {
141 return erasure(type, JavaTypeSubstitutor.EMPTY);
142 }
143
144 /**
145 * @see com.intellij.psi.util.TypeConversionUtil#erasure(com.intellij.psi.PsiType, com.intellij.psi.PsiSubstitutor)
146 */
147 @Nullable
148 public static JavaType erasure(@NotNull JavaType type, @NotNull JavaTypeSubstitutor substitutor) {
149 if (type instanceof JavaClassifierType) {
150 JavaClassifier classifier = ((JavaClassifierType) type).getClassifier();
151 if (classifier instanceof JavaClass) {
152 return ((JavaClass) classifier).getDefaultType();
153 }
154 else if (classifier instanceof JavaTypeParameter) {
155 JavaTypeParameter typeParameter = (JavaTypeParameter) classifier;
156 return typeParameterErasure(typeParameter, new HashSet<JavaTypeParameter>(), substitutor);
157 }
158 else {
159 return null;
160 }
161 }
162 else if (type instanceof JavaPrimitiveType) {
163 return type;
164 }
165 else if (type instanceof JavaArrayType) {
166 JavaType erasure = erasure(((JavaArrayType) type).getComponentType(), substitutor);
167 return erasure == null ? null : erasure.createArrayType();
168 }
169 else if (type instanceof JavaWildcardType) {
170 JavaWildcardType wildcardType = (JavaWildcardType) type;
171 JavaType bound = wildcardType.getBound();
172 if (bound != null && wildcardType.isExtends()) {
173 return erasure(bound, substitutor);
174 }
175 return wildcardType.getTypeProvider().createJavaLangObjectType();
176 }
177 else {
178 throw new IllegalStateException("Unsupported type: " + type);
179 }
180 }
181
182 /**
183 * @see com.intellij.psi.util.TypeConversionUtil#typeParameterErasure(com.intellij.psi.PsiTypeParameter)
184 */
185 @Nullable
186 private static JavaType typeParameterErasure(
187 @NotNull JavaTypeParameter typeParameter,
188 @NotNull HashSet<JavaTypeParameter> visited,
189 @NotNull JavaTypeSubstitutor substitutor
190 ) {
191 Collection<JavaClassifierType> upperBounds = typeParameter.getUpperBounds();
192 if (!upperBounds.isEmpty()) {
193 JavaClassifier classifier = upperBounds.iterator().next().getClassifier();
194 if (classifier instanceof JavaTypeParameter && !visited.contains(classifier)) {
195 JavaTypeParameter typeParameterBound = (JavaTypeParameter) classifier;
196 visited.add(typeParameterBound);
197 JavaType substitutedType = substitutor.substitute(typeParameterBound);
198 if (substitutedType != null) {
199 return erasure(substitutedType);
200 }
201 return typeParameterErasure(typeParameterBound, visited, substitutor);
202 }
203 else if (classifier instanceof JavaClass) {
204 return ((JavaClass) classifier).getDefaultType();
205 }
206 }
207 return typeParameter.getTypeProvider().createJavaLangObjectType();
208 }
209
210 @NotNull
211 public static Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> recreateTypeParametersAndReturnMapping(
212 @NotNull List<TypeParameterDescriptor> originalParameters,
213 @Nullable DeclarationDescriptor newOwner
214 ) {
215 // LinkedHashMap to save the order of type parameters
216 Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> result =
217 new LinkedHashMap<TypeParameterDescriptor, TypeParameterDescriptorImpl>();
218 for (TypeParameterDescriptor typeParameter : originalParameters) {
219 result.put(typeParameter,
220 TypeParameterDescriptorImpl.createForFurtherModification(
221 newOwner == null ? typeParameter.getContainingDeclaration() : newOwner,
222 typeParameter.getAnnotations(),
223 typeParameter.isReified(),
224 typeParameter.getVariance(),
225 typeParameter.getName(),
226 typeParameter.getIndex(),
227 SourceElement.NO_SOURCE)
228 );
229 }
230 return result;
231 }
232
233 @NotNull
234 public static TypeSubstitutor createSubstitutorForTypeParameters(
235 @NotNull Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> originalToAltTypeParameters
236 ) {
237 Map<TypeConstructor, TypeProjection> typeSubstitutionContext = new HashMap<TypeConstructor, TypeProjection>();
238 for (Map.Entry<TypeParameterDescriptor, TypeParameterDescriptorImpl> originalToAltTypeParameter : originalToAltTypeParameters
239 .entrySet()) {
240 typeSubstitutionContext.put(originalToAltTypeParameter.getKey().getTypeConstructor(),
241 new TypeProjectionImpl(originalToAltTypeParameter.getValue().getDefaultType()));
242 }
243 return TypeSubstitutor.create(typeSubstitutionContext);
244 }
245 }