Fix false positive ``protected-access`` in typing  (#4937)

* Fix false positive ``protected-access`` in typing
Class functions can return protected members which can then be passed
as arguments to other functions.
When using type hints in function definitions these raised a message
which they shouldn't do.
diff --git a/ChangeLog b/ChangeLog
index c0d6cb3..043639d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -43,6 +43,8 @@
 
   Closes #4936
 
+* Fix false positive for ``protected-access`` if a protected member is used in type hints of function definitions
+
 
 What's New in Pylint 2.10.3?
 ============================
diff --git a/doc/whatsnew/2.10.rst b/doc/whatsnew/2.10.rst
index 09fc528..85cba1c 100644
--- a/doc/whatsnew/2.10.rst
+++ b/doc/whatsnew/2.10.rst
@@ -82,9 +82,6 @@
 
 * ``consider-using-with`` is no longer triggered if a context manager is returned from a function.
 
-* Fix false positive for ``consider-using-with`` if a context manager is assigned to a
-  variable in different paths of control flow (e. g. if-else clause).
-
 * pylint does not crash with a traceback anymore when a file is problematic. It
   creates a template text file for opening an issue on the bug tracker instead.
   The linting can go on for other non problematic files instead of being impossible.
diff --git a/doc/whatsnew/2.11.rst b/doc/whatsnew/2.11.rst
index c233391..8524c0a 100644
--- a/doc/whatsnew/2.11.rst
+++ b/doc/whatsnew/2.11.rst
@@ -20,13 +20,11 @@
 Extensions
 ==========
 
-
 * Added new extension ``SetMembershipChecker`` with ``use-set-for-membership`` check:
   Emitted when using an in-place defined ``list`` or ``tuple`` to do a membership test. ``sets`` are better optimized for that.
 
   Closes #4776
 
-
 * ``CodeStyleChecker``
 
   * Added ``consider-using-assignment-expr``: Emitted when an assignment is directly followed by an if statement
@@ -40,8 +38,16 @@
 
 * Added ``py-version`` config key (if ``[MASTER]`` section). Used for version dependant checks.
   Will default to whatever Python version pylint is executed with.
+
 * The ``invalid-name`` message is now more detailed when using multiple naming style regexes.
 
+* Fix false positive for ``consider-using-with`` if a context manager is assigned to a
+  variable in different paths of control flow (e. g. if-else clause).
+
+  Closes #4751
+
 * Fix false positive for ``function-redefined`` for simple type annotations
 
   Closes #4936
+
+* Fix false positive for ``protected-access`` if a protected member is used in type hints of function definitions
diff --git a/pylint/checkers/classes.py b/pylint/checkers/classes.py
index 3b18b7e..0b37a9f 100644
--- a/pylint/checkers/classes.py
+++ b/pylint/checkers/classes.py
@@ -52,7 +52,7 @@
 import astroid
 from astroid import nodes
 
-from pylint.checkers import BaseChecker
+from pylint.checkers import BaseChecker, utils
 from pylint.checkers.utils import (
     PYMETHODS,
     SPECIAL_METHODS_PARAMS,
@@ -1563,7 +1563,7 @@
         if any(method_name == member.name for member in parent_class.mymethods()):
             self.add_message(msg, node=node.targets[0])
 
-    def _check_protected_attribute_access(self, node):
+    def _check_protected_attribute_access(self, node: nodes.Attribute):
         """Given an attribute access node (set or get), check if attribute
         access is legitimate. Call _check_first_attr with node before calling
         this method. Valid cases are:
@@ -1586,6 +1586,10 @@
             # through the class object or through super
             callee = node.expr.as_string()
 
+            # Typing annotations in funciton definitions can include protected members
+            if utils.is_node_in_type_annotation_context(node):
+                return
+
             # We are not in a class, no remaining valid case
             if klass is None:
                 self.add_message("protected-access", node=node, args=attrname)
diff --git a/tests/functional/a/access/access_to_protected_members_typing.py b/tests/functional/a/access/access_to_protected_members_typing.py
new file mode 100644
index 0000000..4e5eee4
--- /dev/null
+++ b/tests/functional/a/access/access_to_protected_members_typing.py
@@ -0,0 +1,32 @@
+# pylint: disable=too-few-public-methods, invalid-name
+"""Test typing with a protected member"""
+from __future__ import annotations
+
+
+class MyClass:
+    """Class with protected members."""
+
+    class _Inner_Class:
+        """Inner class with protected members."""
+
+        def __init__(self) -> None:
+            self.data = 1
+
+        def return_data(self) -> int:
+            """Return data"""
+            return self.data
+
+    def return_private_class(self) -> MyClass._Inner_Class:
+        """Doing nothing."""
+        return self._Inner_Class()
+
+
+def access_protected_class(data: MyClass._Inner_Class) -> int:
+    """Function that always receives a protected class."""
+    return data.return_data() + 1
+
+
+def pass_protected_class() -> None:
+    """Function that passes a protected class to another function."""
+    data_value = access_protected_class(MyClass().return_private_class())
+    print(data_value)
diff --git a/tests/functional/a/access/access_to_protected_members_typing.rc b/tests/functional/a/access/access_to_protected_members_typing.rc
new file mode 100644
index 0000000..a17bb22
--- /dev/null
+++ b/tests/functional/a/access/access_to_protected_members_typing.rc
@@ -0,0 +1,2 @@
+[testoptions]
+min_pyver=3.7
diff --git a/tests/functional/a/access/access_to_protected_members_typing.txt b/tests/functional/a/access/access_to_protected_members_typing.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/functional/a/access/access_to_protected_members_typing.txt