Ejemplo n.º 1
0
  private void processPrimaryConstructor(
      @NotNull TopDownAnalysisContext c,
      @NotNull MutableClassDescriptor classDescriptor,
      @NotNull JetClass klass) {
    // TODO : not all the parameters are real properties
    JetScope memberScope = classDescriptor.getScopeForClassHeaderResolution();
    ConstructorDescriptor constructorDescriptor =
        descriptorResolver.resolvePrimaryConstructorDescriptor(
            memberScope, classDescriptor, klass, trace);
    if (constructorDescriptor != null) {
      List<ValueParameterDescriptor> valueParameterDescriptors =
          constructorDescriptor.getValueParameters();
      List<JetParameter> primaryConstructorParameters = klass.getPrimaryConstructorParameters();
      assert valueParameterDescriptors.size() == primaryConstructorParameters.size();
      List<ValueParameterDescriptor> notProperties = new ArrayList<ValueParameterDescriptor>();
      for (ValueParameterDescriptor valueParameterDescriptor : valueParameterDescriptors) {
        JetParameter parameter =
            primaryConstructorParameters.get(valueParameterDescriptor.getIndex());
        if (parameter.getValOrVarNode() != null) {
          PropertyDescriptor propertyDescriptor =
              descriptorResolver.resolvePrimaryConstructorParameterToAProperty(
                  classDescriptor, valueParameterDescriptor, memberScope, parameter, trace);
          classDescriptor.getBuilder().addPropertyDescriptor(propertyDescriptor);
          c.getPrimaryConstructorParameterProperties().put(parameter, propertyDescriptor);
        } else {
          notProperties.add(valueParameterDescriptor);
        }
      }

      if (classDescriptor.getKind() != ClassKind.TRAIT) {
        classDescriptor.setPrimaryConstructor(constructorDescriptor);
        classDescriptor.addConstructorParametersToInitializersScope(notProperties);
      }
    }
  }
 private static String renderParameter(
     ValueParameterDescriptor descriptor, boolean named, BindingContext bindingContext) {
   StringBuilder builder = new StringBuilder();
   if (named) builder.append("[");
   if (descriptor.getVarargElementType() != null) {
     builder.append("vararg ");
   }
   builder
       .append(descriptor.getName())
       .append(": ")
       .append(DescriptorRenderer.TEXT.renderType(getActualParameterType(descriptor)));
   if (descriptor.hasDefaultValue()) {
     PsiElement element = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor);
     String defaultExpression = "?";
     if (element instanceof JetParameter) {
       JetParameter parameter = (JetParameter) element;
       JetExpression defaultValue = parameter.getDefaultValue();
       if (defaultValue != null) {
         if (defaultValue instanceof JetConstantExpression) {
           JetConstantExpression constantExpression = (JetConstantExpression) defaultValue;
           defaultExpression = constantExpression.getText();
           if (defaultExpression.length() > 10) {
             if (defaultExpression.startsWith("\"")) defaultExpression = "\"...\"";
             else if (defaultExpression.startsWith("\'")) defaultExpression = "\'...\'";
             else defaultExpression = defaultExpression.substring(0, 7) + "...";
           }
         }
       }
     }
     builder.append(" = ").append(defaultExpression);
   }
   if (named) builder.append("]");
   return builder.toString();
 }
  private List<ValueParameterDescriptor> createValueParameterDescriptors(
      ExpressionTypingContext context,
      JetFunctionLiteral functionLiteral,
      FunctionDescriptorImpl functionDescriptor,
      boolean functionTypeExpected) {
    List<ValueParameterDescriptor> valueParameterDescriptors = Lists.newArrayList();
    List<JetParameter> declaredValueParameters = functionLiteral.getValueParameters();

    List<ValueParameterDescriptor> expectedValueParameters =
        (functionTypeExpected)
            ? JetStandardClasses.getValueParameters(functionDescriptor, context.expectedType)
            : null;

    boolean hasDeclaredValueParameters = functionLiteral.getValueParameterList() != null;
    if (functionTypeExpected
        && !hasDeclaredValueParameters
        && expectedValueParameters.size() == 1) {
      ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0);
      ValueParameterDescriptor it =
          new ValueParameterDescriptorImpl(
              functionDescriptor,
              0,
              Collections.<AnnotationDescriptor>emptyList(),
              "it",
              false,
              valueParameterDescriptor.getOutType(),
              valueParameterDescriptor.hasDefaultValue(),
              valueParameterDescriptor.getVarargElementType());
      valueParameterDescriptors.add(it);
      context.trace.record(AUTO_CREATED_IT, it);
    } else {
      for (int i = 0; i < declaredValueParameters.size(); i++) {
        JetParameter declaredParameter = declaredValueParameters.get(i);
        JetTypeReference typeReference = declaredParameter.getTypeReference();

        JetType type;
        if (typeReference != null) {
          type = context.getTypeResolver().resolveType(context.scope, typeReference);
        } else {
          if (expectedValueParameters != null && i < expectedValueParameters.size()) {
            type = expectedValueParameters.get(i).getOutType();
          } else {
            context.trace.report(CANNOT_INFER_PARAMETER_TYPE.on(declaredParameter));
            type = ErrorUtils.createErrorType("Cannot be inferred");
          }
        }
        ValueParameterDescriptor valueParameterDescriptor =
            context
                .getDescriptorResolver()
                .resolveValueParameterDescriptor(functionDescriptor, declaredParameter, i, type);
        valueParameterDescriptors.add(valueParameterDescriptor);
      }
    }
    return valueParameterDescriptors;
  }
  @NotNull
  private static List<ValueParameterDescriptor> createValueParameterDescriptors(
      @NotNull ExpressionTypingContext context,
      @NotNull JetFunctionLiteral functionLiteral,
      @NotNull FunctionDescriptorImpl functionDescriptor,
      boolean functionTypeExpected) {
    List<ValueParameterDescriptor> valueParameterDescriptors = Lists.newArrayList();
    List<JetParameter> declaredValueParameters = functionLiteral.getValueParameters();

    List<ValueParameterDescriptor> expectedValueParameters =
        (functionTypeExpected)
            ? KotlinBuiltIns.getInstance()
                .getValueParameters(functionDescriptor, context.expectedType)
            : null;

    JetParameterList valueParameterList = functionLiteral.getValueParameterList();
    boolean hasDeclaredValueParameters = valueParameterList != null;
    if (functionTypeExpected
        && !hasDeclaredValueParameters
        && expectedValueParameters.size() == 1) {
      ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0);
      ValueParameterDescriptor it =
          new ValueParameterDescriptorImpl(
              functionDescriptor,
              0,
              Collections.<AnnotationDescriptor>emptyList(),
              Name.identifier("it"),
              valueParameterDescriptor.getType(),
              valueParameterDescriptor.hasDefaultValue(),
              valueParameterDescriptor.getVarargElementType());
      valueParameterDescriptors.add(it);
      context.trace.record(AUTO_CREATED_IT, it);
    } else {
      if (expectedValueParameters != null
          && declaredValueParameters.size() != expectedValueParameters.size()) {
        List<JetType> expectedParameterTypes =
            DescriptorUtils.getValueParametersTypes(expectedValueParameters);
        context.trace.report(
            EXPECTED_PARAMETERS_NUMBER_MISMATCH.on(
                functionLiteral, expectedParameterTypes.size(), expectedParameterTypes));
      }
      for (int i = 0; i < declaredValueParameters.size(); i++) {
        ValueParameterDescriptor valueParameterDescriptor =
            createValueParameterDescriptor(
                context, functionDescriptor, declaredValueParameters, expectedValueParameters, i);
        valueParameterDescriptors.add(valueParameterDescriptor);
      }
    }
    return valueParameterDescriptors;
  }
