@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; }
@Nullable private static JetSimpleNameExpression getCallSimpleNameExpression( JetValueArgumentList argumentList) { PsiElement argumentListParent = argumentList.getParent(); return (argumentListParent instanceof JetCallElement) ? PsiUtilPackage.getCallNameExpression((JetCallElement) argumentListParent) : null; }
private static JetValueArgumentList findCallAndUpdateContext(UpdateParameterInfoContext context) { PsiFile file = context.getFile(); PsiElement element = file.findElementAt(context.getOffset()); if (element == null) return null; PsiElement parent = element.getParent(); while (parent != null && !(parent instanceof JetValueArgumentList)) { element = element.getParent(); parent = parent.getParent(); } if (parent == null) return null; JetValueArgumentList argumentList = (JetValueArgumentList) parent; if (element instanceof JetValueArgument) { JetValueArgument arg = (JetValueArgument) element; int i = argumentList.getArguments().indexOf(arg); context.setCurrentParameter(i); context.setHighlightedParameter(arg); } return argumentList; }
@Override public void updateParameterInfo( @NotNull JetValueArgumentList argumentList, @NotNull UpdateParameterInfoContext context) { if (context.getParameterOwner() != argumentList) context.removeHint(); int offset = context.getOffset(); ASTNode child = argumentList.getNode().getFirstChildNode(); int i = 0; while (child != null && child.getStartOffset() < offset) { if (child.getElementType() == JetTokens.COMMA) ++i; child = child.getTreeNext(); } context.setCurrentParameter(i); }
@NotNull @Override public JetValueArgument[] getActualParameters(@NotNull JetValueArgumentList arguments) { List<JetValueArgument> argumentList = arguments.getArguments(); return argumentList.toArray(new JetValueArgument[argumentList.size()]); }
@Override public void updateUI( Pair<? extends FunctionDescriptor, ResolutionFacade> itemToShow, @NotNull 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; ResolutionFacade resolutionFacade = 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 = KotlinBuiltIns.isDeprecated(functionDescriptor); 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 = resolutionFacade.analyze((JetElement) owner, BodyResolveMode.FULL); 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)); if (i <= currentParameterIndex && !isArgumentTypeValid(bindingContext, argument, param)) { isGrey = true; } usedIndexes[i] = true; } } else { ValueParameterDescriptor param = valueParameters.get(i); builder.append(renderParameter(param, false)); } } 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)); 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)); 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); }
@Override public void showParameterInfo( @NotNull JetValueArgumentList element, @NotNull CreateParameterInfoContext context) { context.showHint(element, element.getTextRange().getStartOffset(), this); }
@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); } }