From b4c21038f3685f6be76ae0228b33f91c536f5d8e Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Tue, 13 Mar 2018 17:28:51 +0300 Subject: [PATCH] Don't inspect protocol attributes inherited from non-protocols (PY-28720) --- .../python/codeInsight/typing/PyProtocols.kt | 11 ++++- .../PyTypeCheckerInspectionTest.java | 43 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/typing/PyProtocols.kt b/python/src/com/jetbrains/python/codeInsight/typing/PyProtocols.kt index ed9df849e69a..dee3ee619344 100644 --- a/python/src/com/jetbrains/python/codeInsight/typing/PyProtocols.kt +++ b/python/src/com/jetbrains/python/codeInsight/typing/PyProtocols.kt @@ -1,11 +1,11 @@ // Copyright 2000-2018 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.codeInsight.typing -import com.intellij.openapi.util.io.FileUtil import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider.PROTOCOL import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider.PROTOCOL_EXT import com.jetbrains.python.psi.AccessDirection import com.jetbrains.python.psi.PyClass +import com.jetbrains.python.psi.PyPossibleClassMember import com.jetbrains.python.psi.PyTypedElement import com.jetbrains.python.psi.resolve.PyResolveContext import com.jetbrains.python.psi.resolve.RatedResolveResult @@ -35,7 +35,14 @@ fun inspectProtocolSubclass(protocol: PyClassType, subclass: PyClassType, contex protocol.toInstance().visitMembers( { e -> - if (e is PyTypedElement && FileUtil.getNameWithoutExtension(e.containingFile.name) != "typing_extensions") { + if (e is PyTypedElement) { + if (e is PyPossibleClassMember) { + val cls = e.containingClass + if (cls != null && !isProtocol(cls, context)) { + return@visitMembers true + } + } + val name = e.name ?: return@visitMembers true val resolveResults = subclassAsInstance.resolveMember(name, null, AccessDirection.READ, resolveContext) diff --git a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java index 87c260069fc1..e2d22ab1d7cf 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java @@ -521,6 +521,49 @@ public class PyTypeCheckerInspectionTest extends PyInspectionTestCase { runWithLanguageLevel(LanguageLevel.PYTHON35, this::doTest); } + // PY-28720 + public void testOverriddenBuiltinMethodAgainstTypingProtocol() { + runWithLanguageLevel( + LanguageLevel.PYTHON35, + () -> + doTestByText("import typing\n" + + "class Proto(typing.Protocol):\n" + + " def function(self) -> None:\n" + + " pass\n" + + "class Cls:\n" + + " def __eq__(self, other) -> 'Cls':\n" + + " pass\n" + + " def function(self) -> None:\n" + + " pass\n" + + "def method(p: Proto):\n" + + " pass\n" + + "method(Cls())") + ); + } + + // PY-28720 + public void testAgainstInvalidProtocol() { + runWithLanguageLevel( + LanguageLevel.PYTHON34, + () -> + doTestByText( + "from typing import Any, Protocol\n" + + "class B:\n" + + " def foo(self):\n" + + " ...\n" + + "class C(B, Protocol):\n" + + " def bar(self):\n" + + " ...\n" + + "class Bar:\n" + + " def bar(self):\n" + + " ...\n" + + "def f(x: C) -> Any:\n" + + " ...\n" + + "f(Bar())" + ) + ); + } + // PY-23161 public void testGenericWithTypeVarBounds() { runWithLanguageLevel(LanguageLevel.PYTHON35, this::doTest);