Suppress unresolved reference insp for unittest.mock.patch members.

Py3UnresolvedReferencesInspectionTest.testMockPatchObject fixed.
This commit is contained in:
Semyon Proshev
2017-10-23 19:51:10 +03:00
parent 542ba81a14
commit d272b82bd8
2 changed files with 35 additions and 42 deletions
@@ -4,19 +4,17 @@ package com.jetbrains.python.codeInsight.stdlib;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiElement;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.PyCustomMember;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
import com.jetbrains.python.psi.types.PyClassMembersProviderBase;
import com.jetbrains.python.psi.types.PyClassType;
import com.jetbrains.python.psi.types.PyFunctionType;
import com.jetbrains.python.psi.types.TypeEvalContext;
import com.jetbrains.python.psi.types.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* @author yole
@@ -27,7 +25,7 @@ public class PyStdlibClassMembersProvider extends PyClassMembersProviderBase {
private static final Key<List<PyCustomMember>> SOCKET_MEMBERS_KEY = Key.create("socket.members");
@NotNull
private static final List<PyCustomMember> MOCK_PATCH_MEMBERS = calcMockPatchMembers();
public static final List<PyCustomMember> MOCK_PATCH_MEMBERS = calcMockPatchMembers();
@NotNull
@Override
@@ -45,8 +43,8 @@ public class PyStdlibClassMembersProvider extends PyClassMembersProviderBase {
}
if (location instanceof PyReferenceExpression) {
final PyCallable mockPatchCallable = mockPatchCallable(classType, ((PyReferenceExpression)location).getQualifier(), context);
if (mockPatchCallable != null) {
final PyExpression qualifier = ((PyReferenceExpression)location).getQualifier();
if (qualifier instanceof PyReferenceExpression && referenceToMockPatch((PyReferenceExpression)qualifier, context)) {
return MOCK_PATCH_MEMBERS;
}
}
@@ -56,8 +54,8 @@ public class PyStdlibClassMembersProvider extends PyClassMembersProviderBase {
@Override
public PsiElement resolveMember(PyClassType clazz, String name, @Nullable PsiElement location, @NotNull PyResolveContext resolveContext) {
final PyCallable mockPatchCallable = mockPatchCallable(clazz, location, resolveContext.getTypeEvalContext());
if (mockPatchCallable != null && location!= null) {
final TypeEvalContext context = resolveContext.getTypeEvalContext();
if (location instanceof PyReferenceExpression && referenceToMockPatch((PyReferenceExpression)location, context)) {
for (PyCustomMember member : MOCK_PATCH_MEMBERS) {
if (name.equals(member.getName())) {
return member.resolve(location, resolveContext);
@@ -68,6 +66,14 @@ public class PyStdlibClassMembersProvider extends PyClassMembersProviderBase {
return super.resolveMember(clazz, name, location, resolveContext);
}
public static boolean referenceToMockPatch(@NotNull PyReferenceExpression referenceExpression, @NotNull TypeEvalContext context) {
final PyType type = context.getType(referenceExpression);
if (type instanceof PyFunctionType) {
return "unittest.mock.patch".equals(((PyFunctionType)type).getCallable().getQualifiedName());
}
return false;
}
private static List<PyCustomMember> calcSocketMembers(PyFile socketFile) {
final List<PyCustomMember> result = new ArrayList<>();
addMethodsFromAttr(socketFile, result, "_socketmethods");
@@ -75,21 +81,6 @@ public class PyStdlibClassMembersProvider extends PyClassMembersProviderBase {
return result;
}
@Nullable
private static PyCallable mockPatchCallable(@NotNull PyClassType classType, @Nullable PsiElement location, @NotNull TypeEvalContext context) {
if (!PyNames.TYPES_FUNCTION_TYPE.equals(classType.getClassQName())) {
return null;
}
return Optional
.ofNullable(PyUtil.as(location, PyReferenceExpression.class))
.map(context::getType)
.map(qualifierType -> PyUtil.as(qualifierType, PyFunctionType.class))
.map(PyFunctionType::getCallable)
.filter(callable -> "unittest.mock.patch".equals(QualifiedNameFinder.getQualifiedName(callable)))
.orElse(null);
}
@NotNull
private static List<PyCustomMember> calcMockPatchMembers() {
final String[] members = new String[]{"object", "dict", "multiple", "stopall", "TEST_PREFIX"};
@@ -1,24 +1,14 @@
/*
* 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.jetbrains.python.inspections.stdlib
import com.intellij.psi.PsiReference
import com.jetbrains.python.PyNames
import com.jetbrains.python.codeInsight.stdlib.PyNamedTupleType
import com.jetbrains.python.codeInsight.stdlib.PyStdlibClassMembersProvider
import com.jetbrains.python.inspections.PyInspectionExtension
import com.jetbrains.python.psi.PyElement
import com.jetbrains.python.psi.PyFunction
import com.jetbrains.python.psi.PyReferenceExpression
import com.jetbrains.python.psi.types.PyClassLikeType
import com.jetbrains.python.psi.types.PyType
import com.jetbrains.python.psi.types.TypeEvalContext
@@ -37,4 +27,16 @@ class PyStdlibInspectionExtension : PyInspectionExtension() {
return false
}
override fun ignoreUnresolvedReference(node: PyElement, reference: PsiReference): Boolean {
if (node is PyReferenceExpression && node.isQualified) {
val qualifier = node.qualifier
if (qualifier is PyReferenceExpression) {
return PyStdlibClassMembersProvider.referenceToMockPatch(qualifier, TypeEvalContext.codeInsightFallback(qualifier.project)) &&
PyStdlibClassMembersProvider.MOCK_PATCH_MEMBERS.find { it.name == node.name } != null
}
}
return false
}
}