@Nullable
  private static JetSimpleNameExpression getCallSimpleNameExpression(
      JetValueArgumentList argumentList) {
    if (!(argumentList.getParent() instanceof JetCallElement)) {
      return null;
    }

    JetCallElement callExpression = (JetCallElement) argumentList.getParent();
    JetExpression calleeExpression = callExpression.getCalleeExpression();
    if (calleeExpression == null) {
      return null;
    }

    if (calleeExpression instanceof JetSimpleNameExpression) {
      return (JetSimpleNameExpression) calleeExpression;
    } else if (calleeExpression instanceof JetConstructorCalleeExpression) {
      JetConstructorCalleeExpression constructorCalleeExpression =
          (JetConstructorCalleeExpression) calleeExpression;
      if (constructorCalleeExpression.getConstructorReferenceExpression()
          instanceof JetSimpleNameExpression) {
        return (JetSimpleNameExpression)
            constructorCalleeExpression.getConstructorReferenceExpression();
      }
    }

    return null;
  }
 private static JetValueArgumentList findCall(CreateParameterInfoContext context) {
   // todo: calls to this constructors, when we will have auxiliary constructors
   PsiFile file = context.getFile();
   if (!(file instanceof JetFile)) return null;
   PsiElement element = file.findElementAt(context.getOffset());
   while (element != null && !(element instanceof JetValueArgumentList)) {
     element = element.getParent();
   }
   if (element == null) return null;
   JetValueArgumentList argumentList = (JetValueArgumentList) element;
   JetCallElement callExpression;
   if (element.getParent() instanceof JetCallElement) {
     callExpression = (JetCallElement) element.getParent();
   } else {
     return null;
   }
   BindingContext bindingContext = AnalyzeSingleFileUtil.getContextForSingleFile((JetFile) file);
   JetExpression calleeExpression = callExpression.getCalleeExpression();
   if (calleeExpression == null) return null;
   JetSimpleNameExpression refExpression = null;
   if (calleeExpression instanceof JetSimpleNameExpression) {
     refExpression = (JetSimpleNameExpression) calleeExpression;
   } else if (calleeExpression instanceof JetConstructorCalleeExpression) {
     JetConstructorCalleeExpression constructorCalleeExpression =
         (JetConstructorCalleeExpression) calleeExpression;
     if (constructorCalleeExpression.getConstructorReferenceExpression()
         instanceof JetSimpleNameExpression) {
       refExpression =
           (JetSimpleNameExpression)
               constructorCalleeExpression.getConstructorReferenceExpression();
     }
   }
   if (refExpression != null) {
     JetScope scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, refExpression);
     DeclarationDescriptor placeDescriptor = null;
     if (scope != null) {
       placeDescriptor = scope.getContainingDeclaration();
     }
     Collection<DeclarationDescriptor> variants =
         TipsManager.getReferenceVariants(refExpression, bindingContext);
     Name refName = refExpression.getReferencedNameAsName();
     PsiReference[] references = refExpression.getReferences();
     if (references.length == 0) return null;
     ArrayList<DeclarationDescriptor> itemsToShow = new ArrayList<DeclarationDescriptor>();
     for (DeclarationDescriptor variant : variants) {
       if (variant instanceof FunctionDescriptor) {
         FunctionDescriptor functionDescriptor = (FunctionDescriptor) variant;
         if (functionDescriptor.getName().equals(refName)) {
           // todo: renamed functions?
           if (placeDescriptor != null
               && !JetVisibilityChecker.isVisible(placeDescriptor, functionDescriptor)) continue;
           itemsToShow.add(functionDescriptor);
         }
       } else if (variant instanceof ClassDescriptor) {
         ClassDescriptor classDescriptor = (ClassDescriptor) variant;
         if (classDescriptor.getName().equals(refName)) {
           // todo: renamed classes?
           for (ConstructorDescriptor constructorDescriptor : classDescriptor.getConstructors()) {
             if (placeDescriptor != null
                 && !JetVisibilityChecker.isVisible(placeDescriptor, constructorDescriptor))
               continue;
             itemsToShow.add(constructorDescriptor);
           }
         }
       }
     }
     context.setItemsToShow(ArrayUtil.toObjectArray(itemsToShow));
     return argumentList;
   }
   return null;
 }
  @Override
  public void updateUI(Object descriptor, ParameterInfoUIContext context) {
    // todo: when we will have ability to pass Array as vararg, implement such feature here too?
    if (context == null
        || context.getParameterOwner() == null
        || !context.getParameterOwner().isValid()) {
      return;
    }
    PsiElement parameterOwner = context.getParameterOwner();
    if (parameterOwner instanceof JetValueArgumentList) {
      JetValueArgumentList argumentList = (JetValueArgumentList) parameterOwner;
      if (descriptor instanceof FunctionDescriptor) {
        JetFile file = (JetFile) argumentList.getContainingFile();
        BindingContext bindingContext = AnalyzeSingleFileUtil.getContextForSingleFile(file);
        FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
        StringBuilder builder = new StringBuilder();
        List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
        List<JetValueArgument> valueArguments = argumentList.getArguments();
        int currentParameterIndex = context.getCurrentParameterIndex();
        int boldStartOffset = -1;
        int boldEndOffset = -1;
        boolean isGrey = false;
        boolean isDeprecated = false; // todo: add deprecation check
        Color color = context.getDefaultParameterColor();
        PsiElement parent = argumentList.getParent();
        if (parent instanceof JetCallElement) {
          JetCallElement callExpression = (JetCallElement) parent;
          JetExpression calleeExpression = callExpression.getCalleeExpression();
          JetSimpleNameExpression refExpression = null;
          if (calleeExpression instanceof JetSimpleNameExpression) {
            refExpression = (JetSimpleNameExpression) calleeExpression;
          } else if (calleeExpression instanceof JetConstructorCalleeExpression) {
            JetConstructorCalleeExpression constructorCalleeExpression =
                (JetConstructorCalleeExpression) calleeExpression;
            if (constructorCalleeExpression.getConstructorReferenceExpression()
                instanceof JetSimpleNameExpression) {
              refExpression =
                  (JetSimpleNameExpression)
                      constructorCalleeExpression.getConstructorReferenceExpression();
            }
          }
          if (refExpression != null) {
            DeclarationDescriptor declarationDescriptor =
                bindingContext.get(BindingContext.REFERENCE_TARGET, refExpression);
            if (declarationDescriptor != null) {
              if (declarationDescriptor == functionDescriptor) {
                color = GREEN_BACKGROUND;
              }
            }
          }
        }

        boolean[] usedIndexes = new boolean[valueParameters.size()];
        boolean namedMode = false;
        Arrays.fill(usedIndexes, false);
        if ((currentParameterIndex >= valueParameters.size()
                && (valueParameters.size() > 0 || currentParameterIndex > 0))
            && (valueParameters.size() == 0
                || valueParameters.get(valueParameters.size() - 1).getVarargElementType()
                    == null)) {
          isGrey = true;
        }
        if (valueParameters.size() == 0)
          builder.append(CodeInsightBundle.message("parameter.info.no.parameters"));
        for (int i = 0; i < valueParameters.size(); ++i) {
          if (i != 0) builder.append(", ");
          boolean highlightParameter =
              i == currentParameterIndex
                  || (!namedMode
                      && i < currentParameterIndex
                      && valueParameters.get(valueParameters.size() - 1).getVarargElementType()
                          != null);
          if (highlightParameter) boldStartOffset = builder.length();
          if (!namedMode) {
            if (valueArguments.size() > i) {
              JetValueArgument argument = valueArguments.get(i);
              if (argument.isNamed()) {
                namedMode = true;
              } else {
                ValueParameterDescriptor param = valueParameters.get(i);
                builder.append(renderParameter(param, false, bindingContext));
                if (i < currentParameterIndex) {
                  if (argument.getArgumentExpression() != null) {
                    // check type
                    JetType paramType = getActualParameterType(param);
                    JetType exprType =
                        bindingContext.get(
                            BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression());
                    if (exprType != null
                        && !JetTypeChecker.INSTANCE.isSubtypeOf(exprType, paramType)) isGrey = true;
                  } else isGrey = true;
                }
                usedIndexes[i] = true;
              }
            } else {
              ValueParameterDescriptor param = valueParameters.get(i);
              builder.append(renderParameter(param, false, bindingContext));
            }
          }
          if (namedMode) {
            boolean takeAnyArgument = true;
            if (valueArguments.size() > i) {
              JetValueArgument argument = valueArguments.get(i);
              if (argument.isNamed()) {
                for (int j = 0; j < valueParameters.size(); ++j) {
                  JetSimpleNameExpression referenceExpression =
                      argument.getArgumentName().getReferenceExpression();
                  ValueParameterDescriptor param = valueParameters.get(j);
                  if (referenceExpression != null
                      && !usedIndexes[j]
                      && param.getName().equals(referenceExpression.getReferencedNameAsName())) {
                    takeAnyArgument = false;
                    usedIndexes[j] = true;
                    builder.append(renderParameter(param, true, bindingContext));
                    if (i < currentParameterIndex) {
                      if (argument.getArgumentExpression() != null) {
                        // check type
                        JetType paramType = getActualParameterType(param);
                        JetType exprType =
                            bindingContext.get(
                                BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression());
                        if (exprType != null
                            && !JetTypeChecker.INSTANCE.isSubtypeOf(exprType, paramType))
                          isGrey = true;
                      } else isGrey = true;
                    }
                    break;
                  }
                }
              }
            }

            if (takeAnyArgument) {
              if (i < currentParameterIndex) isGrey = true;

              for (int j = 0; j < valueParameters.size(); ++j) {
                ValueParameterDescriptor param = valueParameters.get(j);
                if (!usedIndexes[j]) {
                  usedIndexes[j] = true;
                  builder.append(renderParameter(param, true, bindingContext));
                  break;
                }
              }
            }
          }
          if (highlightParameter) boldEndOffset = builder.length();
        }
        if (builder.toString().isEmpty()) context.setUIComponentEnabled(false);
        else
          context.setupUIComponentPresentation(
              builder.toString(),
              boldStartOffset,
              boldEndOffset,
              isGrey,
              isDeprecated,
              false,
              color);
      } else context.setUIComponentEnabled(false);
    }
  }
