Index: trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(revision 2406)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(revision 2407)
@@ -543,5 +543,4 @@
 
             newSelection.add(n);
-            ds.setSelected(n);
         } else if (!newNode) {
             title = tr("Connect existing way to node");
Index: trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java	(revision 2406)
+++ trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java	(revision 2407)
@@ -39,5 +39,5 @@
         this.regexSearch = regexSearch;
         this.tokenizer = tokenizer;
-        childBackRefs = new CollectBackReferencesVisitor(Main.main.getCurrentDataSet());
+        childBackRefs = new CollectBackReferencesVisitor(true);
     }
 
@@ -230,42 +230,42 @@
 
             switch (mode) {
-                case NONE:
-                    return false;
-                case MISSING_KEY:
-                    return osm.get(key) == null;
-                case ANY:
-                    return true;
-                case ANY_VALUE:
-                    return osm.get(key) != null;
-                case ANY_KEY:
-                    for (String v:osm.getKeys().values()) {
-                        if (v.equals(value))
+            case NONE:
+                return false;
+            case MISSING_KEY:
+                return osm.get(key) == null;
+            case ANY:
+                return true;
+            case ANY_VALUE:
+                return osm.get(key) != null;
+            case ANY_KEY:
+                for (String v:osm.getKeys().values()) {
+                    if (v.equals(value))
+                        return true;
+                }
+                return false;
+            case EXACT:
+                return value.equals(osm.get(key));
+            case ANY_KEY_REGEXP:
+                for (String v:osm.getKeys().values()) {
+                    if (valuePattern.matcher(v).matches())
+                        return true;
+                }
+                return false;
+            case ANY_VALUE_REGEXP:
+            case EXACT_REGEXP:
+                for (Entry<String, String> entry:osm.entrySet()) {
+                    if (keyPattern.matcher(entry.getKey()).matches()) {
+                        if (mode == Mode.ANY_VALUE_REGEXP
+                                || valuePattern.matcher(entry.getValue()).matches())
                             return true;
                     }
-                    return false;
-                case EXACT:
-                    return value.equals(osm.get(key));
-                case ANY_KEY_REGEXP:
-                    for (String v:osm.getKeys().values()) {
-                        if (valuePattern.matcher(v).matches())
-                            return true;
-                    }
-                    return false;
-                case ANY_VALUE_REGEXP:
-                case EXACT_REGEXP:
-                    for (Entry<String, String> entry:osm.entrySet()) {
-                        if (keyPattern.matcher(entry.getKey()).matches()) {
-                            if (mode == Mode.ANY_VALUE_REGEXP
-                                    || valuePattern.matcher(entry.getValue()).matches())
-                                return true;
-                        }
-                    }
-                    return false;
-                case MISSING_KEY_REGEXP:
-                    for (String k:osm.keySet()) {
-                        if (keyPattern.matcher(k).matches())
-                            return false;
-                    }
-                    return true;
+                }
+                return false;
+            case MISSING_KEY_REGEXP:
+                for (String k:osm.keySet()) {
+                    if (keyPattern.matcher(k).matches())
+                        return false;
+                }
+                return true;
             }
             throw new AssertionError("Missed state");
Index: trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 2406)
+++ trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 2407)
@@ -147,10 +147,15 @@
      * 
      * @return DataSet this primitive is part of.
-     * @throws DataIntegrityProblemException when primitive is not part of any dataset
      */
     public DataSet getDataSet() {
+        return dataSet;
+    }
+
+    /**
+     * Throws exception if primitive is not part of the dataset
+     */
+    public void checkDataset() {
         if (dataSet == null)
-            throw new DataIntegrityProblemException("Primitive must be part of the dataset");
-        return dataSet;
+            throw new DataIntegrityProblemException("Primitive  must be part of the dataset: " + toString());
     }
 
@@ -648,4 +653,107 @@
         return keys.keySet();
     }
