@NotNull @Override public MyResult weigh(@NotNull LookupElement item) { final Object object = item.getObject(); if (object instanceof PsiClass) { if (object instanceof PsiTypeParameter) return MyResult.typeParameter; if (myTypeParameter != null && object.equals( PsiUtil.resolveClassInType( TypeConversionUtil.typeParameterErasure(myTypeParameter)))) { return MyResult.exactlyExpected; } } if (myExpectedTypes == null) return MyResult.normal; PsiType itemType = JavaCompletionUtil.getLookupElementType(item); if (itemType == null || !itemType.isValid()) return MyResult.normal; if (object instanceof PsiClass) { for (final ExpectedTypeInfo info : myExpectedTypes) { if (TypeConversionUtil.erasure(info.getType().getDeepComponentType()) .equals(TypeConversionUtil.erasure(itemType))) { return AbstractExpectedTypeSkipper.skips(item, myLocation) ? MyResult.expectedNoSelect : MyResult.exactlyExpected; } } } for (final ExpectedTypeInfo expectedInfo : myExpectedTypes) { final PsiType defaultType = expectedInfo.getDefaultType(); final PsiType expectedType = expectedInfo.getType(); if (!expectedType.isValid()) { return MyResult.normal; } if (defaultType != expectedType) { if (defaultType.equals(itemType)) { return MyResult.exactlyDefault; } if (defaultType.isAssignableFrom(itemType)) { return MyResult.ofDefaultType; } } if (PsiType.VOID.equals(itemType) && PsiType.VOID.equals(expectedType)) { return MyResult.exactlyExpected; } } return MyResult.normal; }
private static boolean shouldInsertParentheses(PsiClass psiClass, PsiElement position) { final PsiJavaCodeReferenceElement ref = PsiTreeUtil.getParentOfType(position, PsiJavaCodeReferenceElement.class); if (ref == null) { return false; } final PsiReferenceParameterList parameterList = ref.getParameterList(); if (parameterList != null && parameterList.getTextLength() > 0) { return false; } final PsiElement prevElement = FilterPositionUtil.searchNonSpaceNonCommentBack(ref); if (prevElement != null && prevElement.getParent() instanceof PsiNewExpression) { Set<PsiType> expectedTypes = new HashSet<PsiType>(); for (ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes((PsiExpression) prevElement.getParent(), true)) { expectedTypes.add(info.getType()); } return JavaCompletionUtil.isDefinitelyExpected(psiClass, expectedTypes, position); } return false; }
private static boolean mayExpectBoolean(CompletionParameters parameters) { for (ExpectedTypeInfo info : JavaSmartCompletionContributor.getExpectedTypes(parameters)) { PsiType type = info.getType(); if (type instanceof PsiClassType || type == PsiType.BOOLEAN) return true; } return false; }
@Override protected void addCompletions( @NotNull final CompletionParameters parameters, final ProcessingContext processingContext, @NotNull final CompletionResultSet resultSet) { final PsiElement context = parameters.getPosition(); final Pair<PsiClass, Integer> pair = getTypeParameterInfo(context); if (pair == null) return; PsiExpression expression = PsiTreeUtil.getContextOfType(context, PsiExpression.class, true); if (expression != null) { ExpectedTypeInfo[] types = ExpectedTypesProvider.getExpectedTypes(expression, true, false, false); if (types.length > 0) { for (ExpectedTypeInfo info : types) { PsiType type = info.getType(); if (type instanceof PsiClassType && !type.equals(expression.getType())) { fillExpectedTypeArgs( resultSet, context, pair.first, pair.second, ((PsiClassType) type).resolveGenerics(), mySmart ? info.getTailType() : TailType.NONE); } } return; } } if (mySmart) { addInheritors(parameters, resultSet, pair.first, pair.second); } }
private List<PsiType> matchingTypeParameters( PsiType[] paramVals, PsiTypeParameter[] params, ExpectedTypeInfo info) { PsiType type = info.getType(); int kind = info.getKind(); List<PsiType> result = new ArrayList<>(); for (int i = 0; i < paramVals.length; i++) { PsiType val = paramVals[i]; if (val != null) { switch (kind) { case ExpectedTypeInfo.TYPE_STRICTLY: if (val.equals(type)) result.add(myFactory.createType(params[i])); break; case ExpectedTypeInfo.TYPE_OR_SUBTYPE: if (type.isAssignableFrom(val)) result.add(myFactory.createType(params[i])); break; case ExpectedTypeInfo.TYPE_OR_SUPERTYPE: if (val.isAssignableFrom(type)) result.add(myFactory.createType(params[i])); break; } } } return result; }
protected void addCompletions( @NotNull final CompletionParameters parameters, final ProcessingContext processingContext, @NotNull final CompletionResultSet resultSet) { final PsiElement context = parameters.getPosition(); final Pair<PsiClass, Integer> pair = getTypeParameterInfo(context); if (pair == null) return; ExpectedTypeInfo[] types = JavaSmartCompletionContributor.getExpectedTypes(parameters, false); if (types.length > 0) { for (ExpectedTypeInfo info : types) { PsiType type = info.getType(); if (type instanceof PsiClassType) { fillExpectedTypeArgs( resultSet, context, pair.first, pair.second, ((PsiClassType) type).resolveGenerics(), mySmart ? info.getTailType() : TailType.NONE); } } } else if (mySmart) { addInheritors(parameters, resultSet, pair.first, pair.second); } }
private static boolean hasNonVoid(ExpectedTypeInfo[] expectedInfos) { boolean hasNonVoid = false; for (ExpectedTypeInfo info : expectedInfos) { if (!PsiType.VOID.equals(info.getType())) { hasNonVoid = true; } } return hasNonVoid; }
private static void suggestCollectionUtilities( CompletionParameters parameters, final CompletionResultSet result, PsiElement position) { if (StringUtil.isNotEmpty(result.getPrefixMatcher().getPrefix())) { for (ExpectedTypeInfo info : JavaSmartCompletionContributor.getExpectedTypes(parameters)) { new CollectionsUtilityMethodsProvider( position, info.getType(), info.getDefaultType(), result) .addCompletions(true); } } }
private static ExpectedTypeMatching getExpectedTypeMatching( LookupElement item, ExpectedTypeInfo[] expectedInfos) { PsiType itemType = JavaCompletionUtil.getLookupElementType(item); if (itemType != null) { for (final ExpectedTypeInfo expectedInfo : expectedInfos) { final PsiType defaultType = expectedInfo.getDefaultType(); final PsiType expectedType = expectedInfo.getType(); if (defaultType != expectedType && defaultType.isAssignableFrom(itemType)) { return ExpectedTypeMatching.ofDefaultType; } if (expectedType.isAssignableFrom(itemType)) { return ExpectedTypeMatching.expected; } } } boolean hasNonVoid = false; for (ExpectedTypeInfo info : expectedInfos) { if (!PsiType.VOID.equals(info.getType())) { hasNonVoid = true; } } if (hasNonVoid) { if (item.getObject() instanceof PsiKeyword) { String keyword = ((PsiKeyword) item.getObject()).getText(); if (PsiKeyword.NEW.equals(keyword) || PsiKeyword.NULL.equals(keyword)) { return ExpectedTypeMatching.maybeExpected; } } } else if (expectedInfos.length > 0) { return ExpectedTypeMatching.unexpected; } return ExpectedTypeMatching.normal; }
@Nullable public static Set<PsiType> getExpectedTypes(final CompletionParameters parameters) { final PsiExpression expr = PsiTreeUtil.getContextOfType(parameters.getPosition(), PsiExpression.class, true); if (expr != null) { final Set<PsiType> set = new THashSet<PsiType>(); for (final ExpectedTypeInfo expectedInfo : JavaSmartCompletionContributor.getExpectedTypes(parameters)) { set.add(expectedInfo.getType()); } return set; } return null; }
private static ExpectedTypeMatching getExpectedTypeMatching( LookupElement item, ExpectedTypeInfo[] expectedInfos, @Nullable String expectedMemberName) { PsiType itemType = JavaCompletionUtil.getLookupElementType(item); if (itemType != null) { PsiUtil.ensureValidType(itemType); for (final ExpectedTypeInfo expectedInfo : expectedInfos) { final PsiType defaultType = expectedInfo.getDefaultType(); final PsiType expectedType = expectedInfo.getType(); assert expectedType.isValid(); assert defaultType.isValid(); if (defaultType != expectedType && defaultType.isAssignableFrom(itemType)) { return ExpectedTypeMatching.ofDefaultType; } if (expectedType.isAssignableFrom(itemType)) { return ExpectedTypeMatching.expected; } } } if (hasNonVoid(expectedInfos)) { if (item.getObject() instanceof PsiKeyword) { String keyword = ((PsiKeyword) item.getObject()).getText(); if (PsiKeyword.NEW.equals(keyword) || PsiKeyword.NULL.equals(keyword)) { return ExpectedTypeMatching.maybeExpected; } } } else if (expectedInfos.length > 0) { return ExpectedTypeMatching.unexpected; } return preferByMemberName(expectedMemberName, itemType); }
public Result weigh( @NotNull final LookupElement element, @NotNull final CompletionLocation location) { if (location == null) { return null; } if (location.getCompletionType() != CompletionType.BASIC && location.getCompletionType() != CompletionType.SMART) return Result.normal; final Object object = element.getObject(); if (!(object instanceof PsiModifierListOwner) && !(object instanceof PsiExpression)) return Result.normal; final PsiMethod positionMethod = JavaCompletionUtil.POSITION_METHOD.getValue(location); if (positionMethod == null) return Result.normal; final PsiElement position = location.getCompletionParameters().getPosition(); final ElementFilter filter = JavaCompletionUtil.recursionFilter(position); if (filter != null && !filter.isAcceptable(object, position)) { return Result.recursive; } final PsiMethodCallExpression expression = PsiTreeUtil.getParentOfType(position, PsiMethodCallExpression.class, true, PsiClass.class); final PsiReferenceExpression reference = expression != null ? expression.getMethodExpression() : PsiTreeUtil.getParentOfType(position, PsiReferenceExpression.class); if (reference == null) return Result.normal; final PsiExpression qualifier = reference.getQualifierExpression(); boolean isDelegate = qualifier != null && !(qualifier instanceof PsiThisExpression); if (isPassingObjectToItself(object, qualifier, isDelegate)) { return Result.passingObjectToItself; } if (expression != null) { final ExpectedTypeInfo[] expectedInfos = JavaCompletionUtil.EXPECTED_TYPES.getValue(location); if (expectedInfos != null) { final PsiType itemType = JavaCompletionUtil.getLookupElementType(element); if (itemType != null) { for (final ExpectedTypeInfo expectedInfo : expectedInfos) { if (positionMethod.equals(expectedInfo.getCalledMethod()) && expectedInfo.getType().isAssignableFrom(itemType)) { return isDelegate ? Result.delegation : Result.recursive; } } } } return Result.normal; } if (object instanceof PsiMethod) { final PsiMethod method = (PsiMethod) object; if (PsiTreeUtil.isAncestor(reference, position, false) && Comparing.equal(method.getName(), positionMethod.getName()) && method.getParameterList().getParametersCount() == positionMethod.getParameterList().getParametersCount()) { if (findDeepestSuper(method).equals(findDeepestSuper(positionMethod))) { return isDelegate ? Result.delegation : Result.recursive; } } } return Result.normal; }
public void setupTypeElement( PsiTypeElement typeElement, ExpectedTypeInfo[] infos, PsiSubstitutor substitutor, TemplateBuilder builder, @Nullable PsiElement context, PsiClass targetClass) { LOG.assertTrue(typeElement.isValid()); ApplicationManager.getApplication().assertWriteAccessAllowed(); PsiManager manager = typeElement.getManager(); GlobalSearchScope scope = typeElement.getResolveScope(); Project project = manager.getProject(); if (infos.length == 1 && substitutor != null && substitutor != PsiSubstitutor.EMPTY) { ExpectedTypeInfo info = infos[0]; Map<PsiTypeParameter, PsiType> map = substitutor.getSubstitutionMap(); PsiType[] vals = map.values().toArray(PsiType.createArray(map.size())); PsiTypeParameter[] params = map.keySet().toArray(new PsiTypeParameter[map.size()]); List<PsiType> types = matchingTypeParameters(vals, params, info); if (!types.isEmpty()) { ContainerUtil.addAll( types, ExpectedTypesProvider.processExpectedTypes( infos, new MyTypeVisitor(manager, scope), project)); builder.replaceElement( typeElement, new TypeExpression(project, types.toArray(PsiType.createArray(types.size())))); return; } else { PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); PsiType type = info.getType(); PsiType defaultType = info.getDefaultType(); try { PsiTypeElement inplaceTypeElement = ((PsiVariable) factory.createVariableDeclarationStatement("foo", type, null) .getDeclaredElements()[0]) .getTypeElement(); PsiSubstitutor rawingSubstitutor = getRawingSubstitutor(context, targetClass); int substitionResult = substituteToTypeParameters( typeElement, inplaceTypeElement, vals, params, builder, rawingSubstitutor, true); if (substitionResult != SUBSTITUTED_NONE) { if (substitionResult == SUBSTITUTED_IN_PARAMETERS) { PsiJavaCodeReferenceElement refElement = typeElement.getInnermostComponentReferenceElement(); LOG.assertTrue(refElement != null && refElement.getReferenceNameElement() != null); type = getComponentType(type); LOG.assertTrue(type != null); defaultType = getComponentType(defaultType); LOG.assertTrue(defaultType != null); ExpectedTypeInfo info1 = ExpectedTypesProvider.createInfo( ((PsiClassType) defaultType).rawType(), ExpectedTypeInfo.TYPE_STRICTLY, ((PsiClassType) defaultType).rawType(), info.getTailType()); MyTypeVisitor visitor = new MyTypeVisitor(manager, scope); builder.replaceElement( refElement.getReferenceNameElement(), new TypeExpression( project, ExpectedTypesProvider.processExpectedTypes( new ExpectedTypeInfo[] {info1}, visitor, project))); } return; } } catch (IncorrectOperationException e) { LOG.error(e); } } } PsiType[] types = infos.length == 0 ? new PsiType[] {typeElement.getType()} : ExpectedTypesProvider.processExpectedTypes( infos, new MyTypeVisitor(manager, scope), project); builder.replaceElement(typeElement, new TypeExpression(project, types)); }