protected RichDiagnosticFormatter(Context context) {
   super((AbstractDiagnosticFormatter) Log.instance(context).getDiagnosticFormatter());
   setRichPrinter(new RichPrinter());
   this.syms = Symtab.instance(context);
   this.diags = JCDiagnostic.Factory.instance(context);
   this.types = Types.instance(context);
   this.messages = JavacMessages.instance(context);
   whereClauses = new LinkedHashMap<WhereClauseKind, Map<Type, JCDiagnostic>>();
   configuration = new RichConfiguration(Options.instance(context), formatter);
   for (WhereClauseKind kind : WhereClauseKind.values())
     whereClauses.put(kind, new LinkedHashMap<Type, JCDiagnostic>());
 }
 @Override
 public Void visitCapturedType(CapturedType t, Void ignored) {
   if (indexOf(t, WhereClauseKind.CAPTURED) == -1) {
     String suffix = t.lower == syms.botType ? ".1" : "";
     JCDiagnostic d =
         diags.fragment("where.captured" + suffix, t, t.bound, t.lower, t.wildcard);
     whereClauses.get(WhereClauseKind.CAPTURED).put(t, d);
     visit(t.wildcard);
     visit(t.lower);
     visit(t.bound);
   }
   return null;
 }
        @Override
        public Void visitTypeVar(TypeVar t, Void ignored) {
          if (indexOf(t, WhereClauseKind.TYPEVAR) == -1) {
            // access the bound type and skip error types
            Type bound = t.bound;
            while ((bound instanceof ErrorType)) bound = ((ErrorType) bound).getOriginalType();
            // retrieve the bound list - if the type variable
            // has not been attributed the bound is not set
            List<Type> bounds =
                (bound != null && bound.tsym != null) ? types.getBounds(t) : List.<Type>nil();

            nameSimplifier.addUsage(t.tsym);

            boolean boundErroneous =
                bounds.head == null || bounds.head.tag == NONE || bounds.head.tag == ERROR;

            if ((t.tsym.flags() & SYNTHETIC) == 0) {
              // this is a true typevar
              JCDiagnostic d =
                  diags.fragment(
                      "where.typevar" + (boundErroneous ? ".1" : ""),
                      t,
                      bounds,
                      Kinds.kindName(t.tsym.location()),
                      t.tsym.location());
              whereClauses.get(WhereClauseKind.TYPEVAR).put(t, d);
              symbolPreprocessor.visit(t.tsym.location(), null);
              visit(bounds);
            } else {
              Assert.check(!boundErroneous);
              // this is a fresh (synthetic) tvar
              JCDiagnostic d = diags.fragment("where.fresh.typevar", t, bounds);
              whereClauses.get(WhereClauseKind.TYPEVAR).put(t, d);
              visit(bounds);
            }
          }
          return null;
        }
 /**
  * Build a list of multiline diagnostics containing detailed info about type-variables, captured
  * types, and intersection types
  *
  * @return where clause list
  */
 protected List<JCDiagnostic> getWhereClauses() {
   List<JCDiagnostic> clauses = List.nil();
   for (WhereClauseKind kind : WhereClauseKind.values()) {
     List<JCDiagnostic> lines = List.nil();
     for (Map.Entry<Type, JCDiagnostic> entry : whereClauses.get(kind).entrySet()) {
       lines = lines.prepend(entry.getValue());
     }
     if (!lines.isEmpty()) {
       String key = kind.key();
       if (lines.size() > 1) key += ".1";
       JCDiagnostic d = diags.fragment(key, whereClauses.get(kind).keySet());
       d = new JCDiagnostic.MultilineDiagnostic(d, lines.reverse());
       clauses = clauses.prepend(d);
     }
   }
   return clauses.reverse();
 }
 @Override
 public Void visitClassType(ClassType t, Void ignored) {
   if (t.isCompound()) {
     if (indexOf(t, WhereClauseKind.INTERSECTION) == -1) {
       Type supertype = types.supertype(t);
       List<Type> interfaces = types.interfaces(t);
       JCDiagnostic d =
           diags.fragment("where.intersection", t, interfaces.prepend(supertype));
       whereClauses.get(WhereClauseKind.INTERSECTION).put(t, d);
       visit(supertype);
       visit(interfaces);
     }
   }
   nameSimplifier.addUsage(t.tsym);
   visit(t.getTypeArguments());
   if (t.getEnclosingType() != Type.noType) visit(t.getEnclosingType());
   return null;
 }