def isAccessible()

in scala/scala-impl/src/org/jetbrains/plugins/scala/lang/resolve/ResolveUtils.scala [79:348]


  def isAccessible(memb: PsiMember, _place: PsiElement, forCompletion: Boolean = false): Boolean =
    isAccessibleWithNewModifiers(memb, _place, memb.getModifierList, forCompletion)


  def isAccessibleWithNewModifiers(memb: PsiMember, _place: PsiElement, modifierList: PsiModifierList, forCompletion: Boolean = false): Boolean = {
    if (!memb.isValid || !_place.isValid) {
      return false
    }

    var place = _place
    memb match {
      case b: ScBindingPattern =>
        b.nameContext match {
          case memb: ScMember => return isAccessibleWithNewModifiers(memb, place, modifierList)
          case _ => return true
        }
      //todo: ugly workaround, probably FakePsiMethod is better to remove?
      case FakePsiMethod(method: PsiMember) => return isAccessibleWithNewModifiers(method, place, modifierList)
      case _: FakePsiMethod =>
      case _ =>
    }
    if (place.getLanguage == JavaLanguage.INSTANCE) {
      return JavaResolveUtil.isAccessible(memb, memb.containingClass, modifierList, place, null, null)
    }

    import org.jetbrains.plugins.scala.lang.psi.ScalaPsiUtil.getPlaceTd
    //this is to make place and member on same level (resolve from library source)
    var member: PsiMember = memb
    memb.getContainingFile match {
      case file: ScalaFile if file.isCompiled =>
        place.getContainingFile match {
          case file: ScalaFile if file.isCompiled =>
          case _ if !member.isInstanceOf[ScMember] =>
            member = member.getOriginalElement.asInstanceOf[PsiMember]
          case _ => //todo: is it neccessary? added to avoid performance and other problems
        }
      case _ =>
    }
    if (forCompletion && place != null) {
      val originalFile: PsiFile = place.getContainingFile.getOriginalFile
      if (originalFile == member.getContainingFile) {
        val newPlace = originalFile.findElementAt(place.getTextRange.getStartOffset)
        place = newPlace
      }
    }

    def checkProtected(td: PsiClass, withCompanion: Boolean): Boolean = {
      val isConstr = member match {
        case m: PsiMethod => m.isConstructor
        case _ => false
      }
      var placeTd: ScTemplateDefinition = getPlaceTd(place, isConstr)
      if (isConstr) {
        if (placeTd != null && !placeTd.is[ScTypeDefinition] && placeTd.extendsBlock.templateBody.isEmpty) {
          placeTd = getPlaceTd(placeTd)
        } else if (placeTd != null) {
          if (td != null && isInheritorOrSelfOrSame(placeTd, td)) return true
        }
        while (placeTd != null) {
          if (td == placeTd) return true
          if (getCompanionModule(placeTd).contains(td)) return true
          placeTd = getPlaceTd(placeTd)
        }
        return false
      }
      while (placeTd != null) {
        if (td != null && isInheritorOrSelfOrSame(placeTd, td)) return true
        if (withCompanion &&
          td != null
          && getCompanionModule(placeTd).exists(isInheritorDeep(_, td))) return true
        placeTd = getPlaceTd(placeTd)
      }
      false
    }

    (member, modifierList) match {
      case (scMember: ScMember, scModifierList: ScModifierList) =>
        // if member is a scala member, the modifier list also have to be a scala one
        scModifierList.accessModifier match {
          case None => true
          case Some(accessModifier: ScAccessModifier) =>
            if (accessModifier.isPrivate) {
              if (accessModifier.isThis) {
                val containingClass = scMember.containingClass
                if (containingClass == null) return true

                if (scModifierList.hasModifierProperty("implicit"))
                  return PsiTreeUtil.isContextAncestor(containingClass, place, false)
                /*
                ScalaRefernce.pdf:
                  A member M marked with this modifier can be accessed only from
                  within the object in which it is defined.
                */
                place match {
                  case ref: ScReference =>
                    ref.qualifier match {
                      case None =>
                        return PsiTreeUtil.isContextAncestor(containingClass, place, false)
                      case Some(t: ScThisReference) =>
                        return t.refTemplate match {
                          case Some(templ) => templ == containingClass
                          case _ => PsiTreeUtil.isContextAncestor(containingClass, place, false)
                        }
                      case Some(ref: ScReference) =>
                        val resolve = ref.resolve()
                        if (containingClass.extendsBlock.selfTypeElement.contains(resolve)) return true
                        else return false
                      case _ => return false
                    }
                  case _ =>
                    return PsiTreeUtil.isContextAncestor(containingClass, place, false)
                }
              }
              val ref = accessModifier.getReference
              if (ref != null) {
                val bind = ref.resolve
                if (bind == null) return true
                def processPackage(packageName: String): Boolean = {
                  val placePackageName = ScalaPsiUtil.getPlacePackageName(place)
                  if (placePackageName == null)
                    false
                  else
                    packageContains(packageName, placePackageName)
                }
                bind match {
                  case td: ScTemplateDefinition if smartContextAncestor(td, place, checkCompanion = true) =>
                    true
                  case obj: ScObject =>
                    obj.isPackageObject && processPackage(obj.qualifiedName)
                  case pack: PsiPackage =>
                    val packageName = pack.getQualifiedName
                    processPackage(packageName)
                  case _ => true
                }
              }
              else {
                /*
                ScalaReference.pdf:
                  Such members can be accessed only from within the directly enclosing
                  template and its companion module or companion class
                */
                val enclosing = PsiTreeUtil.getContextOfType(scMember, true,
                  classOf[ScalaFile], classOf[ScPackaging], classOf[ScTemplateDefinition])
                enclosing match {
                  case td: ScTemplateDefinition =>
                    smartContextAncestor(td, place, checkCompanion = true)
                  case _ =>
                    place.contexts.find {
                      case _: ScPackaging | _: ScalaFile => true
                      case o: ScObject if o.isPackageObject => true
                      case _ => false
                    } match {
                      case None => false // not Scala
                      case Some(placeEnclosing) =>
                        def packaging(element: PsiElement) = element match {
                          case p: ScPackaging => p.fullPackageName
                          case o: ScObject =>
                            val packageName = o.getParent.asOptionOf[ScPackaging].map(_.fullPackageName).mkString
                            s"$packageName.${o.name}"
                          case _ => ""
                        }

                        packageContains(packaging(enclosing), packaging(placeEnclosing))
                    }
                }
              }
            } else { //todo: it's wrong if reference after not appropriate class type
              val withCompanion = !accessModifier.isThis
              val ref = accessModifier.getReference
              if (ref != null) {
                val bind = ref.resolve
                if (bind == null) return true

                def processPackage(packageName: String): Option[Boolean] = {
                  val placePackageName = ScalaPsiUtil.getPlacePackageName(place)
                  if (placePackageName == null)
                    Some(false)
                  else if (packageContains(packageName, placePackageName))
                    Some(true)
                  else
                    None
                }

                bind match {
                  case td: ScTemplateDefinition =>
                    if (smartContextAncestor(td, place, checkCompanion = true)) return true
                    td match {
                      case o: ScObject if o.isPackageObject =>
                        processPackage(o.qualifiedName) match {
                          case Some(x) => return x
                          case None =>
                        }
                      case _ =>
                    }
                  case pack: PsiPackage => //like private (nothing related to real life)
                    val packageName = pack.getQualifiedName
                    processPackage(packageName) match {
                      case Some(x) => return x
                      case None =>
                    }
                  case _ => return true
                }
              }

              if (accessModifier.isThis) {
                place match {
                  case ref: ScReference =>
                    ref.qualifier match {
                      case None =>
                      case Some(_: ScThisReference) =>
                      case Some(_: ScSuperReference) =>
                      case Some(ResolvesTo(_: ScSelfTypeElement)) =>
                        val enclosing = PsiTreeUtil.getContextOfType(scMember, true, classOf[ScTemplateDefinition])
                        if (enclosing == null) return false
                      case _ => return false
                    }
                  case _ =>
                }
              }

              val enclosing = PsiTreeUtil.getContextOfType(scMember, true, classOf[ScalaFile], classOf[ScPackaging], classOf[ScTemplateDefinition])
              assert(enclosing != null, s"Enclosing is null in file ${scMember.getContainingFile.getName}:\n${scMember.getContainingFile.getText}")

              enclosing match {
                case td: ScTypeDefinition =>
                  if (smartContextAncestor(td, place, withCompanion))
                    true
                  else
                    checkProtected(td, withCompanion)
                case td: ScTemplateDefinition =>
                  //it'd anonymous class, has access only inside
                  PsiTreeUtil.isContextAncestor(td, place, false)
                case _ =>
                  //same as for private
                  val packageName = enclosing match {
                    case _: ScalaFile => ""
                    case packaging: ScPackaging => packaging.fullPackageName
                  }
                  val placeEnclosing: PsiElement = PsiTreeUtil.getContextOfType(place, true, classOf[ScPackaging], classOf[ScalaFile])
                  if (placeEnclosing == null) return false //not Scala
                  val placePackageName = placeEnclosing match {
                    case _: ScalaFile => ""
                    case pack: ScPackaging => pack.fullPackageName
                  }
                  packageContains(packageName, placePackageName)
              }
            }
        }
      case _ => //non-scala member, Java code
        if (modifierList.hasModifierProperty(PsiModifier.PUBLIC)) true
        else if (modifierList.hasModifierProperty(PsiModifier.PRIVATE)) false
        else if (modifierList.hasModifierProperty(PsiModifier.PROTECTED) &&
          checkProtected(member.containingClass, withCompanion = true)) true
        else {
          val containingFile = member.getContainingFile
          val packageName = containingFile match {
            case _: ScalaFile =>
              throw new AssertionError("not expecting scala file here")
            case f: PsiClassOwner => f.getPackageName
            case _ =>
              return false
          }
          val placePackageName = ScalaPsiUtil.getPlacePackageName(place)
          if (placePackageName == null)
            false
          else
            packageContains(packageName, placePackageName)
        }
    }
  }