Index: src/org/openstreetmap/josm/actions/CombineWayAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/CombineWayAction.java	(revision 15562)
+++ src/org/openstreetmap/josm/actions/CombineWayAction.java	(working copy)
@@ -31,7 +31,12 @@
 import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.data.osm.TagCollection;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
+import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.JoinedWay;
 import org.openstreetmap.josm.data.preferences.BooleanProperty;
+import org.openstreetmap.josm.data.validation.Test;
+import org.openstreetmap.josm.data.validation.tests.OverlappingWays;
+import org.openstreetmap.josm.data.validation.tests.SelfIntersectingWay;
 import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.Notification;
@@ -122,8 +127,7 @@
         }
 
         // try to build a new way which includes all the combined ways
-        NodeGraph graph = NodeGraph.createNearlyUndirectedGraphFromNodeWays(ways);
-        List<Node> path = graph.buildSpanningPathNoRemove();
+        List<Node> path = tryJoin(ways);
         if (path == null) {
             warnCombiningImpossible();
             return null;
@@ -138,10 +142,23 @@
         List<Way> unreversedWays = new LinkedList<>();
         for (Way w: ways) {
             // Treat zero or one-node ways as unreversed as Combine action action is a good way to fix them (see #8971)
-            if (w.getNodesCount() < 2 || (path.indexOf(w.getNode(0)) + 1) == path.lastIndexOf(w.getNode(1))) {
+            if (w.getNodesCount() < 2) {
                 unreversedWays.add(w);
             } else {
-                reversedWays.add(w);
+                boolean foundStartSegment = false;
+                int last = path.lastIndexOf(w.getNode(0));
+
+                for (int i = path.indexOf(w.getNode(0)); i <= last; i++) {
+                    if (path.get(i) == w.getNode(0) && i + 1 < path.size() && w.getNode(1) == path.get(i + 1)) {
+                        foundStartSegment = true;
+                        break;
+                    }
+                }
+                if (foundStartSegment) {
+                    unreversedWays.add(w);
+                } else {
+                    reversedWays.add(w);
+                }
             }
         }
         // reverse path if all ways have been reversed
@@ -212,6 +229,38 @@
         return new Pair<>(targetWay, sequenceCommand);
     }
 
+    static List<Node> tryJoin(Collection<Way> ways) {
+        List<Node> path = joinWithMultipolygonCode(ways);
+        if (path == null) {
+            NodeGraph graph = NodeGraph.createNearlyUndirectedGraphFromNodeWays(ways);
+            path = graph.buildSpanningPathNoRemove();
+        }
+        return path;
+    }
+
+    /**
+     * Use {@link Multipolygon#joinWays(Collection)} to join ways.
+     * @param ways the ways
+     * @return List of nodes of the combined ways or null if ways could not be combined to a single way.
+     * Result may contain overlapping segments.
+     */
+    private static List<Node> joinWithMultipolygonCode(Collection<Way> ways) {
+        // sort so that old unclosed ways appear first
+        LinkedList<Way> toJoin = new LinkedList<>(ways);
+        toJoin.sort((o1, o2) -> {
+            int d = Boolean.compare(o1.isNew(), o2.isNew());
+            if (d == 0)
+                d = Boolean.compare(o1.isClosed(), o2.isClosed());
+            return d;
+        });
+        Collection<JoinedWay> list = Multipolygon.joinWays(toJoin);
+        if (list.size() == 1) {
+            // ways form a single line string
+            return new ArrayList<>(list.iterator().next().getNodes());
+        }
+        return null;
+    }
+
     @Override
     public void actionPerformed(ActionEvent event) {
         final DataSet ds = getLayerManager().getEditDataSet();
@@ -237,8 +286,24 @@
 
         if (combineResult == null)
             return;
+
         final Way selectedWay = combineResult.a;
         UndoRedoHandler.getInstance().add(combineResult.b);
+        Test test = new OverlappingWays();
+        test.startTest(null);
+        test.visit(combineResult.a);
+        test.endTest();
+        if (test.getErrors().isEmpty()) {
+            test = new SelfIntersectingWay();
+            test.startTest(null);
+            test.visit(combineResult.a);
+            test.endTest();
+        }
+        if (!test.getErrors().isEmpty()) {
+            new Notification(test.getErrors().get(0).getMessage())
+            .setIcon(JOptionPane.WARNING_MESSAGE)
+            .show();
+        }
         if (selectedWay != null) {
             GuiHelper.runInEDT(() -> ds.setSelected(selectedWay));
         }
@@ -261,4 +326,5 @@
         }
         setEnabled(numWays >= 2);
     }
