def _check_protected_attribute_access(self, node):
attrname = node.attrname<EOL>if (<EOL>is_attr_protected(attrname)<EOL>and attrname not in self.config.exclude_protected<EOL>):<EOL><INDENT>klass = node_frame_class(node)<EOL>callee = node.expr.as_string()<EOL>if klass is None:<EOL><INDENT>self.add_message("<STR_LIT>", node=node, args=attrname)<EOL>return<EOL><DEDENT>if (<EOL>isinstance(node.expr, astroid.Call)<EOL>and isinstance(node.expr.func, astroid.Name)<EOL>and node.expr.func.name == "<STR_LIT>"<EOL>):<EOL><INDENT>return<EOL><DEDENT>if self._is_type_self_call(node.expr):<EOL><INDENT>return<EOL><DEDENT>if not (callee == klass.name or callee in klass.basenames):<EOL><INDENT>stmt = node.parent.statement()<EOL>if (<EOL>isinstance(stmt, astroid.Assign)<EOL>and len(stmt.targets) == <NUM_LIT:1><EOL>and isinstance(stmt.targets[<NUM_LIT:0>], astroid.AssignName)<EOL>):<EOL><INDENT>name = stmt.targets[<NUM_LIT:0>].name<EOL>if _is_attribute_property(name, klass):<EOL><INDENT>return<EOL><DEDENT><DEDENT>self.add_message("<STR_LIT>", node=node, args=attrname)<EOL><DEDENT><DEDENT>
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:
        * self._attr in a method or cls._attr in a classmethod. Checked by
        _check_first_attr.
        * Klass._attr inside "Klass" class.
        * Klass2._attr inside "Klass" class when Klass2 is a base class of
            Klass.