private function checkAccessError(XRef_IProjectDatabase $db, $class_name, $key, $name, $from_class, $is_static, $check_parent_only)
 {
     /** @var $lr XRef_LookupResult */
     $lr = null;
     switch ($key) {
         case 'property':
             $lr = $db->lookupProperty($class_name, $name, $check_parent_only);
             break;
         case 'method':
             $lr = $db->lookupMethod($class_name, $name, $check_parent_only);
             break;
         case 'constant':
             $lr = $db->lookupConstant($class_name, $name, $check_parent_only);
             break;
     }
     if (!$lr || $lr->code == XRef_LookupResult::NOT_FOUND) {
         // definition not found
         if ($key == 'property') {
             $lr_magic = $db->lookupMethod($class_name, '__get', $check_parent_only);
             if ($lr_magic->code == XRef_LookupResult::FOUND) {
                 // can't validate reference to (missing) property,
                 // because it or it's base class has method '__get'
                 return array(self::E_MAGIC_GETTER, $class_name, array($class_name));
             }
         }
         if ($key == 'method' && $name == '__construct') {
             // ok, php creates a default constructor
         } else {
             switch ($key) {
                 case 'method':
                     $error_code = self::E_ACCESS_TO_UNDEFINED_METHOD;
                     break;
                 case 'constant':
                     $error_code = self::E_ACCESS_TO_UNDEFINED_CONSTANT;
                     break;
                 case 'property':
                     $error_code = self::E_ACCESS_TO_UNDEFINED_PROPERTY;
                     break;
                 default:
                     throw new Exception($key);
             }
             $uniq = "{$from_class}/{$class_name}/{$key}/{$name}";
             return array($error_code, $uniq, array($name, $class_name));
         }
     } elseif ($lr->code == XRef_LookupResult::CLASS_MISSING) {
         // definition not found because definition of either class or its base class is missing
         $missing_class_name = $lr->missingClassName;
         if (!isset($this->ignore_missing_classes[strtolower($missing_class_name)])) {
             if (strtolower($missing_class_name) == strtolower($class_name)) {
                 // class definition is missing
                 return array(self::E_MISSING_CLASS, $class_name, array($class_name));
             } else {
                 // base class definition is missing
                 return array(self::E_MISSING_BASE_CLASS, $class_name, array($class_name, $missing_class_name));
             }
         }
     } else {
         // got definition, check access
         $attributes = $lr->elements[0]->attributes;
         $found_in_class = $lr->elements[0]->className;
         // 1. static vs. instance
         if ($key != 'constant' && !($key == 'method' && $name == '__construct')) {
             if ($is_static) {
                 if (!XRef::isStatic($attributes)) {
                     // reference to instance method or property as if they were static
                     if ($key == 'method' || $key == 'property') {
                         return array(self::E_ACCESS_INSTANCE_AS_STATIC, "{$from_class}/{$class_name}/{$key}/{$name}", array($name, $found_in_class));
                     } else {
                         throw new Exception($key);
                     }
                 }
             } else {
                 if ($key == 'property' && XRef::isStatic($attributes)) {
                     // reference to static property as if it were instance
                     return array(self::E_ACCESS_STATIC_AS_INSTANCE, "{$from_class}/{$class_name}/{$name}", array($name, $found_in_class));
                 }
             }
         }
         // 2. public, private, protected
         if (XRef::isPublic($attributes)) {
             // ok
         } elseif (XRef::isPrivate($attributes)) {
             if (!$from_class || strtolower($found_in_class) != strtolower($from_class)) {
                 // attempt to access a private member (method or property) of class $found_in_class
                 // from $class_name
                 return array(self::E_PRIVATE_MEMBER, "{$from_class}/{$class_name}/{$name}", array($name, $found_in_class));
             }
         } elseif (XRef::isProtected($attributes)) {
             if (!$from_class || !$this->isSubclassOf($from_class, $found_in_class)) {
                 return array(self::E_PROTECTED_MEMBER, "{$from_class}/{$class_name}/{$name}", array($name, $found_in_class));
             }
         } else {
             // shouldn't be here
             throw new Exception("Should be public? {$attributes}");
         }
         // 3. check that the called method is defined, not only declared.
         // however, allow to call declared methods from abstract classes and traits
         if ($key == 'method' && is_null($lr->elements[0]->bodyStarts)) {
             $lc = $db->lookupClass($from_class);
             if ($lc && $lc->code == XRef_LookupResult::FOUND && ($lc->elements[0]->isAbstract || $lc->elements[0]->kind == T_TRAIT)) {
                 // ok, allow to call abstract method
             } else {
                 $found_in_class = $lr->elements[0]->className;
                 return array(self::E_ACCESS_TO_UNDEFINED_METHOD, "{$from_class}/{$found_in_class}/{$name}", array($name, $found_in_class));
             }
         }
     }
     return;
 }