Index: src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 15102)
+++ src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(working copy)
@@ -69,8 +69,6 @@
 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource.MapCSSRuleIndex;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.AbstractSelector;
-import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector;
-import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelectorType;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.GeneralSelector;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.OptimizedGeneralSelector;
 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser;
@@ -99,6 +97,7 @@
  */
 public class MapCSSTagChecker extends Test.TagTest {
     IndexData indexData;
+    final Set<OsmPrimitive> tested = new HashSet<>();
 
     /**
      * Helper class to store indexes of rules.
@@ -864,27 +863,6 @@
         while (candidates.hasNext()) {
             MapCSSRule r = candidates.next();
             env.clearSelectorMatchingInformation();
-            if (partialSelection && r.selector instanceof Selector.ChildOrParentSelector) {
-                ChildOrParentSelector sel = (Selector.ChildOrParentSelector) r.selector;
-                boolean needEnclosing = sel.type == ChildOrParentSelectorType.SUBSET_OR_EQUAL
-                        || sel.type == ChildOrParentSelectorType.NOT_SUBSET_OR_EQUAL;
-                if (needEnclosing && p.getDataSet() != null) {
-                    List<OsmPrimitive> toCheck = new ArrayList<>();
-                    toCheck.addAll(p.getDataSet().searchWays(p.getBBox()));
-                    toCheck.addAll(p.getDataSet().searchRelations(p.getBBox()));
-                    toCheck.removeIf(OsmPrimitive::isSelected);
-                    if (!toCheck.isEmpty()) {
-                        Set<Set<TagCheck>> checksCol = Collections.singleton(Collections.singleton(indexData.getCheck(r)));
-                        for (OsmPrimitive p2 : toCheck) {
-                            for (TestError e : getErrorsForPrimitive(p2, includeOtherSeverity, checksCol)) {
-                                if (e.getPrimitives().contains(p)) {
-                                    addIfNotSimilar(e, res);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
             if (r.selector.matches(env)) { // as side effect env.parent will be set (if s is a child selector)
                 TagCheck check = indexData.getCheck(r);
                 if (check != null) {
@@ -963,6 +941,9 @@
         for (TestError e : getErrorsForPrimitive(p, ValidatorPrefHelper.PREF_OTHER.get())) {
             addIfNotSimilar(e, errors);
         }
+        if (partialSelection && p.isTagged()) {
+            tested.add(p);
+        }
     }
 
     /**
@@ -1145,19 +1126,50 @@
     }
 
     @Override
-    public void startTest(ProgressMonitor progressMonitor) {
+    public synchronized void startTest(ProgressMonitor progressMonitor) {
         super.startTest(progressMonitor);
         super.setShowElements(true);
         if (indexData == null) {
-            indexData = new IndexData(checks, ValidatorPrefHelper.PREF_OTHER.get());
+            indexData = new IndexData(checks, includeOtherSeverityChecks());
         }
+        tested.clear();
     }
 
     @Override
-    public void endTest() {
+    public synchronized void endTest() {
+        if (partialSelection && !tested.isEmpty()) {
+            // see ticket 14287
+            // execute tests for objects which might contain previously tested elements
+            Set<OsmPrimitive> surrounding = new HashSet<>();
+            for (OsmPrimitive p : tested) {
+                if (p.getDataSet() != null) {
+                    surrounding.addAll(p.getDataSet().searchWays(p.getBBox()));
+                    surrounding.addAll(p.getDataSet().searchRelations(p.getBBox()));
+                }
+            }
+
+            final boolean includeOtherSeverity = includeOtherSeverityChecks();
+            for (OsmPrimitive p : surrounding) {
+                if (tested.contains(p) )
+                    continue;
+                if (p.isMultipolygon()) {
+                    long dd = 4;
+                }
+                Collection<TestError> additionalErrors = getErrorsForPrimitive(p, includeOtherSeverity);
+                for (TestError e : additionalErrors) {
+                    if (e.getPrimitives().stream().anyMatch(tested::contains))
+                        addIfNotSimilar(e, errors);
+                }
+            }
+            tested.clear();
+        }
         super.endTest();
         // no need to keep the index, it is quickly build and doubles the memory needs
         indexData = null;
     }
 
+    private boolean includeOtherSeverityChecks() {
+        return isBeforeUpload ? ValidatorPrefHelper.PREF_OTHER_UPLOAD.get() : ValidatorPrefHelper.PREF_OTHER.get();
+    }
+
 }
