예제 #1
0
    @Override
    public boolean isMemberEnabled(MemberInfo member) {
      final PsiClass currentSuperClass = getSuperClass();
      if (currentSuperClass == null) return true;
      if (myMemberInfoStorage.getDuplicatedMemberInfos(currentSuperClass).contains(member))
        return false;
      if (myMemberInfoStorage.getExtending(currentSuperClass).contains(member.getMember()))
        return false;
      final boolean isInterface = currentSuperClass.isInterface();
      if (!isInterface) return true;

      PsiElement element = member.getMember();
      if (element instanceof PsiClass && ((PsiClass) element).isInterface()) return true;
      if (element instanceof PsiField) {
        return ((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC);
      }
      if (element instanceof PsiMethod) {
        final PsiSubstitutor superSubstitutor =
            TypeConversionUtil.getSuperClassSubstitutor(
                currentSuperClass, myClass, PsiSubstitutor.EMPTY);
        final MethodSignature signature = ((PsiMethod) element).getSignature(superSubstitutor);
        final PsiMethod superClassMethod =
            MethodSignatureUtil.findMethodBySignature(currentSuperClass, signature, false);
        if (superClassMethod != null && !PsiUtil.isLanguageLevel8OrHigher(currentSuperClass))
          return false;
        return !((PsiModifierListOwner) element).hasModifierProperty(PsiModifier.STATIC)
            || PsiUtil.isLanguageLevel8OrHigher(currentSuperClass);
      }
      return true;
    }
  private static void makeVariableFinalIfNeeded(
      InsertionContext context, @Nullable PsiReferenceExpression ref) {
    if (!Registry.is("java.completion.make.outer.variables.final")
        || ref == null
        || PsiUtil.isLanguageLevel8OrHigher(ref)
        || JspPsiUtil.isInJspFile(ref)) {
      return;
    }

    PsiElement target = ref.resolve();
    if (target instanceof PsiLocalVariable || target instanceof PsiParameter) {
      PsiClass placeClass =
          PsiTreeUtil.findElementOfClassAtOffset(
              context.getFile(), context.getTailOffset() - 1, PsiClass.class, false);
      if (placeClass != null
          && !PsiTreeUtil.isAncestor(placeClass, target, true)
          && !HighlightControlFlowUtil.isReassigned(
              (PsiVariable) target,
              new HashMap<PsiElement, Collection<ControlFlowUtil.VariableInfo>>())) {
        PsiModifierList modifierList = ((PsiVariable) target).getModifierList();
        if (modifierList != null) {
          modifierList.setModifierProperty(PsiModifier.FINAL, true);
        }
      }
    }
  }
예제 #3
0
 @Override
 public boolean isAbstractEnabled(MemberInfo member) {
   PsiClass currentSuperClass = getSuperClass();
   if (currentSuperClass == null || !currentSuperClass.isInterface()) return true;
   if (PsiUtil.isLanguageLevel8OrHigher(currentSuperClass)) {
     return true;
   }
   return false;
 }
 @NotNull
 @Override
 public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
   if (!PsiUtil.isLanguageLevel8OrHigher(holder.getFile())) {
     return PsiElementVisitor.EMPTY_VISITOR;
   }
   return new PsiElementVisitor() {
     @Override
     public void visitElement(PsiElement element) {
       if (element instanceof PsiMethodCallExpression) {
         final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) element;
         String qName = methodCallExpression.getMethodExpression().getQualifiedName();
         if (qName == null) {
           return;
         }
         qName = StringUtil.getShortName(qName);
         final Collection<StaticPseudoFunctionalStyleMethodOptions.PipelineElement> handlerInfos =
             myOptions.findElementsByMethodName(qName);
         if (handlerInfos.isEmpty()) {
           return;
         }
         final PsiMethod method = methodCallExpression.resolveMethod();
         if (method == null) {
           return;
         }
         final PsiClass aClass = method.getContainingClass();
         if (aClass == null) {
           return;
         }
         final String classQualifiedName = aClass.getQualifiedName();
         if (classQualifiedName == null) {
           return;
         }
         StaticPseudoFunctionalStyleMethodOptions.PipelineElement suitableHandler = null;
         for (StaticPseudoFunctionalStyleMethodOptions.PipelineElement h : handlerInfos) {
           if (h.getHandlerClass().equals(classQualifiedName)) {
             suitableHandler = h;
             break;
           }
         }
         if (suitableHandler == null) {
           return;
         }
         final PseudoLambdaReplaceTemplate.ValidationInfo validationInfo =
             suitableHandler.getTemplate().validate(methodCallExpression);
         if (validationInfo != null) {
           holder.registerProblem(
               methodCallExpression.getMethodExpression(),
               "Pseudo functional style code",
               new ReplacePseudoLambdaWithLambda(suitableHandler));
         }
       }
     }
   };
 }