+
+
+    /*------------
+     * Referrers
+     ------------*/
+
+    private Object referrers;
+
+
+    /**
+     * Add new referrer. If referrer is already included then no action is taken
+     * @param referrer
+     */
+    protected void addReferrer(OsmPrimitive referrer) {
+        // Based on methods from josm-ng
+        if (referrers == null) {
+            referrers = referrer;
+        } else if (referrers instanceof OsmPrimitive) {
+            if (referrers != referrer) {
+                referrers = new OsmPrimitive[] { (OsmPrimitive)referrers, referrer };
+            }
+        } else {
+            for (OsmPrimitive primitive:(OsmPrimitive[])referrers) {
+                if (primitive == referrer)
+                    return;
+            }
+            OsmPrimitive[] orig = (OsmPrimitive[])referrers;
+            OsmPrimitive[] bigger = new OsmPrimitive[orig.length+1];
+            System.arraycopy(orig, 0, bigger, 0, orig.length);
+            bigger[orig.length] = referrer;
+            referrers = bigger;
+        }
+    }
+
+    /**
+     * Remove referrer. No action is taken if referrer is not registered
+     * @param referrer
+     */
+    protected void removeReferrer(OsmPrimitive referrer) {
+        // Based on methods from josm-ng
+        if (referrers instanceof OsmPrimitive) {
+            if (referrers == referrer) {
+                referrers = null;
+            }
+        } else if (referrers instanceof OsmPrimitive[]) {
+            OsmPrimitive[] orig = (OsmPrimitive[])referrers;
+            int idx = -1;
+            for (int i=0; i<orig.length; i++) {
+                if (orig[i] == referrer) {
+                    idx = i;
+                    break;
+                }
+            }
+            if (idx == -1)
+                return;
+
+            if (orig.length == 2) {
+                referrers = orig[1-idx]; // idx is either 0 or 1, take the other
+            } else { // downsize the array
+                OsmPrimitive[] smaller = new OsmPrimitive[orig.length-1];
+                System.arraycopy(orig, 0, smaller, 0, idx);
+                System.arraycopy(orig, idx+1, smaller, idx, smaller.length-idx);
+                referrers = smaller;
+            }
+        }
+    }
+    /**
+     * Find primitives that reference this primitive. Returns only primitives that are included in the same
+     * dataset as this primitive. <br>
+     * 
+     * For example following code will add wnew as referer to all nodes of existingWay, but this method will
+     * not return wnew because it's not part of the dataset <br>
+     * 
+     * <code>Way wnew = new Way(existingWay)</code>
+     * 
+     * @return a collection of all primitives that reference this primitive.
+     */
+
+    public final List<OsmPrimitive> getReferrers() {
+        checkDataset();
+        // Method copied from OsmPrimitive in josm-ng
+        // Returns only referrers that are members of the same dataset (primitive can have some fake references, for example
+        // when way is cloned
+        if (referrers == null)
+            return Collections.emptyList();
+
+        if (referrers instanceof OsmPrimitive) {
+            if (((OsmPrimitive)referrers).dataSet == dataSet)
+                return Collections.singletonList((OsmPrimitive)referrers);
+            else
+                return Collections.emptyList();
+        }
+
+        List<OsmPrimitive> result = new ArrayList<OsmPrimitive>();
+        for (OsmPrimitive o:(OsmPrimitive[])referrers) {
+            if (dataSet == o.dataSet) {
+                result.add(o);
+            }
+        }
+
+        return result;
+    }
+
 
     /**
Index: trunk/src/org/openstreetmap/josm/data/osm/Relation.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Relation.java	(revision 2406)
+++ trunk/src/org/openstreetmap/josm/data/osm/Relation.java	(revision 2407)
@@ -39,8 +39,16 @@
      */
     public void setMembers(List<RelationMember> members) {
+        for (RelationMember rm:this.members) {
+            rm.getMember().removeReferrer(this);
+        }
+
         this.members.clear();
         if (members != null) {
             this.members.addAll(members);
         }
+        for (RelationMember rm:this.members) {
+            rm.getMember().addReferrer(this);
+        }
+
     }
 
@@ -70,4 +78,5 @@
     public void addMember(RelationMember member) {
         members.add(member);
+        member.getMember().addReferrer(this);
     }
 
@@ -80,4 +89,5 @@
     public void addMember(int index, RelationMember member) {
         members.add(index, member);
+        member.getMember().addReferrer(this);
     }
 
