Index: resources/data/validator/geometry.mapcss
===================================================================
--- resources/data/validator/geometry.mapcss	(revision 17456)
+++ resources/data/validator/geometry.mapcss	(working copy)
@@ -200,6 +200,11 @@
   throwWarning: tr("Water area inside water area");
 }
 
+/* #20130 Building crossing landuse (spatial test) */
+area:closed:areaStyle[landuse=~ /^(commercial|farmyard|garages|industrial|retail|residential)$/] ⧉o area[building][building!~/no|entrance/] {
+  throwWarning: tr("Building partly outside of landuse area");
+}
+
 area:closed:areaStyle ⧉ area:closed:areaStyle {
   throwOther: tr("Overlapping Areas");
 }
Index: src/org/openstreetmap/josm/data/validation/tests/CrossingWays.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/tests/CrossingWays.java	(revision 17456)
+++ src/org/openstreetmap/josm/data/validation/tests/CrossingWays.java	(working copy)
@@ -56,7 +56,7 @@
      * Type of way. Entries have to be declared in alphabetical order, see sort below.
      */
     private enum WayType {
-        BARRIER, BUILDING, HIGHWAY, RAILWAY, RESIDENTIAL_AREA, WATERWAY, WAY;
+        BARRIER, BUILDING, HIGHWAY, RAILWAY, WATERWAY, WAY;
 
         static WayType of(Way w) {
             if (w.hasKey(CrossingWays.BARRIER))
@@ -67,8 +67,6 @@
                 return HIGHWAY;
             else if (isRailway(w))
                 return RAILWAY;
-            else if (isResidentialArea(w))
-                return RESIDENTIAL_AREA;
             else if (w.hasKey(CrossingWays.WATERWAY))
                 return WATERWAY;
             else
@@ -106,8 +104,7 @@
                     || isRailway(w)
                     || isCoastline(w)
                     || isBuilding(w)
-                    || w.hasKey(BARRIER)
-                    || isResidentialArea(w));
+                    || w.hasKey(BARRIER));
         }
 
         @Override
@@ -118,11 +115,6 @@
                 return true;
             if (isBuilding(w1) && isBuilding(w2))
                 return true; // handled by mapcss tests
-            if (((isResidentialArea(w1) || w1.hasKey(BARRIER, HIGHWAY, RAILWAY, WATERWAY) || isWaterArea(w1))
-                    && isResidentialArea(w2))
-                    || ((isResidentialArea(w2) || w2.hasKey(BARRIER, HIGHWAY, RAILWAY, WATERWAY) || isWaterArea(w2))
-                            && isResidentialArea(w1)))
-                return true;
             if (isWaterArea(w1) && isWaterArea(w2))
                 return true; // handled by mapcss tests
             if (w1.hasKey(RAILWAY) && w2.hasKey(RAILWAY) && w1.hasTag(RAILWAY, "yard") != w2.hasTag(RAILWAY, "yard")) {
@@ -174,8 +166,6 @@
                         return new MessageHelper(tr("Crossing building/highway"), 612);
                     case RAILWAY:
                         return new MessageHelper(tr("Crossing building/railway"), 613);
-                    case RESIDENTIAL_AREA:
-                        return new MessageHelper(tr("Crossing building/residential area"), 614);
                     case WATERWAY:
                         return new MessageHelper(tr("Crossing building/waterway"), 615);
                     case WAY:
@@ -200,8 +190,6 @@
                     default:
                         return new MessageHelper(tr("Crossing railway/way"), 631);
                     }
-                case RESIDENTIAL_AREA:
-                    return new MessageHelper(tr("Crossing residential area/way"), 641);
                 case WATERWAY:
                 default:
                     return new MessageHelper(tr("Crossing waterway/way"), 651);
Index: src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj	(revision 17456)
+++ src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj	(working copy)
@@ -217,6 +217,7 @@
 |   < SUPERSET_OR_EQUAL: "⊇" >
 |   < NOT_SUPERSET_OR_EQUAL: "⊉" >
 |   < CROSSING: "⧉" >
+|   < CROSSING_OUTSIDE: "⧉o" >
 |   < PERCENT: "%" >
 |   < COMMENT_START: "/*" > : COMMENT
 |   < UNEXPECTED_CHAR : ~[] > // avoid TokenMgrErrors because they are hard to recover from
@@ -633,6 +634,8 @@
                 <NOT_SUPERSET_OR_EQUAL> { type = Selector.ChildOrParentSelectorType.NOT_SUPERSET_OR_EQUAL; }
             |
                 <CROSSING> { type = Selector.ChildOrParentSelectorType.CROSSING; }
+            |
+                <CROSSING_OUTSIDE> { type = Selector.ChildOrParentSelectorType.CROSSING_OUTSIDE; }
             )
             w()
         |
Index: src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 17456)
+++ src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(working copy)
@@ -126,7 +126,7 @@
      * @see ChildOrParentSelector
      */
     enum ChildOrParentSelectorType {
-        CHILD, PARENT, SUBSET_OR_EQUAL, NOT_SUBSET_OR_EQUAL, SUPERSET_OR_EQUAL, NOT_SUPERSET_OR_EQUAL, CROSSING, SIBLING,
+        CHILD, PARENT, SUBSET_OR_EQUAL, NOT_SUBSET_OR_EQUAL, SUPERSET_OR_EQUAL, NOT_SUPERSET_OR_EQUAL, CROSSING, SIBLING, CROSSING_OUTSIDE,
     }
 
     /**
@@ -324,11 +324,13 @@
             private Area area;
             /** Will contain all way segments, grouped by cells */
             Map<Point2D, List<WaySegment>> cellSegments;
