Index: /applications/editors/josm/plugins/buildings_tools/build.xml
===================================================================
--- /applications/editors/josm/plugins/buildings_tools/build.xml	(revision 31090)
+++ /applications/editors/josm/plugins/buildings_tools/build.xml	(revision 31091)
@@ -2,5 +2,5 @@
 <project name="buildings_tools" default="dist" basedir=".">
     <!-- enter the SVN commit message -->
-    <property name="commit.message" value="BuildingTools: update to current JOSM"/>
+    <property name="commit.message" value="BuildingTools: Add merge address points function"/>
     <!-- enter the *lowest* JOSM version this plugin is currently compatible with -->
     <property name="plugin.main.version" value="7128"/>
Index: /applications/editors/josm/plugins/buildings_tools/src/buildings_tools/BuildingsToolsPlugin.java
===================================================================
--- /applications/editors/josm/plugins/buildings_tools/src/buildings_tools/BuildingsToolsPlugin.java	(revision 31090)
+++ /applications/editors/josm/plugins/buildings_tools/src/buildings_tools/BuildingsToolsPlugin.java	(revision 31091)
@@ -28,4 +28,5 @@
         Main.main.menu.editMenu.addSeparator();
         MainMenu.add(Main.main.menu.dataMenu, new BuildingSizeAction());
+        MainMenu.add(Main.main.menu.dataMenu, new MergeAddrPointsAction());
     }
 
Index: /applications/editors/josm/plugins/buildings_tools/src/buildings_tools/DrawBuildingAction.java
===================================================================
--- /applications/editors/josm/plugins/buildings_tools/src/buildings_tools/DrawBuildingAction.java	(revision 31090)
+++ /applications/editors/josm/plugins/buildings_tools/src/buildings_tools/DrawBuildingAction.java	(revision 31091)
@@ -419,4 +419,6 @@
                     ways.add((Way) p);
                     break;
+                default:
+                    break;
                 }
             }
Index: /applications/editors/josm/plugins/buildings_tools/src/buildings_tools/MergeAddrPointsAction.java
===================================================================
--- /applications/editors/josm/plugins/buildings_tools/src/buildings_tools/MergeAddrPointsAction.java	(revision 31091)
+++ /applications/editors/josm/plugins/buildings_tools/src/buildings_tools/MergeAddrPointsAction.java	(revision 31091)
@@ -0,0 +1,149 @@
+// License: GPL. For details, see LICENSE file.
+package buildings_tools;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map.Entry;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.command.ChangeCommand;
+import org.openstreetmap.josm.command.ChangePropertyCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.DeleteCommand;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+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.Notification;
+import org.openstreetmap.josm.tools.Geometry;
+import org.openstreetmap.josm.tools.Shortcut;
+
+@SuppressWarnings("serial")
+public class MergeAddrPointsAction extends JosmAction {
+
+    public MergeAddrPointsAction() {
+        super(tr("Merge address points"), null,
+                tr("Move tags from address nodes inside buildings to building ways"),
+                Shortcut.registerShortcut("edit:mergeaddrpoints", tr("Edit: {0}", tr("Merge address points")),
+                        KeyEvent.CHAR_UNDEFINED, Shortcut.NONE),
+                true);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent arg0) {
+        if (!isEnabled())
+            return;
+        Collection<OsmPrimitive> selection = getCurrentDataSet().getSelected();
+        if (selection.isEmpty()) {
+            new Notification(tr("Select both address nodes and building ways to merge"))
+                    .setIcon(JOptionPane.INFORMATION_MESSAGE).show();
+            return;
+        }
+        List<Node> addrNodes = new LinkedList<>();
+        List<Way> buildings = new LinkedList<>();
+        scanSelection:
+        for (OsmPrimitive p : selection) {
+            if (p.getType() == OsmPrimitiveType.NODE) {
+                for (OsmPrimitive r : p.getReferrers())
+                    if (r.getType() == OsmPrimitiveType.WAY)
+                       continue scanSelection; // Don't use nodes if they're referenced by ways
+                for (String key : p.getKeys().keySet())
+                    if (key.startsWith("addr:")) {
+                        addrNodes.add((Node)p); // Found address node
+                        break;
+                    }
+            } else if (p.getType() == OsmPrimitiveType.WAY && p.getKeys().containsKey("building"))
+                buildings.add((Way)p);
+        }
+        if (addrNodes.isEmpty()) {
+            new Notification(tr("No address nodes found in the selection"))
+                    .setIcon(JOptionPane.ERROR_MESSAGE).show();
+            return;
+        }
+        if (buildings.isEmpty()) {
+            new Notification(tr("No building ways found in the selection"))
+                    .setIcon(JOptionPane.ERROR_MESSAGE).show();
+            return;
+        }
+        List<Command> cmds = new LinkedList<>();
+        int multi = 0;
+        int conflicts = 0;
+        buildingsLoop: for (Way w : buildings) {
+            Node mergeNode = null;
+            for (Node n : addrNodes) {
+                if (Geometry.nodeInsidePolygon(n, w.getNodes()))
+                    if (mergeNode != null) {
+                        multi++;
+                        continue buildingsLoop; // Multiple address nodes inside
+                                                // one building -- skipping
+                    } else
+                        mergeNode = n;
+            }
+            if (mergeNode != null) {
+                boolean hasConflicts = false;
+                AbstractMap<String, String> tags = new HashMap<>();
+                for (Entry<String, String> entry : mergeNode.getKeys().entrySet()) {
+                    String newValue = entry.getValue();
+                    if (newValue == null)
+                        continue;
+                    String oldValue = w.getKeys().get(entry.getKey());
+                    if (!newValue.equals(oldValue)) {
+                        if (oldValue == null) {
+                            tags.put(entry.getKey(), newValue);
+                        } else
+                            hasConflicts = true;
+                    }
+                }
+                if (hasConflicts)
+                    conflicts++;
+                if (!tags.isEmpty())
+                    cmds.add(new ChangePropertyCommand(Collections.singleton(w), tags));
+                if (!hasConflicts) {
+                    for (OsmPrimitive p : mergeNode.getReferrers()) {
+                        Relation r = (Relation) p;
+                        Relation rnew = new Relation(r);
+                        for (int i = 0; i < r.getMembersCount(); i++) {
+                            RelationMember member = r.getMember(i);
+                            if (member.getMember() == mergeNode) {
+                                rnew.removeMember(i);
+                                rnew.addMember(i, new RelationMember(member.getRole(), w));
+                            }
+                        }
+                        cmds.add(new ChangeCommand(r, rnew));
+                    }
+                    cmds.add(new DeleteCommand(mergeNode));
+                }
+            }
+        }
+        if (multi != 0)
+            new Notification(tr("There are {0} buildings with multiple address nodes inside", multi))
+                    .setIcon(JOptionPane.WARNING_MESSAGE).show();
+        if (conflicts != 0)
+            new Notification(tr("There are {0} buildings with address conflicts", conflicts))
+                    .setIcon(JOptionPane.WARNING_MESSAGE).show();
+        if (cmds.isEmpty() && multi == 0 && conflicts == 0)
+            new Notification(tr("No address nodes inside buildings found"))
+                    .setIcon(JOptionPane.INFORMATION_MESSAGE).show();
+        if (!cmds.isEmpty())
+            Main.main.undoRedo.add(new SequenceCommand("Merge addresses", cmds));
+    }
+
+    @Override
+    protected void updateEnabledState() {
+        setEnabled(getCurrentDataSet() != null);
+    }
+}