예제 #5
0
  @NotNull
  public static SearchScope getMemberUseScope(@NotNull PsiMember member) {
    PsiFile file = member.getContainingFile();
    PsiElement topElement = file == null ? member : file;
    Project project = topElement.getProject();
    final GlobalSearchScope maximalUseScope =
        ResolveScopeManager.getInstance(project).getUseScope(topElement);
    if (isInServerPage(file)) return maximalUseScope;

    PsiClass aClass = member.getContainingClass();
    if (aClass instanceof PsiAnonymousClass
        && !(aClass instanceof PsiEnumConstantInitializer
            && member instanceof PsiMethod
            && member.hasModifierProperty(PsiModifier.PUBLIC)
            && ((PsiMethod) member).findSuperMethods().length > 0)) {
      // member from anonymous class can be called from outside the class
      PsiElement methodCallExpr =
          PsiUtil.isLanguageLevel8OrHigher(aClass)
              ? PsiTreeUtil.getTopmostParentOfType(aClass, PsiStatement.class)
              : PsiTreeUtil.getParentOfType(aClass, PsiMethodCallExpression.class);
      return new LocalSearchScope(methodCallExpr != null ? methodCallExpr : aClass);
    }

    PsiModifierList modifierList = member.getModifierList();
    int accessLevel =
        modifierList == null ? PsiUtil.ACCESS_LEVEL_PUBLIC : PsiUtil.getAccessLevel(modifierList);
    if (accessLevel == PsiUtil.ACCESS_LEVEL_PUBLIC
        || accessLevel == PsiUtil.ACCESS_LEVEL_PROTECTED) {
      return maximalUseScope; // class use scope doesn't matter, since another very visible class
      // can inherit from aClass
    }
    if (accessLevel == PsiUtil.ACCESS_LEVEL_PRIVATE) {
      PsiClass topClass = PsiUtil.getTopLevelClass(member);
      return topClass != null
          ? new LocalSearchScope(topClass)
          : file == null ? maximalUseScope : new LocalSearchScope(file);
    }
    if (file instanceof PsiJavaFile) {
      PsiPackage aPackage =
          JavaPsiFacade.getInstance(project).findPackage(((PsiJavaFile) file).getPackageName());
      if (aPackage != null) {
        SearchScope scope = PackageScope.packageScope(aPackage, false);
        return scope.intersectWith(maximalUseScope);
      }
    }
    return maximalUseScope;
  }
  public void fillCompletions(
      CompletionParameters parameters, final Consumer<LookupElement> result) {
    final PsiElement position = parameters.getPosition();
    if (PsiTreeUtil.getParentOfType(position, PsiComment.class, false) != null) {
      return;
    }

    PsiStatement statement = PsiTreeUtil.getParentOfType(position, PsiExpressionStatement.class);
    if (statement == null) {
      statement = PsiTreeUtil.getParentOfType(position, PsiDeclarationStatement.class);
    }
    PsiElement prevLeaf = PsiTreeUtil.prevVisibleLeaf(position);
    if (statement != null
        && statement.getTextRange().getStartOffset() == position.getTextRange().getStartOffset()) {
      if (!psiElement()
          .withSuperParent(2, PsiSwitchStatement.class)
          .afterLeaf("{")
          .accepts(statement)) {
        PsiTryStatement tryStatement = PsiTreeUtil.getParentOfType(prevLeaf, PsiTryStatement.class);
        if (tryStatement == null
            || tryStatement.getCatchSections().length > 0
            || tryStatement.getFinallyBlock() != null) {
          result.consume(
              new OverrideableSpace(
                  createKeyword(position, PsiKeyword.FINAL), TailType.HUMBLE_SPACE_BEFORE_WORD));
        }
      }
    }

    if (isStatementPosition(position)) {
      if (PsiTreeUtil.getParentOfType(position, PsiSwitchStatement.class, false, PsiMember.class)
          != null) {
        result.consume(
            new OverrideableSpace(createKeyword(position, PsiKeyword.CASE), TailType.INSERT_SPACE));
        result.consume(
            new OverrideableSpace(
                createKeyword(position, PsiKeyword.DEFAULT), TailType.CASE_COLON));
        if (START_SWITCH.accepts(position)) {
          return;
        }
      }

      addBreakContinue(result, position);
      addStatementKeywords(result, position);
    }

    if (SUPER_OR_THIS_PATTERN.accepts(position)) {
      final boolean afterDot = AFTER_DOT.accepts(position);
      final boolean insideQualifierClass = isInsideQualifierClass(position);
      final boolean insideInheritorClass =
          PsiUtil.isLanguageLevel8OrHigher(position) && isInsideInheritorClass(position);
      if (!afterDot || insideQualifierClass || insideInheritorClass) {
        if (!afterDot || insideQualifierClass) {
          result.consume(createKeyword(position, PsiKeyword.THIS));
        }

        final LookupItem superItem = (LookupItem) createKeyword(position, PsiKeyword.SUPER);
        if (psiElement()
            .afterLeaf(psiElement().withText("{").withSuperParent(2, psiMethod().constructor(true)))
            .accepts(position)) {
          final PsiMethod method =
              PsiTreeUtil.getParentOfType(position, PsiMethod.class, false, PsiClass.class);
          assert method != null;
          final boolean hasParams = superConstructorHasParameters(method);
          superItem.setInsertHandler(
              new ParenthesesInsertHandler<LookupElement>() {
                @Override
                protected boolean placeCaretInsideParentheses(
                    InsertionContext context, LookupElement item) {
                  return hasParams;
                }

                @Override
                public void handleInsert(InsertionContext context, LookupElement item) {
                  super.handleInsert(context, item);
                  TailType.insertChar(context.getEditor(), context.getTailOffset(), ';');
                }
              });
        }

        result.consume(superItem);
      }
    }

    if (isExpressionPosition(position)) {
      if (PsiTreeUtil.getParentOfType(position, PsiAnnotation.class) == null) {
        result.consume(
            TailTypeDecorator.withTail(
                createKeyword(position, PsiKeyword.NEW), TailType.INSERT_SPACE));
        result.consume(createKeyword(position, PsiKeyword.NULL));
      }
      if (mayExpectBoolean(parameters)) {
        result.consume(createKeyword(position, PsiKeyword.TRUE));
        result.consume(createKeyword(position, PsiKeyword.FALSE));
      }
    }

    PsiFile file = position.getContainingFile();
    if (!(file instanceof PsiExpressionCodeFragment)
        && !(file instanceof PsiJavaCodeReferenceCodeFragment)
        && !(file instanceof PsiTypeCodeFragment)) {
      if (prevLeaf == null) {
        result.consume(
            new OverrideableSpace(
                createKeyword(position, PsiKeyword.PACKAGE), TailType.HUMBLE_SPACE_BEFORE_WORD));
        result.consume(
            new OverrideableSpace(
                createKeyword(position, PsiKeyword.IMPORT), TailType.HUMBLE_SPACE_BEFORE_WORD));
      } else if (END_OF_BLOCK.getValue().isAcceptable(position, position)
          && PsiTreeUtil.getParentOfType(position, PsiMember.class) == null) {
        result.consume(
            new OverrideableSpace(
                createKeyword(position, PsiKeyword.IMPORT), TailType.HUMBLE_SPACE_BEFORE_WORD));
      }
    }

    if ((isInsideParameterList(position)
            || isAtResourceVariableStart(position)
            || isAtCatchVariableStart(position))
        && !psiElement().afterLeaf(PsiKeyword.FINAL).accepts(position)
        && !AFTER_DOT.accepts(position)) {
      result.consume(
          TailTypeDecorator.withTail(
              createKeyword(position, PsiKeyword.FINAL), TailType.HUMBLE_SPACE_BEFORE_WORD));
    }

    if (isInstanceofPlace(position)) {
      result.consume(
          LookupElementDecorator.withInsertHandler(
              createKeyword(position, PsiKeyword.INSTANCEOF),
              new InsertHandler<LookupElementDecorator<LookupElement>>() {
                @Override
                public void handleInsert(
                    InsertionContext context, LookupElementDecorator<LookupElement> item) {
                  TailType tailType = TailType.HUMBLE_SPACE_BEFORE_WORD;
                  if (tailType.isApplicable(context)) {
                    tailType.processTail(context.getEditor(), context.getTailOffset());
                  }

                  if ('!' == context.getCompletionChar()) {
                    context.setAddCompletionChar(false);
                    context.commitDocument();
                    PsiInstanceOfExpression expr =
                        PsiTreeUtil.findElementOfClassAtOffset(
                            context.getFile(),
                            context.getStartOffset(),
                            PsiInstanceOfExpression.class,
                            false);
                    if (expr != null) {
                      String space =
                          context.getCodeStyleSettings().SPACE_WITHIN_PARENTHESES ? " " : "";
                      context
                          .getDocument()
                          .insertString(expr.getTextRange().getStartOffset(), "!(" + space);
                      context.getDocument().insertString(context.getTailOffset(), space + ")");
                    }
                  }
                }
              }));
    }

    if (isSuitableForClass(position)) {
      for (String s : ModifierChooser.getKeywords(position)) {
        result.consume(
            new OverrideableSpace(createKeyword(position, s), TailType.HUMBLE_SPACE_BEFORE_WORD));
      }
      result.consume(
          new OverrideableSpace(
              createKeyword(position, PsiKeyword.CLASS), TailType.HUMBLE_SPACE_BEFORE_WORD));
      if (PsiTreeUtil.getParentOfType(position, PsiCodeBlock.class, true, PsiMember.class)
          == null) {
        result.consume(
            new OverrideableSpace(
                createKeyword(position, PsiKeyword.INTERFACE), TailType.HUMBLE_SPACE_BEFORE_WORD));
        if (PsiUtil.getLanguageLevel(position).isAtLeast(LanguageLevel.JDK_1_5)) {
          result.consume(
              new OverrideableSpace(
                  createKeyword(position, PsiKeyword.ENUM), TailType.INSERT_SPACE));
        }
      }
    }

    addPrimitiveTypes(result, position);

    if (isAfterTypeDot(position)) {
      result.consume(createKeyword(position, PsiKeyword.CLASS));
    }

    addUnfinishedMethodTypeParameters(position, result);

    if (JavaMemberNameCompletionContributor.INSIDE_TYPE_PARAMS_PATTERN.accepts(position)) {
      result.consume(
          new OverrideableSpace(
              createKeyword(position, PsiKeyword.EXTENDS), TailType.HUMBLE_SPACE_BEFORE_WORD));
      result.consume(
          new OverrideableSpace(
              createKeyword(position, PsiKeyword.SUPER), TailType.HUMBLE_SPACE_BEFORE_WORD));
    }
  }
  static HighlightInfo checkDuplicateAnnotations(@NotNull PsiAnnotation annotationToCheck) {
    PsiAnnotationOwner owner = annotationToCheck.getOwner();
    if (owner == null) return null;

    PsiJavaCodeReferenceElement element = annotationToCheck.getNameReferenceElement();
    if (element == null) return null;
    PsiElement resolved = element.resolve();
    if (!(resolved instanceof PsiClass)) return null;

    PsiClass annotationType = (PsiClass) resolved;

    PsiClass contained = contained(annotationType);
    String containedElementFQN = contained == null ? null : contained.getQualifiedName();

    if (containedElementFQN != null) {
      PsiClass container = annotationType;
      String containerName = container.getQualifiedName();
      if (isAnnotationRepeatedTwice(owner, containedElementFQN)) {
        String description =
            JavaErrorMessages.message("annotation.container.wrong.place", containerName);
        return annotationError(annotationToCheck, description);
      }
    } else if (isAnnotationRepeatedTwice(owner, annotationType.getQualifiedName())) {
      if (!PsiUtil.isLanguageLevel8OrHigher(annotationToCheck)) {
        String description = JavaErrorMessages.message("annotation.duplicate.annotation");
        return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
            .range(element)
            .descriptionAndTooltip(description)
            .create();
      }
      PsiAnnotation metaAnno =
          PsiImplUtil.findAnnotation(
              annotationType.getModifierList(), CommonClassNames.JAVA_LANG_ANNOTATION_REPEATABLE);

      if (metaAnno == null) {
        String explanation =
            JavaErrorMessages.message(
                "annotation.non.repeatable", annotationType.getQualifiedName());
        String description =
            JavaErrorMessages.message("annotation.duplicate.explained", explanation);
        return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
            .range(element)
            .descriptionAndTooltip(description)
            .create();
      }

      String explanation = doCheckRepeatableAnnotation(metaAnno);
      if (explanation != null) {
        String description =
            JavaErrorMessages.message("annotation.duplicate.explained", explanation);
        return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
            .range(element)
            .descriptionAndTooltip(description)
            .create();
      }

      PsiClass container = getRepeatableContainer(metaAnno);
      if (container != null) {
        PsiAnnotation.TargetType[] targets = PsiImplUtil.getTargetsForLocation(owner);
        PsiAnnotation.TargetType applicable = PsiImplUtil.findApplicableTarget(container, targets);
        if (applicable == null) {
          String target = JavaErrorMessages.message("annotation.target." + targets[0]);
          String message =
              JavaErrorMessages.message(
                  "annotation.container.not.applicable", container.getName(), target);
          return annotationError(annotationToCheck, message);
        }
      }
    }

    for (PsiAnnotation annotation : owner.getAnnotations()) {
      if (annotation == annotationToCheck) continue;
      PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement();
      if (nameRef == null) continue;
      PsiElement aClass = nameRef.resolve();
      if (!resolved.equals(aClass)) continue;
    }

    return null;
  }
