Skip to content

BRO1126: Using directives should be qualified

A using directive inside a namespace names its namespace or type fully. Replaces StyleCop SA1135. Only relevant when usings go inside the namespace (StyleCop's SA1200 default; the preset puts them outside).

Example

Before

namespace System.Reporting
{
    using IO;
    using Builder = Text.StringBuilder;

    public class Export
    {
        public Builder Lines { get; } = new Builder();

        public FileInfo? Target { get; set; }
    }
}

After

namespace System.Reporting
{
    using System.IO;
    using Builder = System.Text.StringBuilder;

    public class Export
    {
        public Builder Lines { get; } = new Builder();

        public FileInfo? Target { get; set; }
    }
}

Why

Inside a namespace, using IO; means something different depending on the namespace around it, so moving the code or renaming the namespace can change what it refers to.

How the fix works

The name is replaced with its fully qualified form, type arguments included (int stays int). using static and aliases are checked too. An alias's own type stays a name (System.ValueTuple<System.IO.Stream, int>, System.Nullable<...>, System.Int32): (.., ..), T? and int there need C# 12. Inside type arguments the shorthand is kept, and so is the way a built-in type is written: System.ReadOnlyMemory<System.Char> stays (with dotnet_style_predefined_type_* set to false, IDE0049 would report char, and dotnet format can't fix it in an alias), and List<String> becomes System.Collections.Generic.List<System.String>, like StyleCop.

When usings are sorted (dotnet_sort_system_directives_first or dotnet_separate_import_directive_groups is set, so dotnet format sorts them), the fix sorts them too, with the same organizer: the qualified name usually belongs elsewhere, and dotnet format would otherwise move it only on its next run.

Not reported

  • Usings outside a namespace, names starting with global:: or an alias, and a type of the namespace the directive is in (like StyleCop).
  • A type argument that starts with an alias (using T2 = System.ValueTuple<Tasks.Task, int>; with using Tasks = System.Threading.Tasks; outside): it's kept as written, like an alias at the start of the name.
  • A qualified name that an enclosing namespace would hide: inside namespace Lib.Inner, with a namespace Lib.Inner.Lib around, Lib.Thing would mean Lib.Inner.Lib.Thing.

Compared with StyleCop

Same positions and output, except the hidden-name case above (StyleCop's fix then refers to the wrong namespace) and a type argument that starts with an alias: StyleCop accepts using T1 = Tasks.Task; but reports using T2 = System.ValueTuple<Tasks.Task, int>; (#3884, open).