@@ -90,5 +100,10 @@
      */
     public RelationMember setMember(int index, RelationMember member) {
-        return members.set(index, member);
+        RelationMember result = members.set(index, member);
+        if (result.getMember() != member.getMember()) {
+            member.getMember().addReferrer(this);
+            result.getMember().removeReferrer(this);
+        }
+        return result;
     }
 
@@ -100,5 +115,12 @@
      */
     public RelationMember removeMember(int index) {
-        return members.remove(index);
+        RelationMember result = members.remove(index);
+        for (RelationMember rm:members) {
+            // Do not remove referrer if this primitive is used in relation twice
+            if (rm.getMember() == result.getMember())
+                return result;
+        }
+        result.getMember().removeReferrer(this);
+        return result;
     }
 
@@ -139,10 +161,6 @@
     @Override public void cloneFrom(OsmPrimitive osm) {
         super.cloneFrom(osm);
-        members.clear();
-        // we must not add the members themselves, but instead
-        // add clones of the members
-        for (RelationMember em : ((Relation)osm).getMembers()) {
-            members.add(new RelationMember(em));
-        }
+        // It's not necessary to clone members as RelationMember class is immutable
+        setMembers(((Relation)osm).getMembers());
     }
 
@@ -236,6 +254,20 @@
             }
         }
+        primitive.removeReferrer(this);
         members.removeAll(todelete);
     }
+
+    @Override
+    public void setDeleted(boolean deleted) {
+        for (RelationMember rm:members) {
+            if (deleted) {
+                rm.getMember().removeReferrer(this);
+            } else {
+                rm.getMember().addReferrer(this);
+            }
+        }
+        super.setDeleted(deleted);
+    }
+
 
     /**
@@ -255,4 +287,7 @@
         }
         members.removeAll(todelete);
+        for (OsmPrimitive primitive:primitives) {
+            primitive.removeReferrer(this);
+        }
     }
 
Index: trunk/src/org/openstreetmap/josm/data/osm/Way.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Way.java	(revision 2406)
+++ trunk/src/org/openstreetmap/josm/data/osm/Way.java	(revision 2407)
@@ -45,4 +45,8 @@
      */
     public void setNodes(List<Node> nodes) {
+        for (Node node:this.nodes) {
+            node.removeReferrer(this);
+        }
+
         if (nodes == null) {
             this.nodes = new Node[0];
@@ -50,4 +54,8 @@
             this.nodes = nodes.toArray(new Node[nodes.size()]);
         }
+        for (Node node:this.nodes) {
+            node.addReferrer(this);
+        }
+
         clearCached();
     }
@@ -194,6 +202,5 @@
         super.cloneFrom(osm);
         Way otherWay = (Way)osm;
-        nodes = new Node[otherWay.nodes.length];
-        System.arraycopy(otherWay.nodes, 0, nodes, 0, otherWay.nodes.length);
+        setNodes(otherWay.getNodes());
     }
 
@@ -229,4 +236,5 @@
         i = copy.size();
         if (closed && i > 2) {
+            // TODO Should this be copy.addNode(firstNode)?
             addNode(firstNode());
         } else if (i >= 2 && i <= 3 && copy.get(0) == copy.get(i-1)) {
@@ -257,4 +265,5 @@
             throw new IllegalStateException(tr("Cannot add node {0} to incomplete way {1}.", n.getId(), getId()));
         clearCached();
+        n.addReferrer(this);
         Node[] newNodes = new Node[nodes.length + 1];
         System.arraycopy(nodes, 0, newNodes, 0, nodes.length);
@@ -277,4 +286,5 @@
             throw new IllegalStateException(tr("Cannot add node {0} to incomplete way {1}.", n.getId(), getId()));
         clearCached();
+        n.addReferrer(this);
         Node[] newNodes = new Node[nodes.length + 1];
         System.arraycopy(nodes, 0, newNodes, 0, offs);
@@ -284,4 +294,17 @@
     }
 
