private void reportNullableReturns( DataFlowInstructionVisitor visitor, ProblemsHolder holder, Set<PsiElement> reportedAnchors, @NotNull PsiElement block) { final PsiMethod method = getScopeMethod(block); if (method == null || NullableStuffInspectionBase.isNullableNotInferred(method, true)) return; boolean notNullRequired = NullableNotNullManager.isNotNull(method); if (!notNullRequired && !SUGGEST_NULLABLE_ANNOTATIONS) return; PsiType returnType = method.getReturnType(); // no warnings in void lambdas, where the expression is not returned anyway if (block instanceof PsiExpression && block.getParent() instanceof PsiLambdaExpression && returnType == PsiType.VOID) return; // no warnings for Void methods, where only null can be possibly returned if (returnType == null || returnType.equalsToText(CommonClassNames.JAVA_LANG_VOID)) return; for (PsiElement statement : visitor.getProblems(NullabilityProblem.nullableReturn)) { assert statement instanceof PsiExpression; final PsiExpression expr = (PsiExpression) statement; if (!reportedAnchors.add(expr)) continue; if (notNullRequired) { final String text = isNullLiteralExpression(expr) ? InspectionsBundle.message("dataflow.message.return.null.from.notnull") : InspectionsBundle.message("dataflow.message.return.nullable.from.notnull"); holder.registerProblem(expr, text); } else if (AnnotationUtil.isAnnotatingApplicable(statement)) { final NullableNotNullManager manager = NullableNotNullManager.getInstance(expr.getProject()); final String defaultNullable = manager.getDefaultNullable(); final String presentableNullable = StringUtil.getShortName(defaultNullable); final String text = isNullLiteralExpression(expr) ? InspectionsBundle.message( "dataflow.message.return.null.from.notnullable", presentableNullable) : InspectionsBundle.message( "dataflow.message.return.nullable.from.notnullable", presentableNullable); final LocalQuickFix[] fixes = PsiTreeUtil.getParentOfType(expr, PsiMethod.class, PsiLambdaExpression.class) instanceof PsiLambdaExpression ? LocalQuickFix.EMPTY_ARRAY : new LocalQuickFix[] { new AnnotateMethodFix( defaultNullable, ArrayUtil.toStringArray(manager.getNotNulls())) { @Override public int shouldAnnotateBaseMethod( PsiMethod method, PsiMethod superMethod, Project project) { return 1; } } }; holder.registerProblem(expr, text, fixes); } } }
@Override protected String validateAndCommitData() { PsiManager manager = PsiManager.getInstance(myProject); PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); String name = getMethodName(); if (!JavaPsiFacade.getInstance(manager.getProject()).getNameHelper().isIdentifier(name)) { return RefactoringMessageUtil.getIncorrectIdentifierMessage(name); } if (myMethod.canChangeReturnType() == MethodDescriptor.ReadWriteOption.ReadWrite) { try { ((PsiTypeCodeFragment) myReturnTypeCodeFragment).getType(); } catch (PsiTypeCodeFragment.TypeSyntaxException e) { myReturnTypeField.requestFocus(); return RefactoringBundle.message( "changeSignature.wrong.return.type", myReturnTypeCodeFragment.getText()); } catch (PsiTypeCodeFragment.NoTypeException e) { myReturnTypeField.requestFocus(); return RefactoringBundle.message("changeSignature.no.return.type"); } } List<ParameterTableModelItemBase<ParameterInfoImpl>> parameterInfos = myParametersTableModel.getItems(); final int newParametersNumber = parameterInfos.size(); for (int i = 0; i < newParametersNumber; i++) { final ParameterTableModelItemBase<ParameterInfoImpl> item = parameterInfos.get(i); if (!JavaPsiFacade.getInstance(manager.getProject()) .getNameHelper() .isIdentifier(item.parameter.getName())) { return RefactoringMessageUtil.getIncorrectIdentifierMessage(item.parameter.getName()); } final PsiType type; try { type = ((PsiTypeCodeFragment) parameterInfos.get(i).typeCodeFragment).getType(); } catch (PsiTypeCodeFragment.TypeSyntaxException e) { return RefactoringBundle.message( "changeSignature.wrong.type.for.parameter", item.typeCodeFragment.getText(), item.parameter.getName()); } catch (PsiTypeCodeFragment.NoTypeException e) { return RefactoringBundle.message( "changeSignature.no.type.for.parameter", item.parameter.getName()); } item.parameter.setType(type); if (type instanceof PsiEllipsisType && i != newParametersNumber - 1) { return RefactoringBundle.message("changeSignature.vararg.not.last"); } if (item.parameter.oldParameterIndex < 0) { item.parameter.defaultValue = ApplicationManager.getApplication() .runWriteAction( new Computable<String>() { @Override public String compute() { return JavaCodeStyleManager.getInstance(myProject) .qualifyClassReferences(item.defaultValueCodeFragment) .getText(); } }); String def = item.parameter.defaultValue; def = def.trim(); if (!(type instanceof PsiEllipsisType)) { try { if (!StringUtil.isEmpty(def)) { factory.createExpressionFromText(def, null); } } catch (IncorrectOperationException e) { return e.getMessage(); } } } } ThrownExceptionInfo[] exceptionInfos = myExceptionsModel.getThrownExceptions(); PsiTypeCodeFragment[] typeCodeFragments = myExceptionsModel.getTypeCodeFragments(); for (int i = 0; i < exceptionInfos.length; i++) { ThrownExceptionInfo exceptionInfo = exceptionInfos[i]; PsiTypeCodeFragment typeCodeFragment = typeCodeFragments[i]; try { PsiType type = typeCodeFragment.getType(); if (!(type instanceof PsiClassType)) { return RefactoringBundle.message( "changeSignature.wrong.type.for.exception", typeCodeFragment.getText()); } PsiClassType throwable = JavaPsiFacade.getInstance(myProject) .getElementFactory() .createTypeByFQClassName("java.lang.Throwable", type.getResolveScope()); if (!throwable.isAssignableFrom(type)) { return RefactoringBundle.message( "changeSignature.not.throwable.type", typeCodeFragment.getText()); } exceptionInfo.setType((PsiClassType) type); } catch (PsiTypeCodeFragment.TypeSyntaxException e) { return RefactoringBundle.message( "changeSignature.wrong.type.for.exception", typeCodeFragment.getText()); } catch (PsiTypeCodeFragment.NoTypeException e) { return RefactoringBundle.message("changeSignature.no.type.for.exception"); } } // warnings try { if (myMethod.canChangeReturnType() == MethodDescriptor.ReadWriteOption.ReadWrite) { if (!RefactoringUtil.isResolvableType( ((PsiTypeCodeFragment) myReturnTypeCodeFragment).getType())) { if (Messages.showOkCancelDialog( myProject, RefactoringBundle.message( "changeSignature.cannot.resolve.return.type", myReturnTypeCodeFragment.getText()), RefactoringBundle.message("changeSignature.refactoring.name"), Messages.getWarningIcon()) != 0) { return EXIT_SILENTLY; } } } for (ParameterTableModelItemBase<ParameterInfoImpl> item : parameterInfos) { if (!RefactoringUtil.isResolvableType( ((PsiTypeCodeFragment) item.typeCodeFragment).getType())) { if (Messages.showOkCancelDialog( myProject, RefactoringBundle.message( "changeSignature.cannot.resolve.parameter.type", item.typeCodeFragment.getText(), item.parameter.getName()), RefactoringBundle.message("changeSignature.refactoring.name"), Messages.getWarningIcon()) != 0) { return EXIT_SILENTLY; } } } } catch (PsiTypeCodeFragment.IncorrectTypeException ignored) { } return null; }
@NotNull private static LookupElement castQualifier( @NotNull LookupElement item, @Nullable final PsiTypeLookupItem castTypeItem, @Nullable PsiType plainQualifier, JavaCompletionProcessor processor) { if (castTypeItem == null) { return item; } if (plainQualifier != null) { Object o = item.getObject(); if (o instanceof PsiMethod) { PsiType castType = castTypeItem.getType(); if (plainQualifier instanceof PsiClassType && castType instanceof PsiClassType) { PsiMethod method = (PsiMethod) o; PsiClassType.ClassResolveResult plainResult = ((PsiClassType) plainQualifier).resolveGenerics(); PsiClass plainClass = plainResult.getElement(); if (plainClass != null && plainClass.findMethodBySignature(method, true) != null) { PsiClass castClass = ((PsiClassType) castType).resolveGenerics().getElement(); if (castClass == null || !castClass.isInheritor(plainClass, true)) { return item; } PsiSubstitutor plainSub = plainResult.getSubstitutor(); PsiSubstitutor castSub = TypeConversionUtil.getSuperClassSubstitutor(plainClass, (PsiClassType) castType); PsiType returnType = method.getReturnType(); if (method.getSignature(plainSub).equals(method.getSignature(castSub))) { PsiType typeAfterCast = toRaw(castSub.substitute(returnType)); PsiType typeDeclared = toRaw(plainSub.substitute(returnType)); if (typeAfterCast != null && typeDeclared != null && typeAfterCast.isAssignableFrom(typeDeclared) && processor.isAccessible(plainClass.findMethodBySignature(method, true))) { return item; } } } } } else if (containsMember(plainQualifier, o)) { return item; } } return LookupElementDecorator.withInsertHandler( item, new InsertHandlerDecorator<LookupElement>() { @Override public void handleInsert( InsertionContext context, LookupElementDecorator<LookupElement> item) { final Document document = context.getEditor().getDocument(); context.commitDocument(); final PsiFile file = context.getFile(); final PsiJavaCodeReferenceElement ref = PsiTreeUtil.findElementOfClassAtOffset( file, context.getStartOffset(), PsiJavaCodeReferenceElement.class, false); if (ref != null) { final PsiElement qualifier = ref.getQualifier(); if (qualifier != null) { final CommonCodeStyleSettings settings = context.getCodeStyleSettings(); final String parenSpace = settings.SPACE_WITHIN_PARENTHESES ? " " : ""; document.insertString(qualifier.getTextRange().getEndOffset(), parenSpace + ")"); final String spaceWithin = settings.SPACE_WITHIN_CAST_PARENTHESES ? " " : ""; final String prefix = "(" + parenSpace + "(" + spaceWithin; final String spaceAfter = settings.SPACE_AFTER_TYPE_CAST ? " " : ""; final int exprStart = qualifier.getTextRange().getStartOffset(); document.insertString(exprStart, prefix + spaceWithin + ")" + spaceAfter); CompletionUtil.emulateInsertion(context, exprStart + prefix.length(), castTypeItem); PsiDocumentManager.getInstance(file.getProject()) .doPostponedOperationsAndUnblockDocument(document); context.getEditor().getCaretModel().moveToOffset(context.getTailOffset()); } } item.getDelegate().handleInsert(context); } }); }