+
 }
Index: test/data/regress/18367/nocombine.osm
===================================================================
--- test/data/regress/18367/nocombine.osm	(nonexistent)
+++ test/data/regress/18367/nocombine.osm	(working copy)
@@ -0,0 +1,22 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' generator='JOSM' upload='false'>
+  <node id='-143178' action='modify' visible='true' lat='0.02196380816' lon='-0.02295195551' />
+  <node id='-143179' action='modify' visible='true' lat='0.02142481903' lon='0.00624329122' />
+  <node id='-143181' action='modify' visible='true' lat='0.02708420481' lon='0.01828071603' />
+  <node id='-143183' action='modify' visible='true' lat='0.03597752476' lon='0.01908919979' />
+  <node id='-143185' action='modify' visible='true' lat='0.03139611761' lon='0.0279825211' />
+  <node id='-143187' action='modify' visible='true' lat='-0.00696194343' lon='-0.00112289411' />
+  <way id='-143180' action='modify' visible='true'>
+    <nd ref='-143178' />
+    <nd ref='-143179' />
+    <nd ref='-143181' />
+    <nd ref='-143183' />
+    <nd ref='-143185' />
+  </way>
+  <way id='-143188' action='modify' visible='true'>
+    <nd ref='-143187' />
+    <nd ref='-143179' />
+    <nd ref='-143181' />
+    <nd ref='-143185' />
+  </way>
+</osm>
Index: test/unit/org/openstreetmap/josm/actions/CombineWayActionTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/actions/CombineWayActionTest.java	(revision 15562)
+++ test/unit/org/openstreetmap/josm/actions/CombineWayActionTest.java	(working copy)
@@ -2,12 +2,12 @@
 package org.openstreetmap.josm.actions;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -71,9 +71,8 @@
     public void testTicket18385() throws IOException, IllegalDataException {
         try (InputStream is = TestUtils.getRegressionDataStream(18385, "data.osm")) {
             DataSet ds = OsmReader.parseDataSet(is, null);
-            NodeGraph graph = NodeGraph.createNearlyUndirectedGraphFromNodeWays(ds.getWays());
-            List<Node> path = graph.buildSpanningPathNoRemove();
-            assertNull(path);
+            List<Node> path = CombineWayAction.tryJoin(ds.getWays());
+            assertTrue(path != null);
         }
     }
 
@@ -90,13 +89,36 @@
             assertEquals(2, selection.size());
             if (!selection.get(0).isNew())
                 Collections.reverse(selection);
-            NodeGraph graph = NodeGraph.createNearlyUndirectedGraphFromNodeWays(selection);
-            List<Node> path = graph.buildSpanningPathNoRemove();
+            double expectedLen = getOriginalLength(selection);
+            List<Node> path = CombineWayAction.tryJoin(selection);
             assertTrue(path != null);
+            Way combined = new Way(0);
+            combined.setNodes(path);
+            assertEquals(expectedLen, combined.getLength(), 0.01);
         }
     }
 
     /**
+     * Non-regression test for bug #18367 (Lines cannot be combined when they share an overlapping segment)
+     * @throws IOException if any I/O error occurs
+     * @throws IllegalDataException if OSM parsing fails
+     */
+    @Test
+    public void testTicket18367() throws IOException, IllegalDataException {
+        try (InputStream is = TestUtils.getRegressionDataStream(18367, "nocombine.osm")) {
+            DataSet ds = OsmReader.parseDataSet(is, null);
+            ArrayList<Way> selection = new ArrayList<>(ds.getWays());
+            assertEquals(2, selection.size());
+            double expectedLen = getOriginalLength(selection);
+            List<Node> path = CombineWayAction.tryJoin(selection);
+            assertTrue(path != null);
+            Way combined = new Way(0);
+            combined.setNodes(path);
+            assertEquals(expectedLen, combined.getLength(), 1e-7);
+        }
+    }
+
+    /**
      * Unit test of methods {@link NodePair#equals} and {@link NodePair#hashCode}.
      */
     @Test
@@ -106,4 +128,13 @@
             .withPrefabValues(Node.class, new Node(1), new Node(2))
             .verify();
     }
+
+    private static double getOriginalLength(Collection<Way> ways) {
+        double len = 0;
+        for (Way w : ways) {
+            len += w.getLength();
+        }
+        return len;
+    }
+
 }
