Index: trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 7273)
+++ trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 7275)
@@ -18,4 +18,5 @@
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -49,4 +50,5 @@
 import org.openstreetmap.josm.io.UTFInputStreamReader;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
+import org.openstreetmap.josm.tools.MultiMap;
 import org.openstreetmap.josm.tools.Predicate;
 import org.openstreetmap.josm.tools.Utils;
@@ -58,8 +60,19 @@
 public class MapCSSTagChecker extends Test.TagTest {
 
+    /**
+     * A grouped MapCSSRule with multiple selectors for a single declaration.
+     * @see MapCSSRule
+     */
     public static class GroupedMapCSSRule {
+        /** MapCSS selectors **/
         final public List<Selector> selectors;
+        /** MapCSS declaration **/
         final public Declaration declaration;
 
+        /**
+         * Constructs a new {@code GroupedMapCSSRule}.
+         * @param selectors MapCSS selectors
+         * @param declaration MapCSS declaration
+         */
         public GroupedMapCSSRule(List<Selector> selectors, Declaration declaration) {
             this.selectors = selectors;
@@ -112,5 +125,5 @@
     }
 
-    final List<TagCheck> checks = new ArrayList<>();
+    final MultiMap<String, TagCheck> checks = new MultiMap<>();
 
     static class TagCheck implements Predicate<OsmPrimitive> {
@@ -204,5 +217,6 @@
                         check.change.add(toTag);
                     } else if ("fixRemove".equals(ai.key)) {
-                        CheckParameterUtil.ensureThat(!(ai.val instanceof String) || !val.contains("="), "Unexpected '='. Please only specify the key to remove!");
+                        CheckParameterUtil.ensureThat(!(ai.val instanceof String) || !(val != null && val.contains("=")),
+                                "Unexpected '='. Please only specify the key to remove!");
                         final PrimitiveToTag toTag = PrimitiveToTag.ofMapCSSObject(ai.val, true);
                         check.change.add(toTag);
@@ -323,5 +337,5 @@
 
         /**
-         * Replaces occurrences of {@code {i.key}}, {@code {i.value}}, {@code {i.tag}} in {@code s} by the corresponding
+         * Replaces occurrences of <code>{i.key}</code>, <code>{i.value}</code>, <code>{i.tag}</code> in {@code s} by the corresponding
          * key/value/tag of the {@code index}-th {@link Condition} of {@code matchingSelector}.
          */
@@ -484,19 +498,24 @@
     /**
      * Obtains all {@link TestError}s for the {@link OsmPrimitive} {@code p}.
+     * @param p The OSM primitive
+     * @param includeOtherSeverity if {@code true}, errors of severity {@link Severity#OTHER} (info) will also be returned
+     * @return all errors for the given primitive, with or without those of "info" severity
      */
     public Collection<TestError> getErrorsForPrimitive(OsmPrimitive p, boolean includeOtherSeverity) {
         final ArrayList<TestError> r = new ArrayList<>();
         final Environment env = new Environment(p, new MultiCascade(), Environment.DEFAULT_LAYER, null);
-        for (TagCheck check : checks) {
-            if (Severity.OTHER.equals(check.getSeverity()) && !includeOtherSeverity) {
-                continue;
-            }
-            final Selector selector = check.whichSelectorMatchesEnvironment(env);
-            if (selector != null) {
-                check.rule.declaration.execute(env);
-                final TestError error = check.getErrorForPrimitive(p, selector, env);
-                if (error != null) {
-                    error.setTester(new MapCSSTagCheckerAndRule(check.rule));
-                    r.add(error);
+        for (Set<TagCheck> schecks : checks.values()) {
+            for (TagCheck check : schecks) {
+                if (Severity.OTHER.equals(check.getSeverity()) && !includeOtherSeverity) {
+                    continue;
+                }
+                final Selector selector = check.whichSelectorMatchesEnvironment(env);
+                if (selector != null) {
+                    check.rule.declaration.execute(env);
+                    final TestError error = check.getErrorForPrimitive(p, selector, env);
+                    if (error != null) {
+                        error.setTester(new MapCSSTagCheckerAndRule(check.rule));
+                        r.add(error);
+                    }
                 }
             }
@@ -516,10 +535,15 @@
 
     /**
-     * Adds a new MapCSS config file from the given {@code Reader}.
-     * @param css The reader
+     * Adds a new MapCSS config file from the given URL.
+     * @param url The unique URL of the MapCSS config file
      * @throws ParseException if the config file does not match MapCSS syntax
+     * @throws IOException if any I/O error occurs
+     * @since
      */
-    public void addMapCSS(Reader css) throws ParseException {
-        checks.addAll(TagCheck.readMapCSS(css));
+    public void addMapCSS(String url) throws ParseException, IOException {
+        CheckParameterUtil.ensureParameterNotNull(url, "url");
+        try (InputStream s = new CachedFile(url).getInputStream()) {
+            checks.putAll(url, TagCheck.readMapCSS(new BufferedReader(UTFInputStreamReader.create(s))));
+        }
     }
 
@@ -534,7 +558,5 @@
                     Main.info(tr("Adding {0} to tag checker", i));
                 }
-                try (InputStream s = new CachedFile(i).getInputStream()) {
-                    addMapCSS(new BufferedReader(UTFInputStreamReader.create(s)));
-                }
+                addMapCSS(i);
             } catch (IOException ex) {
                 Main.warn(tr("Failed to add {0} to tag checker", i));
Index: trunk/src/org/openstreetmap/josm/tools/MultiMap.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/MultiMap.java	(revision 7273)
+++ trunk/src/org/openstreetmap/josm/tools/MultiMap.java	(revision 7275)
@@ -12,9 +12,13 @@
 
 /**
- * MultiMap - maps keys to multiple values
+ * MultiMap - maps keys to multiple values.
  *
  * Corresponds to Google guava LinkedHashMultimap and Apache Collections MultiValueMap
  * but it is an independent (simple) implementation.
  *
+ * @param <A> Key type
+ * @param <B> Value type
+ *
+ * @since 2702
  */
 public class MultiMap<A, B> {
@@ -30,5 +34,5 @@
 
     /**
-     * Constructs a new {@code MultiMap} with the specified initial capacity. 
+     * Constructs a new {@code MultiMap} with the specified initial capacity.
      * @param capacity the initial capacity
      */
@@ -41,4 +45,6 @@
      *
      * Can be called multiple times with the same key, but different value.
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
      */
     public void put(A key, B value) {
@@ -56,4 +62,5 @@
      * Afterwards containsKey(key) will return true and get(key) will return
      * an empty Set instead of null.
+     * @param key key with which an empty set is to be associated
      */
     public void putVoid(A key) {
@@ -67,4 +74,6 @@
      *
      * Adds to the mappings that are already there.
+     * @param key key with which the specified values are to be associated
+     * @param values values to be associated with the specified key
      */
     public void putAll(A key, Collection<B> values) {
@@ -79,4 +88,6 @@
     /**
      * Get the keySet.
+     * @return a set view of the keys contained in this map
+     * @see Map#keySet()
      */
     public Set<A> keySet() {
@@ -90,4 +101,7 @@
      * Modifications of the returned list changes the underling map,
      * but you should better not do that.
+     * @param key the key whose associated value is to be returned
+     * @return the set of values to which the specified key is mapped, or {@code null} if this map contains no mapping for the key
+     * @see Map#get(Object)
      */
     public Set<B> get(A key) {
@@ -97,4 +111,6 @@
     /**
      * Like get, but returns an empty Set if nothing has been mapped to the key.
+     * @param key the key whose associated value is to be returned
+     * @return the set of values to which the specified key is mapped, or an empty set if this map contains no mapping for the key
      */
     public Set<B> getValues(A key) {
@@ -104,8 +120,19 @@
     }
 
+    /**
+     * Returns {@code true} if this map contains no key-value mappings.
+     * @return {@code true} if this map contains no key-value mappings
+     * @see Map#isEmpty()
+     */
     public boolean isEmpty() {
         return map.isEmpty();
     }
 
+    /**
+     * Returns {@code true} if this map contains a mapping for the specified key.
+     * @param key key whose presence in this map is to be tested
+     * @return {@code true} if this map contains a mapping for the specified key
+     * @see Map#containsKey(Object)
+     */
     public boolean containsKey(A key) {
         return map.containsKey(key);
@@ -124,8 +151,18 @@
     }
 
+    /**
+     * Removes all of the mappings from this map. The map will be empty after this call returns.
+     * @see Map#clear()
+     */
     public void clear() {
         map.clear();
     }
 
+    /**
+     * Returns a Set view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are reflected in the set, and vice-versa.
+     * @return a set view of the mappings contained in this map
+     * @see Map#entrySet()
+     */
     public Set<Entry<A, Set<B>>> entrySet() {
         return map.entrySet();
@@ -134,4 +171,6 @@
     /**
      * Returns the number of keys.
+     * @return the number of key-value mappings in this map
+     * @see Map#size()
      */
     public int size() {
@@ -141,4 +180,6 @@
     /**
      * Returns a collection of all value sets.
+     * @return a collection view of the values contained in this map
+     * @see Map#values()
      */
     public Collection<Set<B>> values() {
@@ -147,7 +188,9 @@
 
     /**
-     * Removes a cerain key=value mapping.
-     *
-     * @return true, if something was removed
+     * Removes a certain key=value mapping.
+     * @param key key whose mapping is to be removed from the map
+     * @param value value whose mapping is to be removed from the map
+     *
+     * @return {@code true}, if something was removed
      */
     public boolean remove(A key, B value) {
@@ -161,4 +204,7 @@
     /**
      * Removes all mappings for a certain key.
+     * @param key key whose mapping is to be removed from the map
+     * @return the previous value associated with key, or {@code null} if there was no mapping for key.
+     * @see Map#remove(Object)
      */
     public Set<B> remove(A key) {
