in scala/scala-impl/src/org/jetbrains/plugins/scala/lang/parameterInfo/ScalaFunctionParameterInfoHandler.scala [554:748]
private def elementsForParameterInfo(args: Invocation): Seq[Object] = {
implicit val project: ProjectContext = args.element.projectContext
def elementsForConstructorInvocationParameterInfo(clazz: PsiClass,
subst: ScSubstitutor,
argumentLists: Seq[ScalaPsiElement],
maybeTypeArgs: Option[ScTypeArgs]): Seq[Object] = {
val resultBuilder = ArraySeq.newBuilder[Object]
val i = argumentLists.indexOf(args.element)
clazz match {
case constructorOwner: ScConstructorOwner =>
constructorOwner.constructor match {
case Some(constructor: ScPrimaryConstructor) if i < constructor.effectiveParameterClauses.length =>
maybeTypeArgs match {
case Some(typeArgs) =>
val substitutor = ScSubstitutor.bind(constructorOwner.typeParameters, typeArgs.typeArgs)(_.calcType)
resultBuilder += ((constructor, substitutor.followed(subst), i))
case _ => resultBuilder += ((constructor, subst, i))
}
case Some(_) if i == 0 => resultBuilder += ""
case None => resultBuilder += ""
case _ =>
}
constructorOwner.functions.foreach { function =>
if (function.isConstructor && function.clauses.fold(1)(_.clauses.length) > i) {
resultBuilder += ((new PhysicalMethodSignature(function, subst), i))
}
}
case annotation: PsiClass if annotation.annotationType =>
val seq = annotation.getMethods.toSeq.collect {
case method: PsiAnnotationMethod =>
(method.name, method.getReturnType.toScType(), method.getDefaultValue)
}
resultBuilder += ((AnnotationParameters(seq), i))
case psiClass: PsiClass if !psiClass.is[ScTypeDefinition] =>
psiClass.getConstructors.foreach { constructor =>
maybeTypeArgs match {
case Some(typeArgs) =>
val substitutor = ScSubstitutor.bind(psiClass.getTypeParameters, typeArgs.typeArgs)(_.calcType)
val signature = new PhysicalMethodSignature(constructor, substitutor.followed(subst))
resultBuilder += ((signature, i))
case _ =>
val signature = new PhysicalMethodSignature(constructor, subst)
resultBuilder += ((signature, i))
}
}
case _ =>
}
resultBuilder.result()
}
args.parent match {
case UniversalApplyCall(UniversalApplyCallContext(constructor, substitutor, argumentLists, maybeTypeArgs)) =>
val psiClass = constructor.containingClass
elementsForConstructorInvocationParameterInfo(psiClass, substitutor, argumentLists, maybeTypeArgs)
case constrInvocation: ScConstructorInvocation =>
val typeElement = constrInvocation.typeElement
typeElement.calcType.extractClassType match {
case Some((psiClass: PsiClass, substitutor: ScSubstitutor)) =>
val maybeTypeArgs = typeElement match {
case gen: ScParameterizedTypeElement =>
Some(gen.typeArgList)
case _ => None
}
elementsForConstructorInvocationParameterInfo(psiClass, substitutor, constrInvocation.arguments, maybeTypeArgs)
case _ => Seq.empty
}
case call@(_: MethodInvocation | _: ScReferenceExpression) =>
val resultBuilder = ArraySeq.newBuilder[Object]
def collectResult(): Unit = {
val canBeUpdate = call.getParent match {
case assignStmt: ScAssignment if call == assignStmt.leftExpression => true
case notExpr if !notExpr.is[ScExpression] || notExpr.is[ScBlockExpr] => true
case _ => false
}
val count = args.invocationCount
val gen = args.callGeneric.getOrElse(null: ScGenericCall)
def collectSubstitutor(element: PsiElement): ScSubstitutor = {
if (gen == null) return ScSubstitutor.empty
val typeParams = element match {
case tpo: ScTypeParametersOwner => tpo.typeParameters.toArray
case ptpo: PsiTypeParameterListOwner => ptpo.getTypeParameters
case _ => return ScSubstitutor.empty
}
ScSubstitutor.bind(typeParams, gen.arguments)(_.calcType)
}
def collectForType(typez: ScType): Unit = {
def process(functionName: String): Unit = {
val i = if (functionName == "update") -1 else 0
val processor: CompletionProcessor = new CompletionProcessor(StdKinds.refExprQualRef, call, withImplicitConversions = true) {
override protected val forName: Option[String] = Some(functionName)
}
processor.processType(typez, call)
val variants: Array[ScalaResolveResult] = processor.candidates
for {
variant <- variants
if !variant.getElement.isInstanceOf[PsiMember] ||
ResolveUtils.isAccessible(variant.getElement.asInstanceOf[PsiMember], call)
} {
variant match {
case ScalaResolveResult(method: ScFunction, subst: ScSubstitutor) =>
val signature: PhysicalMethodSignature = new PhysicalMethodSignature(method, subst.followed(collectSubstitutor(method)))
resultBuilder += ((signature, i))
resultBuilder ++= ScalaParameterInfoEnhancer.enhance(signature, args.arguments).map((_, i))
case _ =>
}
}
}
process("apply")
if (canBeUpdate) process("update")
}
args.callReference match {
case Some(ref: ScReferenceExpression) =>
if (count > 1) {
//todo: missed case with last implicit call
ref.bind() match {
case Some(ScalaResolveResult(function: ScFunction, subst: ScSubstitutor)) if function.
effectiveParameterClauses.length >= count =>
resultBuilder += ((new PhysicalMethodSignature(function, subst.followed(collectSubstitutor(function))), count - 1))
case Some(ScalaResolveResult(function: ScFunction, _)) if function.effectiveParameterClauses.isEmpty =>
function.`type`().foreach(collectForType)
case _ =>
call match {
case invocation: MethodInvocation =>
for (typez <- invocation.getEffectiveInvokedExpr.`type`()) //todo: implicit conversions
{collectForType(typez)}
case _ =>
}
}
} else {
val variants = {
val sameName = ref.getSameNameVariants
if (sameName.isEmpty) ref.multiResolveScala(false)
else sameName
}
for {
variant <- variants
if !variant.getElement.isInstanceOf[PsiMember] ||
ResolveUtils.isAccessible(variant.getElement.asInstanceOf[PsiMember], ref)
} {
variant match {
//todo: Synthetic function
case ScalaResolveResult(method: PsiMethod, subst: ScSubstitutor) =>
val signature: PhysicalMethodSignature = new PhysicalMethodSignature(method, subst.followed(collectSubstitutor(method)))
resultBuilder += ((signature, 0))
resultBuilder ++= ScalaParameterInfoEnhancer.enhance(signature, args.arguments).map((_, 0))
case ScalaResolveResult(typed: ScTypedDefinition, subst: ScSubstitutor) =>
val typez = subst(typed.`type`().getOrNothing) //todo: implicit conversions
collectForType(typez)
case _ =>
}
}
}
case None =>
call match {
case call: ScMethodCall =>
for (typez <- call.getEffectiveInvokedExpr.`type`()) { //todo: implicit conversions
collectForType(typez)
}
}
}
}
collectResult()
resultBuilder.result()
case self: ScSelfInvocation =>
val resultBuilder = ArraySeq.newBuilder[Object]
val i = self.arguments.indexOf(args.element)
self.parentOfType(classOf[ScClass]).foreach { clazz =>
clazz.constructor match {
case Some(constr: ScPrimaryConstructor) if i < constr.effectiveParameterClauses.length =>
resultBuilder += ((constr, ScSubstitutor.empty, i))
case Some(_) if i == 0 => resultBuilder += ""
case None => resultBuilder += ""
case _ =>
}
for {
constr <- clazz.functions
if constr.isConstructor &&
constr.clauses.map(_.clauses.length).getOrElse(1) > i
} {
if (!PsiTreeUtil.isAncestor(constr, self, true) &&
constr.getTextRange.getStartOffset < self.getTextRange.getStartOffset) {
resultBuilder += ((new PhysicalMethodSignature(constr, ScSubstitutor.empty), i))
}
}
}
resultBuilder.result()
}
}