diff --git a/python-checks/src/main/java/org/sonar/python/checks/FunctionReturnTypeCheck.java b/python-checks/src/main/java/org/sonar/python/checks/FunctionReturnTypeCheck.java index 75c257812b..4160ff6721 100644 --- a/python-checks/src/main/java/org/sonar/python/checks/FunctionReturnTypeCheck.java +++ b/python-checks/src/main/java/org/sonar/python/checks/FunctionReturnTypeCheck.java @@ -146,7 +146,8 @@ public void visitReturnStatement(ReturnStatement returnStatement) { Expression expression = expressions.get(0); InferredType inferredType = expression.type(); if (returnType.mustBeOrExtend("typing.TypedDict")) { - // Avoid FPs for TypedDict + // TODO SONARPY-1340: This is a workaround to avoid FPs with TypedDict, however, this produces false-negatives. We should have a more + // fine-grained solution to check dictionaries against TypedDict. return; } diff --git a/python-checks/src/test/resources/checks/argumentType.py b/python-checks/src/test/resources/checks/argumentType.py index e9c67fb6bd..1a68de939e 100644 --- a/python-checks/src/test/resources/checks/argumentType.py +++ b/python-checks/src/test/resources/checks/argumentType.py @@ -6,7 +6,7 @@ import _heapq import imaplib from unittest.mock import Mock -from typing import Dict, Tuple, Set +from typing import Dict, Tuple, Set, TypedDict from collections import OrderedDict, Counter from emoji import emojize @@ -130,6 +130,15 @@ def with_tuple(a : Tuple[int]): ... with_tuple((42, 43)) # OK with_tuple(42) # Noncompliant + class Movie(TypedDict): + name: str + year: int + + def with_typed_dict(movie: Movie): ... + with_typed_dict({'name': "Ad Astra", 'year': 2019}) # Ok + with_typed_dict({'name': "Ad Astra", 'year': 2019, 'other': 'foo'}) # FN + + def edge_cases(): ambiguous = 42 def ambiguous(a: str): ... diff --git a/python-frontend/src/main/java/org/sonar/python/types/InferredTypes.java b/python-frontend/src/main/java/org/sonar/python/types/InferredTypes.java index 6e64a23774..3d6a858327 100644 --- a/python-frontend/src/main/java/org/sonar/python/types/InferredTypes.java +++ b/python-frontend/src/main/java/org/sonar/python/types/InferredTypes.java @@ -100,6 +100,9 @@ public class InferredTypes { // str <=> bytes equivalence only for Python2 HARDCODED_COMPATIBLE_TYPES.put(BuiltinTypes.STR, new HashSet<>(Arrays.asList(UNICODE, BYTES))); HARDCODED_COMPATIBLE_TYPES.put(BYTES, new HashSet<>(Collections.singletonList(BuiltinTypes.STR))); + // TODO SONARPY-1340: This is a workaround to avoid FPs with TypedDict, however, this produces false-negatives. We should have a more + // fine-grained solution to check dictionaries against TypedDict. + HARDCODED_COMPATIBLE_TYPES.put(BuiltinTypes.DICT, Set.of("typing.TypedDict")); } protected static final Map BUILTINS_TYPE_CATEGORY = new HashMap<>();