Beispiel #1
1
  /*
   * Replace Placeholders for repeating annotations with their containers
   */
  private <T extends Attribute.Compound> void complete(Annotate.AnnotateRepeatedContext<T> ctx) {
    Log log = ctx.log;
    Env<AttrContext> env = ctx.env;
    JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile);
    try {
      // TODO: can we reduce duplication in the following branches?
      if (ctx.isTypeCompound) {
        Assert.check(!isTypesEmpty());

        if (isTypesEmpty()) {
          return;
        }

        List<Attribute.TypeCompound> result = List.nil();
        for (Attribute.TypeCompound a : getTypeAttributes()) {
          if (a instanceof Placeholder) {
            @SuppressWarnings("unchecked")
            Placeholder<Attribute.TypeCompound> ph = (Placeholder<Attribute.TypeCompound>) a;
            Attribute.TypeCompound replacement = replaceOne(ph, ph.getRepeatedContext());

            if (null != replacement) {
              result = result.prepend(replacement);
            }
          } else {
            result = result.prepend(a);
          }
        }

        type_attributes = result.reverse();

        Assert.check(Annotations.this.getTypePlaceholders().isEmpty());
      } else {
        Assert.check(!pendingCompletion());

        if (isEmpty()) {
          return;
        }

        List<Attribute.Compound> result = List.nil();
        for (Attribute.Compound a : getDeclarationAttributes()) {
          if (a instanceof Placeholder) {
            @SuppressWarnings("unchecked")
            Attribute.Compound replacement = replaceOne((Placeholder<T>) a, ctx);

            if (null != replacement) {
              result = result.prepend(replacement);
            }
          } else {
            result = result.prepend(a);
          }
        }

        attributes = result.reverse();

        Assert.check(Annotations.this.getPlaceholders().isEmpty());
      }
    } finally {
      log.useSource(oldSource);
    }
  }
 public void run() {
   Context ctx = new Context();
   Options options = Options.instance(ctx);
   outputKind.init(options);
   multiPolicy.init(options);
   xdiagsSource.init(options);
   xdiagsCompact.init(options);
   caretKind.init(options);
   sourceLineKind.init(options);
   String indentString = "";
   indentString = (summaryIndent == IndentKind.CUSTOM) ? "3" : "0";
   indentString += (detailsIndent == IndentKind.CUSTOM) ? "|3" : "|0";
   indentString += (sourceIndent == IndentKind.CUSTOM) ? "|3" : "|0";
   indentString += (subdiagsIndent == IndentKind.CUSTOM) ? "|3" : "|0";
   options.put("diagsIndentation", indentString);
   MyLog log = new MyLog(ctx);
   JavacMessages messages = JavacMessages.instance(ctx);
   messages.add("tester");
   JCDiagnostic.Factory diags = JCDiagnostic.Factory.instance(ctx);
   log.useSource(new MyFileObject("This is a source line"));
   JCDiagnostic d =
       diags.error(null, log.currentSource(), posKind.pos(), errorKind.key(), "Hello!");
   if (multiKind != MultilineKind.NONE) {
     JCDiagnostic sub = diags.fragment(errorKind.key(), "Hello!");
     if (multiKind.isNested()) sub = new JCDiagnostic.MultilineDiagnostic(sub, List.of(sub));
     List<JCDiagnostic> subdiags = multiKind.isDouble() ? List.of(sub, sub) : List.of(sub);
     d = new JCDiagnostic.MultilineDiagnostic(d, subdiags);
   }
   String diag = log.getDiagnosticFormatter().format(d, messages.getCurrentLocale());
   checkOutput(diag);
 }
  /**
   * Given a list of field names and a node referring to a type, finds each name in the list that
   * does not match a field within the type.
   */
  public static List<Integer> createListOfNonExistentFields(
      List<String> list, JavacNode type, boolean excludeStandard, boolean excludeTransient) {
    boolean[] matched = new boolean[list.size()];

    for (JavacNode child : type.down()) {
      if (list.isEmpty()) break;
      if (child.getKind() != Kind.FIELD) continue;
      JCVariableDecl field = (JCVariableDecl) child.get();
      if (excludeStandard) {
        if ((field.mods.flags & Flags.STATIC) != 0) continue;
        if (field.name.toString().startsWith("$")) continue;
      }
      if (excludeTransient && (field.mods.flags & Flags.TRANSIENT) != 0) continue;

      int idx = list.indexOf(child.getName());
      if (idx > -1) matched[idx] = true;
    }

    ListBuffer<Integer> problematic = ListBuffer.lb();
    for (int i = 0; i < list.size(); i++) {
      if (!matched[i]) problematic.append(i);
    }

    return problematic.toList();
  }
  private static void injectField(
      JavacNode typeNode, JCVariableDecl field, boolean addSuppressWarnings) {
    JCClassDecl type = (JCClassDecl) typeNode.get();

    if (addSuppressWarnings)
      addSuppressWarningsAll(field.mods, typeNode, field.pos, getGeneratedBy(field));

    List<JCTree> insertAfter = null;
    List<JCTree> insertBefore = type.defs;
    while (insertBefore.tail != null) {
      if (insertBefore.head instanceof JCVariableDecl) {
        JCVariableDecl f = (JCVariableDecl) insertBefore.head;
        if (isEnumConstant(f) || isGenerated(f)) {
          insertAfter = insertBefore;
          insertBefore = insertBefore.tail;
          continue;
        }
      }
      break;
    }
    List<JCTree> fieldEntry = List.<JCTree>of(field);
    fieldEntry.tail = insertBefore;
    if (insertAfter == null) {
      type.defs = fieldEntry;
    } else {
      insertAfter.tail = fieldEntry;
    }

    typeNode.add(field, Kind.FIELD);
  }
  static JCExpression createFieldAccessor(
      TreeMaker maker, JavacNode field, FieldAccess fieldAccess, JCExpression receiver) {
    boolean lookForGetter = lookForGetter(field, fieldAccess);

    GetterMethod getter = lookForGetter ? findGetter(field) : null;
    JCVariableDecl fieldDecl = (JCVariableDecl) field.get();

    if (getter == null) {
      if (receiver == null) {
        if ((fieldDecl.mods.flags & Flags.STATIC) == 0) {
          receiver = maker.Ident(field.toName("this"));
        } else {
          JavacNode containerNode = field.up();
          if (containerNode != null && containerNode.get() instanceof JCClassDecl) {
            JCClassDecl container = (JCClassDecl) field.up().get();
            receiver = maker.Ident(container.name);
          }
        }
      }

      return receiver == null
          ? maker.Ident(fieldDecl.name)
          : maker.Select(receiver, fieldDecl.name);
    }

    if (receiver == null) receiver = maker.Ident(field.toName("this"));
    JCMethodInvocation call =
        maker.Apply(
            List.<JCExpression>nil(),
            maker.Select(receiver, getter.name),
            List.<JCExpression>nil());
    return call;
  }