+            private final boolean markOutsideArea;
 
-            private CrossingFinder(Environment e) {
+            private CrossingFinder(Environment e, boolean markOutside) {
                 super(e);
                 CheckParameterUtil.ensureThat(isArea(e.osm), "Only areas are supported");
                 layer = OsmUtils.getLayer(e.osm);
+                this.markOutsideArea = markOutside;
             }
 
             private Area getAreaEastNorth(IPrimitive p, Environment e) {
@@ -393,15 +395,24 @@
                     Pair<PolygonIntersection, Area> is = Geometry.polygonIntersectionResult(
                             otherArea, area, Geometry.INTERSECTION_EPS_EAST_NORTH);
                     if (Geometry.PolygonIntersection.CROSSING == is.a) {
+                        final Area hiliteArea;
+                        if (markOutsideArea) {
+                            hiliteArea = new Area(area);
+                            hiliteArea.subtract(otherArea);
+                            if (hiliteArea.isEmpty()) {
+                                return; // can happen with multipolygon if only a node is shared
+                            }
+                        } else {
+                            hiliteArea = is.b;
+                        }
                         addToChildren(e, p);
                         // store intersection area to improve highlight and zoom to problem
                         if (e.intersections == null) {
                             e.intersections = new HashMap<>();
                         }
-                        e.intersections.put(p, is.b);
+                        e.intersections.put(p, hiliteArea);
                     }
                 }
-
             }
 
             private void useFindCrossings(IPrimitive p) {
@@ -545,10 +556,11 @@
                 visitBBox(e, insideOrEqualFinder);
                 return ChildOrParentSelectorType.SUPERSET_OR_EQUAL == type ? e.children != null : e.children == null;
 
-            } else if (ChildOrParentSelectorType.CROSSING == type) {
+            } else if (ChildOrParentSelectorType.CROSSING == type || ChildOrParentSelectorType.CROSSING_OUTSIDE == type) {
                 e.parent = e.osm;
                 if (e.osm.getDataSet() != null && isArea(e.osm)) {
-                    final CrossingFinder crossingFinder = new CrossingFinder(e);
+                    boolean markOutside = ChildOrParentSelectorType.CROSSING_OUTSIDE == type;
+                    final CrossingFinder crossingFinder = new CrossingFinder(e, markOutside);
                     visitBBox(e, crossingFinder);
                     return e.children != null;
                 }
Index: test/unit/org/openstreetmap/josm/data/validation/tests/CrossingWaysTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/data/validation/tests/CrossingWaysTest.java	(revision 17456)
+++ test/unit/org/openstreetmap/josm/data/validation/tests/CrossingWaysTest.java	(working copy)
@@ -133,7 +133,7 @@
         assertTrue(test.isPrimitiveUsable(newUsableWay("railway=rail")));
         assertTrue(test.isPrimitiveUsable(newUsableWay("natural=water")));
         assertTrue(test.isPrimitiveUsable(newUsableWay("building=yes")));
-        assertTrue(test.isPrimitiveUsable(newUsableWay("landuse=residential")));
+        assertFalse(test.isPrimitiveUsable(newUsableWay("landuse=residential")));
         // createMessage
         testMessage(601, test, "amenity=restaurant", "amenity=restaurant");
         testMessage(611, test, "building=yes", "amenity=restaurant");
@@ -140,7 +140,6 @@
         testMessage(611, test, "building=yes", "natural=water");
         testMessage(612, test, "building=yes", "highway=road");
         testMessage(613, test, "building=yes", "railway=rail");
-        testMessage(614, test, "building=yes", "landuse=residential");
         testMessage(615, test, "building=yes", "waterway=river");
         testMessage(620, test, "highway=road", "highway=road");
         testMessage(621, test, "highway=road", "amenity=restaurant");
@@ -151,7 +150,6 @@
         testMessage(631, test, "railway=rail", "amenity=restaurant");
         testMessage(631, test, "railway=rail", "natural=water");
         testMessage(632, test, "railway=rail", "waterway=river");
-        testMessage(641, test, "landuse=residential", "amenity=restaurant");
         testMessage(650, test, "waterway=river", "waterway=river");
         testMessage(651, test, "waterway=river", "amenity=restaurant");
         testMessage(603, test, "barrier=hedge", "barrier=yes");
@@ -161,9 +159,6 @@
         testMessage(664, test, "barrier=hedge", "waterway=river");
         testMessage(665, test, "barrier=hedge", "natural=water");
 
-        testIgnore(true, test, "landuse=residential", "natural=water");
-        testIgnore(false, test, "landuse=residential", "building=yes");
-
         assertFalse(test.isPrimitiveUsable(newUsableWay("amenity=restaurant")));
         assertFalse(test.isPrimitiveUsable(TestUtils.newWay("barrier=yes"))); // Unusable (0 node)
         assertTrue(test.isPrimitiveUsable(newUsableWay("barrier=yes"))); // Usable (2 nodes)
