private static void findTypeParameterExternalUsages(
      final PsiTypeParameter typeParameter, final Collection<UsageInfo> usages) {
    PsiTypeParameterListOwner owner = typeParameter.getOwner();
    if (owner != null) {
      final PsiTypeParameterList parameterList = owner.getTypeParameterList();
      if (parameterList != null) {
        final int paramsCount = parameterList.getTypeParameters().length;
        final int index = parameterList.getTypeParameterIndex(typeParameter);

        ReferencesSearch.search(owner)
            .forEach(
                reference -> {
                  if (reference instanceof PsiJavaCodeReferenceElement) {
                    final PsiReferenceParameterList parameterList1 =
                        ((PsiJavaCodeReferenceElement) reference).getParameterList();
                    if (parameterList1 != null) {
                      PsiTypeElement[] typeArgs = parameterList1.getTypeParameterElements();
                      if (typeArgs.length > index) {
                        if (typeArgs.length == 1
                            && paramsCount > 1
                            && typeArgs[0].getType() instanceof PsiDiamondType) return true;
                        usages.add(
                            new SafeDeleteReferenceJavaDeleteUsageInfo(
                                typeArgs[index], typeParameter, true));
                      }
                    }
                  }
                  return true;
                });
      }
    }
  }
Beispiel #2
0
  private static boolean changeClassTypeArgument(
      PsiMethod myMethod,
      Project project,
      PsiType superReturnType,
      PsiClass superClass,
      Editor editor,
      PsiType returnType) {
    if (superClass == null || !superClass.hasTypeParameters()) return true;
    final PsiClass superReturnTypeClass = PsiUtil.resolveClassInType(superReturnType);
    if (superReturnTypeClass == null
        || !(superReturnTypeClass instanceof PsiTypeParameter
            || superReturnTypeClass.hasTypeParameters())) return true;

    final PsiClass derivedClass = myMethod.getContainingClass();
    if (derivedClass == null) return true;

    final PsiReferenceParameterList referenceParameterList =
        findTypeArgumentsList(superClass, derivedClass);
    if (referenceParameterList == null) return true;

    final PsiElement resolve =
        ((PsiJavaCodeReferenceElement) referenceParameterList.getParent()).resolve();
    if (!(resolve instanceof PsiClass)) return true;
    final PsiClass baseClass = (PsiClass) resolve;

    if (returnType instanceof PsiPrimitiveType) {
      returnType = ((PsiPrimitiveType) returnType).getBoxedType(derivedClass);
    }

    final PsiSubstitutor superClassSubstitutor =
        TypeConversionUtil.getSuperClassSubstitutor(superClass, baseClass, PsiSubstitutor.EMPTY);
    final PsiType superReturnTypeInBaseClassType =
        superClassSubstitutor.substitute(superReturnType);
    final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(project).getResolveHelper();
    final PsiSubstitutor psiSubstitutor =
        resolveHelper.inferTypeArguments(
            PsiTypesUtil.filterUnusedTypeParameters(
                superReturnTypeInBaseClassType, baseClass.getTypeParameters()),
            new PsiType[] {superReturnTypeInBaseClassType},
            new PsiType[] {returnType},
            PsiUtil.getLanguageLevel(superClass));

    final TypeMigrationRules rules = new TypeMigrationRules();
    final PsiSubstitutor compoundSubstitutor =
        TypeConversionUtil.getSuperClassSubstitutor(superClass, derivedClass, PsiSubstitutor.EMPTY)
            .putAll(psiSubstitutor);
    rules.setBoundScope(new LocalSearchScope(derivedClass));
    TypeMigrationProcessor.runHighlightingTypeMigration(
        project,
        editor,
        rules,
        referenceParameterList,
        JavaPsiFacade.getElementFactory(project).createType(baseClass, compoundSubstitutor));

    return false;
  }
  @Override
  public void beforeCompletion(@NotNull final CompletionInitializationContext context) {
    final PsiFile file = context.getFile();

    if (file instanceof PsiJavaFile) {
      JavaCompletionUtil.initOffsets(file, context.getOffsetMap());

      autoImport(file, context.getStartOffset() - 1, context.getEditor());

      if (context.getCompletionType() == CompletionType.BASIC) {
        if (semicolonNeeded(context.getEditor(), file, context.getStartOffset())) {
          context.setDummyIdentifier(CompletionInitializationContext.DUMMY_IDENTIFIER.trim() + ";");
          return;
        }

        final PsiJavaCodeReferenceElement ref =
            PsiTreeUtil.findElementOfClassAtOffset(
                file, context.getStartOffset(), PsiJavaCodeReferenceElement.class, false);
        if (ref != null && !(ref instanceof PsiReferenceExpression)) {
          if (ref.getParent() instanceof PsiTypeElement) {
            context.setDummyIdentifier(
                CompletionInitializationContext.DUMMY_IDENTIFIER.trim() + ";");
          }

          if (JavaSmartCompletionContributor.AFTER_NEW.accepts(ref)) {
            final PsiReferenceParameterList paramList = ref.getParameterList();
            if (paramList != null && paramList.getTextLength() > 0) {
              context
                  .getOffsetMap()
                  .addOffset(
                      ConstructorInsertHandler.PARAM_LIST_START,
                      paramList.getTextRange().getStartOffset());
              context
                  .getOffsetMap()
                  .addOffset(
                      ConstructorInsertHandler.PARAM_LIST_END,
                      paramList.getTextRange().getEndOffset());
            }
          }

          return;
        }

        final PsiElement element = file.findElementAt(context.getStartOffset());

        if (psiElement().inside(PsiAnnotation.class).accepts(element)) {
          return;
        }

        context.setDummyIdentifier(CompletionInitializationContext.DUMMY_IDENTIFIER_TRIMMED);
      }
    }
  }
  private void markTypeParameterUsages(
      final PsiClass psiClass,
      PsiClassType migrationType,
      PsiReferenceParameterList referenceParameterList,
      final Map<PsiElement, Pair<PsiReference[], PsiType>> roots) {

    final PsiSubstitutor[] fullHierarchySubstitutor = {
      migrationType.resolveGenerics().getSubstitutor()
    };
    RefactoringHierarchyUtil.processSuperTypes(
        migrationType,
        new RefactoringHierarchyUtil.SuperTypeVisitor() {
          @Override
          public void visitType(PsiType aType) {
            fullHierarchySubstitutor[0] =
                fullHierarchySubstitutor[0].putAll(
                    ((PsiClassType) aType).resolveGenerics().getSubstitutor());
          }

          @Override
          public void visitClass(PsiClass aClass) {
            // do nothing
          }
        });

    final PsiClass resolvedClass =
        (PsiClass) ((PsiJavaCodeReferenceElement) referenceParameterList.getParent()).resolve();
    ;
    LOG.assertTrue(resolvedClass != null);
    final Set<PsiClass> superClasses = new HashSet<PsiClass>();
    superClasses.add(resolvedClass);
    InheritanceUtil.getSuperClasses(resolvedClass, superClasses, true);
    for (PsiClass superSuperClass : superClasses) {
      final TypeParameterSearcher parameterSearcher =
          new TypeParameterSearcher(superSuperClass.getTypeParameters());
      superSuperClass.accept(
          new JavaRecursiveElementVisitor() {
            @Override
            public void visitMethod(final PsiMethod method) {
              super.visitMethod(method);
              processMemberType(
                  method, parameterSearcher, psiClass, fullHierarchySubstitutor[0], roots);
              for (PsiParameter parameter : method.getParameterList().getParameters()) {
                processMemberType(
                    parameter, parameterSearcher, psiClass, fullHierarchySubstitutor[0], roots);
              }
            }

            @Override
            public void visitField(final PsiField field) {
              super.visitField(field);
              processMemberType(
                  field, parameterSearcher, psiClass, fullHierarchySubstitutor[0], roots);
            }
          });
    }
  }
  public static int insertClassReference(
      PsiClass psiClass, PsiFile file, int startOffset, int endOffset) {
    final Project project = file.getProject();
    PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
    documentManager.commitAllDocuments();

    final PsiManager manager = file.getManager();

    final Document document =
        FileDocumentManager.getInstance().getDocument(file.getViewProvider().getVirtualFile());

    final PsiReference reference = file.findReferenceAt(startOffset);
    if (reference != null) {
      final PsiElement resolved = reference.resolve();
      if (resolved instanceof PsiClass) {
        if (((PsiClass) resolved).getQualifiedName() == null
            || manager.areElementsEquivalent(psiClass, resolved)) {
          return endOffset;
        }
      }
    }

    String name = psiClass.getName();
    if (name == null) {
      return endOffset;
    }

    assert document != null;
    document.replaceString(startOffset, endOffset, name);

    int newEndOffset = startOffset + name.length();
    final RangeMarker toDelete = insertTemporary(newEndOffset, document, " ");

    documentManager.commitAllDocuments();

    PsiElement element = file.findElementAt(startOffset);
    if (element instanceof PsiIdentifier) {
      PsiElement parent = element.getParent();
      if (parent instanceof PsiJavaCodeReferenceElement
          && !((PsiJavaCodeReferenceElement) parent).isQualified()
          && !(parent.getParent() instanceof PsiPackageStatement)) {
        PsiJavaCodeReferenceElement ref = (PsiJavaCodeReferenceElement) parent;

        if (psiClass.isValid()
            && !psiClass.getManager().areElementsEquivalent(psiClass, resolveReference(ref))) {
          final boolean staticImport = ref instanceof PsiImportStaticReferenceElement;
          PsiElement newElement;
          try {
            newElement =
                staticImport
                    ? ((PsiImportStaticReferenceElement) ref).bindToTargetClass(psiClass)
                    : ref.bindToElement(psiClass);
          } catch (IncorrectOperationException e) {
            return endOffset; // can happen if fqn contains reserved words, for example
          }

          final RangeMarker rangeMarker = document.createRangeMarker(newElement.getTextRange());
          documentManager.doPostponedOperationsAndUnblockDocument(document);
          documentManager.commitDocument(document);

          newElement =
              CodeInsightUtilCore.findElementInRange(
                  file,
                  rangeMarker.getStartOffset(),
                  rangeMarker.getEndOffset(),
                  PsiJavaCodeReferenceElement.class,
                  JavaLanguage.INSTANCE);
          rangeMarker.dispose();
          if (newElement != null) {
            newEndOffset = newElement.getTextRange().getEndOffset();
            if (!(newElement instanceof PsiReferenceExpression)) {
              PsiReferenceParameterList parameterList =
                  ((PsiJavaCodeReferenceElement) newElement).getParameterList();
              if (parameterList != null) {
                newEndOffset = parameterList.getTextRange().getStartOffset();
              }
            }

            if (!staticImport
                && !psiClass
                    .getManager()
                    .areElementsEquivalent(psiClass, resolveReference((PsiReference) newElement))
                && !PsiUtil.isInnerClass(psiClass)) {
              final String qName = psiClass.getQualifiedName();
              if (qName != null) {
                document.replaceString(
                    newElement.getTextRange().getStartOffset(), newEndOffset, qName);
                newEndOffset = newElement.getTextRange().getStartOffset() + qName.length();
              }
            }
          }
        }
      }
    }

    if (toDelete.isValid()) {
      document.deleteString(toDelete.getStartOffset(), toDelete.getEndOffset());
    }

    return newEndOffset;
  }
  public static boolean isFreeFromTypeInferenceArgs(
      final PsiParameter[] methodParameters,
      final PsiLambdaExpression lambdaExpression,
      final PsiExpression expression,
      final PsiSubstitutor subst,
      final PsiType functionalInterfaceType,
      final PsiTypeParameter typeParam) {
    if (expression instanceof PsiCallExpression
        && ((PsiCallExpression) expression).getTypeArguments().length > 0) return true;
    if (expression instanceof PsiNewExpression) {
      final PsiJavaCodeReferenceElement classReference =
          ((PsiNewExpression) expression).getClassOrAnonymousClassReference();
      if (classReference != null) {
        final PsiReferenceParameterList parameterList = classReference.getParameterList();
        if (parameterList != null) {
          final PsiTypeElement[] typeParameterElements = parameterList.getTypeParameterElements();
          if (typeParameterElements.length > 0) {
            if (!(typeParameterElements[0].getType() instanceof PsiDiamondType)) {
              return true;
            }
          }
        }
      }
    }
    final PsiParameter[] lambdaParams = lambdaExpression.getParameterList().getParameters();
    if (lambdaParams.length != methodParameters.length) return false;
    final boolean[] independent = {true};
    final PsiMethod interfaceMethod = getFunctionalInterfaceMethod(functionalInterfaceType);
    if (interfaceMethod == null) return false;
    final TypeParamsChecker paramsChecker = new TypeParamsChecker(lambdaExpression);
    for (PsiParameter parameter : interfaceMethod.getParameterList().getParameters()) {
      subst.substitute(parameter.getType()).accept(paramsChecker);
    }
    paramsChecker.myUsedTypeParams.add(typeParam);

    expression.accept(
        new JavaRecursiveElementWalkingVisitor() {
          @Override
          public void visitConditionalExpression(PsiConditionalExpression expression) {
            final PsiExpression thenExpression = expression.getThenExpression();
            if (thenExpression != null) {
              thenExpression.accept(this);
            }
            final PsiExpression elseExpression = expression.getElseExpression();
            if (elseExpression != null) {
              elseExpression.accept(this);
            }
          }

          @Override
          public void visitReferenceExpression(PsiReferenceExpression expression) {
            super.visitReferenceExpression(expression);
            int usedParamIdx = -1;
            for (int i = 0; i < lambdaParams.length; i++) {
              PsiParameter param = lambdaParams[i];
              if (expression.isReferenceTo(param)) {
                usedParamIdx = i;
                break;
              }
            }

            if (usedParamIdx > -1
                && dependsOnTypeParams(
                    subst.substitute(methodParameters[usedParamIdx].getType()),
                    functionalInterfaceType,
                    lambdaExpression,
                    paramsChecker.myUsedTypeParams.toArray(
                        new PsiTypeParameter[paramsChecker.myUsedTypeParams.size()]))) {
              independent[0] = false;
            }
          }
        });
    return independent[0];
  }