Beispiel #6
0
 public void visitTry(JCTry tree) {
   try {
     print("try ");
     if (tree.resources.nonEmpty()) {
       print("(");
       boolean first = true;
       for (JCTree var : tree.resources) {
         if (!first) {
           println();
           indent();
         }
         printStat(var);
         first = false;
       }
       print(") ");
     }
     printStat(tree.body);
     for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
       printStat(l.head);
     }
     if (tree.finalizer != null) {
       print(" finally ");
       printStat(tree.finalizer);
     }
   } catch (IOException e) {
     throw new UncheckedIOException(e);
   }
 }
  @Override
  public void handle(
      AnnotationValues<EqualsAndHashCode> annotation, JCAnnotation ast, JavacNode annotationNode) {
    deleteAnnotationIfNeccessary(annotationNode, EqualsAndHashCode.class);
    EqualsAndHashCode ann = annotation.getInstance();
    List<String> excludes = List.from(ann.exclude());
    List<String> includes = List.from(ann.of());
    JavacNode typeNode = annotationNode.up();

    checkForBogusFieldNames(typeNode, annotation);

    Boolean callSuper = ann.callSuper();
    if (!annotation.isExplicit("callSuper")) callSuper = null;
    if (!annotation.isExplicit("exclude")) excludes = null;
    if (!annotation.isExplicit("of")) includes = null;

    if (excludes != null && includes != null) {
      excludes = null;
      annotation.setWarning(
          "exclude",
          "exclude and of are mutually exclusive; the 'exclude' parameter will be ignored.");
    }

    FieldAccess fieldAccess = ann.doNotUseGetters() ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;

    generateMethods(typeNode, annotationNode, excludes, includes, callSuper, true, fieldAccess);
  }
 @Override
 public String visitCapturedType(CapturedType t, Locale locale) {
   if (!allCaptured.contains(t)) {
     allCaptured = allCaptured.append(t);
   }
   return super.visitCapturedType(t, locale);
 }
