in scala/scala-impl/src/org/jetbrains/plugins/scala/lang/resolve/processor/BaseProcessor.scala [142:317]
def processType(
t: ScType,
place: PsiElement,
state: ResolveState = ScalaResolveState.empty,
updateWithProjectionType: Boolean = true
): Boolean = processTypeImpl(t, place, state, updateWithProjectionType)(RecursionState.empty)
private def processTypeImpl(
t: ScType,
place: PsiElement,
state: ResolveState = ScalaResolveState.empty,
updateWithProjectionSubst: Boolean = true
)(implicit
recState: RecursionState
): Boolean = {
implicit val context: Context = Context(place)
ProgressManager.checkCanceled()
t match {
case ScDesignatorType(clazz: PsiClass) if clazz.qualifiedName == "java.lang.String" =>
val plusMethod: ScType => ScSyntheticFunction = SyntheticClasses.get(place.getProject).stringPlusMethod
if (plusMethod != null) execute(plusMethod(t), state) //add + method
case _ =>
}
if (place.isInScala3File && kinds.contains(ResolveTargets.METHOD)) {
if (!processSelectable(t, place, state, execute)) {
return false
}
}
t match {
case ScThisType(clazz) =>
clazz.selfType match {
case None =>
processElement(clazz, ScSubstitutor.empty, place, state)
case Some(ScThisType(`clazz`)) =>
//to prevent SOE, let's process Element
processElement(clazz, ScSubstitutor.empty, place, state)
case Some(ScProjectionType(_, element)) if recState.visitedProjections.contains(element) =>
//recursion detected
true
case Some(selfType) =>
val clazzType = clazz.getTypeWithProjections().getOrElse(return true)
if (selfType.conforms(clazzType)) {
val newState =
state
.withCompoundOrSelfType(t)
.withSubstitutor(ScSubstitutor(ScThisType(clazz)))
processTypeImpl(selfType, place, newState)
} else if (clazzType.conforms(selfType)) {
processElement(clazz, ScSubstitutor.empty, place, state)
} else {
//@TODO: temporary fix, should be removed once lub/glb is implemented in a version specific manner
val glb =
if (place.isInScala3File) ScAndType(clazzType, selfType)
else selfType.glb(clazzType)
val newState = state.withCompoundOrSelfType(t)
processTypeImpl(glb, place, newState)
}
}
case d@ScDesignatorType(e: PsiClass) if d.isStatic && !e.is[ScTemplateDefinition] =>
//not scala from scala
var break = true
for (method <- e.getMethods if break && method.hasModifierProperty("static")) {
if (!execute(method, state)) break = false
}
for (cl <- e.getInnerClasses if break && cl.hasModifierProperty("static")) {
if (!execute(cl, state)) break = false
}
for (field <- e.getFields if break && field.hasModifierProperty("static")) {
if (!execute(field, state)) break = false
}
if (!break) return false
processEnum(e, execute(_, state))
case ScDesignatorType(o: ScObject) =>
processElement(o, ScSubstitutor.empty, place, state)
case ScDesignatorType(e: ScTypedDefinition) if place.is[ScTypeProjection] =>
val result: TypeResult =
e match {
case p: ScParameter => p.insideParamType
case _ => e.`type`()
}
result match {
case Right(tp) => processTypeImpl(tp, place, state)
case _ => true
}
case ScDesignatorType(e) => processElement(e, ScSubstitutor.empty, place, state)
case tpt: TypeParameterType => processTypeImpl(tpt.upperType, place, state, updateWithProjectionSubst = false)
case j: JavaArrayType =>
implicit val elementScope: ElementScope = place.elementScope
processTypeImpl(j.getParameterizedType.getOrElse(return true), place, state)
case p@ParameterizedType(designator, typeArgs) =>
val cont = designator match {
case tpt: TypeParameterType =>
if (recState.visitedTypeParameter.contains(tpt)) return true
val newState = state.withSubstitutor(ScSubstitutor(p))
val upper = tpt.upperType
val substedType =
if (upper.isAny || upper.isAnyRef) upper
else p.substitutor(ParameterizedType(tpt.upperType, typeArgs))
processTypeImpl(substedType, place, newState)(recState.add(tpt))
case _ =>
p.extractDesignatedType(expandAliases = false) match {
case Some((des, subst)) =>
processElement(des, subst, place, state)
case None =>
true
}
}
cont && processNamedTuple(p, state, execute) && processScala3Tuple(p, execute(_, state))
case proj: ScProjectionType =>
val withActual = new ScProjectionType.withActual(updateWithProjectionSubst)
proj match {
case withActual(elem, s) =>
if (recState.visitedProjections.contains(elem))
return true
elem match {
case alias: ScTypeAlias =>
val upper = alias.upperBound.getOrElse(return true)
processTypeImpl(s(upper), place, state.withSubstitutor(ScSubstitutor.empty))(recState.add(alias))
case elem =>
val subst =
if (updateWithProjectionSubst) ScSubstitutor(proj) followed s
else s
processElement(elem, subst, place, state)(recState.add(elem))
}
}
case lit: ScLiteralType => processType(lit.wideType, place, state, updateWithProjectionSubst)
case StdType(name, tSuper) =>
SyntheticClasses.get(place.getProject).byName(name) match {
case Some(c) =>
if (!c.processDeclarations(this, state, null, place) ||
!(tSuper match {
case Some(ts) => processTypeImpl(ts, place)
case _ => true
})) return false
case None => //nothing to do
}
val scope = place.resolveScope
val obj: PsiClass = ScalaPsiManager.instance(place.getProject).getCachedClass(scope, "java.lang.Object").orNull
if (obj != null) {
val namesSet = Set("hashCode", "toString", "equals", "getClass")
val methods = obj.getMethods.iterator
while (methods.hasNext) {
val method = methods.next()
if (name == "AnyRef" || namesSet.contains(method.name)) {
if (!execute(method, state)) return false
}
}
}
true
case comp: ScCompoundType => processDeclarations(comp, this, state, null, place)
case and: ScAndType => processDeclarations(and, this, state, null, place)
case or: ScOrType => processTypeImpl(or.join, place, state, updateWithProjectionSubst)
case matchType: ScMatchType =>
val redex = matchType.reduce.getOrElse(matchType.upperBound.getOrElse(Any))
processTypeImpl(redex, place, state)
case ex: ScExistentialType =>
processTypeImpl(ex.quantified, place, state.withSubstitutor(ScSubstitutor.empty))
case ScExistentialArgument(_, _, _, upper) =>
processTypeImpl(upper, place, state)
case _ => true
}
}