public static PsiType getLambdaParameterType(PsiParameter param) {
    final PsiElement paramParent = param.getParent();
    if (paramParent instanceof PsiParameterList) {
      final int parameterIndex = ((PsiParameterList) paramParent).getParameterIndex(param);
      if (parameterIndex > -1) {
        final PsiLambdaExpression lambdaExpression =
            PsiTreeUtil.getParentOfType(param, PsiLambdaExpression.class);
        if (lambdaExpression != null) {

          PsiType type = getFunctionalInterfaceType(lambdaExpression, true, parameterIndex);
          if (type == null) {
            type = getFunctionalInterfaceType(lambdaExpression, false);
          }
          if (type instanceof PsiIntersectionType) {
            final PsiType[] conjuncts = ((PsiIntersectionType) type).getConjuncts();
            for (PsiType conjunct : conjuncts) {
              final PsiType lambdaParameterFromType =
                  getLambdaParameterFromType(parameterIndex, lambdaExpression, conjunct);
              if (lambdaParameterFromType != null) return lambdaParameterFromType;
            }
          } else {
            final PsiType lambdaParameterFromType =
                getLambdaParameterFromType(parameterIndex, lambdaExpression, type);
            if (lambdaParameterFromType != null) {
              return lambdaParameterFromType;
            }
          }
        }
      }
    }
    return new PsiLambdaParameterType(param);
  }
 private static PsiAnnotation[] getHierarchyAnnotations(
     PsiModifierListOwner listOwner, PsiModifierList modifierList) {
   final Set<PsiAnnotation> all =
       new HashSet<PsiAnnotation>() {
         public boolean add(PsiAnnotation o) {
           // don't overwrite "higher level" annotations
           return !contains(o) && super.add(o);
         }
       };
   if (listOwner instanceof PsiMethod) {
     ContainerUtil.addAll(all, modifierList.getAnnotations());
     SuperMethodsSearch.search((PsiMethod) listOwner, null, true, true)
         .forEach(
             new Processor<MethodSignatureBackedByPsiMethod>() {
               public boolean process(final MethodSignatureBackedByPsiMethod superMethod) {
                 ContainerUtil.addAll(
                     all, superMethod.getMethod().getModifierList().getAnnotations());
                 return true;
               }
             });
     return all.toArray(new PsiAnnotation[all.size()]);
   }
   if (listOwner instanceof PsiParameter) {
     PsiParameter parameter = (PsiParameter) listOwner;
     PsiElement declarationScope = parameter.getDeclarationScope();
     PsiParameterList parameterList;
     if (declarationScope instanceof PsiMethod
         && parameter.getParent()
             == (parameterList = ((PsiMethod) declarationScope).getParameterList())) {
       PsiMethod method = (PsiMethod) declarationScope;
       final int parameterIndex = parameterList.getParameterIndex(parameter);
       ContainerUtil.addAll(all, modifierList.getAnnotations());
       SuperMethodsSearch.search(method, null, true, true)
           .forEach(
               new Processor<MethodSignatureBackedByPsiMethod>() {
                 public boolean process(final MethodSignatureBackedByPsiMethod superMethod) {
                   PsiParameter superParameter =
                       superMethod.getMethod().getParameterList().getParameters()[parameterIndex];
                   PsiModifierList modifierList = superParameter.getModifierList();
                   if (modifierList != null) {
                     ContainerUtil.addAll(all, modifierList.getAnnotations());
                   }
                   return true;
                 }
               });
       return all.toArray(new PsiAnnotation[all.size()]);
     }
   }
   return modifierList.getAnnotations();
 }
  private static void fixExceptions(PsiElement ref, PsiClassType[] newExceptions)
      throws IncorrectOperationException {
    // methods' throws lists are already modified, may use ExceptionUtil.collectUnhandledExceptions
    newExceptions = filterCheckedExceptions(newExceptions);

    PsiElement context = PsiTreeUtil.getParentOfType(ref, PsiTryStatement.class, PsiMethod.class);
    if (context instanceof PsiTryStatement) {
      PsiTryStatement tryStatement = (PsiTryStatement) context;
      PsiCodeBlock tryBlock = tryStatement.getTryBlock();

      // Remove unused catches
      Collection<PsiClassType> classes =
          ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock);
      PsiParameter[] catchParameters = tryStatement.getCatchBlockParameters();
      for (PsiParameter parameter : catchParameters) {
        final PsiType caughtType = parameter.getType();

        if (!(caughtType instanceof PsiClassType)) continue;
        if (ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType) caughtType)) continue;

        if (!isCatchParameterRedundant((PsiClassType) caughtType, classes)) continue;
        parameter.getParent().delete(); // delete catch section
      }

      PsiClassType[] exceptionsToAdd = filterUnhandledExceptions(newExceptions, tryBlock);
      addExceptions(exceptionsToAdd, tryStatement);

      adjustPossibleEmptyTryStatement(tryStatement);
    } else {
      newExceptions = filterUnhandledExceptions(newExceptions, ref);
      if (newExceptions.length > 0) {
        // Add new try statement
        PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(ref.getProject());
        PsiTryStatement tryStatement =
            (PsiTryStatement)
                elementFactory.createStatementFromText("try {} catch (Exception e) {}", null);
        PsiStatement anchor = PsiTreeUtil.getParentOfType(ref, PsiStatement.class);
        LOG.assertTrue(anchor != null);
        tryStatement.getTryBlock().add(anchor);
        tryStatement = (PsiTryStatement) anchor.getParent().addAfter(tryStatement, anchor);

        addExceptions(newExceptions, tryStatement);
        anchor.delete();
        tryStatement.getCatchSections()[0].delete(); // Delete dummy catch section
      }
    }
  }
  private static AllowedValues parseBeanInfo(@NotNull PsiModifierListOwner owner) {
    PsiMethod method = null;
    if (owner instanceof PsiParameter) {
      PsiParameter parameter = (PsiParameter) owner;
      PsiElement scope = parameter.getDeclarationScope();
      if (!(scope instanceof PsiMethod)) return null;
      PsiElement nav = scope.getNavigationElement();
      if (!(nav instanceof PsiMethod)) return null;
      method = (PsiMethod) nav;
      if (method.isConstructor()) {
        // not a property, try the @ConstructorProperties({"prop"})
        PsiAnnotation annotation =
            AnnotationUtil.findAnnotation(method, "java.beans.ConstructorProperties");
        if (annotation == null) return null;
        PsiAnnotationMemberValue value = annotation.findAttributeValue("value");
        if (!(value instanceof PsiArrayInitializerMemberValue)) return null;
        PsiAnnotationMemberValue[] initializers =
            ((PsiArrayInitializerMemberValue) value).getInitializers();
        PsiElement parent = parameter.getParent();
        if (!(parent instanceof PsiParameterList)) return null;
        int index = ((PsiParameterList) parent).getParameterIndex(parameter);
        if (index >= initializers.length) return null;
        PsiAnnotationMemberValue initializer = initializers[index];
        if (!(initializer instanceof PsiLiteralExpression)) return null;
        Object val = ((PsiLiteralExpression) initializer).getValue();
        if (!(val instanceof String)) return null;
        PsiMethod setter =
            PropertyUtil.findPropertySetter(
                method.getContainingClass(), (String) val, false, false);
        if (setter == null) return null;
        // try the @beaninfo of the corresponding setter
        method = (PsiMethod) setter.getNavigationElement();
      }
    } else if (owner instanceof PsiMethod) {
      PsiElement nav = owner.getNavigationElement();
      if (!(nav instanceof PsiMethod)) return null;
      method = (PsiMethod) nav;
    }
    if (method == null) return null;

    PsiClass aClass = method.getContainingClass();
    if (aClass == null) return null;
    if (PropertyUtil.isSimplePropertyGetter(method)) {
      List<PsiMethod> setters =
          PropertyUtil.getSetters(aClass, PropertyUtil.getPropertyNameByGetter(method));
      if (setters.size() != 1) return null;
      method = setters.get(0);
    }
    if (!PropertyUtil.isSimplePropertySetter(method)) return null;
    PsiDocComment doc = method.getDocComment();
    if (doc == null) return null;
    PsiDocTag beaninfo = doc.findTagByName("beaninfo");
    if (beaninfo == null) return null;
    String data =
        StringUtil.join(
            beaninfo.getDataElements(),
            new Function<PsiElement, String>() {
              @Override
              public String fun(PsiElement element) {
                return element.getText();
              }
            },
            "\n");
    int enumIndex = StringUtil.indexOfSubstringEnd(data, "enum:");
    if (enumIndex == -1) return null;
    data = data.substring(enumIndex);
    int colon = data.indexOf(":");
    int last = colon == -1 ? data.length() : data.substring(0, colon).lastIndexOf("\n");
    data = data.substring(0, last);

    List<PsiAnnotationMemberValue> values = new ArrayList<PsiAnnotationMemberValue>();
    for (String line : StringUtil.splitByLines(data)) {
      List<String> words = StringUtil.split(line, " ", true, true);
      if (words.size() != 2) continue;
      String ref = words.get(1);
      PsiExpression constRef =
          JavaPsiFacade.getElementFactory(aClass.getProject())
              .createExpressionFromText(ref, aClass);
      if (!(constRef instanceof PsiReferenceExpression)) continue;
      PsiReferenceExpression expr = (PsiReferenceExpression) constRef;
      values.add(expr);
    }
    if (values.isEmpty()) return null;
    PsiAnnotationMemberValue[] array = values.toArray(new PsiAnnotationMemberValue[values.size()]);
    return new AllowedValues(array, false);
  }
 public static int getParameterIndex(
     @NotNull PsiParameter parameter, @NotNull PsiParameterList parameterList) {
   PsiParameter[] parameters = parameterList.getParameters();
   for (int i = 0; i < parameters.length; i++) {
     PsiParameter paramInList = parameters[i];
     if (parameter.equals(paramInList)) return i;
   }
   String name = parameter.getName();
   PsiParameter suspect = null;
   int i;
   for (i = parameters.length - 1; i >= 0; i--) {
     PsiParameter paramInList = parameters[i];
     if (name.equals(paramInList.getName())) {
       suspect = paramInList;
       break;
     }
   }
   String message =
       parameter
           + ":"
           + parameter.getClass()
           + " not found among parameters: "
           + Arrays.asList(parameters)
           + "."
           + " parameterList' parent: "
           + parameterList.getParent()
           + ";"
           + " parameter.getParent()==paramList: "
           + (parameter.getParent() == parameterList)
           + "; "
           + parameterList.getClass()
           + ";"
           + " parameter.isValid()="
           + parameter.isValid()
           + ";"
           + " parameterList.isValid()= "
           + parameterList.isValid()
           + ";"
           + " parameterList stub: "
           + (parameterList instanceof StubBasedPsiElement
               ? ((StubBasedPsiElement) parameterList).getStub()
               : "---")
           + "; "
           + " parameter stub: "
           + (parameter instanceof StubBasedPsiElement
               ? ((StubBasedPsiElement) parameter).getStub()
               : "---")
           + ";"
           + " suspect: "
           + suspect
           + " (index="
           + i
           + "); "
           + (suspect == null ? null : suspect.getClass())
           + " suspect stub: "
           + (suspect instanceof StubBasedPsiElement
               ? ((StubBasedPsiElement) suspect).getStub()
               : suspect == null ? "-null-" : "---" + suspect.getClass())
           + ";"
           + " parameter.equals(suspect) = "
           + parameter.equals(suspect)
           + "; "
           + " parameter.getNode() == suspect.getNode():  "
           + (parameter.getNode() == (suspect == null ? null : suspect.getNode()))
           + "; "
           + ".";
   LOG.error(message);
   return i;
 }
  public void inlineElement(
      final Project project, final Editor editor, final PsiElement psiElement) {
    final PsiParameter psiParameter = (PsiParameter) psiElement;
    final PsiParameterList parameterList = (PsiParameterList) psiParameter.getParent();
    if (!(parameterList.getParent() instanceof PsiMethod)) {
      return;
    }
    final int index = parameterList.getParameterIndex(psiParameter);
    final PsiMethod method = (PsiMethod) parameterList.getParent();

    String errorMessage = getCannotInlineMessage(psiParameter, method);
    if (errorMessage != null) {
      CommonRefactoringUtil.showErrorHint(
          project,
          editor,
          errorMessage,
          RefactoringBundle.message("inline.parameter.refactoring"),
          null);
      return;
    }

    final Ref<PsiExpression> refInitializer = new Ref<PsiExpression>();
    final Ref<PsiExpression> refConstantInitializer = new Ref<PsiExpression>();
    final Ref<PsiCallExpression> refMethodCall = new Ref<PsiCallExpression>();
    final List<PsiReference> occurrences =
        Collections.synchronizedList(new ArrayList<PsiReference>());
    final Collection<PsiFile> containingFiles = Collections.synchronizedSet(new HashSet<PsiFile>());
    containingFiles.add(psiParameter.getContainingFile());
    boolean result =
        ReferencesSearch.search(method)
            .forEach(
                new Processor<PsiReference>() {
                  public boolean process(final PsiReference psiReference) {
                    PsiElement element = psiReference.getElement();
                    final PsiElement parent = element.getParent();
                    if (parent instanceof PsiCallExpression) {
                      final PsiCallExpression methodCall = (PsiCallExpression) parent;
                      occurrences.add(psiReference);
                      containingFiles.add(element.getContainingFile());
                      final PsiExpression[] expressions =
                          methodCall.getArgumentList().getExpressions();
                      if (expressions.length <= index) return false;
                      PsiExpression argument = expressions[index];
                      if (!refInitializer.isNull()) {
                        return argument != null
                            && PsiEquivalenceUtil.areElementsEquivalent(
                                refInitializer.get(), argument)
                            && PsiEquivalenceUtil.areElementsEquivalent(
                                refMethodCall.get(), methodCall);
                      }
                      if (InlineToAnonymousConstructorProcessor.isConstant(argument)
                          || getReferencedFinalField(argument) != null) {
                        if (refConstantInitializer.isNull()) {
                          refConstantInitializer.set(argument);
                        } else if (!isSameConstant(argument, refConstantInitializer.get())) {
                          return false;
                        }
                      } else if (!isRecursiveReferencedParameter(argument, psiParameter)) {
                        if (!refConstantInitializer.isNull()) return false;
                        refInitializer.set(argument);
                        refMethodCall.set(methodCall);
                      }
                    }
                    return true;
                  }
                });
    final int offset = editor.getCaretModel().getOffset();
    final PsiElement refExpr = psiElement.getContainingFile().findElementAt(offset);
    final PsiCodeBlock codeBlock = PsiTreeUtil.getParentOfType(refExpr, PsiCodeBlock.class);
    if (codeBlock != null) {
      final PsiElement[] defs = DefUseUtil.getDefs(codeBlock, psiParameter, refExpr);
      if (defs.length == 1) {
        final PsiElement def = defs[0];
        if (def instanceof PsiReferenceExpression
            && PsiUtil.isOnAssignmentLeftHand((PsiExpression) def)) {
          final PsiExpression rExpr = ((PsiAssignmentExpression) def.getParent()).getRExpression();
          if (rExpr != null) {
            final PsiElement[] refs = DefUseUtil.getRefs(codeBlock, psiParameter, refExpr);

            if (InlineLocalHandler.checkRefsInAugmentedAssignmentOrUnaryModified(refs, def)
                == null) {
              new WriteCommandAction(project) {
                @Override
                protected void run(Result result) throws Throwable {
                  for (final PsiElement ref : refs) {
                    InlineUtil.inlineVariable(
                        psiParameter, rExpr, (PsiJavaCodeReferenceElement) ref);
                  }
                  def.getParent().delete();
                }
              }.execute();
              return;
            }
          }
        }
      }
    }
    if (occurrences.isEmpty()) {
      CommonRefactoringUtil.showErrorHint(
          project,
          editor,
          "Method has no usages",
          RefactoringBundle.message("inline.parameter.refactoring"),
          null);
      return;
    }
    if (!result) {
      CommonRefactoringUtil.showErrorHint(
          project,
          editor,
          "Cannot find constant initializer for parameter",
          RefactoringBundle.message("inline.parameter.refactoring"),
          null);
      return;
    }
    if (!refInitializer.isNull()) {
      if (ApplicationManager.getApplication().isUnitTestMode()) {
        final InlineParameterExpressionProcessor processor =
            new InlineParameterExpressionProcessor(
                refMethodCall.get(),
                method,
                psiParameter,
                refInitializer.get(),
                method
                    .getProject()
                    .getUserData(InlineParameterExpressionProcessor.CREATE_LOCAL_FOR_TESTS));
        processor.run();
      } else {
        final boolean createLocal = ReferencesSearch.search(psiParameter).findAll().size() > 1;
        InlineParameterDialog dlg =
            new InlineParameterDialog(
                refMethodCall.get(), method, psiParameter, refInitializer.get(), createLocal);
        dlg.show();
      }
      return;
    }
    if (refConstantInitializer.isNull()) {
      CommonRefactoringUtil.showErrorHint(
          project,
          editor,
          "Cannot find constant initializer for parameter",
          RefactoringBundle.message("inline.parameter.refactoring"),
          null);
      return;
    }

    final Ref<Boolean> isNotConstantAccessible = new Ref<Boolean>();
    final PsiExpression constantExpression = refConstantInitializer.get();
    constantExpression.accept(
        new JavaRecursiveElementVisitor() {
          @Override
          public void visitReferenceExpression(PsiReferenceExpression expression) {
            super.visitReferenceExpression(expression);
            final PsiElement resolved = expression.resolve();
            if (resolved instanceof PsiMember
                && !PsiUtil.isAccessible((PsiMember) resolved, method, null)) {
              isNotConstantAccessible.set(Boolean.TRUE);
            }
          }
        });
    if (!isNotConstantAccessible.isNull() && isNotConstantAccessible.get()) {
      CommonRefactoringUtil.showErrorHint(
          project,
          editor,
          "Constant initializer is not accessible in method body",
          RefactoringBundle.message("inline.parameter.refactoring"),
          null);
      return;
    }

    for (PsiReference psiReference : ReferencesSearch.search(psiParameter)) {
      final PsiElement element = psiReference.getElement();
      if (element instanceof PsiExpression
          && PsiUtil.isAccessedForWriting((PsiExpression) element)) {
        CommonRefactoringUtil.showErrorHint(
            project,
            editor,
            "Inline parameter which has write usages is not supported",
            RefactoringBundle.message("inline.parameter.refactoring"),
            null);
        return;
      }
    }

    if (!ApplicationManager.getApplication().isUnitTestMode()) {
      String occurencesString = RefactoringBundle.message("occurences.string", occurrences.size());
      String question =
          RefactoringBundle.message(
                  "inline.parameter.confirmation",
                  psiParameter.getName(),
                  constantExpression.getText())
              + " "
              + occurencesString;
      RefactoringMessageDialog dialog =
          new RefactoringMessageDialog(
              REFACTORING_NAME,
              question,
              HelpID.INLINE_VARIABLE,
              "OptionPane.questionIcon",
              true,
              project);
      dialog.show();
      if (!dialog.isOK()) {
        return;
      }
    }

    final RefactoringEventData data = new RefactoringEventData();
    data.addElement(psiElement.copy());
    project
        .getMessageBus()
        .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC)
        .refactoringStarted(REFACTORING_ID, data);

    SameParameterValueInspection.InlineParameterValueFix.inlineSameParameterValue(
        method, psiParameter, constantExpression);

    project
        .getMessageBus()
        .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC)
        .refactoringDone(REFACTORING_ID, null);
  }