We have to use Is there a GraphicsPrimitiveQ (or a complete list of Heads of graphics primitives)?
primitivesQ = MatchQ[#,
Alternatives @@ {Point, PointBox, Line, LineBox, Arrow, ArrowBox, Rectangle, RectangleBox, Parallelogram, Triangle, JoinedCurve, JoinedCurveBox, FilledCurve, FilledCurveBox, StadiumShape, DiskSegment, Annulus, BezierCurve, BezierCurveBox, BSplineCurve, BSplineCurveBox, BSplineSurface, BSplineSurface3DBox, SphericalShell, CapsuleShape, Raster, RasterBox, Raster3D, Raster3DBox, Polygon, PolygonBox, RegularPolygon, Disk, DiskBox, Circle, CircleBox, Sphere, SphereBox, Ball, Ellipsoid, Cylinder, CylinderBox, Tetrahedron, TetrahedronBox, Cuboid, CuboidBox, Parallelepiped, Hexahedron, HexahedronBox, Prism, PrismBox, Pyramid, PyramidBox, Simplex, ConicHullRegion, ConicHullRegionBox, Hyperplane, HalfSpace, AffineHalfSpace, AffineSpace, ConicHullRegion3DBox, Cone, ConeBox, InfiniteLine, InfinitePlane, HalfLine, InfinitePlane, HalfPlane, Tube,
TubeBox, GraphicsComplex, GraphicsComplexBox, GraphicsGroup, GraphicsGroupBox, GeoGraphics, Graphics, GraphicsBox, Graphics3D, Graphics3DBox, MeshRegion, BoundaryMeshRegion, GeometricTransformation, GeometricTransformationBox, Rotate, Translate, Scale, SurfaceGraphics, Text, TextBox, Inset, InsetBox, Inset3DBox, Panel, PanelBox, Legended, Placed, LineLegend, Texture}
] &;
code
labelPositions[graphics_] := Fold[
Function[{plot, pos},
MapAt[Tooltip[#, Column@{Head[#], pos}] &, plot, pos]],
graphics,
Position[graphics, x_[___] /; primitivesQ[x], \[Infinity]]
]
test
plot = Graphics[{Thick, Green, Rectangle[{0, -1}, {2, 1}], Red,
Disk[], Blue, Circle[{2, 0}], Yellow,
Polygon[{{2, 0}, {4, 1}, {4, -1}}], Purple, Arrowheads[Large],
Arrow[{{4, 3/2}, {0, 3/2}, {0, 0}}], Black, Dashed,
Line[{{-1, 0}, {4, 0}}]}];
labelPositions @ plot

todo
This is done with an assumption that primitives are not nested within others. In general that's not true, like for FilledCurve @ BSplineCurve[...] so those cases should be handled with more care.