Ejemplo n.º 4
0
  @NotNull
  /*package*/ OverloadResolutionResultsImpl<FunctionDescriptor> resolveFunctionCall(
      @NotNull BasicCallResolutionContext context) {

    ProgressIndicatorProvider.checkCanceled();

    List<ResolutionTask<CallableDescriptor, FunctionDescriptor>> prioritizedTasks;

    JetExpression calleeExpression = context.call.getCalleeExpression();
    JetReferenceExpression functionReference;
    if (calleeExpression instanceof JetSimpleNameExpression) {
      JetSimpleNameExpression expression = (JetSimpleNameExpression) calleeExpression;
      functionReference = expression;

      ExpressionTypingUtils.checkCapturingInClosure(expression, context.trace, context.scope);

      Name name = expression.getReferencedNameAsName();

      prioritizedTasks =
          TaskPrioritizer.<CallableDescriptor, FunctionDescriptor>computePrioritizedTasks(
              context,
              name,
              functionReference,
              CallableDescriptorCollectors.FUNCTIONS_AND_VARIABLES);
      ResolutionTask.DescriptorCheckStrategy abstractConstructorCheck =
          new ResolutionTask.DescriptorCheckStrategy() {
            @Override
            public <D extends CallableDescriptor> boolean performAdvancedChecks(
                D descriptor, BindingTrace trace, TracingStrategy tracing) {
              if (descriptor instanceof ConstructorDescriptor) {
                Modality modality =
                    ((ConstructorDescriptor) descriptor).getContainingDeclaration().getModality();
                if (modality == Modality.ABSTRACT) {
                  tracing.instantiationOfAbstractClass(trace);
                  return false;
                }
              }
              return true;
            }
          };
      for (ResolutionTask task : prioritizedTasks) {
        task.setCheckingStrategy(abstractConstructorCheck);
      }
    } else {
      JetValueArgumentList valueArgumentList = context.call.getValueArgumentList();
      PsiElement reportAbsenceOn =
          valueArgumentList == null ? context.call.getCallElement() : valueArgumentList;
      if (calleeExpression instanceof JetConstructorCalleeExpression) {
        assert !context.call.getExplicitReceiver().exists();

        JetConstructorCalleeExpression expression =
            (JetConstructorCalleeExpression) calleeExpression;
        functionReference = expression.getConstructorReferenceExpression();
        if (functionReference == null) {
          return checkArgumentTypesAndFail(context); // No type there
        }
        JetTypeReference typeReference = expression.getTypeReference();
        assert typeReference != null;
        JetType constructedType =
            typeResolver.resolveType(context.scope, typeReference, context.trace, true);

        if (constructedType.isError()) {
          return checkArgumentTypesAndFail(context);
        }

        DeclarationDescriptor declarationDescriptor =
            constructedType.getConstructor().getDeclarationDescriptor();
        if (declarationDescriptor instanceof ClassDescriptor) {
          ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
          Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors();
          if (constructors.isEmpty()) {
            context.trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
            return checkArgumentTypesAndFail(context);
          }
          Collection<ResolutionCandidate<CallableDescriptor>> candidates =
              TaskPrioritizer.<CallableDescriptor>convertWithImpliedThis(
                  context.scope,
                  Collections.<ReceiverValue>singletonList(NO_RECEIVER),
                  constructors);
          prioritizedTasks =
              TaskPrioritizer
                  .<CallableDescriptor, FunctionDescriptor>computePrioritizedTasksFromCandidates(
                      context, functionReference, candidates, null);
        } else {
          context.trace.report(NOT_A_CLASS.on(calleeExpression));
          return checkArgumentTypesAndFail(context);
        }
      } else if (calleeExpression instanceof JetThisReferenceExpression) {
        functionReference = (JetThisReferenceExpression) calleeExpression;
        DeclarationDescriptor containingDeclaration = context.scope.getContainingDeclaration();
        if (containingDeclaration instanceof ConstructorDescriptor) {
          containingDeclaration = containingDeclaration.getContainingDeclaration();
        }
        assert containingDeclaration instanceof ClassDescriptor;
        ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;

        Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors();
        if (constructors.isEmpty()) {
          context.trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn));
          return checkArgumentTypesAndFail(context);
        }
        List<ResolutionCandidate<CallableDescriptor>> candidates =
            ResolutionCandidate.<CallableDescriptor>convertCollection(
                constructors, JetPsiUtil.isSafeCall(context.call));
        prioritizedTasks =
            Collections.singletonList(
                new ResolutionTask<CallableDescriptor, FunctionDescriptor>(
                    candidates, functionReference, context)); // !! DataFlowInfo.EMPTY
      } else if (calleeExpression != null) {
        // Here we handle the case where the callee expression must be something of type function,
        // e.g. (foo.bar())(1, 2)
        JetType calleeType =
            expressionTypingServices.safeGetType(
                context.scope,
                calleeExpression,
                NO_EXPECTED_TYPE,
                context.dataFlowInfo,
                context
                    .trace); // We are actually expecting a function, but there seems to be no easy
                             // way of expressing this

        if (!KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(calleeType)) {
          //                    checkTypesWithNoCallee(trace, scope, call);
          if (!calleeType.isError()) {
            context.trace.report(CALLEE_NOT_A_FUNCTION.on(calleeExpression, calleeType));
          }
          return checkArgumentTypesAndFail(context);
        }

        FunctionDescriptorImpl functionDescriptor =
            new ExpressionAsFunctionDescriptor(
                context.scope.getContainingDeclaration(),
                Name.special("<for expression " + calleeExpression.getText() + ">"),
                calleeExpression);
        FunctionDescriptorUtil.initializeFromFunctionType(
            functionDescriptor,
            calleeType,
            NO_RECEIVER_PARAMETER,
            Modality.FINAL,
            Visibilities.LOCAL);
        ResolutionCandidate<CallableDescriptor> resolutionCandidate =
            ResolutionCandidate.<CallableDescriptor>create(
                functionDescriptor, JetPsiUtil.isSafeCall(context.call));
        resolutionCandidate.setReceiverArgument(context.call.getExplicitReceiver());
        resolutionCandidate.setExplicitReceiverKind(ExplicitReceiverKind.RECEIVER_ARGUMENT);

        // strictly speaking, this is a hack:
        // we need to pass a reference, but there's no reference in the PSI,
        // so we wrap what we have into a fake reference and pass it on (unwrap on the other end)
        functionReference = new JetFakeReference(calleeExpression);

        prioritizedTasks =
            Collections.singletonList(
                new ResolutionTask<CallableDescriptor, FunctionDescriptor>(
                    Collections.singleton(resolutionCandidate), functionReference, context));
      } else {
        //                checkTypesWithNoCallee(trace, scope, call);
        return checkArgumentTypesAndFail(context);
      }
    }

    return doResolveCallOrGetCachedResults(
        ResolutionResultsCache.FUNCTION_MEMBER_TYPE,
        context,
        prioritizedTasks,
        CallTransformer.FUNCTION_CALL_TRANSFORMER,
        functionReference);
  }