https://bazel.build/extending/rules#migrating_from_legacy_providers describes that using "struct access" patterns is already a legacy approach, and the preferred "modern" approach is to use explicit providers. That is
ctx.atr.foo.default_runfiles
should instead become
ctx.attr.foo[DefaultInfo].default_runfiles
Addressing the default provider directly by strings - e.g., ctx.attr.foo.data_runfiles - has the potential for namespace clash. This has happened in the past. That is, ctx.attr.foo.fieldname can potentially return a provider rather than a data field. However, ctx.attr.foo[fieldname] will always return a provider.