Avoid having different types with same name

Rule ND2012 Naming Conventions

Warns about multiple same-named types in different application or third-party namespaces or assemblies: confusion and naming collisions in source files using several of them.

How to fix

Rename concerned types.

CQLinq source

This rule is written in CQLinq, C# LINQ over the NDepend code model. It ships with every new NDepend project: you can read it, adapt it, or use it as a starting point for your own custom rules.

// <Name>Avoid having different types with same name</Name>
// <Id>ND2012:AvoidHavingDifferentTypesWithSameName</Id>

warnif count > 0

// Special type names for which multiple types
// with such name are allowed.
let nonReportedTypeName = new [] { 
   "Program", "NamespaceDoc", "Initial", "Startup",
   "SwaggerConfig", "Constants", "MainWindow", "App", "Index",
   "Create", "Read", "Update", "Delete", "Edit", "Details",
   "View" }

// Special type name suffixes for which multiple types
// with such suffix are allowed.
let nonReportedTypeNameSuffix = new [] { 
   "Service", "Model", "Controller", "Page", "Pages" }

// This rule matches also collisions between 
// application and third-party types sharing a same name.
let groups = JustMyCode.Types.Union(ThirdParty.Types)
       // Discard nested types, whose name is
       // prefixed with the parent type name.
       .Where(t => !t.IsNested && 
                   !nonReportedTypeName.Contains(t.Name) &&
                   !t.Name.EndsWithAny(nonReportedTypeNameSuffix))
       // Group types by name.
       .GroupBy(t => t.Name)

from @group in groups 
   where @group.Count() > 1

   // Let's see if types with the same name are declared
   // in different namespaces.
   // (t.FullName is {namespaceName}.{typeName} )
   let groupsFullName = @group.GroupBy(t => t.FullName)
   where groupsFullName.Count() > 1

   // If several types with same name are declared in different
   // namespaces eliminate the case where all types are declared
   // in third-party assemblies.
   let types = groupsFullName.SelectMany(g => g)
   where types.Any(t => !t.IsThirdParty)
          // Uncomment this line, to only gets naming collision involving
          // both application and third-party types.
          //         && types.Any(t => t.IsThirdParty)

   // Discard the group if at least two types are declared in
   // the same source file(s): it means such files are shared
   // amongst projects and it is not a problem.
   let filePaths = types
      .Where(t => t.SourceFileDeclAvailable)
      .SelectMany(t => t.SourceDecls
         .Select(d => d.SourceFile.FilePathString)
         .Distinct(StringComparer.OrdinalIgnoreCase))
      .ToArray()
   where filePaths.Length == filePaths
      .Distinct(StringComparer.OrdinalIgnoreCase).Count()

orderby types.Count() descending

// Don't match types containing extension methods
// whose name is less relevant
where !types.All(t => t.IsStatic &&
                      t.Methods.Any(m => m.IsExtensionMethod))

// Order types by parent namespace and assembly name, this way
// we always get the same type across sessions. Without this
// astute, the same issue would be seen as added/removed when
// the first type choosen in the group was not always the same,
// a situation that actually happens. Also make sure that the
// chosen type is not a third-party one.
let tMatched = types.OrderBy(t =>
      (t.IsThirdParty ? "1" : "0") +
      t.ParentNamespace.Name + t.ParentAssembly.Name).First()

select new { 

   t = tMatched,
   
   // In the 'types' column, make sure to group matched types 
   // by parent assemblies and parent namespaces, to get a
   // result more readable.
   types,
   
   namespaces = types.Except(tMatched)
      .Select(t => t.ParentNamespace).Distinct(n => n.Name),
   
   Debt = 10.ToMinutes().ToDebt(),
   Severity = Severity.High
}

//<Expl>
// {2?A type:Several types} with the same name as the *{0}*
// {2?is:are} defined in the *{2}*.
// This leads to confusion and also naming collision.
//</Expl>

//<Desc>
// Warns about multiple same-named types in different
// *application* or *third-party* namespaces or assemblies:
// confusion and naming collisions in source files using
// several of them.
//</Desc>

//<HowToFix>
// Rename concerned types.
//</HowToFix>

Naming Conventions: all 23 items