Beispiel #9
0
 /** Derived visitor method: print list of statements, each on a separate line. */
 public void printStats(List<? extends JCTree> trees) throws IOException {
   for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) {
     align();
     printStat(l.head);
     println();
   }
 }
Beispiel #10
0
  public JCMethodDecl generateBuilderMethod(
      String builderMethodName,
      String builderClassName,
      JavacNode type,
      List<JCTypeParameter> typeParams) {
    JavacTreeMaker maker = type.getTreeMaker();

    ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>();
    for (JCTypeParameter typeParam : typeParams) {
      typeArgs.append(maker.Ident(typeParam.name));
    }

    JCExpression call =
        maker.NewClass(
            null,
            List.<JCExpression>nil(),
            namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams),
            List.<JCExpression>nil(),
            null);
    JCStatement statement = maker.Return(call);

    JCBlock body = maker.Block(0, List.<JCStatement>of(statement));
    return maker.MethodDef(
        maker.Modifiers(Flags.STATIC | Flags.PUBLIC),
        type.toName(builderMethodName),
        namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams),
        copyTypeParams(maker, typeParams),
        List.<JCVariableDecl>nil(),
        List.<JCExpression>nil(),
        body,
        null);
  }
Beispiel #11
0
 /**
  * Converts a class name into a (possibly localized) string. Anonymous inner classes gets
  * converted into a localized string.
  *
  * @param t the type of the class whose name is to be rendered
  * @param longform if set, the class' fullname is displayed - if unset the short name is chosen
  *     (w/o package)
  * @param locale the locale in which the string is to be rendered
  * @return localized string representation
  */
 protected String className(ClassType t, boolean longform, Locale locale) {
   Symbol sym = t.tsym;
   if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) {
     StringBuilder s = new StringBuilder(visit(t.supertype_field, locale));
     for (List<Type> is = t.interfaces_field; is.nonEmpty(); is = is.tail) {
       s.append("&");
       s.append(visit(is.head, locale));
     }
     return s.toString();
   } else if (sym.name.length() == 0) {
     String s;
     ClassType norm = (ClassType) t.tsym.type;
     if (norm == null) {
       s = localize(locale, "compiler.misc.anonymous.class", (Object) null);
     } else if (norm.interfaces_field != null && norm.interfaces_field.nonEmpty()) {
       s =
           localize(
               locale, "compiler.misc.anonymous.class", visit(norm.interfaces_field.head, locale));
     } else {
       s = localize(locale, "compiler.misc.anonymous.class", visit(norm.supertype_field, locale));
     }
     return s;
   } else if (longform) {
     return sym.getQualifiedName().toString();
   } else {
     return sym.name.toString();
   }
 }
  @Override
  public boolean handle(
      AnnotationValues<Synchronized> annotation, JCAnnotation ast, Node annotationNode) {
    Node methodNode = annotationNode.up();

    if (methodNode == null
        || methodNode.getKind() != Kind.METHOD
        || !(methodNode.get() instanceof JCMethodDecl)) {
      annotationNode.addError("@Synchronized is legal only on methods.");
      return true;
    }

    JCMethodDecl method = (JCMethodDecl) methodNode.get();

    if ((method.mods.flags & Flags.ABSTRACT) != 0) {
      annotationNode.addError("@Synchronized is legal only on concrete methods.");
      return true;
    }
    boolean isStatic = (method.mods.flags & Flags.STATIC) != 0;
    String lockName = annotation.getInstance().value();
    boolean autoMake = false;
    if (lockName.length() == 0) {
      autoMake = true;
      lockName = isStatic ? STATIC_LOCK_NAME : INSTANCE_LOCK_NAME;
    }

    TreeMaker maker = methodNode.getTreeMaker();

    if (fieldExists(lockName, methodNode) == MemberExistsResult.NOT_EXISTS) {
      if (!autoMake) {
        annotationNode.addError("The field " + new String(lockName) + " does not exist.");
        return true;
      }
      JCExpression objectType = chainDots(maker, methodNode, "java", "lang", "Object");
      // We use 'new Object[0];' because quite unlike 'new Object();', empty arrays *ARE*
      // serializable!
      JCNewArray newObjectArray =
          maker.NewArray(
              chainDots(maker, methodNode, "java", "lang", "Object"),
              List.<JCExpression>of(maker.Literal(TypeTags.INT, 0)),
              null);
      JCVariableDecl fieldDecl =
          maker.VarDef(
              maker.Modifiers(Flags.FINAL | (isStatic ? Flags.STATIC : 0)),
              methodNode.toName(lockName),
              objectType,
              newObjectArray);
      injectField(methodNode.up(), fieldDecl);
    }

    if (method.body == null) return false;

    JCExpression lockNode = maker.Ident(methodNode.toName(lockName));

    method.body = maker.Block(0, List.<JCStatement>of(maker.Synchronized(lockNode, method.body)));

    methodNode.rebuild();

    return true;
  }