예제 #8
0
  private void doMoveMethod(PsiSubstitutor substitutor, MemberInfo info) {
    PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject);
    PsiMethod method = (PsiMethod) info.getMember();
    PsiMethod sibling = method;
    PsiMethod anchor = null;
    while (sibling != null) {
      sibling = PsiTreeUtil.getNextSiblingOfType(sibling, PsiMethod.class);
      if (sibling != null) {
        anchor =
            MethodSignatureUtil.findMethodInSuperClassBySignatureInDerived(
                method.getContainingClass(),
                myTargetSuperClass,
                sibling.getSignature(PsiSubstitutor.EMPTY),
                false);
        if (anchor != null) {
          break;
        }
      }
    }
    PsiMethod methodCopy = (PsiMethod) method.copy();
    Language language = myTargetSuperClass.getLanguage();
    final PsiMethod superClassMethod = myTargetSuperClass.findMethodBySignature(methodCopy, false);
    if (superClassMethod != null && superClassMethod.findDeepestSuperMethods().length == 0
        || method.findSuperMethods(myTargetSuperClass).length == 0) {
      deleteOverrideAnnotationIfFound(methodCopy);
    }
    boolean isOriginalMethodAbstract =
        method.hasModifierProperty(PsiModifier.ABSTRACT)
            || method.hasModifierProperty(PsiModifier.DEFAULT);
    boolean isOriginalMethodPrototype =
        method instanceof HaxeFunctionPrototypeDeclarationWithAttributes;
    if (myIsTargetInterface || info.isToAbstract()) {
      ChangeContextUtil.clearContextInfo(method);

      if (!info.isToAbstract()
          && !method.hasModifierProperty(PsiModifier.ABSTRACT)
          && PsiUtil.isLanguageLevel8OrHigher(myTargetSuperClass)) {
        // pull as default
        RefactoringUtil.makeMethodDefault(methodCopy);
        isOriginalMethodAbstract = true;
      } else {
        RefactoringUtil.makeMethodAbstract(myTargetSuperClass, methodCopy);
      }

      RefactoringUtil.replaceMovedMemberTypeParameters(
          methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);

      myJavaDocPolicy.processCopiedJavaDoc(
          methodCopy.getDocComment(), method.getDocComment(), isOriginalMethodAbstract);

      final PsiMember movedElement;
      if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
        movedElement =
            (PsiMember) superClassMethod.replace(convertMethodToLanguage(methodCopy, language));
      } else {
        methodCopy =
            HaxeElementGenerator.createFunctionPrototypeDeclarationWithAttributes(
                myProject, methodCopy.getText().trim() + ";");

        movedElement =
            anchor != null
                ? (PsiMember) myTargetSuperClass.addBefore(methodCopy, anchor)
                : (PsiMember)
                    myTargetSuperClass.addBefore(methodCopy, myTargetSuperClass.getRBrace());

        reformat(movedElement);
      }
      CodeStyleSettings styleSettings = CodeStyleSettingsManager.getSettings(method.getProject());
      if (styleSettings.INSERT_OVERRIDE_ANNOTATION) {
        if (PsiUtil.isLanguageLevel5OrHigher(mySourceClass) && !myIsTargetInterface
            || PsiUtil.isLanguageLevel6OrHigher(mySourceClass)) {
          new AddAnnotationFix(Override.class.getName(), method)
              .invoke(method.getProject(), null, mySourceClass.getContainingFile());
        }
      }
      if (!PsiUtil.isLanguageLevel6OrHigher(mySourceClass) && myIsTargetInterface) {
        if (isOriginalMethodAbstract) {
          for (PsiMethod oMethod : OverridingMethodsSearch.search(method)) {
            deleteOverrideAnnotationIfFound(oMethod);
          }
        }
        deleteOverrideAnnotationIfFound(method);
      }
      myMembersAfterMove.add(movedElement);
      // if (isOriginalMethodAbstract) {
      method.delete();
      // }
    } else {
      if (isOriginalMethodAbstract) {
        PsiUtil.setModifierProperty(myTargetSuperClass, PsiModifier.ABSTRACT, true);
      }
      RefactoringUtil.replaceMovedMemberTypeParameters(
          methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
      fixReferencesToStatic(methodCopy);

      if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
        superClassMethod.replace(convertMethodToLanguage(methodCopy, language));
      } else {
        final PsiMember movedElement =
            anchor != null
                ? (PsiMember)
                    myTargetSuperClass.addBefore(
                        convertMethodToLanguage(methodCopy, language), anchor)
                : (PsiMember)
                    myTargetSuperClass.addBefore(
                        convertMethodToLanguage(methodCopy, language),
                        myTargetSuperClass.getRBrace());
        reformat(movedElement);
        myMembersAfterMove.add(movedElement);
      }
      method.delete();
    }
  }
  @NotNull
  @Override
  public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
    if (!PsiUtil.isLanguageLevel8OrHigher(holder.getFile())) {
      return PsiElementVisitor.EMPTY_VISITOR;
    }
    return new JavaElementVisitor() {
      private final AtomicNotNullLazyValue<Map<String, PsiClass>> myGuavaClassConversions =
          new AtomicNotNullLazyValue<Map<String, PsiClass>>() {
            @NotNull
            @Override
            protected Map<String, PsiClass> compute() {
              Map<String, PsiClass> map = new HashMap<String, PsiClass>();
              for (TypeConversionRule rule : TypeConversionRule.EP_NAME.getExtensions()) {
                if (rule instanceof BaseGuavaTypeConversionRule) {
                  final String fromClass = ((BaseGuavaTypeConversionRule) rule).ruleFromClass();
                  final String toClass = ((BaseGuavaTypeConversionRule) rule).ruleToClass();

                  final Project project = holder.getProject();
                  final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
                  final PsiClass targetClass =
                      javaPsiFacade.findClass(toClass, GlobalSearchScope.allScope(project));

                  if (targetClass != null) {
                    map.put(fromClass, targetClass);
                  }
                }
              }
              return map;
            }
          };

      @Override
      public void visitVariable(PsiVariable variable) {
        final PsiType type = variable.getType();
        if (type instanceof PsiClassType) {
          final PsiClassType.ClassResolveResult resolveResult =
              ((PsiClassType) type).resolveGenerics();
          final PsiClass psiClass = resolveResult.getElement();
          if (psiClass != null) {
            final String qName = psiClass.getQualifiedName();
            final PsiClass targetClass = myGuavaClassConversions.getValue().get(qName);
            if (targetClass != null) {
              final VariableTypeFix fix =
                  TypeMigrationVariableTypeFixProvider.createTypeMigrationFix(
                      variable, addTypeParameters(type, resolveResult, targetClass));
              holder.registerProblem(variable, PROBLEM_DESCRIPTION_FOR_VARIABLE, fix);
            }
          }
        }
      }

      private PsiClassType addTypeParameters(
          PsiType currentType,
          PsiClassType.ClassResolveResult currentTypeResolveResult,
          PsiClass targetClass) {
        final Map<PsiTypeParameter, PsiType> substitutionMap =
            currentTypeResolveResult.getSubstitutor().getSubstitutionMap();
        final PsiElementFactory elementFactory =
            JavaPsiFacade.getElementFactory(holder.getProject());
        if (substitutionMap.size() == 1) {
          return elementFactory.createType(
              targetClass, ContainerUtil.getFirstItem(substitutionMap.values()));
        } else {
          LOG.assertTrue(substitutionMap.size() == 2);
          LOG.assertTrue(
              GuavaFunctionConversionRule.JAVA_UTIL_FUNCTION_FUNCTION.equals(
                  targetClass.getQualifiedName()));
          final PsiType returnType = LambdaUtil.getFunctionalInterfaceReturnType(currentType);
          final List<PsiType> types = new ArrayList<PsiType>(substitutionMap.values());
          types.remove(returnType);
          final PsiType parameterType = types.get(0);
          return elementFactory.createType(targetClass, parameterType, returnType);
        }
      }
    };
  }
  @NotNull
  @Override
  public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
    if (!PsiUtil.isLanguageLevel8OrHigher(holder.getFile())) {
      return PsiElementVisitor.EMPTY_VISITOR;
    }
    return new JavaElementVisitor() {
      void handleIteratorLoop(
          PsiLoopStatement statement, PsiJavaToken endToken, IteratorDeclaration declaration) {
        if (endToken == null || declaration == null || !declaration.isCollection()) return;
        PsiStatement body = statement.getBody();
        if (!(body instanceof PsiBlockStatement)) return;
        PsiStatement[] statements = ((PsiBlockStatement) body).getCodeBlock().getStatements();
        if (statements.length == 2 && statements[1] instanceof PsiIfStatement) {
          PsiVariable element = declaration.getNextElementVariable(statements[0]);
          if (element == null) return;
          PsiIfStatement ifStatement = (PsiIfStatement) statements[1];
          if (checkAndExtractCondition(declaration, ifStatement) == null) return;
          registerProblem(statement, endToken);
        } else if (statements.length == 1 && statements[0] instanceof PsiIfStatement) {
          PsiIfStatement ifStatement = (PsiIfStatement) statements[0];
          PsiExpression condition = checkAndExtractCondition(declaration, ifStatement);
          if (condition == null) return;
          PsiElement ref = declaration.findOnlyIteratorRef(condition);
          if (ref != null
              && declaration.isIteratorMethodCall(ref.getParent().getParent(), "next")
              && isAlwaysExecuted(condition, ref)) {
            registerProblem(statement, endToken);
          }
        }
      }

      private boolean isAlwaysExecuted(PsiExpression condition, PsiElement ref) {
        while (ref != condition) {
          PsiElement parent = ref.getParent();
          if (parent instanceof PsiPolyadicExpression) {
            PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression) parent;
            IElementType type = polyadicExpression.getOperationTokenType();
            if ((type.equals(JavaTokenType.ANDAND) || type.equals(JavaTokenType.OROR))
                && polyadicExpression.getOperands()[0] != ref) {
              return false;
            }
          }
          if (parent instanceof PsiConditionalExpression
              && ((PsiConditionalExpression) parent).getCondition() != ref) {
            return false;
          }
          ref = parent;
        }
        return true;
      }

      private void registerProblem(PsiLoopStatement statement, PsiJavaToken endToken) {
        //noinspection DialogTitleCapitalization
        holder.registerProblem(
            statement,
            new TextRange(0, endToken.getTextOffset() - statement.getTextOffset() + 1),
            QuickFixBundle.message("java.8.collection.removeif.inspection.description"),
            new ReplaceWithRemoveIfQuickFix());
      }

      @Nullable
      private PsiExpression checkAndExtractCondition(
          IteratorDeclaration declaration, PsiIfStatement ifStatement) {
        PsiExpression condition = ifStatement.getCondition();
        if (condition == null || ifStatement.getElseBranch() != null) return null;
        PsiStatement thenStatement = ControlFlowUtils.stripBraces(ifStatement.getThenBranch());
        if (!(thenStatement instanceof PsiExpressionStatement)) return null;
        if (!declaration.isIteratorMethodCall(
            ((PsiExpressionStatement) thenStatement).getExpression(), "remove")) return null;
        if (!LambdaGenerationUtil.canBeUncheckedLambda(condition)) return null;
        return condition;
      }

      @Override
      public void visitForStatement(PsiForStatement statement) {
        super.visitForStatement(statement);
        IteratorDeclaration declaration = IteratorDeclaration.fromLoop(statement);
        handleIteratorLoop(statement, statement.getRParenth(), declaration);
      }

      @Override
      public void visitWhileStatement(PsiWhileStatement statement) {
        super.visitWhileStatement(statement);
        IteratorDeclaration declaration = IteratorDeclaration.fromLoop(statement);
        handleIteratorLoop(statement, statement.getRParenth(), declaration);
      }
    };
  }