diff --git a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaDescriptorResolver.java index 6dfe7bc2c8b..741e5906c10 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForJavaDescriptorResolver.java @@ -23,6 +23,7 @@ import org.jetbrains.jet.lang.resolve.java.resolver.TraceBasedExternalSignatureR import org.jetbrains.jet.lang.resolve.java.resolver.TraceBasedJavaResolverCache; import org.jetbrains.jet.lang.resolve.java.resolver.FakeOverrideVisibilityResolverImpl; import org.jetbrains.jet.lang.resolve.java.resolver.TraceBasedErrorReporter; +import org.jetbrains.jet.lang.resolve.java.resolver.PsiBasedMethodSignatureChecker; import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.lang.resolve.java.PsiClassFinderImpl; import org.jetbrains.jet.lang.resolve.java.vfilefinder.VirtualFileFinder; @@ -52,6 +53,7 @@ public class InjectorForJavaDescriptorResolver { private final TraceBasedJavaResolverCache traceBasedJavaResolverCache; private final FakeOverrideVisibilityResolverImpl fakeOverrideVisibilityResolver; private final TraceBasedErrorReporter traceBasedErrorReporter; + private final PsiBasedMethodSignatureChecker psiBasedMethodSignatureChecker; private final JavaDescriptorResolver javaDescriptorResolver; private final PsiClassFinderImpl psiClassFinder; private final VirtualFileFinder virtualFileFinder; @@ -80,6 +82,7 @@ public class InjectorForJavaDescriptorResolver { this.traceBasedJavaResolverCache = new TraceBasedJavaResolverCache(); this.fakeOverrideVisibilityResolver = new FakeOverrideVisibilityResolverImpl(); this.traceBasedErrorReporter = new TraceBasedErrorReporter(); + this.psiBasedMethodSignatureChecker = new PsiBasedMethodSignatureChecker(); this.javaDescriptorResolver = new JavaDescriptorResolver(); this.psiClassFinder = new PsiClassFinderImpl(); this.virtualFileFinder = com.intellij.openapi.components.ServiceManager.getService(project, VirtualFileFinder.class); @@ -107,6 +110,8 @@ public class InjectorForJavaDescriptorResolver { traceBasedErrorReporter.setTrace(bindingTrace); + psiBasedMethodSignatureChecker.setExternalSignatureResolver(traceBasedExternalSignatureResolver); + this.javaDescriptorResolver.setClassResolver(javaClassResolver); this.javaDescriptorResolver.setConstructorResolver(javaConstructorResolver); this.javaDescriptorResolver.setFunctionResolver(javaFunctionResolver); @@ -151,6 +156,7 @@ public class InjectorForJavaDescriptorResolver { javaFunctionResolver.setCache(traceBasedJavaResolverCache); javaFunctionResolver.setExternalSignatureResolver(traceBasedExternalSignatureResolver); javaFunctionResolver.setFakeOverrideVisibilityResolver(fakeOverrideVisibilityResolver); + javaFunctionResolver.setSignatureChecker(psiBasedMethodSignatureChecker); javaFunctionResolver.setTypeParameterResolver(javaTypeParameterResolver); javaFunctionResolver.setTypeTransformer(javaTypeTransformer); javaFunctionResolver.setValueParameterResolver(javaValueParameterResolver); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java index fa7ec976295..176cc9a5d59 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java @@ -35,6 +35,7 @@ import org.jetbrains.jet.lang.resolve.java.resolver.TraceBasedExternalSignatureR import org.jetbrains.jet.lang.resolve.java.resolver.TraceBasedJavaResolverCache; import org.jetbrains.jet.lang.resolve.java.resolver.FakeOverrideVisibilityResolverImpl; import org.jetbrains.jet.lang.resolve.java.resolver.TraceBasedErrorReporter; +import org.jetbrains.jet.lang.resolve.java.resolver.PsiBasedMethodSignatureChecker; import org.jetbrains.jet.lang.resolve.NamespaceFactoryImpl; import org.jetbrains.jet.lang.resolve.java.vfilefinder.VirtualFileFinder; import org.jetbrains.jet.lang.resolve.DeclarationResolver; @@ -91,6 +92,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly private final TraceBasedJavaResolverCache traceBasedJavaResolverCache; private final FakeOverrideVisibilityResolverImpl fakeOverrideVisibilityResolver; private final TraceBasedErrorReporter traceBasedErrorReporter; + private final PsiBasedMethodSignatureChecker psiBasedMethodSignatureChecker; private final NamespaceFactoryImpl namespaceFactory; private final VirtualFileFinder virtualFileFinder; private final DeclarationResolver declarationResolver; @@ -148,6 +150,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly this.traceBasedJavaResolverCache = new TraceBasedJavaResolverCache(); this.fakeOverrideVisibilityResolver = new FakeOverrideVisibilityResolverImpl(); this.traceBasedErrorReporter = new TraceBasedErrorReporter(); + this.psiBasedMethodSignatureChecker = new PsiBasedMethodSignatureChecker(); this.namespaceFactory = new NamespaceFactoryImpl(); this.virtualFileFinder = com.intellij.openapi.components.ServiceManager.getService(project, VirtualFileFinder.class); this.declarationResolver = new DeclarationResolver(); @@ -233,6 +236,8 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly traceBasedErrorReporter.setTrace(bindingTrace); + psiBasedMethodSignatureChecker.setExternalSignatureResolver(traceBasedExternalSignatureResolver); + this.namespaceFactory.setModuleDescriptor(moduleDescriptor); this.namespaceFactory.setTrace(bindingTrace); @@ -338,6 +343,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly javaFunctionResolver.setCache(traceBasedJavaResolverCache); javaFunctionResolver.setExternalSignatureResolver(traceBasedExternalSignatureResolver); javaFunctionResolver.setFakeOverrideVisibilityResolver(fakeOverrideVisibilityResolver); + javaFunctionResolver.setSignatureChecker(psiBasedMethodSignatureChecker); javaFunctionResolver.setTypeParameterResolver(javaTypeParameterResolver); javaFunctionResolver.setTypeTransformer(javaTypeTransformer); javaFunctionResolver.setValueParameterResolver(javaValueParameterResolver); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java index 18ca4a059c7..4e80750e9f6 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaFunctionResolver.java @@ -16,9 +16,7 @@ package org.jetbrains.jet.lang.resolve.java.resolver; -import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,27 +30,22 @@ import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmByte import org.jetbrains.jet.lang.resolve.java.descriptor.JavaMethodDescriptor; import org.jetbrains.jet.lang.resolve.java.descriptor.SamAdapterDescriptor; import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor; -import org.jetbrains.jet.lang.resolve.java.kotlinSignature.SignaturesUtil; import org.jetbrains.jet.lang.resolve.java.scope.NamedMembers; import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod; -import org.jetbrains.jet.lang.resolve.java.structure.JavaSignatureFormatter; import org.jetbrains.jet.lang.resolve.java.structure.JavaType; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.types.*; -import org.jetbrains.jet.lang.types.checker.JetTypeChecker; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeUtils; import javax.inject.Inject; import java.util.*; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; -import static org.jetbrains.jet.lang.resolve.OverridingUtil.*; import static org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils.resolveOverrides; import static org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils.*; public final class JavaFunctionResolver { - private static final Logger LOG = Logger.getInstance(JavaFunctionResolver.class); - private JavaTypeTransformer typeTransformer; private JavaResolverCache cache; private JavaTypeParameterResolver typeParameterResolver; @@ -60,6 +53,7 @@ public final class JavaFunctionResolver { private JavaAnnotationResolver annotationResolver; private ExternalSignatureResolver externalSignatureResolver; private FakeOverrideVisibilityResolver fakeOverrideVisibilityResolver; + private MethodSignatureChecker signatureChecker; @Inject public void setTypeTransformer(JavaTypeTransformer typeTransformer) { @@ -96,6 +90,11 @@ public final class JavaFunctionResolver { this.fakeOverrideVisibilityResolver = fakeOverrideVisibilityResolver; } + @Inject + public void setSignatureChecker(MethodSignatureChecker signatureChecker) { + this.signatureChecker = signatureChecker; + } + @Nullable SimpleFunctionDescriptor resolveFunctionMutely(@NotNull JavaMethod method, @NotNull ClassOrNamespaceDescriptor owner) { return resolveMethodToFunctionDescriptor(method, owner, false); @@ -183,58 +182,11 @@ public final class JavaFunctionResolver { cache.recordMethod(method, functionDescriptorImpl); } - if (!RawTypesCheck.hasRawTypesInHierarchicalSignature(method) - && JavaMethodSignatureUtil.isMethodReturnTypeCompatible(method) - && !containsErrorType(superFunctions, functionDescriptorImpl)) { - if (signatureErrors.isEmpty()) { - checkFunctionsOverrideCorrectly(method, superFunctions, functionDescriptorImpl); - } - else if (record) { - externalSignatureResolver.reportSignatureErrors(functionDescriptorImpl, signatureErrors); - } - } + signatureChecker.checkSignature(method, record, functionDescriptorImpl, signatureErrors, superFunctions); return functionDescriptorImpl; } - private static void checkFunctionsOverrideCorrectly( - @NotNull JavaMethod method, - @NotNull List superFunctions, - @NotNull FunctionDescriptor functionDescriptor - ) { - for (FunctionDescriptor superFunction : superFunctions) { - ClassDescriptor klass = (ClassDescriptor) functionDescriptor.getContainingDeclaration(); - List substitutions = Lists.newArrayList(); - while (true) { - substitutions.add(SubstitutionUtils.buildDeepSubstitutor(klass.getDefaultType()).getSubstitution()); - if (!klass.isInner()) { - break; - } - klass = (ClassDescriptor) klass.getContainingDeclaration(); - } - TypeSubstitutor substitutor = TypeSubstitutor.create(substitutions.toArray(new TypeSubstitution[substitutions.size()])); - FunctionDescriptor superFunctionSubstituted = superFunction.substitute(substitutor); - - assert superFunctionSubstituted != null : - "Couldn't substitute super function: " + superFunction + ", substitutor = " + substitutor; - - OverrideCompatibilityInfo.Result overridableResult = - isOverridableBy(superFunctionSubstituted, functionDescriptor).getResult(); - boolean paramsOk = overridableResult == OverrideCompatibilityInfo.Result.OVERRIDABLE; - boolean returnTypeOk = - isReturnTypeOkForOverride(JetTypeChecker.INSTANCE, superFunctionSubstituted, functionDescriptor); - if (!paramsOk || !returnTypeOk) { - LOG.error("Loaded Java method overrides another, but resolved as Kotlin function, doesn't.\n" - + "super function = " + superFunction + "\n" - + "super class = " + superFunction.getContainingDeclaration() + "\n" - + "sub function = " + functionDescriptor + "\n" - + "sub class = " + functionDescriptor.getContainingDeclaration() + "\n" - + "sub method = " + JavaSignatureFormatter.getExternalName(method) + "\n" - + "@KotlinSignature = " + SignaturesUtil.getKotlinSignature(method)); - } - } - } - @NotNull public Set resolveFunctionGroupForClass(@NotNull NamedMembers members, @NotNull ClassOrNamespaceDescriptor owner) { Name methodName = members.getName(); @@ -374,18 +326,4 @@ public final class JavaFunctionResolver { } return result; } - - private static boolean containsErrorType(@NotNull List superFunctions, @NotNull FunctionDescriptor function) { - if (ErrorUtils.containsErrorType(function)) { - return true; - } - - for (FunctionDescriptor superFunction : superFunctions) { - if (ErrorUtils.containsErrorType(superFunction)) { - return true; - } - } - - return false; - } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaMethodSignatureUtil.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaMethodSignatureUtil.java deleted file mode 100644 index bba194d33e7..00000000000 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaMethodSignatureUtil.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.lang.resolve.java.resolver; - -import com.intellij.psi.*; -import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; -import com.intellij.psi.util.MethodSignatureUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod; - -import java.util.List; - -// originally from com.intellij.codeInsight.daemon.impl.analysis.HighlightMethodUtil -class JavaMethodSignatureUtil { - // This and following methods are originally from com.intellij.codeInsight.daemon.impl.analysis.HighlightMethodUtil - static boolean isMethodReturnTypeCompatible(@NotNull JavaMethod method) { - if (method.isStatic()) return true; - - HierarchicalMethodSignature methodSignature = method.getPsi().getHierarchicalMethodSignature(); - List superSignatures = methodSignature.getSuperSignatures(); - - PsiType returnType = methodSignature.getSubstitutor().substitute(method.getPsi().getReturnType()); - if (returnType == null) return true; - - for (MethodSignatureBackedByPsiMethod superMethodSignature : superSignatures) { - PsiMethod superMethod = superMethodSignature.getMethod(); - PsiType declaredReturnType = superMethod.getReturnType(); - PsiType superReturnType = superMethodSignature.isRaw() ? TypeConversionUtil.erasure(declaredReturnType) : declaredReturnType; - if (superReturnType == null || method == superMethod || superMethod.getContainingClass() == null) continue; - if (!areMethodsReturnTypesCompatible(superMethodSignature, superReturnType, methodSignature, returnType)) { - return false; - } - } - - return true; - } - - private static boolean areMethodsReturnTypesCompatible( - @NotNull MethodSignatureBackedByPsiMethod superMethodSignature, - @NotNull PsiType superReturnType, - @NotNull MethodSignatureBackedByPsiMethod methodSignature, - @NotNull PsiType returnType - ) { - PsiType substitutedSuperReturnType; - boolean isJdk15 = PsiUtil.isLanguageLevel5OrHigher(methodSignature.getMethod()); - if (isJdk15 && !superMethodSignature.isRaw() && superMethodSignature.equals(methodSignature)) { //see 8.4.5 - PsiSubstitutor unifyingSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, - superMethodSignature); - substitutedSuperReturnType = unifyingSubstitutor == null - ? superReturnType - : unifyingSubstitutor.substitute(superReturnType); - } - else { - substitutedSuperReturnType = TypeConversionUtil.erasure(superMethodSignature.getSubstitutor().substitute(superReturnType)); - } - - if (returnType.equals(substitutedSuperReturnType)) return true; - if (!(returnType instanceof PsiPrimitiveType) && substitutedSuperReturnType.getDeepComponentType() instanceof PsiClassType) { - if (isJdk15 && TypeConversionUtil.isAssignable(substitutedSuperReturnType, returnType)) { - return true; - } - } - - return false; - } - - private JavaMethodSignatureUtil() { - } -} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/MethodSignatureChecker.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/MethodSignatureChecker.java new file mode 100644 index 00000000000..d860b8fe24a --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/MethodSignatureChecker.java @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.java.resolver; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor; +import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod; + +import java.util.List; + +public interface MethodSignatureChecker { + void checkSignature( + @NotNull JavaMethod method, + boolean reportSignatureErrors, + @NotNull SimpleFunctionDescriptor descriptor, + @NotNull List signatureErrors, + @NotNull List superFunctions + ); +} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/PsiBasedMethodSignatureChecker.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/PsiBasedMethodSignatureChecker.java new file mode 100644 index 00000000000..fa2cc14d3a5 --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/PsiBasedMethodSignatureChecker.java @@ -0,0 +1,262 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.java.resolver; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.*; +import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; +import com.intellij.psi.util.MethodSignatureUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.TypeConversionUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor; +import org.jetbrains.jet.lang.resolve.OverridingUtil; +import org.jetbrains.jet.lang.resolve.java.kotlinSignature.SignaturesUtil; +import org.jetbrains.jet.lang.resolve.java.structure.*; +import org.jetbrains.jet.lang.types.ErrorUtils; +import org.jetbrains.jet.lang.types.SubstitutionUtils; +import org.jetbrains.jet.lang.types.TypeSubstitution; +import org.jetbrains.jet.lang.types.TypeSubstitutor; +import org.jetbrains.jet.lang.types.checker.JetTypeChecker; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.List; + +import static org.jetbrains.jet.lang.resolve.OverridingUtil.isOverridableBy; +import static org.jetbrains.jet.lang.resolve.OverridingUtil.isReturnTypeOkForOverride; + +public class PsiBasedMethodSignatureChecker implements MethodSignatureChecker { + private static final Logger LOG = Logger.getInstance(PsiBasedMethodSignatureChecker.class); + + private ExternalSignatureResolver externalSignatureResolver; + + @Inject + public void setExternalSignatureResolver(ExternalSignatureResolver externalSignatureResolver) { + this.externalSignatureResolver = externalSignatureResolver; + } + + private static void checkFunctionOverridesCorrectly( + @NotNull JavaMethod method, + @NotNull FunctionDescriptor function, + @NotNull FunctionDescriptor superFunction + ) { + ClassDescriptor klass = (ClassDescriptor) function.getContainingDeclaration(); + List substitutions = new ArrayList(); + while (true) { + substitutions.add(SubstitutionUtils.buildDeepSubstitutor(klass.getDefaultType()).getSubstitution()); + if (!klass.isInner()) { + break; + } + klass = (ClassDescriptor) klass.getContainingDeclaration(); + } + TypeSubstitutor substitutor = TypeSubstitutor.create(substitutions.toArray(new TypeSubstitution[substitutions.size()])); + FunctionDescriptor superFunctionSubstituted = superFunction.substitute(substitutor); + + assert superFunctionSubstituted != null : "Couldn't substitute super function: " + superFunction + ", substitutor = " + substitutor; + + OverridingUtil.OverrideCompatibilityInfo.Result overridableResult = isOverridableBy(superFunctionSubstituted, function).getResult(); + boolean paramsOk = overridableResult == OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE; + boolean returnTypeOk = isReturnTypeOkForOverride(JetTypeChecker.INSTANCE, superFunctionSubstituted, function); + if (!paramsOk || !returnTypeOk) { + LOG.error("Loaded Java method overrides another, but resolved as Kotlin function, doesn't.\n" + + "super function = " + superFunction + "\n" + + "super class = " + superFunction.getContainingDeclaration() + "\n" + + "sub function = " + function + "\n" + + "sub class = " + function.getContainingDeclaration() + "\n" + + "sub method = " + JavaSignatureFormatter.getExternalName(method) + "\n" + + "@KotlinSignature = " + SignaturesUtil.getKotlinSignature(method)); + } + } + + private static boolean containsErrorType(@NotNull List superFunctions, @NotNull FunctionDescriptor function) { + if (ErrorUtils.containsErrorType(function)) { + return true; + } + + for (FunctionDescriptor superFunction : superFunctions) { + if (ErrorUtils.containsErrorType(superFunction)) { + return true; + } + } + + return false; + } + + // Originally from com.intellij.codeInsight.daemon.impl.analysis.HighlightMethodUtil + private static boolean isMethodReturnTypeCompatible(@NotNull JavaMethod method) { + if (method.isStatic()) return true; + + HierarchicalMethodSignature methodSignature = method.getPsi().getHierarchicalMethodSignature(); + List superSignatures = methodSignature.getSuperSignatures(); + + PsiType returnType = methodSignature.getSubstitutor().substitute(method.getPsi().getReturnType()); + if (returnType == null) return true; + + for (MethodSignatureBackedByPsiMethod superMethodSignature : superSignatures) { + PsiMethod superMethod = superMethodSignature.getMethod(); + PsiType declaredReturnType = superMethod.getReturnType(); + PsiType superReturnType = superMethodSignature.isRaw() ? TypeConversionUtil.erasure(declaredReturnType) : declaredReturnType; + if (superReturnType == null || method == superMethod || superMethod.getContainingClass() == null) continue; + if (!areMethodsReturnTypesCompatible(superMethodSignature, superReturnType, methodSignature, returnType)) { + return false; + } + } + + return true; + } + + // Originally from com.intellij.codeInsight.daemon.impl.analysis.HighlightMethodUtil + private static boolean areMethodsReturnTypesCompatible( + @NotNull MethodSignatureBackedByPsiMethod superMethodSignature, + @NotNull PsiType superReturnType, + @NotNull MethodSignatureBackedByPsiMethod methodSignature, + @NotNull PsiType returnType + ) { + PsiType substitutedSuperReturnType; + boolean isJdk15 = PsiUtil.isLanguageLevel5OrHigher(methodSignature.getMethod()); + if (isJdk15 && !superMethodSignature.isRaw() && superMethodSignature.equals(methodSignature)) { //see 8.4.5 + PsiSubstitutor unifyingSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, + superMethodSignature); + substitutedSuperReturnType = unifyingSubstitutor == null + ? superReturnType + : unifyingSubstitutor.substitute(superReturnType); + } + else { + substitutedSuperReturnType = TypeConversionUtil.erasure(superMethodSignature.getSubstitutor().substitute(superReturnType)); + } + + if (returnType.equals(substitutedSuperReturnType)) return true; + if (!(returnType instanceof PsiPrimitiveType) && substitutedSuperReturnType.getDeepComponentType() instanceof PsiClassType) { + if (isJdk15 && TypeConversionUtil.isAssignable(substitutedSuperReturnType, returnType)) { + return true; + } + } + + return false; + } + + @Override + public void checkSignature( + @NotNull JavaMethod method, + boolean reportSignatureErrors, + @NotNull SimpleFunctionDescriptor descriptor, + @NotNull List signatureErrors, + @NotNull List superFunctions + ) { + if (!RawTypesCheck.hasRawTypesInHierarchicalSignature(method) && + isMethodReturnTypeCompatible(method) && + !containsErrorType(superFunctions, descriptor)) { + if (signatureErrors.isEmpty()) { + for (FunctionDescriptor superFunction : superFunctions) { + checkFunctionOverridesCorrectly(method, descriptor, superFunction); + } + } + else if (reportSignatureErrors) { + externalSignatureResolver.reportSignatureErrors(descriptor, signatureErrors); + } + } + } + + private static class RawTypesCheck { + private static boolean isPartiallyRawType(@NotNull JavaType type) { + if (type instanceof JavaPrimitiveType) { + return false; + } + else if (type instanceof JavaClassifierType) { + JavaClassifierType classifierType = (JavaClassifierType) type; + + if (classifierType.isRaw()) { + return true; + } + + for (JavaType argument : classifierType.getTypeArguments()) { + if (isPartiallyRawType(argument)) { + return true; + } + } + + return false; + } + else if (type instanceof JavaArrayType) { + return isPartiallyRawType(((JavaArrayType) type).getComponentType()); + } + else if (type instanceof JavaWildcardType) { + JavaType bound = ((JavaWildcardType) type).getBound(); + return bound != null && isPartiallyRawType(bound); + } + else { + throw new IllegalStateException("Unexpected type: " + type); + } + } + + private static boolean hasRawTypesInSignature(@NotNull JavaMethod method) { + JavaType returnType = method.getReturnType(); + if (returnType != null && isPartiallyRawType(returnType)) { + return true; + } + + for (JavaValueParameter parameter : method.getValueParameters()) { + if (isPartiallyRawType(parameter.getType())) { + return true; + } + } + + for (JavaTypeParameter typeParameter : method.getTypeParameters()) { + for (JavaClassifierType upperBound : typeParameter.getUpperBounds()) { + if (isPartiallyRawType(upperBound)) { + return true; + } + } + } + + return false; + } + + public static boolean hasRawTypesInHierarchicalSignature(@NotNull JavaMethod method) { + // This is a very important optimization: package-classes are big and full of static methods + // building method hierarchies for such classes takes a very long time + if (method.isStatic()) return false; + + if (hasRawTypesInSignature(method)) { + return true; + } + + for (HierarchicalMethodSignature superSignature : method.getPsi().getHierarchicalMethodSignature().getSuperSignatures()) { + JavaMethod superMethod = new JavaMethod(superSignature.getMethod()); + if (superSignature.isRaw() || typeParameterIsErased(method, superMethod) || hasRawTypesInSignature(superMethod)) { + return true; + } + } + + return false; + } + + private static boolean typeParameterIsErased(@NotNull JavaMethod method, @NotNull JavaMethod superMethod) { + // Java allows you to write + // T foo(), in the superclass and then + // Foo foo(), in the subclass + // this is a valid Java override, but in fact it is an erasure + return method.getTypeParameters().size() != superMethod.getTypeParameters().size(); + } + + private RawTypesCheck() { + } + } +} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/RawTypesCheck.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/RawTypesCheck.java deleted file mode 100644 index 00f40236690..00000000000 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/RawTypesCheck.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.lang.resolve.java.resolver; - -import com.intellij.psi.HierarchicalMethodSignature; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.resolve.java.structure.*; - -public class RawTypesCheck { - private static boolean isPartiallyRawType(@NotNull JavaType type) { - if (type instanceof JavaPrimitiveType) { - return false; - } - else if (type instanceof JavaClassifierType) { - JavaClassifierType classifierType = (JavaClassifierType) type; - - if (classifierType.isRaw()) { - return true; - } - - for (JavaType argument : classifierType.getTypeArguments()) { - if (isPartiallyRawType(argument)) { - return true; - } - } - - return false; - } - else if (type instanceof JavaArrayType) { - return isPartiallyRawType(((JavaArrayType) type).getComponentType()); - } - else if (type instanceof JavaWildcardType) { - JavaType bound = ((JavaWildcardType) type).getBound(); - return bound != null && isPartiallyRawType(bound); - } - else { - throw new IllegalStateException("Unexpected type: " + type); - } - } - - private static boolean hasRawTypesInSignature(@NotNull JavaMethod method) { - JavaType returnType = method.getReturnType(); - if (returnType != null && isPartiallyRawType(returnType)) { - return true; - } - - for (JavaValueParameter parameter : method.getValueParameters()) { - if (isPartiallyRawType(parameter.getType())) { - return true; - } - } - - for (JavaTypeParameter typeParameter : method.getTypeParameters()) { - for (JavaClassifierType upperBound : typeParameter.getUpperBounds()) { - if (isPartiallyRawType(upperBound)) { - return true; - } - } - } - - return false; - } - - static boolean hasRawTypesInHierarchicalSignature(@NotNull JavaMethod method) { - // This is a very important optimization: package-classes are big and full of static methods - // building method hierarchies for such classes takes a very long time - if (method.isStatic()) return false; - - if (hasRawTypesInSignature(method)) { - return true; - } - - for (HierarchicalMethodSignature superSignature : method.getPsi().getHierarchicalMethodSignature().getSuperSignatures()) { - JavaMethod superMethod = new JavaMethod(superSignature.getMethod()); - if (superSignature.isRaw() || typeParameterIsErased(method, superMethod) || hasRawTypesInSignature(superMethod)) { - return true; - } - } - - return false; - } - - private static boolean typeParameterIsErased(@NotNull JavaMethod method, @NotNull JavaMethod superMethod) { - // Java allows you to write - // T foo(), in the superclass and then - // Foo foo(), in the subclass - // this is a valid Java override, but in fact it is an erasure - return method.getTypeParameters().size() != superMethod.getTypeParameters().size(); - } - - private RawTypesCheck() { - } -} diff --git a/generators/org/jetbrains/jet/generators/injectors/GenerateInjectors.java b/generators/org/jetbrains/jet/generators/injectors/GenerateInjectors.java index ab1ad6a5c7f..9463ff44982 100644 --- a/generators/org/jetbrains/jet/generators/injectors/GenerateInjectors.java +++ b/generators/org/jetbrains/jet/generators/injectors/GenerateInjectors.java @@ -37,10 +37,7 @@ import org.jetbrains.jet.lang.resolve.java.JavaBridgeConfiguration; import org.jetbrains.jet.lang.resolve.java.JavaClassFinderImpl; import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.lang.resolve.java.PsiClassFinderImpl; -import org.jetbrains.jet.lang.resolve.java.resolver.FakeOverrideVisibilityResolverImpl; -import org.jetbrains.jet.lang.resolve.java.resolver.TraceBasedErrorReporter; -import org.jetbrains.jet.lang.resolve.java.resolver.TraceBasedExternalSignatureResolver; -import org.jetbrains.jet.lang.resolve.java.resolver.TraceBasedJavaResolverCache; +import org.jetbrains.jet.lang.resolve.java.resolver.*; import org.jetbrains.jet.lang.resolve.java.vfilefinder.VirtualFileFinder; import org.jetbrains.jet.lang.resolve.lazy.ResolveSession; import org.jetbrains.jet.lang.resolve.lazy.ScopeProvider; @@ -113,6 +110,7 @@ public class GenerateInjectors { generator.addField(TraceBasedJavaResolverCache.class); generator.addField(FakeOverrideVisibilityResolverImpl.class); generator.addField(TraceBasedErrorReporter.class); + generator.addField(PsiBasedMethodSignatureChecker.class); generator.addPublicField(NamespaceFactoryImpl.class); generator.addField(false, VirtualFileFinder.class, "virtualFileFinder", new GivenExpression( @@ -134,6 +132,7 @@ public class GenerateInjectors { generator.addField(TraceBasedJavaResolverCache.class); generator.addField(FakeOverrideVisibilityResolverImpl.class); generator.addField(TraceBasedErrorReporter.class); + generator.addField(PsiBasedMethodSignatureChecker.class); generator.addPublicField(JavaDescriptorResolver.class); generator.addPublicField(PsiClassFinderImpl.class); generator.addField(false, VirtualFileFinder.class, "virtualFileFinder",