private def checkNotQualifiedReferenceElement()

in scala/scala-impl/src/org/jetbrains/plugins/scala/annotator/element/ScReferenceAnnotator.scala [170:339]


  private def checkNotQualifiedReferenceElement(refElement: ScReference, typeAware: Boolean)
                                               (implicit holder: ScalaAnnotationHolder): Unit = {
    refElement match {
      case _: ScInterpolatedExpressionPrefix => return // do not inspect interpolated literal, it will be highlighted in other place
      case _ if refElement.isSoft => return
      case _ =>
    }

    val resolve = refElement.multiResolveScala(false)

    refElement match {
      case scalaDocRef: ScDocResolvableCodeReference =>
        annotateScalaDocReference(scalaDocRef, resolve)
        return
      case _ =>
    }

    if (resolve.length != 1) {
      def addUnknownSymbolProblem(): Unit = {
        if (resolve.isEmpty) {
          createUnknownSymbolProblem(refElement)
        }
      }

      val parent = refElement.getParent
      refElement match {
        case refElement: ScReferenceExpression =>
          // Let's try to hide dynamic named parameter usage
          refElement.getContext match {
            case assignment@ScAssignment(`refElement`, _) if resolve.isEmpty && assignment.isDynamicNamedAssignment => return
            case _ => addUnknownSymbolProblem()
          }
        case _ =>
          parent match {
            case ScInfixPattern(_, `refElement`, _) if refElement.isInstanceOf[ScStableCodeReference] =>
              // todo: this is hide A op B in patterns
              () //skip
            case _: ScImportSelector if resolve.length > 0 =>
              () //skip
            case tag: ScDocTag =>
              if (MyScaladocParsing.TagNames.ParamOrTParamSet.contains(tag.name)) {
                //skip, references to parameters in ScalaDoc tags are handled in [[org.jetbrains.plugins.scala.codeInspection.scaladoc.ScalaDocReferenceInspection]]
              }
              else {
                holder.createWeakWarningAnnotation(refElement, ScalaBundle.message("cannot.resolve", refElement.refName))
              }
            case _ =>
              addUnknownSymbolProblem()
          }
      }
    } else {
      def showError(): Unit = {
        val error = ScalaBundle.message("forward.reference.detected")
        holder.createErrorAnnotation(refElement.nameId, error)
      }

      refElement.getContainingFile match {
        case file: ScalaFile if !file.allowsForwardReferences =>
          resolve(0) match {
            case r if r.isForwardReference =>
              r.getActualElement.nameContext match {
                case v: ScValue if !v.hasModifierProperty("lazy") => showError()
                case _: ScVariable => showError()
                case nameContext if nameContext.isValid =>
                  //if it has not lazy val or var between reference and statement then it's forward reference
                  val context = findCommonContext(refElement, nameContext)
                  if (context != null) {
                    val neighbour = (findFirstContext(nameContext, false, elem => elem.getContext.eq(context)) match {
                      case s: ScalaPsiElement => s.getDeepSameElementInContext
                      case elem => elem
                    }).getPrevSibling

                    @scala.annotation.tailrec
                    def check(neighbour: PsiElement): Boolean = {
                      if (neighbour == null ||
                        neighbour.getTextRange.getStartOffset <= refElement.getTextRange.getStartOffset) return false
                      neighbour match {
                        case v: ScValue if !v.hasModifierProperty("lazy") => true
                        case _: ScVariable => true
                        case _ => check(neighbour.getPrevSibling)
                      }
                    }
                    if (check(neighbour)) showError()
                  }
              }
            case _ =>
          }
        case _ =>
      }
    }

    runCommonChecksForReference(resolve, refElement)

    if (resolve.length == 1) {
      val resolveResult = resolve(0)
      refElement match {
        case e: ScReferenceExpression if e.getParent.isInstanceOf[ScPrefixExpr] &&
          e.getParent.asInstanceOf[ScPrefixExpr].operation == e =>
          resolveResult.implicitFunction match {
            case Some(_) =>
              highlightImplicitMethod(refElement)
            case _ =>
          }
        case e: ScReferenceExpression if e.getParent.isInstanceOf[ScInfixExpr] &&
          e.getParent.asInstanceOf[ScInfixExpr].operation == e =>
          resolveResult.implicitFunction match {
            case Some(_) =>
              highlightImplicitMethod(refElement)
            case _ =>
          }
        case _ =>
      }
    }

    def isOnTopLevel(element: PsiElement) = element match {
      case scalaPsi: ScalaPsiElement => !scalaPsi.parents.exists(_.isInstanceOf[ScTypeDefinition])
      case _ => false
    }

    //don't highlight ambiguous definitions, if they are resolved to multiple top-level declarations
    //needed for worksheet and scala notebook files (e.g. zeppelin)
    def isTopLevelResolve =
      resolve.length > 1 && resolve.headOption.map(_.element).filter(isOnTopLevel).exists {
        firstElement =>
          val fFile = firstElement.getContainingFile
          resolve.tail.map(_.element).forall(nextEl => nextEl.getContainingFile == fFile && isOnTopLevel(nextEl))
      }

    if (typeAware && resolve.length != 1 && !(refElement.containingScalaFile.exists(_.isMultipleDeclarationsAllowed) && isTopLevelResolve)) {
      val parent = refElement.getParent
      def addCreateApplyOrUnapplyFix(errorWithRefName: String => String, fix: ScTypeDefinition => IntentionAction): Boolean = {
        val refWithoutArgs = ScalaPsiElementFactory.createReferenceFromText(refElement.getText, parent.getContext, parent)
        if (refWithoutArgs != null && refWithoutArgs.multiResolveScala(false).exists(!_.getElement.isInstanceOf[PsiPackage])) {
          // We can't resolve the method call A(arg1, arg2), but we can resolve A. Highlight this differently.
          val message = errorWithRefName(refElement.refName)
          val typeDefFix = refWithoutArgs match {
            case ResolvesTo(obj: ScObject) => fix(obj) :: Nil
            case InstanceOfClass(td: ScTypeDefinition) => fix(td) :: Nil
            case _ => Nil
          }

          holder.createErrorAnnotation(
            refElement.nameId,
            message,
            ReportHighlightingErrorQuickFix :: typeDefFix
          )

          true
        } else false
      }

      parent match {
        case _: ScImportSelector if resolve.length > 0 => return
        case _: MethodInvocation if resolve.length > 1 =>
          val error = ScalaBundle.message("cannot.resolve.overloaded", refElement.refName)
          holder.createErrorAnnotation(refElement.nameId, error)
        case mc: ScMethodCall if addCreateApplyOrUnapplyFix(
          ScalaBundle.message("cannot.resolve.apply.method", _),
          td => new CreateApplyQuickFix(td, mc)
        ) =>
          return
        case (p: ScPattern) & (_: ScExtractorPattern) =>
          val errorWithRefName: String => String = ScalaBundle.message("cannot.resolve.unapply.method", _)
          if (addCreateApplyOrUnapplyFix(errorWithRefName, td => new CreateUnapplyQuickFix(td, p))) return
        case scalaDocTag: ScDocTag if scalaDocTag.name == MyScaladocParsing.TagNames.Throws =>
          return //see SCL-9490
        case _ =>
      }
    }
  }