Beispiel #13
0
 /**
  * Print unit consisting of package clause and import statements in toplevel, followed by class
  * definition. if class definition == null, print all definitions in toplevel.
  *
  * @param tree The toplevel tree
  * @param cdef The class definition, which is assumed to be part of the toplevel tree.
  */
 public void printUnit(JCCompilationUnit tree, JCClassDecl cdef) throws IOException {
   docComments = tree.docComments;
   printDocComment(tree);
   if (tree.pid != null) {
     consumeComments(tree.pos);
     print("package ");
     printExpr(tree.pid);
     print(";");
     println();
   }
   boolean firstImport = true;
   for (List<JCTree> l = tree.defs;
       l.nonEmpty() && (cdef == null || getTag(l.head) == IMPORT);
       l = l.tail) {
     if (getTag(l.head) == IMPORT) {
       JCImport imp = (JCImport) l.head;
       Name name = TreeInfo.name(imp.qualid);
       if (name == name.table.fromChars(new char[] {'*'}, 0, 1)
           || cdef == null
           || isUsed(TreeInfo.symbol(imp.qualid), cdef)) {
         if (firstImport) {
           firstImport = false;
           println();
         }
         printStat(imp);
       }
     } else {
       printStat(l.head);
     }
   }
   if (cdef != null) {
     printStat(cdef);
     println();
   }
 }
 /** Print info about this round. */
 private void printRoundInfo(boolean lastRound) {
   if (printRounds || verbose) {
     List<ClassSymbol> tlc = lastRound ? List.<ClassSymbol>nil() : topLevelClasses;
     Set<TypeElement> ap = lastRound ? Collections.<TypeElement>emptySet() : annotationsPresent;
     log.printNoteLines("x.print.rounds", number, "{" + tlc.toString(", ") + "}", ap, lastRound);
   }
 }
Beispiel #15
0
 /** Print a block. */
 public void printEnumBody(List<JCTree> stats) throws IOException {
   print("{");
   println();
   indent();
   boolean first = true;
   for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
     if (isEnumerator(l.head)) {
       if (!first) {
         print(",");
         println();
       }
       align();
       printStat(l.head);
       first = false;
     }
   }
   print(";");
   println();
   int x = 0;
   for (List<JCTree> l = stats; l.nonEmpty(); l = l.tail) {
     x++;
     if (!isEnumerator(l.head)) {
       align();
       printStat(l.head);
       println();
     }
   }
   undent();
   align();
   print("}");
 }
Beispiel #16
0
 public void visitForLoop(JCForLoop tree) {
   try {
     print("for (");
     if (tree.init.nonEmpty()) {
       if (getTag(tree.init.head) == VARDEF) {
         printExpr(tree.init.head);
         for (List<JCStatement> l = tree.init.tail; l.nonEmpty(); l = l.tail) {
           JCVariableDecl vdef = (JCVariableDecl) l.head;
           print(", " + vdef.name + " = ");
           printExpr(vdef.init);
         }
       } else {
         printExprs(tree.init);
       }
     }
     print("; ");
     if (tree.cond != null) printExpr(tree.cond);
     print("; ");
     printExprs(tree.step);
     print(") ");
     printStat(tree.body);
   } catch (IOException e) {
     throw new UncheckedIOException(e);
   }
 }
