void (PsiParameterListOwner method) { PsiElement body = method.getBody(); if (body == null) return; PsiParameter methodParameter = method.getParameterList().getParameter(1); if (methodParameter == null) return; if (body instanceof PsiCodeBlock && !ControlFlowUtils.containsReturn(body)) return; if (!VariableAccessUtils.variableIsUsed(methodParameter, body)) { holder.registerProblem(Objects.requireNonNull(methodParameter.getNameIdentifier()), JavaAnalysisBundle.message("suspicious.invocation.handler.implementation.method.unused.message")); return; } InvocationHandlerAnalysisRunner runner = new InvocationHandlerAnalysisRunner(holder, body, methodParameter); DfaVariableValue methodName = runner.myDfaMethodName; if (methodName == null) return; Map<String, Map<PsiExpression, DfType>> returnMap = new TreeMap<>(); RunnerResult result = runner.analyzeMethod(body, new JavaDfaListener() { @Override public void beforeValueReturn(@NotNull DfaValue value, @Nullable PsiExpression expression, @NotNull PsiElement context, @NotNull DfaMemoryState state) { if (context != method) return; String name = state.getDfType(methodName).getConstantOfType(String.class); if (name == null) { runner.cancel(); return; } DfType type = state.getDfType(value); if (type instanceof DfPrimitiveType) { type = DfTypes.typedObject(((DfPrimitiveType)type).getPsiType().getBoxedType(body), Nullability.NOT_NULL); } returnMap.computeIfAbsent(name, k -> new HashMap<>()).merge(expression, type, DfType::join); } }); if (result != RunnerResult.OK) return; Set<PsiExpression> reportedAnchors = new HashSet<>(); returnMap.forEach((name, map) -> { DfType reduced = map.values().stream().reduce(DfType.BOTTOM, DfType::join); PsiType wantedType = getWantedType(body, name); if (wantedType == null) return; TypeConstraint wantedConstraint = TypeConstraints.exact(wantedType); if (reduced.meet(wantedConstraint.asDfType().meet(DfTypes.NOT_NULL_OBJECT)) != DfType.BOTTOM && StreamEx.ofValues(map).map(DfaNullability::fromDfType).anyMatch( n -> n != DfaNullability.NULLABLE && n != DfaNullability.NULL)) { return; } map.forEach((expression, type) -> { if (reportedAnchors.contains(expression)) return; String message = null; TypeConstraint constraint = TypeConstraint.fromDfType(type); if (wantedConstraint.meet(constraint) == TypeConstraints.BOTTOM) { message = JavaAnalysisBundle.message("suspicious.invocation.handler.implementation.type.mismatch.message", name, wantedConstraint.getPresentationText(null), constraint.getPresentationText(null)); } DfaNullability nullability = DfaNullability.fromDfType(type); if (nullability == DfaNullability.NULL) { message = name.equals("toString") ? JavaAnalysisBundle.message("suspicious.invocation.handler.implementation.null.returned.for.toString.message") : JavaAnalysisBundle.message("suspicious.invocation.handler.implementation.null.returned.message", name); } if (message != null) { reportedAnchors.add(expression); holder.registerProblem(expression, message); } }); }); }