Index: resources/data/validator/geometry.mapcss
===================================================================
--- resources/data/validator/geometry.mapcss	(revision 18958)
+++ resources/data/validator/geometry.mapcss	(working copy)
@@ -224,6 +224,11 @@
   throwWarning: tr("Water area inside water area");
 }
 
+/* #20130 Building crossing landuse (spatial test) */
+area[building][building!~/no|entrance/] ⧉o area:closed:areaStyle[landuse=~ /^(commercial|farmyard|garages|industrial|retail|residential)$/][landuse] {
+  throwWarning: tr("Crossing building/{0} area", "{3.tag}");
+}
+
 area:completely_downloaded:closed:areaStyle ⧉ area:completely_downloaded: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 18958)
+++ src/org/openstreetmap/josm/data/validation/tests/CrossingWays.java	(working copy)
@@ -57,7 +57,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))
@@ -68,8 +68,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
@@ -107,8 +105,7 @@
                     || isRailway(w)
                     || isCoastline(w)
                     || isBuilding(w)
-                    || w.hasKey(BARRIER)
-                    || isResidentialArea(w));
+                    || w.hasKey(BARRIER));
         }
 
         @Override
@@ -119,11 +116,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")
@@ -175,8 +167,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:
@@ -201,8 +191,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 18958)
+++ src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj	(working copy)
@@ -218,6 +218,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
@@ -634,6 +635,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 18958)
+++ src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(working copy)
@@ -124,7 +124,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,
     }
 
     /**
@@ -333,11 +333,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) {
@@ -404,15 +406,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(otherArea);
+                            hiliteArea.subtract(area);
+                            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) {
@@ -556,10 +567,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 18958)
+++ test/unit/org/openstreetmap/josm/data/validation/tests/CrossingWaysTest.java	(working copy)
@@ -125,7 +125,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");
@@ -132,7 +132,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");
@@ -143,7 +142,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");
@@ -153,9 +151,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)
