Index: src/org/openstreetmap/josm/data/validation/tests/UnconnectedWays.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/tests/UnconnectedWays.java	(revision 15336)
+++ src/org/openstreetmap/josm/data/validation/tests/UnconnectedWays.java	(working copy)
@@ -33,6 +33,7 @@
 import org.openstreetmap.josm.data.validation.TestError;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.tools.Geometry;
 
 /**
  * Checks if a way has an endpoint very near to another way.
@@ -49,6 +50,15 @@
 
     protected abstract boolean isCandidate(OsmPrimitive p);
 
+    /**
+     * Check if unconnected end node should be ignored.
+     * @param n the node
+     * @return true if node should be ignored
+     */
+    protected boolean ignoreUnconnectedEndNode(Node n) {
+        return false;
+    }
+
     @Override
     public boolean isPrimitiveUsable(OsmPrimitive p) {
         return super.isPrimitiveUsable(p) && ((partialSelection && p instanceof Node) || isCandidate(p));
@@ -71,6 +81,15 @@
         protected boolean isCandidate(OsmPrimitive p) {
             return p.hasKey(HIGHWAY);
         }
+
+        @Override
+        protected boolean ignoreUnconnectedEndNode(Node n) {
+            return n.hasTag(HIGHWAY, "turning_circle", "bus_stop")
+                    || n.hasTag("amenity", "parking_entrance")
+                    || n.isKeyTrue("noexit")
+                    || n.hasKey("entrance", "barrier")
+                    || n.getParentWays().stream().anyMatch(Test::isBuilding);
+        }
     }
 
     /**
@@ -87,8 +106,13 @@
 
         @Override
         protected boolean isCandidate(OsmPrimitive p) {
-            return p.hasKey(RAILWAY) && !p.hasTag(RAILWAY, "abandoned");
+            return p.hasTagDifferent(RAILWAY, "abandoned");
         }
+
+        @Override
+        protected boolean ignoreUnconnectedEndNode(Node n) {
+            return n.hasTag(RAILWAY, "buffer_stop");
+        }
     }
 
     /**
@@ -123,7 +147,7 @@
 
         @Override
         protected boolean isCandidate(OsmPrimitive p) {
-            return p.hasKey("natural", "landuse") && !p.hasTag("natural", "tree_row", "cliff");
+            return p.hasKey("landuse") || p.hasTagDifferent("natural", "tree_row", "cliff");
         }
     }
 
@@ -199,6 +223,22 @@
         dsArea = ds == null ? null : ds.getDataSourceArea();
     }
 
+    private boolean isMuchNearerToBuilding(Node node, double distToHighway) {
+        double fudge = 0.33 * distToHighway * (360.0d / (Ellipsoid.WGS84.a * 2 * Math.PI));
+        double x = node.getCoor().lon();
+        double y = node.getCoor().lat();
+        LatLon topLeft = new LatLon(y+fudge, x-fudge);
+        LatLon botRight = new LatLon(y-fudge, x+fudge);
+        BBox bbox = new BBox(topLeft, botRight);
+        for (Node n : ds.searchNodes(bbox)) {
+            if (isBuilding(n) && node.getCoor().greatCircleDistance(n.getCoor()) < distToHighway) return true;
+        }
+        for (Way w : ds.searchWays(bbox)) {
+            if (isBuilding(w) && Geometry.getDistanceWayNode(w, node) < distToHighway) return true;
+        }
+        return false;
+    }
+
     protected Map<Node, MyWaySegment> getWayEndNodesNearOtherHighway() {
         Map<Node, MyWaySegment> map = new HashMap<>();
         for (MyWaySegment s : waySegments) {
@@ -207,15 +247,12 @@
                 return map;
             }
             for (Node en : s.nearbyNodes(mindist)) {
-                if (en.hasTag(HIGHWAY, "turning_circle", "bus_stop")
-                        || en.hasTag("amenity", "parking_entrance")
-                        || en.hasTag(RAILWAY, "buffer_stop")
-                        || en.isKeyTrue("noexit")
-                        || en.hasKey("entrance", "barrier")) {
-                    continue;
-                }
                 // to handle intersections of 't' shapes and similar
-                if (!en.isConnectedTo(s.w.getNodes(), 3 /* hops */, null)) {
+                if (!en.isConnectedTo(s.w.getNodes(), 1 /* hops */, null)) {
+                    if (isHighwayTest && s.w.hasTag(HIGHWAY, "service", "footway", "steps", "path")
+                            && isMuchNearerToBuilding(en, s.getDist(en))) {
+                        continue;
+                    }
                     addIfNewOrCloser(map, en, s);
                 }
             }
@@ -232,7 +269,7 @@
             }
             if (!s.concernsArea) {
                 for (Node en : s.nearbyNodes(mindist)) {
-                    if (!en.isConnectedTo(s.w.getNodes(), 3 /* hops */, null)) {
+                    if (!en.isConnectedTo(s.w.getNodes(), 1 /* hops */, null)) {
                         addIfNewOrCloser(map, en, s);
                     }
                 }
@@ -249,7 +286,7 @@
                 return map;
             }
             for (Node en : s.nearbyNodes(minmiddledist)) {
-                if (!en.isConnectedTo(s.w.getNodes(), 3 /* hops */, null)) {
+                if (!en.isConnectedTo(s.w.getNodes(), 1 /* hops */, null)) {
                     addIfNewOrCloser(map, en, s);
                 }
             }
@@ -291,7 +328,7 @@
 
         for (Way w : ds.getWays()) {
             if (w.isUsable() && isCandidate(w) && w.getRealNodesCount() > 1
-                    // don't complain about highways ending near platforms
+                    // don't complain about highways or railways ending near platforms
                     && !w.hasTag(HIGHWAY, "platform") && !w.hasTag(RAILWAY, "platform", "platform_edge")
                     ) {
                 waySegments.addAll(getWaySegments(w));
@@ -299,12 +336,15 @@
                 addNode(w.lastNode(), endnodes);
             }
         }
-        searchNodes = new QuadBuckets<>();
-        searchNodes.addAll(endnodes);
-        if (isHighwayTest) {
-            addErrors(Severity.WARNING, getWayEndNodesNearOtherHighway(), tr("Way end node near other highway"));
-        } else {
-            addErrors(Severity.WARNING, getWayEndNodesNearOtherWay(), tr("Way end node near other way"));
+        endnodes.removeIf(this::ignoreUnconnectedEndNode);
+        if (!endnodes.isEmpty()) {
+            searchNodes = new QuadBuckets<>();
+            searchNodes.addAll(endnodes);
+            if (isHighwayTest) {
+                addErrors(Severity.WARNING, getWayEndNodesNearOtherHighway(), tr("Way end node near other highway"));
+            } else {
+                addErrors(Severity.WARNING, getWayEndNodesNearOtherWay(), tr("Way end node near other way"));
+            }
         }
 
         /* the following two use a shorter distance */
