I'm not sure you can get around adding invisible nodes, but here is a solution that doesn't require manually specifying any coordinates.
The function edgeToMidpoint
takes as arguments a graph, a source vertex, which may or may not be an existing vertex in the graph, and a target edge.
edgeToMidpoint[graph_, sourcevert_, targetedge_] :=
Module[{g = graph, coords, coord1, coord2, midpoint, mid,
newc, newcoords, vertshape, m, x, b, y},
coords = AbsoluteOptions[g, VertexCoordinates][[1, 2]];
coord1 = coords[[Position[VertexList[g], targetedge[[1]]][[1, 1]]]];
coord2 = coords[[Position[VertexList[g], targetedge[[2]]][[1, 1]]]];
midpoint = {Mean[{coord1[[1]], coord2[[1]]}],
Mean[{coord1[[2]], coord2[[2]]}]};
If[FreeQ[VertexList[graph], sourcevert],
{
slope = -1/FindFit[{coord1, coord2}, m x + b, {m, b}, x][[1, 2]];
int = midpoint[[2]] - slope midpoint[[1]];
newc = Nearest[
{x, y} /. Reverse[Solve[{EuclideanDistance[{x, y}, midpoint] == 0.5, y == slope x + int}, {x, y}]],
Mean[coords],
DistanceFunction -> (-Norm[#1 - #2] &)][[1]];
newcoords = {newc, midpoint}
},
newcoords = {midpoint}];
vertshape =
If[Length[AbsoluteOptions[graph, VertexShapeFunction][[1, 2]]] == 0,
{_ -> Automatic, mid -> None},
Append[AbsoluteOptions[graph, VertexShapeFunction][[1, 2]], mid -> None]];
Graph[
Join[EdgeList[graph], {sourcevert \[DirectedEdge] mid}],
VertexCoordinates -> Join[coords, newcoords],
VertexLabels ->
Append[AbsoluteOptions[graph, VertexLabels][[1, 2]], mid -> None],
VertexShapeFunction -> vertshape,
ImagePadding -> 10]
];
The example from the OP:
g = Graph[{a \[DirectedEdge] b}, VertexLabels -> "Name"];
edgeToMidpoint[g, c, a \[DirectedEdge] b]

With a slightly more complicated example:
g = Graph[{a -> b, d -> b, b -> c, c -> d}, VertexLabels -> "Name",
VertexShapeFunction -> Automatic, ImagePadding -> 10]

Calling edgeToMidpoint
iteratively to add multiple new vertices-to-edges:
modlist = {{w, d \[DirectedEdge] b}, {x, c \[DirectedEdge] d}, {z, a \[DirectedEdge] b}, {c, d \[DirectedEdge] b}};
h = g;
Do[h = edgeToMidpoint[h, mod[[1]], mod[[2]]], {mod, modlist}]
h

The placement of new vertices is probably not super robust, but it works for these simple examples.
c -> d
if you do not included
in the vertex list? $\endgroup$