PsiType (@NotNull PsiClassType originalType) { final PsiClass resolved = originalType.resolve(); // if resolved to method parameter -> return as is if (resolved instanceof PsiTypeParameter && compiledMethod.equals(((PsiTypeParameter)resolved).getOwner())) return originalType; final PsiType[] typeParameters = originalType.getParameters(); final PsiTypeParameter byName = substitutionMap.get(originalType.getCanonicalText()); if (byName != null) { assert typeParameters.length == 0; return elementFactory.createType(byName); } if (resolved == null) return originalType; if (typeParameters.length == 0) return originalType; // do not go deeper final Ref<Boolean> hasChanges = Ref.create(false); final PsiTypeVisitor<PsiType> $this = this; final PsiType[] substitutes = ContainerUtil.map2Array(typeParameters, PsiType.class, type -> { final PsiType mapped = type.accept($this); hasChanges.set(mapped != type); return mapped; }); return hasChanges.get() ? elementFactory.createType(resolved, substitutes) : originalType; }