@Nullable public static Type resolveVariable( TypeVariable variable, final Class classType, boolean resolveInInterfacesOnly) { final Class aClass = getRawType(classType); int index = ArrayUtilRt.find(ReflectionCache.getTypeParameters(aClass), variable); if (index >= 0) { return variable; } final Class[] classes = ReflectionCache.getInterfaces(aClass); final Type[] genericInterfaces = ReflectionCache.getGenericInterfaces(aClass); for (int i = 0; i <= classes.length; i++) { Class anInterface; if (i < classes.length) { anInterface = classes[i]; } else { anInterface = ReflectionCache.getSuperClass(aClass); if (resolveInInterfacesOnly || anInterface == null) { continue; } } final Type resolved = resolveVariable(variable, anInterface); if (resolved instanceof Class || resolved instanceof ParameterizedType) { return resolved; } if (resolved instanceof TypeVariable) { final TypeVariable typeVariable = (TypeVariable) resolved; index = ArrayUtilRt.find(ReflectionCache.getTypeParameters(anInterface), typeVariable); if (index < 0) { LOG.error( "Cannot resolve type variable:\n" + "typeVariable = " + typeVariable + "\n" + "genericDeclaration = " + declarationToString(typeVariable.getGenericDeclaration()) + "\n" + "searching in " + declarationToString(anInterface)); } final Type type = i < genericInterfaces.length ? genericInterfaces[i] : aClass.getGenericSuperclass(); if (type instanceof Class) { return Object.class; } if (type instanceof ParameterizedType) { return getActualTypeArguments((ParameterizedType) type)[index]; } throw new AssertionError("Invalid type: " + type); } } return null; }
private void reportNullableArgumentsPassedToNonAnnotated( DataFlowInstructionVisitor visitor, ProblemsHolder holder, Set<PsiElement> reportedAnchors) { for (PsiElement expr : visitor.getProblems(NullabilityProblem.passingNullableArgumentToNonAnnotatedParameter)) { if (reportedAnchors.contains(expr)) continue; final String text = isNullLiteralExpression(expr) ? "Passing <code>null</code> argument to non annotated parameter" : "Argument <code>#ref</code> #loc might be null but passed to non annotated parameter"; LocalQuickFix[] fixes = createNPEFixes((PsiExpression) expr, (PsiExpression) expr, holder.isOnTheFly()); final PsiElement parent = expr.getParent(); if (parent instanceof PsiExpressionList) { final int idx = ArrayUtilRt.find(((PsiExpressionList) parent).getExpressions(), expr); if (idx > -1) { final PsiElement gParent = parent.getParent(); if (gParent instanceof PsiCallExpression) { final PsiMethod psiMethod = ((PsiCallExpression) gParent).resolveMethod(); if (psiMethod != null && psiMethod.getManager().isInProject(psiMethod) && AnnotationUtil.isAnnotatingApplicable(psiMethod)) { final PsiParameter[] parameters = psiMethod.getParameterList().getParameters(); if (idx < parameters.length) { final AddNullableAnnotationFix addNullableAnnotationFix = new AddNullableAnnotationFix(parameters[idx]); fixes = fixes == null ? new LocalQuickFix[] {addNullableAnnotationFix} : ArrayUtil.append(fixes, addNullableAnnotationFix); holder.registerProblem(expr, text, fixes); reportedAnchors.add(expr); } } } } } } }
@Nullable public static Class<?> substituteGenericType(final Type genericType, final Type classType) { if (genericType instanceof TypeVariable) { final Class<?> aClass = getRawType(classType); final Type type = resolveVariable((TypeVariable) genericType, aClass); if (type instanceof Class) { return (Class) type; } if (type instanceof ParameterizedType) { return (Class<?>) ((ParameterizedType) type).getRawType(); } if (type instanceof TypeVariable && classType instanceof ParameterizedType) { final int index = ArrayUtilRt.find(ReflectionCache.getTypeParameters(aClass), type); if (index >= 0) { return getRawType(getActualTypeArguments((ParameterizedType) classType)[index]); } } } else { return getRawType(genericType); } return null; }