Beispiel #17
0
  public JCMethodDecl makeSetterMethodForBuilder(
      JavacNode builderType, JavacNode fieldNode, JavacNode source, boolean fluent, boolean chain) {
    Name fieldName = ((JCVariableDecl) fieldNode.get()).name;

    for (JavacNode child : builderType.down()) {
      if (child.getKind() != Kind.METHOD) continue;
      Name existingName = ((JCMethodDecl) child.get()).name;
      if (existingName.equals(fieldName)) return null;
    }

    boolean isBoolean = isBoolean(fieldNode);
    String setterName =
        fluent
            ? fieldNode.getName()
            : toSetterName(builderType.getAst(), null, fieldNode.getName(), isBoolean);

    JavacTreeMaker maker = builderType.getTreeMaker();
    return HandleSetter.createSetter(
        Flags.PUBLIC,
        fieldNode,
        maker,
        setterName,
        chain,
        source,
        List.<JCAnnotation>nil(),
        List.<JCAnnotation>nil());
  }
Beispiel #18
0
 public void printAnnotations(List<JCAnnotation> trees) throws IOException {
   for (List<JCAnnotation> l = trees; l.nonEmpty(); l = l.tail) {
     printStat(l.head);
     println();
     align();
   }
 }
Beispiel #19
0
 /** Visitor method: enter classes of a list of trees, returning a list of types. */
 <T extends JCTree> List<Type> classEnter(List<T> trees, Env<AttrContext> env) {
   ListBuffer<Type> ts = new ListBuffer<Type>();
   for (List<T> l = trees; l.nonEmpty(); l = l.tail) {
     Type t = classEnter(l.head, env);
     if (t != null) ts.append(t);
   }
   return ts.toList();
 }
 /** Add a name usage to the simplifier's internal cache */
 protected void addUsage(Symbol sym) {
   Name n = sym.getSimpleName();
   List<Symbol> conflicts = nameClashes.get(n);
   if (conflicts == null) {
     conflicts = List.nil();
   }
   if (!conflicts.contains(sym)) nameClashes.put(n, conflicts.append(sym));
 }