+    @Override
+    public void setDeleted(boolean deleted) {
+        for (Node n:nodes) {
+            if (deleted) {
+                n.removeReferrer(this);
+            } else {
+                n.addReferrer(this);
+            }
+        }
+        super.setDeleted(deleted);
+    }
+
+
     public boolean isClosed() {
         if (incomplete) return false;
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/CollectBackReferencesVisitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/CollectBackReferencesVisitor.java	(revision 2406)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/CollectBackReferencesVisitor.java	(revision 2407)
@@ -4,6 +4,4 @@
 import java.util.Collection;
 import java.util.HashSet;
-import java.util.HashMap;
-import java.util.Map;
 
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -11,5 +9,4 @@
 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;
 
@@ -23,48 +20,28 @@
 public class CollectBackReferencesVisitor extends AbstractVisitor {
 
-    private final DataSet ds;
     private final boolean indirectRefs;
 
     private Collection<OsmPrimitive> data = new HashSet<OsmPrimitive>();
-    private Map<OsmPrimitive, Collection<OsmPrimitive>> lookupTable = new HashMap<OsmPrimitive, Collection<OsmPrimitive>>();
 
 
     /**
-     * Construct a back reference counter.
-     * has time complexity O(n) - so it is appropriate not to call it in cycle
-     * @param ds The dataset to operate on.
+     * @param ds This parameter is ignored
      */
     public CollectBackReferencesVisitor(DataSet ds) {
-       this(ds, true);
+        this(true);
     }
 
     /**
-     * Construct a back reference counter.
-     * has time complexity O(n) - so it is appropriate not to call it in cycle
-     * @param ds The dataset to operate on.
+     * @param ds This parameter is ignored
      * @param indirectRefs Make also indirect references?
      */
     public CollectBackReferencesVisitor(DataSet ds, boolean indirectRefs) {
-       this.ds = ds;
-       this.indirectRefs = indirectRefs;
-       if(ds != null)
-          makeLookupTable();
+        this.indirectRefs = indirectRefs;
     }
-    
-    private void makeLookupTable() {
-        for (Way w : ds.getWays()) {
-            for (Node n : w.getNodes()) {
-                if (!lookupTable.containsKey(n)) lookupTable.put(n, new HashSet<OsmPrimitive>());
-                lookupTable.get(n).add(w);
-            }
-        }
-        for (Relation r : ds.getRelations()) {
-            for (RelationMember m : r.getMembers()) {
-                OsmPrimitive o = m.getMember();
-                if (!lookupTable.containsKey(o)) lookupTable.put(o, new HashSet<OsmPrimitive>());
-                lookupTable.get(o).add(r);
-            }
-        }
+
+    public CollectBackReferencesVisitor(boolean indirectRefs) {
+        this.indirectRefs = indirectRefs;
     }
+
 
     /**
@@ -72,36 +49,37 @@
      */
     public Collection<OsmPrimitive> getData(){
-       return data;
+        return data;
     }
 
     /**
-     * Initialize data before associated visit calls 
+     * Initialize data before associated visit calls
      */
     public void initialize(){
-       data = new HashSet<OsmPrimitive>();
+        data = new HashSet<OsmPrimitive>();
     }
 
     public void visit(OsmPrimitive o) {
-       if(lookupTable.containsKey(o)){
-          Collection<OsmPrimitive> c = lookupTable.get(o);
-          Collection<OsmPrimitive> oldData = new HashSet<OsmPrimitive>(data);
-          data.addAll(c);
-          if(indirectRefs)
-             for(OsmPrimitive oo : c)
-                if(!oldData.contains(oo))
-                   visit(oo);
-       }
+        Collection<OsmPrimitive> c = o.getReferrers();
+        Collection<OsmPrimitive> oldData = new HashSet<OsmPrimitive>(data);
+        data.addAll(c);
+        if(indirectRefs) {
+            for(OsmPrimitive oo : c)
+                if(!oldData.contains(oo)) {
+                    visit(oo);
+                }
+        }
+
     }
-    
+
     public void visit(Node n) {
-       visit((OsmPrimitive)n);
+        visit((OsmPrimitive)n);
     }
 
     public void visit(Way w) {
-       visit((OsmPrimitive)w);
+        visit((OsmPrimitive)w);
     }
 
     public void visit(Relation r) {
-       visit((OsmPrimitive)r);
+        visit((OsmPrimitive)r);
     }
 }
