Index: src/org/openstreetmap/josm/plugins/validator/tests/SameWay.java
===================================================================
--- src/org/openstreetmap/josm/plugins/validator/tests/SameWay.java	(revision 0)
+++ src/org/openstreetmap/josm/plugins/validator/tests/SameWay.java	(revision 0)
@@ -0,0 +1,117 @@
+// License: GPL. See LICENSE file for details.
+package org.openstreetmap.josm.plugins.validator.tests;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.ChangeCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.DeleteCommand;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.plugins.validator.Severity;
+import org.openstreetmap.josm.plugins.validator.Test;
+import org.openstreetmap.josm.plugins.validator.TestError;
+import org.openstreetmap.josm.plugins.validator.util.Bag;
+/**
+ * Tests if there are same ways (same position, but maybe different tags)
+ */
+public class SameWay extends Test
+{
+
+    private static class WayPair {
+        public List<LatLon> coor;
+        public WayPair(List<LatLon> _coor) {
+            coor=_coor;
+        }
+        @Override
+        public int hashCode() {
+            return coor.hashCode();
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof WayPair)) return false;
+            WayPair wp = (WayPair) obj;
+            return wp.coor.equals(coor);
+        }
+    }
+
+    protected static int SAME_WAY = 1901;
+
+    /** Bag of all ways */
+    Bag<WayPair, OsmPrimitive> ways;
+
+    /**
+     * Constructor
+     */
+    public SameWay()
+    {
+        super(tr("Same ways")+".",
+              tr("This test checks that there are no ways with same node coordinates (tags may differ)."));
+    }
+
+
+    @Override
+    public void startTest(ProgressMonitor monitor)
+    {
+    	super.startTest(monitor);
+        ways = new Bag<WayPair, OsmPrimitive>(1000);
+    }
+
+    @Override
+    public void endTest()
+    {
+    	super.endTest();
+        for(List<OsmPrimitive> sameway : ways.values() )
+        {
+            if( sameway.size() > 1)
+            {
+                TestError testError = new TestError(this, Severity.WARNING, tr("Ways with same position"), SAME_WAY, sameway);
+                errors.add( testError );
+            }
+        }
+        ways = null;
+    }
+
+    @Override
+    public void visit(Way w)
+    {
+        if( !w.isUsable() )
+            return;
+        List<Node> wNodes=w.getNodes();
+        Vector<LatLon> wLat=new Vector<LatLon>(wNodes.size());
+        for(int i=0;i<wNodes.size();i++) {
+                 wLat.add(wNodes.get(i).getCoor());
+        }
+        WayPair wKey=new WayPair(wLat);
+        ways.add(wKey, w);
+    }
+
+    /**
+     * No fix provided
+     */
+    @Override
+    public Command fixError(TestError testError)
+    {
+        return null;
+    }
+
+    @Override
+    public boolean isFixable(TestError testError)
+    {
+        return false;
+    }
+}
Index: src/org/openstreetmap/josm/plugins/validator/tests/DuplicateRelation.java
===================================================================
--- src/org/openstreetmap/josm/plugins/validator/tests/DuplicateRelation.java	(revision 0)
+++ src/org/openstreetmap/josm/plugins/validator/tests/DuplicateRelation.java	(revision 0)
@@ -0,0 +1,211 @@
+// License: GPL. See LICENSE file for details.
+package org.openstreetmap.josm.plugins.validator.tests;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.ChangeCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.DeleteCommand;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.plugins.validator.Severity;
+import org.openstreetmap.josm.plugins.validator.Test;
+import org.openstreetmap.josm.plugins.validator.TestError;
+import org.openstreetmap.josm.plugins.validator.util.Bag;
+/**
+ * Tests if there are duplicate relations
+ */
+public class DuplicateRelation extends Test
+{
+
+    private static class RelationPair {
+        public List<RelationMember> members;
+        public Map<String, String> keys;
+        public RelationPair(List<RelationMember> _members,Map<String, String> _keys) {
+            members=_members;
+            keys=_keys;
+        }
+        @Override
+        public int hashCode() {
+            return members.hashCode()+keys.hashCode();
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof RelationPair)) return false;
+            RelationPair rp = (RelationPair) obj;
+            return rp.members.equals(members) && rp.keys.equals(keys);
+        }
+    }
+
+    protected static int DUPLICATE_RELATION = 2001;
+    protected static int SAME_RELATION = 2002;
+
+    /** Bag of all relations */
+    Bag<RelationPair, OsmPrimitive> relations;
+
+    /** Bag of all relations, regardless of keys */
+    Bag<List<RelationMember>, OsmPrimitive> relations_nokeys;
+
+    /**
+     * Constructor
+     */
+    public DuplicateRelation()
+    {
+        super(tr("Duplicated relations")+".",
+              tr("This test checks that there are no relations with same tags and same members with same roles."));
+    }
+
+
+    @Override
+    public void startTest(ProgressMonitor monitor)
+    {
+    	super.startTest(monitor);
+        relations = new Bag<RelationPair, OsmPrimitive>(1000);
+        relations_nokeys = new Bag<List<RelationMember>, OsmPrimitive>(1000);
+    }
+
+    @Override
+    public void endTest()
+    {
+    	super.endTest();
+        for(List<OsmPrimitive> duplicated : relations.values() )
+        {
+            if( duplicated.size() > 1)
+            {
+                TestError testError = new TestError(this, Severity.ERROR, tr("Duplicated relations"), DUPLICATE_RELATION, duplicated);
+                errors.add( testError );
+            }
+        }
+        relations = null;
+        for(List<OsmPrimitive> duplicated : relations_nokeys.values() )
+        {
+            if( duplicated.size() > 1)
+            {
+                TestError testError = new TestError(this, Severity.WARNING, tr("Relations with same members"), SAME_RELATION, duplicated);
+                errors.add( testError );
+            }
+        }
+        relations_nokeys = null;
+    }
+
+    @Override
+    public void visit(Relation r)
+    {
+        if( !r.isUsable() )
+            return;
+        List<RelationMember> rMembers=r.getMembers();
+        Map<String, String> rkeys=r.getKeys();
+        rkeys.remove("created_by");
+        RelationPair rKey=new RelationPair(rMembers,rkeys);
+        relations.add(rKey, r);
+        relations_nokeys.add(rMembers, r);
+    }
+
+    /**
+     * Fix the error by removing all but one instance of duplicate relations
+     */
+    @Override
+    public Command fixError(TestError testError)
+    {
+        if (testError.getCode() == SAME_RELATION) return null;
+        Collection<? extends OsmPrimitive> sel = testError.getPrimitives();
+        HashSet<Relation> rel_fix = new HashSet<Relation>();
+
+        for (OsmPrimitive osm : sel)
+            if (osm instanceof Relation)
+                rel_fix.add((Relation)osm);
+
+        if( rel_fix.size() < 2 )
+            return null;
+
+        long idToKeep = 0;
+        Relation relationToKeep = rel_fix.iterator().next();
+        // Only one relation will be kept - the one with lowest positive ID, if such exist
+        // or one "at random" if no such exists. Rest of the relations will be deleted
+        for (Relation w: rel_fix) {
+            if (!w.isNew()) {
+                if (idToKeep == 0 || w.getId() < idToKeep) {
+                    idToKeep = w.getId();
+                    relationToKeep = w;
+                }
+            }
+        }
+
+        // Find the relation that is member of one or more relations. (If any)
+        Relation relationWithRelations = null;
+        List<Relation> rel_ref = null;
+        for (Relation w : rel_fix) {
+            List<Relation> rel = OsmPrimitive.getFilteredList(w.getReferrers(), Relation.class);
+            if (!rel.isEmpty()) {
+                if (relationWithRelations != null)
+                    throw new AssertionError("Cannot fix duplicate relations: More than one relation is member of another relation.");
+                relationWithRelations = w;
+                rel_ref = rel;
+            }
+        }
+
+        Collection<Command> commands = new LinkedList<Command>();
+
+        // Fix relations.
+        if (relationWithRelations != null && relationToKeep != relationWithRelations) {
+            for (Relation rel : rel_ref) {
+                Relation newRel = new Relation(rel);
+                for (int i = 0; i < newRel.getMembers().size(); ++i) {
+                    RelationMember m = newRel.getMember(i);
+                    if (relationWithRelations.equals(m.getMember())) {
+                        newRel.setMember(i, new RelationMember(m.getRole(), relationToKeep));
+                    }
+                }
+                commands.add(new ChangeCommand(rel, newRel));
+            }
+        }
+
+        //Delete all relations in the list
+        rel_fix.remove(relationToKeep);
+        commands.add(new DeleteCommand(rel_fix));
+        return new SequenceCommand(tr("Delete duplicate relations"), commands);
+    }
+
+    @Override
+    public boolean isFixable(TestError testError)
+    {
+        if (!(testError.getTester() instanceof DuplicateRelation))
+            return false;
+
+        if (testError.getCode() == SAME_RELATION) return false;
+
+        // We fix it only if there is no more than one relation that is relation member.
+        Collection<? extends OsmPrimitive> sel = testError.getPrimitives();
+        HashSet<Relation> relations = new HashSet<Relation>();
+
+        for (OsmPrimitive osm : sel)
+            if (osm instanceof Relation)
+                relations.add((Relation)osm);
+
+        if (relations.size() < 2)
+            return false;
+
+        int relationsWithRelations = 0;
+        for (Relation w : relations) {
+            List<Relation> rel = OsmPrimitive.getFilteredList(w.getReferrers(), Relation.class);
+            if (!rel.isEmpty()) {
+                ++relationsWithRelations;
+            }
+        }
+        return (relationsWithRelations <= 1);
+    }
+}
Index: src/org/openstreetmap/josm/plugins/validator/OSMValidatorPlugin.java
===================================================================
--- src/org/openstreetmap/josm/plugins/validator/OSMValidatorPlugin.java	(revision 22711)
+++ src/org/openstreetmap/josm/plugins/validator/OSMValidatorPlugin.java	(working copy)
@@ -38,10 +38,12 @@
 import org.openstreetmap.josm.plugins.validator.tests.CrossingWays;
 import org.openstreetmap.josm.plugins.validator.tests.DuplicateNode;
 import org.openstreetmap.josm.plugins.validator.tests.DuplicateWay;
+import org.openstreetmap.josm.plugins.validator.tests.DuplicateRelation;
 import org.openstreetmap.josm.plugins.validator.tests.DuplicatedWayNodes;
 import org.openstreetmap.josm.plugins.validator.tests.MultipolygonTest;
 import org.openstreetmap.josm.plugins.validator.tests.NameMismatch;
 import org.openstreetmap.josm.plugins.validator.tests.NodesWithSameName;
+import org.openstreetmap.josm.plugins.validator.tests.SameWay;
 import org.openstreetmap.josm.plugins.validator.tests.OverlappingWays;
 import org.openstreetmap.josm.plugins.validator.tests.RelationChecker;
 import org.openstreetmap.josm.plugins.validator.tests.SelfIntersectingWay;
@@ -104,6 +106,8 @@
             MultipolygonTest.class, // ID  1601 ..  1699
             RelationChecker.class, // ID  1701 ..  1799
             TurnrestrictionTest.class, // ID  1801 ..  1899
+            SameWay.class, // ID 1901 .. 1999
+            DuplicateRelation.class, // ID 2001 .. 2099
     };
 
     /**
