docs: protected static GenericsType fullyResolve(GenericsType gt, Map<GenericsTypeName, GenericsType> placeholders) {
          GenericsType fromMap = placeholders.get(new GenericsTypeName(gt.getName()));
          if (gt.isPlaceholder() && fromMap != null) {
              gt = fromMap;
          }
  
          ClassNode type = fullyResolveType(gt.getType(), placeholders);
          ClassNode lowerBound = gt.getLowerBound();
          if (lowerBound != null) lowerBound = fullyResolveType(lowerBound, placeholders);
          ClassNode[] upperBounds = gt.getUpperBounds();
          if (upperBounds != null) {
              ClassNode[] copy = new ClassNode[upperBounds.length];
              for (int i = 0, upperBoundsLength = upperBounds.length; i < upperBoundsLength; i++) {
                  final ClassNode upperBound = upperBounds[i];
                  copy[i] = fullyResolveType(upperBound, placeholders);
              }
              upperBounds = copy;
          }
          GenericsType genericsType = new GenericsType(type, upperBounds, lowerBound);
          genericsType.setWildcard(gt.isWildcard());
          return genericsType;
      }