Beispiel #21
0
  /**
   * Reverse list. If the list is empty or a singleton, then the same list is returned. Otherwise a
   * new list is formed.
   */
  public List<A> reverse() {
    // if it is empty or a singleton, return itself
    if (isEmpty() || tail.isEmpty()) return this;

    List<A> rev = nil();
    for (List<A> l = this; l.nonEmpty(); l = l.tail) rev = new List<A>(l.head, rev);
    return rev;
  }
 /**
  * Complete the initialization of an operator helper by storing it into the corresponding operator
  * map.
  */
 @SafeVarargs
 private final <O extends OperatorHelper> void initOperators(Map<Name, List<O>> opsMap, O... ops) {
   for (O o : ops) {
     Name opName = o.name;
     List<O> helpers = opsMap.getOrDefault(opName, List.nil());
     opsMap.put(opName, helpers.prepend(o));
   }
 }
  private JCCompilationUnit ceylonParse(JavaFileObject filename, CharSequence readSource) {
    if (ceylonEnter.hasRun())
      throw new RuntimeException(
          "Trying to load new source file after CeylonEnter has been called: " + filename);
    try {
      String source = readSource.toString();
      ANTLRStringStream input = new ANTLRStringStream(source);
      CeylonLexer lexer = new CeylonLexer(input);

      CommonTokenStream tokens = new CommonTokenStream(lexer);

      CeylonParser parser = new CeylonParser(tokens);
      CompilationUnit cu = parser.compilationUnit();

      char[] chars = source.toCharArray();
      LineMap map = Position.makeLineMap(chars, chars.length, false);

      java.util.List<LexError> lexerErrors = lexer.getErrors();
      for (LexError le : lexerErrors) {
        printError(le, le.getMessage(), "ceylon.lexer", map);
      }

      java.util.List<ParseError> parserErrors = parser.getErrors();
      for (ParseError pe : parserErrors) {
        printError(pe, pe.getMessage(), "ceylon.parser", map);
      }

      if (lexer.getNumberOfSyntaxErrors() != 0) {
        log.error("ceylon.lexer.failed");
      } else if (parser.getNumberOfSyntaxErrors() != 0) {
        log.error("ceylon.parser.failed");
      } else {
        ModuleManager moduleManager = phasedUnits.getModuleManager();
        File sourceFile = new File(filename.toString());
        // FIXME: temporary solution
        VirtualFile file = vfs.getFromFile(sourceFile);
        VirtualFile srcDir = vfs.getFromFile(getSrcDir(sourceFile));
        // FIXME: this is bad in many ways
        String pkgName = getPackage(filename);
        // make a Package with no module yet, we will resolve them later
        com.redhat.ceylon.compiler.typechecker.model.Package p =
            modelLoader.findOrCreatePackage(null, pkgName == null ? "" : pkgName);
        PhasedUnit phasedUnit =
            new CeylonPhasedUnit(file, srcDir, cu, p, moduleManager, ceylonContext, filename, map);
        phasedUnits.addPhasedUnit(file, phasedUnit);
        gen.setMap(map);

        return gen.makeJCCompilationUnitPlaceholder(cu, filename, pkgName, phasedUnit);
      }
    } catch (Exception e) {
      log.error("ceylon", e.getMessage());
    }

    JCCompilationUnit result =
        make.TopLevel(List.<JCAnnotation>nil(), null, List.<JCTree>of(make.Erroneous()));
    result.sourcefile = filename;
    return result;
  }
 private List<ClassSymbol> getTopLevelClassesFromClasses(List<? extends ClassSymbol> syms) {
   List<ClassSymbol> classes = List.nil();
   for (ClassSymbol sym : syms) {
     if (!isPkgInfo(sym)) {
       classes = classes.prepend(sym);
     }
   }
   return classes.reverse();
 }
 private List<PackageSymbol> getPackageInfoFilesFromClasses(List<? extends ClassSymbol> syms) {
   List<PackageSymbol> packages = List.nil();
   for (ClassSymbol sym : syms) {
     if (isPkgInfo(sym)) {
       packages = packages.prepend((PackageSymbol) sym.owner);
     }
   }
   return packages.reverse();
 }
 private List<PackageSymbol> getPackageInfoFiles(List<? extends JCCompilationUnit> units) {
   List<PackageSymbol> packages = List.nil();
   for (JCCompilationUnit unit : units) {
     if (isPkgInfo(unit.sourcefile, JavaFileObject.Kind.SOURCE)) {
       packages = packages.prepend(unit.packge);
     }
   }
   return packages.reverse();
 }
Beispiel #27
0
 private List<Attribute.Compound> getPlaceholders() {
   List<Attribute.Compound> res = List.<Attribute.Compound>nil();
   for (Attribute.Compound a : filterDeclSentinels(attributes)) {
     if (a instanceof Placeholder) {
       res = res.prepend(a);
     }
   }
   return res.reverse();
 }
Beispiel #28
0
 /**
  * Derived visitor method: print list of expression trees, separated by given string.
  *
  * @param sep the separator string
  */
 public <T extends JCTree> void printExprs(List<T> trees, String sep) throws IOException {
   if (trees.nonEmpty()) {
     printExpr(trees.head);
     for (List<T> l = trees.tail; l.nonEmpty(); l = l.tail) {
       print(sep);
       printExpr(l.head);
     }
   }
 }
Beispiel #29
0
 private List<Attribute.TypeCompound> getTypePlaceholders() {
   List<Attribute.TypeCompound> res = List.<Attribute.TypeCompound>nil();
   for (Attribute.TypeCompound a : type_attributes) {
     if (a instanceof Placeholder) {
       res = res.prepend(a);
     }
   }
   return res.reverse();
 }
Beispiel #30
0
 /** Returns the list obtained from 'l' after removing all elements 'elem' */
 public static <A> List<A> filter(List<A> l, A elem) {
   Assert.checkNonNull(elem);
   List<A> res = List.nil();
   for (A a : l) {
     if (a != null && !a.equals(elem)) {
       res = res.prepend(a);
     }
   }
   return res.reverse();
 }