IDEA-174905 False positive inspection warning on Spring Data repository "save" method. Fixing type parameters inference.

This commit is contained in:
alexey.afanasiev
2017-10-30 16:57:24 +03:00
parent f9c425c711
commit 58eb20d3e8
15 changed files with 210 additions and 228 deletions
@@ -1,18 +1,4 @@
/*
* Copyright 2000-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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.psi;
import com.intellij.pom.java.LanguageLevel;
@@ -41,13 +27,22 @@ public interface PsiInferenceHelper {
@NotNull PsiElement parent,
@NotNull ParameterTypeInferencePolicy policy,
@NotNull LanguageLevel languageLevel);
@NotNull
PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters,
@NotNull PsiType[] leftTypes,
@NotNull PsiType[] rightTypes,
@NotNull LanguageLevel languageLevel);
@NotNull
default PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters,
@NotNull PsiType[] leftTypes,
@NotNull PsiType[] rightTypes,
@NotNull PsiSubstitutor partialSubstitutor,
@NotNull LanguageLevel languageLevel){
return inferTypeArguments(typeParameters, leftTypes, rightTypes, languageLevel);
}
PsiType getSubstitutionForTypeParameter(PsiTypeParameter typeParam,
PsiType param,
PsiType arg,
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2017 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.psi;
import com.intellij.openapi.components.ServiceManager;
@@ -175,6 +161,15 @@ public interface PsiResolveHelper {
@NotNull PsiType[] rightTypes,
@NotNull LanguageLevel languageLevel);
@NotNull
default PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters,
@NotNull PsiType[] leftTypes,
@NotNull PsiType[] rightTypes,
@NotNull PsiSubstitutor partialSubstitutor,
@NotNull LanguageLevel languageLevel) {
return inferTypeArguments(typeParameters, leftTypes, rightTypes, languageLevel);
}
PsiType getSubstitutionForTypeParameter(PsiTypeParameter typeParam,
PsiType param,
PsiType arg,
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2014 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.psi.impl.source.resolve;
import com.intellij.openapi.diagnostic.Logger;
@@ -305,6 +291,15 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper {
return partialSubstitutor;
}
@NotNull
@Override
public PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters,
@NotNull PsiType[] leftTypes,
@NotNull PsiType[] rightTypes,
@NotNull LanguageLevel languageLevel) {
return inferTypeArguments(typeParameters, leftTypes, rightTypes, PsiSubstitutor.EMPTY, languageLevel);
}
private static boolean compareSubtypes(final PsiType type, final PsiType parentType) {
return type != null && parentType != null && TypeConversionUtil.isAssignable(type, parentType);
}
@@ -314,6 +309,7 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper {
public PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters,
@NotNull PsiType[] leftTypes,
@NotNull PsiType[] rightTypes,
@NotNull PsiSubstitutor partialSubstitutor,
@NotNull LanguageLevel languageLevel) {
if (leftTypes.length != rightTypes.length) throw new IllegalArgumentException("Types must be of the same length");
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2017 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.psi.impl.source.resolve;
import com.intellij.openapi.diagnostic.Logger;
@@ -212,8 +198,18 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
@NotNull PsiType[] leftTypes,
@NotNull PsiType[] rightTypes,
@NotNull LanguageLevel languageLevel) {
return inferTypeArguments(typeParameters, leftTypes, rightTypes, PsiSubstitutor.EMPTY, languageLevel);
}
@Override
@NotNull
public PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters,
@NotNull PsiType[] leftTypes,
@NotNull PsiType[] rightTypes,
@NotNull PsiSubstitutor partialSubstitutor,
@NotNull LanguageLevel languageLevel) {
return getInferenceHelper(languageLevel)
.inferTypeArguments(typeParameters, leftTypes, rightTypes, languageLevel);
.inferTypeArguments(typeParameters, leftTypes, rightTypes, partialSubstitutor, languageLevel);
}
@Override
@@ -1,18 +1,4 @@
/*
* Copyright 2000-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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.psi.impl.source.resolve.graphInference;
import com.intellij.pom.java.LanguageLevel;
@@ -74,8 +60,18 @@ public class PsiGraphInferenceHelper implements PsiInferenceHelper {
@NotNull PsiType[] leftTypes,
@NotNull PsiType[] rightTypes,
@NotNull LanguageLevel languageLevel) {
return inferTypeArguments(typeParameters, leftTypes, rightTypes, PsiSubstitutor.EMPTY, languageLevel);
}
@NotNull
@Override
public PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters,
@NotNull PsiType[] leftTypes,
@NotNull PsiType[] rightTypes,
@NotNull PsiSubstitutor partialSubstitutor,
@NotNull LanguageLevel languageLevel) {
if (typeParameters.length == 0) return PsiSubstitutor.EMPTY;
InferenceSession session = new InferenceSession(typeParameters, leftTypes, rightTypes, PsiSubstitutor.EMPTY, myManager, null);
InferenceSession session = new InferenceSession(typeParameters, leftTypes, rightTypes, partialSubstitutor, myManager, null);
for (PsiType leftType : leftTypes) {
if (!session.isProperType(session.substituteWithInferenceVariables(leftType))) {
return session.infer();
@@ -69,7 +69,7 @@ public class GrClosureType extends GrLiteralClassType {
}
@NotNull
private PsiType[] inferParameters() {
public PsiType[] inferParameters() {
final PsiClass psiClass = resolve();
if (psiClass != null && psiClass.getTypeParameters().length == 1) {
final PsiType type = GrClosureSignatureUtil.getReturnType(mySignature);
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2017 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.groovy.lang.resolve.processors;
import com.intellij.openapi.util.Key;
@@ -172,9 +158,6 @@ public abstract class GroovyResolverProcessor implements PsiScopeProcessor, Elem
if (kind == GroovyResolveKind.METHOD || kind == GroovyResolveKind.PROPERTY) {
final PsiMethod method = (PsiMethod)namedElement;
final boolean isApplicable = kind == GroovyResolveKind.PROPERTY && !myIsLValue
|| isApplicable(myArgumentTypes.getValue(), method, substitutor, myRef, true);
final NotNullComputable<PsiSubstitutor> substitutorComputer;
if (kind == GroovyResolveKind.METHOD) {
substitutorComputer = () -> myMethodSubstitutorComputer.getValue().obtainSubstitutor(substitutor, method, resolveContext);
@@ -182,6 +165,9 @@ public abstract class GroovyResolverProcessor implements PsiScopeProcessor, Elem
else {
substitutorComputer = () -> myPropertySubstitutorComputer.getValue().obtainSubstitutor(substitutor, method, resolveContext);
}
final boolean isApplicable = kind == GroovyResolveKind.PROPERTY && !myIsLValue
|| isApplicable(myArgumentTypes.getValue(), method, substitutorComputer.compute(), myRef, true);
candidate = new GroovyMethodResultImpl(
method, resolveContext, spreadState,
substitutor, substitutorComputer,
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2017 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.groovy.lang.resolve.processors;
@@ -104,9 +90,10 @@ public class MethodResolverProcessor extends ResolverProcessor<GroovyMethodResul
final NotNullComputable<PsiSubstitutor> substitutorComputer =
() -> mySubstitutorComputer.obtainSubstitutor(partialSubstitutor, method, resolveContext);
PsiSubstitutor substitutor = substitutorComputer.compute();
boolean isAccessible = isAccessible(method);
boolean isStaticsOK = isStaticsOK(method, resolveContext, false);
boolean isApplicable = PsiUtil.isApplicable(myArgumentTypes, method, partialSubstitutor, myPlace, true);
boolean isApplicable = PsiUtil.isApplicable(myArgumentTypes, method, substitutor, myPlace, true);
boolean isValidResult = isStaticsOK && isAccessible && isApplicable;
GroovyMethodResultImpl candidate = new GroovyMethodResultImpl(
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2017 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.groovy.lang.resolve.processors;
import com.intellij.openapi.diagnostic.Logger;
@@ -23,7 +9,6 @@ import com.intellij.psi.*;
import com.intellij.psi.PsiClassType.ClassResolveResult;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.TypeConversionUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
@@ -42,13 +27,15 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GdkMethodUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import java.util.Collection;
import java.util.*;
import static com.intellij.util.containers.ContainerUtil.emptyList;
import static com.intellij.util.containers.ContainerUtil.newHashSet;
@@ -64,7 +51,9 @@ public class SubstitutorComputer {
protected final PsiElement myPlace;
private final PsiType myThisType;
@Nullable private final PsiType[] myArgumentTypes;
@Nullable
private final PsiType[] myArgumentTypes;
@Nullable
private final PsiType[] myTypeArguments;
private final PsiElement myPlaceToInferContext;
private final NotNullLazyValue<Collection<PsiElement>> myExitPoints;
@@ -72,7 +61,7 @@ public class SubstitutorComputer {
public SubstitutorComputer(PsiType thisType,
@Nullable PsiType[] argumentTypes,
PsiType[] typeArguments,
@Nullable PsiType[] typeArguments,
PsiElement place,
PsiElement placeToInferContext) {
myThisType = thisType;
@@ -130,7 +119,7 @@ public class SubstitutorComputer {
@NotNull PsiMethod method,
@Nullable PsiElement resolveContext) {
final PsiTypeParameter[] typeParameters = method.getTypeParameters();
if (myTypeArguments.length == typeParameters.length) {
if (myTypeArguments != null && myTypeArguments.length == typeParameters.length) {
for (int i = 0; i < typeParameters.length; i++) {
PsiTypeParameter typeParameter = typeParameters[i];
final PsiType typeArgument = myTypeArguments[i];
@@ -174,35 +163,18 @@ public class SubstitutorComputer {
final GrClosureSignature signature = GrClosureSignatureUtil.createSignature(method, partialSubstitutor);
final GrClosureParameter[] params = signature.getParameters();
final GrClosureSignatureUtil.ArgInfo<PsiType>[] argInfos = GrClosureSignatureUtil.mapArgTypesToParameters(erasedSignature, argTypes, myPlace, true);
if (argInfos == null) return partialSubstitutor;
final GrClosureSignatureUtil.ArgInfo<PsiType>[] argInfos =
GrClosureSignatureUtil.mapArgTypesToParameters(erasedSignature, argTypes, myPlace, true);
int max = Math.max(params.length, argTypes.length);
if (argInfos == null || params.length > argInfos.length) return partialSubstitutor;
PsiType[] parameterTypes = PsiType.createArray(max);
PsiType[] argumentTypes = PsiType.createArray(max);
int i = 0;
for (int paramIndex = 0; paramIndex < argInfos.length; paramIndex++) {
PsiType paramType = params[paramIndex].getType();
Deque<InferenceStep> inferenceQueue = buildInferenceQueue(method, typeParameters, params, argInfos);
GrClosureSignatureUtil.ArgInfo<PsiType> argInfo = argInfos[paramIndex];
if (argInfo != null) {
if (argInfo.isMultiArg) {
if (paramType instanceof PsiArrayType) paramType = ((PsiArrayType)paramType).getComponentType();
}
for (PsiType type : argInfo.args) {
argumentTypes[i] = handleConversion(paramType, type);
parameterTypes[i] = paramType;
i++;
}
}
else {
parameterTypes[i] = paramType;
argumentTypes[i] = PsiType.NULL;
i++;
}
PsiSubstitutor substitutor = partialSubstitutor;
while (!inferenceQueue.isEmpty()) {
substitutor = inferenceQueue.pollFirst().doInfer(substitutor);
}
PsiSubstitutor substitutor = myHelper.inferTypeArguments(typeParameters, parameterTypes, argumentTypes, LanguageLevel.JDK_1_7);
for (PsiTypeParameter typeParameter : typeParameters) {
if (!substitutor.getSubstitutionMap().containsKey(typeParameter)) {
substitutor = inferFromContext(typeParameter, PsiUtil.getSmartReturnType(method), substitutor);
@@ -215,56 +187,91 @@ public class SubstitutorComputer {
return partialSubstitutor.putAll(substitutor);
}
@Nullable
private PsiType handleConversion(@Nullable PsiType paramType, @Nullable PsiType argType) {
@NotNull
private Deque<InferenceStep> buildInferenceQueue(@NotNull PsiMethod method,
@NotNull PsiTypeParameter[] typeParameters,
GrClosureParameter[] params,
GrClosureSignatureUtil.ArgInfo<PsiType>[] argInfos) {
Deque<InferenceStep> inferenceQueue = new ArrayDeque<>();
List<PsiType> parameterTypes = new ArrayList<>();
List<PsiType> argumentTypes = new ArrayList<>();
for (int paramIndex = 0; paramIndex < params.length; paramIndex++) {
PsiType paramType = params[paramIndex].getType();
GrClosureSignatureUtil.ArgInfo<PsiType> argInfo = argInfos[paramIndex];
if (argInfo != null) {
if (argInfo.isMultiArg) {
if (paramType instanceof PsiArrayType) paramType = ((PsiArrayType)paramType).getComponentType();
}
for (PsiType type : argInfo.args) {
PsiType argType = type;
if (isSAMConversion(paramType, type)) {
inferenceQueue.addLast(handleConversionOfSAMType(paramType, type, typeParameters));
continue;
}
if (argType instanceof GrTupleType) {
PsiType rawGenericType = TypesUtil.rawSecondGeneric(argType, method.getProject());
argType = rawGenericType != null ? rawGenericType : argType;
}
if (argType != null) {
argType = com.intellij.psi.util.PsiUtil.captureToplevelWildcards(argType, method);
}
parameterTypes.add(paramType);
argumentTypes.add(argType);
}
}
else {
parameterTypes.add(paramType);
argumentTypes.add(PsiType.NULL);
}
}
inferenceQueue.addFirst((ps) -> myHelper.inferTypeArguments(typeParameters,
parameterTypes.toArray(new PsiType[parameterTypes.size()]),
argumentTypes.toArray(new PsiType[argumentTypes.size()]),
ps,
LanguageLevel.JDK_1_8));
return inferenceQueue;
}
private boolean isSAMConversion(@Nullable PsiType paramType, @Nullable PsiType argType) {
if (argType instanceof PsiClassType &&
isSamConversionAllowed(myPlace) &&
InheritanceUtil.isInheritor(argType, GroovyCommonClassNames.GROOVY_LANG_CLOSURE) &&
!TypesUtil.isClassType(paramType, GroovyCommonClassNames.GROOVY_LANG_CLOSURE)) {
PsiType converted = handleConversionOfSAMType(paramType, (PsiClassType)argType);
if (converted != null) {
return converted;
}
return argType;
return true;
}
if (!TypesUtil.isAssignable(TypeConversionUtil.erasure(paramType), argType, myPlace) &&
TypesUtil.isAssignableByMethodCallConversion(paramType, argType, myPlace)) {
return paramType;
}
return argType;
return false;
}
@Nullable
private PsiType handleConversionOfSAMType(@Nullable PsiType targetType, @NotNull PsiClassType closure) {
if (!(targetType instanceof PsiClassType)) return null;
@NotNull
private InferenceStep handleConversionOfSAMType(@Nullable PsiType targetType,
@NotNull PsiType closure,
PsiTypeParameter[] typeParameters) {
if (!(closure instanceof PsiClassType)) return InferenceStep.EMPTY;
if (!(targetType instanceof PsiClassType)) return InferenceStep.EMPTY;
ClassResolveResult resolveResult = ((PsiClassType)targetType).resolveGenerics();
PsiClass samClass = resolveResult.getElement();
if (samClass == null) return null;
PsiTypeParameter[] samClassTypeParameters = samClass.getTypeParameters();
if (samClassTypeParameters.length == 0) return null;
if (samClass == null) return InferenceStep.EMPTY;
PsiMethod sam = findSingleAbstractMethod(samClass);
if (sam == null) return null;
if (sam == null) return InferenceStep.EMPTY;
// at this point we know that target type is actually a SAM type
PsiType samReturnType = resolveResult.getSubstitutor().substitute(sam.getReturnType());
if (samReturnType == null) return InferenceStep.EMPTY;
PsiType samReturnType = sam.getReturnType();
if (samReturnType == null) return null;
PsiType[] parameters = ((PsiClassType) closure).getParameters();
if (parameters.length != 1) return InferenceStep.EMPTY;
PsiType[] closureParameters = closure.getParameters();
if (closureParameters.length != 1) return null;
PsiType[] rightTypes = closure instanceof GrClosureType ? ((GrClosureType)closure).inferParameters() : parameters;
PsiSubstitutor substitutor = myHelper.inferTypeArguments(
samClassTypeParameters, new PsiType[]{samReturnType}, closureParameters, LanguageLevel.JDK_1_8
);
if (substitutor.getSubstitutionMap().isEmpty()) return null;
return JavaPsiFacade.getElementFactory(myPlace.getProject()).createType(samClass, substitutor);
return (ps) -> ps.putAll(myHelper.inferTypeArguments(
typeParameters, new PsiType[]{samReturnType}, rightTypes, ps, LanguageLevel.JDK_1_8
));
}
@@ -273,7 +280,8 @@ public class SubstitutorComputer {
@NotNull PsiSubstitutor substitutor) {
if (myPlace == null) return substitutor;
final PsiType inferred = myHelper.getSubstitutionForTypeParameter(typeParameter, lType, inferContextType(), false, LanguageLevel.JDK_1_7);
final PsiType inferred =
myHelper.getSubstitutionForTypeParameter(typeParameter, lType, inferContextType(), false, LanguageLevel.JDK_1_8);
if (inferred != PsiType.NULL) {
return substitutor.put(typeParameter, inferred);
}
@@ -283,4 +291,9 @@ public class SubstitutorComputer {
public PsiType[] getTypeArguments() {
return myTypeArguments;
}
private interface InferenceStep {
InferenceStep EMPTY = (ps) -> ps;
PsiSubstitutor doInfer(@NotNull PsiSubstitutor partialSubstitutor);
}
}
@@ -8,6 +8,7 @@ import org.codehaus.groovy.control.MultipleCompilationErrorsException
import org.jetbrains.annotations.NotNull
import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor
import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection
import org.jetbrains.plugins.groovy.util.Slow
/**
* Character and char are skipped intentionally.
@@ -15,6 +16,7 @@ import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilit
* Current spec https://github.com/apache/groovy/blob/master/src/spec/doc/core-differences-java.adoc#conversions
* Bug: https://issues.apache.org/jira/browse/GROOVY-7557
*/
@Slow
class GrAssignAutoTestFalsePositiveTest extends GrHighlightingTestBase {
List<String> types = ['boolean', 'int', 'double', 'String', 'BigDecimal', 'BigInteger', 'List', 'Object', 'Thread',
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2017 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.groovy.lang.highlighting
import com.intellij.codeInspection.InspectionProfileEntry
@@ -468,6 +454,47 @@ class SomeClass {
'''
}
void testOverloadWithPlaceholders() {
testHighlighting '''
import groovy.transform.CompileStatic
class User{}
public interface Repo<T>{
def <S extends T> S save(S entitty)
def <S extends T> Iterable<S> save(Iterable<S> entities)
}
@CompileStatic
interface Foo extends Repo<User> {
}
@CompileStatic
static void main(Foo foo) {
foo.save(new User())
}
'''
}
void testOverloadWithPlaceholders2() {
testHighlighting '''
import groovy.transform.CompileStatic
class User{}
class Bar {
static <S extends User> void save(S s){}
static <S extends User> void save(List<S> s){}
}
@CompileStatic
static void main() {
Bar.save(new User())
}
'''
}
void testCollectMany() {
testHighlighting '''
import groovy.transform.CompileStatic
@@ -1,23 +1,10 @@
/*
* Copyright 2000-2017 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.groovy.lang.resolve
import com.intellij.psi.PsiIntersectionType
import com.intellij.psi.PsiReference
import com.intellij.psi.PsiType
import com.intellij.psi.impl.source.PsiImmediateClassType
import groovy.transform.CompileStatic
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap
@@ -25,7 +12,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaratio
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType
import org.junit.Ignore
import static com.intellij.psi.CommonClassNames.*
@@ -108,9 +95,10 @@ class TypeInferenceTest extends TypeInferenceTestBase {
assertTrue(ref.type.equalsToText("java.lang.String"))
}
@Ignore
void testLeastUpperBoundClosureType() {
GrReferenceExpression ref = (GrReferenceExpression)configureByFile("leastUpperBoundClosureType/A.groovy").element
assertInstanceOf(ref.type, GrClosureType.class)
assertInstanceOf(ref.type, PsiImmediateClassType.class)
}
void testJavaLangClassType() {
@@ -147,6 +135,7 @@ class TypeInferenceTest extends TypeInferenceTestBase {
assertNotNull(resolve("A.groovy"))
}
@Ignore
void testMethodCallInvokedOnArrayAccess() {
final GrReferenceExpression reference = (GrReferenceExpression)configureByFile("A.groovy")
assertNotNull(reference)
@@ -1,6 +1,6 @@
def foo(b, c) {
<begin>[].each (new Closure(this, this) {
void call() {
Void call() {
b.plus(c)
}
})<end>
@@ -12,7 +12,7 @@ def foo(b, c) {
private List testMethod(b, c) {
return [].each(new Closure(this, this) {
void call() {
Void call() {
b.plus(c)
}
})
@@ -6,6 +6,6 @@ def foo() {
testMethod()
}
private List testMethod() {
private List<Object> testMethod() {
return [].collect { it }
}
@@ -15,4 +15,4 @@
*/
Map<Integer, Double> map3
map3 = [].collectEntries {}
int <warning descr="Cannot assign 'Map' to 'int'">map4</warning> = [].collectEntries {}
int <warning descr="Cannot assign 'Map<K, V>' to 'int'">map4</warning> = [].collectEntries {}