Index: src/org/openstreetmap/josm/data/validation/tests/Highways.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/tests/Highways.java	(revision 18079)
+++ src/org/openstreetmap/josm/data/validation/tests/Highways.java	(working copy)
@@ -15,6 +15,8 @@
 import java.util.stream.Collectors;
 
 import org.openstreetmap.josm.command.ChangePropertyCommand;
+import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmUtils;
@@ -38,8 +40,11 @@
     protected static final int SOURCE_MAXSPEED_CONTEXT_MISMATCH_VS_MAXSPEED = 2705;
     protected static final int SOURCE_MAXSPEED_CONTEXT_MISMATCH_VS_HIGHWAY = 2706;
     protected static final int SOURCE_WRONG_LINK = 2707;
+    protected static final int SOURCE_BUS_STOP_NEEDED = 2708;
 
     protected static final String SOURCE_MAXSPEED = "source:maxspeed";
+    protected static final String BUS = "bus";
+    protected static final String PUBLIC_TRANSPORT = "public_transport";
 
     /**
      * Classified highways in order of importance
@@ -90,6 +95,9 @@
                 // as maxspeed is not set on highways here but on signs, speed cameras, etc.
                 testSourceMaxspeed(n, false);
             }
+
+            // Test for 17188: complain about bus stop position without nearby highway=bus_stop
+            testMissingBusStopNode(n);
         }
     }
 
@@ -243,6 +251,46 @@
         }
     }
 
+    /**
+     * Tests for bus stop ("public_transport"="stop_position"/"bus"="yes") Nodes a long a way that are missing a related nearby Node with "highway=bus_stop"
+     * @param n Node being visited
+     */
+    public void testMissingBusStopNode(Node n) {
+        if (n.hasTag(BUS, "yes") && n.hasTag(PUBLIC_TRANSPORT, "stop_position")) {
+            int countOfNodesWithProperTags = 0;
+            List<Node> nearbyNodesWithinTwentyFiveMeters = getNearbyNodesWithinShortDistance(n, 0.0002);
+            for (Node nearbyNodeWithinTwentyFiveMeters : nearbyNodesWithinTwentyFiveMeters) {
+                if (nearbyNodeWithinTwentyFiveMeters.hasTag(HIGHWAY, "bus_stop") && nearbyNodeWithinTwentyFiveMeters.hasTag(BUS, "yes")) {
+                    countOfNodesWithProperTags += 1;
+                }
+            }
+            if (countOfNodesWithProperTags == 0) {
+                errors.add(TestError.builder(this, Severity.WARNING, SOURCE_BUS_STOP_NEEDED)
+                        .message(tr("Node {2} needs a nearby related node with tags: {0} and {1}.",
+                                "highway=bus_stop", "bus=yes", n.getOsmId()))
+                        .primitives(n)
+                        .build());
+            }
+        }
+        return;
+    }
+
+    /**
+     * Gathers list of Nodes within specified approximate distance (takes double but unit is LatLon degrees) of Node n.
+     * @param n Node being visited
+     * @param expanseDistance Distance to expand Node bounds. Units are in LatLon degrees.
+     * @return List of Nodes
+     */
+    public List<Node> getNearbyNodesWithinShortDistance(Node n, double expanseDistance) {
+
+        DataSet nodeDataSet = n.getDataSet();
+
+        BBox nodeBBox= n.getBBox();
+        nodeBBox.addLatLon(nodeBBox.getCenter(), expanseDistance);
+
+        return nodeDataSet.searchNodes(nodeBBox);
+    }
+
     private void handleCarWay(Node n, Way w) {
         carsWays++;
         if (!w.isFirstLastNode(n) || carsWays > 1) {
