private def superParentPattern()

in scala/scala-impl/src/org/jetbrains/plugins/scala/lang/completion/ScalaSmartCompletionContributor.scala [330:609]


  private def superParentPattern(clazz: Class[_ <: ScalaPsiElement]) =
    identifierWithParentsPattern(classOf[ScReferenceExpression], clazz) ||
      identifierWithParentsPattern(classOf[ScReferenceExpression], classOf[ScReferenceExpression], clazz)

  private def acceptTypes(types: Iterable[ScType], ref: ScReferenceExpression)
                         (implicit parameters: CompletionParameters, result: CompletionResultSet, place: PsiElement): Unit =
    acceptTypes(
      types,
      ref.getVariants,
      result,
      parameters.getInvocationCount > 1,
      ScalaCompletionUtil.hasNoQualifier(ref),
      parameters.getOriginalPosition,
      parameters.getCompletionType == CompletionType.SMART
    )

  private def acceptTypes(typez: Iterable[ScType], variants: Array[Object],
                          result: CompletionResultSet,
                          secondCompletion: Boolean,
                          completeThis: Boolean,
                          originalPlace: PsiElement,
                          isSmart: Boolean)
                         (implicit place: PsiElement): Unit = {
    implicit val projectContext: Project = place.getProject
    implicit val context: Context = Context(place)

    if (typez.isEmpty || typez.forall(_ == Nothing)) return

    def applyVariant(variant: Object, checkForSecondCompletion: Boolean = false): Unit = {

      def handleVariant(scalaLookupItem: ScalaLookupItem, chainVariant: Boolean = false): Unit = {
        val elemToAdd = variant.asInstanceOf[LookupElement]
        if (isAccessible(scalaLookupItem) && !scalaLookupItem.isNamedParameterOrAssignment) {
          def checkType(_tp: ScType, _subst: ScSubstitutor, chainCompletion: Boolean, etaExpanded: Boolean = false): Boolean = {
            val tp = _subst(_tp)
            var elementAdded = false
            val scType = scalaLookupItem.substitutor(tp)
            if (!scType.equiv(Nothing) && typez.exists(scType conforms _)) {
              elementAdded = true
              if (etaExpanded) scalaLookupItem.etaExpanded = true
              result.addElement(PrioritizedLookupElement.withPriority(elemToAdd, 1))
            } else {
              typez.foreach {
                case ParameterizedType(tpe, Seq(arg)) if !elementAdded =>
                  tpe.extractClass match {
                    case Some(clazz) if clazz.qualifiedName == "scala.Option" || clazz.qualifiedName == "scala.Some" =>
                      if (!scType.equiv(Nothing) && scType.conforms(arg)) {
                        scalaLookupItem.someSmartCompletion = true
                        if (etaExpanded) scalaLookupItem.etaExpanded = true
                        result.addElement(elemToAdd)
                        elementAdded = true
                      }
                    case _ =>
                  }
                case _ =>
              }
            }
            if (!elementAdded && chainCompletion && secondCompletion) {
              val processor = new CompletionProcessor(StdKinds.refExprLastRef, place) {

                override protected def postProcess(result: ScalaResolveResult): Unit = {
                  if (!result.isNamedParameter) {
                    val variant = new ScalaChainLookupElement(
                      result.createLookupElement(),
                      scalaLookupItem
                    )

                    applyVariant(variant)
                  }
                }
              }
              processor.processType(scalaLookupItem.substitutor(_tp), place)
              processor.candidatesS
            }
            elementAdded
          }

          def checkTyped(typed: PsiNamedElement with Typeable): Unit = {
            if (!PsiTreeUtil.isContextAncestor(typed.nameContext, place, false) &&
              (originalPlace == null || !PsiTreeUtil.isContextAncestor(typed.nameContext, originalPlace, false)))
              for (tt <- typed.`type`()) checkType(tt, ScSubstitutor.empty, checkForSecondCompletion)
          }

          scalaLookupItem.getPsiElement match {
            case clazz: PsiClass if isExcluded(clazz) =>
            case fun: ScSyntheticFunction =>
              val second = checkForSecondCompletion && fun.paramClauses.flatten.isEmpty
              checkType(fun.retType, ScSubstitutor.empty, second)
            case fun: ScFunction =>
              if (fun.containingClass != null && fun.containingClass.qualifiedName == "scala.Predef") {
                fun.name match {
                  case "implicitly" | "identity" | "locally" => return
                  case _ =>
                }
              }
              val infer = if (chainVariant) ScSubstitutor.empty else ScalaPsiUtil.undefineMethodTypeParams(fun)
              val second = checkForSecondCompletion &&
                fun.paramClauses.clauses.filterNot(_.isImplicit).forall(_.parameters.isEmpty)
              val added = fun.returnType match {
                case Right(tp) => checkType(tp, infer, second)
                case _ => false
              }
              if (!added) {
                fun.`type`() match {
                  case Right(tp) => checkType(tp, infer, second, etaExpanded = true)
                  case _ =>
                }
              }
            case method: PsiMethod =>
              val second = checkForSecondCompletion && method.getParameterList.getParametersCount == 0
              val infer = if (chainVariant) ScSubstitutor.empty else ScalaPsiUtil.undefineMethodTypeParams(method)
              checkType(method.getReturnType.toScType(), infer, second)
            case typed: ScTypedDefinition => checkTyped(typed)
            case typed: ScEnumCase => checkTyped(typed)
            // TODO: java classes?
            case typed: ScTypeDefinition => checkTyped(typed)
            case f: PsiField =>
              checkType(f.getType.toScType(), ScSubstitutor.empty, checkForSecondCompletion)
            case _ =>
          }
        }
      }

      variant match {
        case el: ScalaLookupItem => handleVariant(el)
        case ch: ScalaChainLookupElement => handleVariant(ch.getDelegate, chainVariant = true)
        case _ =>
      }
    }

    place.getContext match {
      case ref: ScReferenceExpression if ref.smartQualifier.isEmpty =>
        //enum and factory methods
        val iterator = typez.iterator
        while (iterator.hasNext) {
          val tp = iterator.next() match {
            // SCL-21582: e.g.: `A1_ >: WeekDayScala3` -> `WeekDayScala3`
            case t: ScAbstractType => t.removeAbstracts
            case t => t
          }

          // todo unify with SbtCompletionContributor.collectAndApplyVariants
          def checkObject(containingClass: ScObject): Unit =
            if (isAccessible(containingClass) && ScalaPsiUtil.hasStablePath(containingClass)) {
              containingClass.membersWithSynthetic.flatMap {
                case function: ScFunction => Seq(function)
                case v: ScValueOrVariable => v.declaredElements
                case obj: ScObject => Seq(obj)
                case _ => Seq.empty
              }.map {
                createLookupElementWithPrefix(_, containingClass)
              }.foreach {
                applyVariant(_)
              }
            }

          def checkTypeProjection(tp: ScType): Unit = {
            tp match {
              case ScProjectionType(proj, _: ScTypeAlias | _: ScClass | _: ScTrait) =>
                proj.extractClass match {
                  case Some(o: ScObject) => checkObject(o)
                  case _ =>
                }
              case _ =>
            }
          }

          @tailrec
          def checkType(tp: ScType): Unit = {
            if (!isSmart) { // SCL-19749
              tp.extractClass match {
                case Some(scEnum: ScEnum) =>
                  if (isAccessible(scEnum)) {
                    val cases = scEnum.cases
                    // cases that are already in scope will be added by ScalaBasicCompletionContributor (SCL-22855)
                    val casesFiltered = cases.filterNot(isAccessibleWithoutExtraImports(_))
                    casesFiltered.foreach { enumCase =>
                      applyVariant(createLookupElement(enumCase, scEnum))
                    }
                  }
                case Some(javaEnum@JavaEnum(fields)) if isAccessible(javaEnum) =>
                  val fieldsFiltered = fields.filterNot(isAccessibleWithoutExtraImports(_))
                  fieldsFiltered.foreach(field => applyVariant(createLookupElementWithPrefix(field, javaEnum)))
                case cls =>
                  val valueType = tp.extractDesignatorSingleton.getOrElse(tp)
                  valueType match {
                    case ScProjectionType(DesignatorOwner(enumeration@ScalaEnumeration(vals)), _) if isAccessible(enumeration) =>
                      val applicableVals = vals.filter(v => isAccessible(v) && v.`type`().exists(_.conforms(valueType)))
                      val fields = applicableVals.flatMap(_.declaredElements)
                      val fieldsFiltered = fields.filterNot(isAccessibleWithoutExtraImports(_))
                      fieldsFiltered.foreach(field => applyVariant(createLookupElementWithPrefix(field, enumeration)))
                    case _ =>
                      cls match {
                        // SCL-21582
                        case Some(sealedClass@SealedClassInheritors(cases)) if isAccessible(sealedClass) =>
                          val casesFiltered = cases.filterNot(isAccessibleWithoutExtraImports(_))
                          casesFiltered.foreach { c =>
                            applyVariant(createLookupElement(c, sealedClass))
                          }
                        case _ =>
                      }
                  }
              }
            } else tp.extractClass match {
              case Some(c: ScClass) if c.qualifiedName == "scala.Option" || c.qualifiedName == "scala.Some" =>
                tp match {
                  case ParameterizedType(_, Seq(scType)) => checkType(scType)
                  case _ =>
                }
              case Some(_: ScObject) => //do nothing
              case Some(clazz: ScTypeDefinition) =>
                checkTypeProjection(tp)
                ScalaPsiUtil.getCompanionModule(clazz) match {
                  case Some(o: ScObject) => checkObject(o)
                  case _ => //do nothing
                }
              case Some(containingClass: PsiClass) if isAccessible(containingClass) =>
                // todo unify with SbtCompletionContributor
                for {
                  member <- containingClass.getAllMethods ++ containingClass.getFields
                  if member.hasModifierProperty(PsiModifier.STATIC) &&
                    isAccessible(member)

                  variant = createLookupElementWithPrefix(member, containingClass)
                } applyVariant(variant)
              case _ => checkTypeProjection(tp)
            }
          }

          checkType(tp)
        }

        if (isSmart) {
          variants.foreach(applyVariant(_, checkForSecondCompletion = true))
          if (typez.exists(_.equiv(Boolean))) {
            ScalaKeywordLookupItem.addFor(result, ScalaKeyword.FALSE, ScalaKeyword.TRUE)
          }
          if (completeThis) {
            var parent = place
            var foundClazz = false
            while (parent != null) {
              parent match {
                case _: ScNewTemplateDefinition if foundClazz => //do nothing, impossible to invoke
                case t: ScTemplateDefinition =>
                  t.getTypeWithProjections(thisProjections = true) match {
                    case Right(scType) =>
                      val lookupString = (if (foundClazz) t.name + "." else "") + "this"
                      val el = new ScalaLookupItem(t, lookupString)
                      if (!scType.equiv(Nothing) && typez.exists(scType conforms _)) {
                        if (!foundClazz) el.bold = true
                        result.addElement(el)
                      } else {
                        var elementAdded = false
                        typez.foreach {
                          case ParameterizedType(tp, Seq(arg)) if !elementAdded =>
                            tp.extractClass match {
                              case Some(clazz) if clazz.qualifiedName == "scala.Option" || clazz.qualifiedName == "scala.Some" =>
                                if (!scType.equiv(Nothing) && scType.conforms(arg)) {
                                  el.someSmartCompletion = true
                                  result.addElement(el)
                                  elementAdded = true
                                }
                              case _ =>
                            }
                          case _ =>
                        }
                      }
                    case _ =>
                  }
                  foundClazz = true
                case _ =>
              }
              parent = parent.getContext
            }
          }
        }
      case _ =>
        if (isSmart) variants.foreach(applyVariant(_, checkForSecondCompletion = true))
    }
  }