Ejemplo n.º 5
0
 private void checkDefaultParameterValues(
     List<JetParameter> valueParameters,
     List<ValueParameterDescriptor> valueParameterDescriptors,
     JetScope declaringScope) {
   for (int i = 0; i < valueParameters.size(); i++) {
     ValueParameterDescriptor valueParameterDescriptor = valueParameterDescriptors.get(i);
     if (valueParameterDescriptor.hasDefaultValue()) {
       JetParameter jetParameter = valueParameters.get(i);
       JetExpression defaultValue = jetParameter.getDefaultValue();
       if (defaultValue != null) {
         expressionTypingServices.getType(
             declaringScope, defaultValue, valueParameterDescriptor.getType(), trace);
       }
     }
   }
 }
Ejemplo n.º 6
0
  private void createComponentFunctions(
      @NotNull MutableClassDescriptor classDescriptor,
      @NotNull ConstructorDescriptor constructorDescriptor) {
    int parameterIndex = 0;
    for (ValueParameterDescriptor parameter : constructorDescriptor.getValueParameters()) {
      if (!parameter.getType().isError()) {
        PropertyDescriptor property =
            trace.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter);
        if (property != null) {
          ++parameterIndex;

          SimpleFunctionDescriptor functionDescriptor =
              DescriptorResolver.createComponentFunctionDescriptor(
                  parameterIndex, property, parameter, classDescriptor, trace);

          classDescriptor.getBuilder().addFunctionDescriptor(functionDescriptor);
        }
      }
    }
  }
 private static String renderParameter(
     ValueParameterDescriptor parameter, boolean named, BindingContext bindingContext) {
   StringBuilder builder = new StringBuilder();
   if (named) builder.append("[");
   if (parameter.getVarargElementType() != null) {
     builder.append("vararg ");
   }
   builder
       .append(parameter.getName())
       .append(": ")
       .append(
           DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(getActualParameterType(parameter)));
   if (parameter.hasDefaultValue()) {
     PsiElement parameterDeclaration =
         BindingContextUtils.descriptorToDeclaration(bindingContext, parameter);
     builder.append(" = ").append(getDefaultExpressionString(parameterDeclaration));
   }
   if (named) builder.append("]");
   return builder.toString();
 }
  @Override
  public JetType visitFunctionLiteralExpression(
      JetFunctionLiteralExpression expression, ExpressionTypingContext context) {
    JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
    JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
    if (bodyExpression == null) return null;

    JetType expectedType = context.expectedType;
    boolean functionTypeExpected =
        expectedType != TypeUtils.NO_EXPECTED_TYPE
            && JetStandardClasses.isFunctionType(expectedType);

    NamedFunctionDescriptorImpl functionDescriptor =
        createFunctionDescriptor(expression, context, functionTypeExpected);

    List<JetType> parameterTypes = Lists.newArrayList();
    List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
    for (ValueParameterDescriptor valueParameter : valueParameters) {
      parameterTypes.add(valueParameter.getOutType());
    }
    ReceiverDescriptor receiverParameter = functionDescriptor.getReceiverParameter();
    JetType receiver = receiverParameter != NO_RECEIVER ? receiverParameter.getType() : null;

    JetType returnType = TypeUtils.NO_EXPECTED_TYPE;
    JetScope functionInnerScope =
        FunctionDescriptorUtil.getFunctionInnerScope(
            context.scope, functionDescriptor, context.trace);
    JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
    if (returnTypeRef != null) {
      returnType = context.getTypeResolver().resolveType(context.scope, returnTypeRef);
      context
          .getServices()
          .checkFunctionReturnType(
              expression,
              context
                  .replaceScope(functionInnerScope)
                  .replaceExpectedType(returnType)
                  .replaceExpectedReturnType(returnType)
                  .replaceDataFlowInfo(context.dataFlowInfo));
    } else {
      if (functionTypeExpected) {
        returnType = JetStandardClasses.getReturnTypeFromFunctionType(expectedType);
      }
      returnType =
          context
              .getServices()
              .getBlockReturnedType(
                  functionInnerScope,
                  bodyExpression,
                  CoercionStrategy.COERCION_TO_UNIT,
                  context.replaceExpectedType(returnType).replaceExpectedReturnType(returnType));
    }
    JetType safeReturnType =
        returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
    functionDescriptor.setReturnType(safeReturnType);

    boolean hasDeclaredValueParameters = functionLiteral.getValueParameterList() != null;
    if (!hasDeclaredValueParameters && functionTypeExpected) {
      JetType expectedReturnType = JetStandardClasses.getReturnTypeFromFunctionType(expectedType);
      if (JetStandardClasses.isUnit(expectedReturnType)) {
        functionDescriptor.setReturnType(JetStandardClasses.getUnitType());
        return DataFlowUtils.checkType(
            JetStandardClasses.getFunctionType(
                Collections.<AnnotationDescriptor>emptyList(),
                receiver,
                parameterTypes,
                JetStandardClasses.getUnitType()),
            expression,
            context);
      }
    }
    return DataFlowUtils.checkType(
        JetStandardClasses.getFunctionType(
            Collections.<AnnotationDescriptor>emptyList(),
            receiver,
            parameterTypes,
            safeReturnType),
        expression,
        context);
  }
  @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);
    }
  }
 private static JetType getActualParameterType(ValueParameterDescriptor descriptor) {
   JetType paramType = descriptor.getType();
   if (descriptor.getVarargElementType() != null) paramType = descriptor.getVarargElementType();
   return paramType;
 }
  @Override
  public void updateUI(
      Pair<? extends FunctionDescriptor, CancelableResolveSession> itemToShow,
      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()) {
      context.setUIComponentEnabled(false);
      return;
    }

    PsiElement parameterOwner = context.getParameterOwner();
    if (!(parameterOwner instanceof JetValueArgumentList)) {
      context.setUIComponentEnabled(false);
      return;
    }

    JetValueArgumentList argumentList = (JetValueArgumentList) parameterOwner;

    FunctionDescriptor functionDescriptor = itemToShow.first;
    CancelableResolveSession resolveSession = itemToShow.second;

    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

    boolean[] usedIndexes = new boolean[valueParameters.size()];
    Arrays.fill(usedIndexes, false);

    boolean namedMode = false;

    if (!isIndexValid(valueParameters, currentParameterIndex)) {
      isGrey = true;
    }

    StringBuilder builder = new StringBuilder();

    PsiElement owner = context.getParameterOwner();
    BindingContext bindingContext = resolveSession.resolveToElement((JetElement) owner);

    for (int i = 0; i < valueParameters.size(); ++i) {
      if (i != 0) {
        builder.append(", ");
      }

      boolean highlightParameter =
          i == currentParameterIndex
              || (!namedMode
                  && i < currentParameterIndex
                  && Iterables.getLast(valueParameters).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
                && !isArgumentTypeValid(bindingContext, argument, param)) {
              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
                    && !isArgumentTypeValid(bindingContext, argument, param)) {
                  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 (valueParameters.size() == 0) {
      builder.append(CodeInsightBundle.message("parameter.info.no.parameters"));
    }

    assert !builder.toString().isEmpty()
        : "A message about 'no parameters' or some parameters should be present: "
            + functionDescriptor;

    Color color =
        isResolvedToDescriptor(argumentList, functionDescriptor, bindingContext)
            ? GREEN_BACKGROUND
            : context.getDefaultParameterColor();
    context.setupUIComponentPresentation(
        builder.toString(), boldStartOffset, boldEndOffset, isGrey, isDeprecated, false, color);
  }