Namespace name should correspond to file location
The namespaces hierarchy should be synchronized with the source files directory hierarchy — a widely accepted convention; misalignment makes code less maintainable and harder to navigate. Matches namespaces whose source file locations don't align with the namespace name.
Comparisons are case-sensitive; the justACaseSensitiveIssue flag indicates a pure casing mismatch (slightly lower debt).
Source files out of the project directory are ignored: such linked files are shared across projects and already matched by the rule Avoid referencing source file out of the project directory.
Comparisons are case-sensitive; the justACaseSensitiveIssue flag indicates a pure casing mismatch (slightly lower debt).
Source files out of the project directory are ignored: such linked files are shared across projects and already matched by the rule Avoid referencing source file out of the project directory.
How to fix
Align the namespace with the directory sub-paths containing the source files.
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>Namespace name should correspond to file location</Name>
// <Id>ND2103:NamespaceNameShouldCorrespondToFileLocation</Id>
warnif count > 0
from a in Application.Assemblies
let assemblyName = a.Name
// Source files out of the project directory are linked files shared across
// projects: they follow no single project's folder layout (ND2100 matches them)
let projectDir = a.VisualStudioProjectFilePath != null ? a.VisualStudioProjectFilePath.ParentDirectoryPath : null
from n in a.ChildNamespaces
where n.SourceFileDeclAvailable
let namespaceName = n.Name
// Build the dirShouldContain string
// and then we check which source file path contains dirShouldContain or not
let dirShouldContain = (
// namespaceName starts with assembly name => gets only components after the assembly name
namespaceName.StartsWith(assemblyName)
? namespaceName.Substring(assemblyName.Length)
// namespaceName contains assembly name => gets only components after the assembly name
: namespaceName.Contains("." + assemblyName)
? namespaceName.Substring(n.Name.IndexOf("." + assemblyName))
// namespaceName has more than one part => gets only components after the first part
: namespaceName.Contains(".")
? namespaceName.Substring(n.Name.IndexOf("."))
: namespaceName)
// Replace dots and underscore by spaces in namespace name
.Replace('.', ' ')
.Replace('_', ' ')
where dirShouldContain.Length > 0
// Obtain a sourceDecl which path doesn't contains dirShouldContain
let sourceDecl = n.SourceDecls
.OrderBy(d => d.SourceFile.FilePathString)
.Where(d => d.SourceFile.CodeElements.All(e => JustMyCode.Contains(e)) &&
(projectDir == null || d.SourceFile.FilePath.IsChildOf(projectDir)))
.FirstOrDefault(decl=>
// Replace dots, path separators, minus and underscores
// by spaces in source files names
!decl.SourceFile.FilePathString
.Replace('.',' ').Replace('\\',' ')
.Replace('-',' ').Replace('_',' ')
.Contains(dirShouldContain)
)
where sourceDecl != null
let dir = sourceDecl.SourceFile.FilePath.ParentDirectoryPath
let justACaseSensitiveIssue = dir.ToString()
.Replace('.',' ').Replace('\\',' ')
.Replace('-',' ').Replace('_',' ')
.IndexOf(dirShouldContain, StringComparison.OrdinalIgnoreCase) >= 0
// Get distinct source files contained in dir through the types thay contain
let typesConcerned = n.ChildTypes
.Where(t => t.SourceFileDeclAvailable)
.Distinct(t => t.SourceDecls.First().SourceFile.FilePathString)
.Where(t => t.SourceDecls.First().SourceFile.FilePath.ParentDirectoryPath.Equals(dir))
.ToArray()
select new {
n,
dirShouldContain,
dir = dir.ToString(),
justACaseSensitiveIssueStr = justACaseSensitiveIssue ? " Please note that this is solely a matter of casing." : "",
typesConcerned,
Debt = (justACaseSensitiveIssue ? 2 : 3).ToMinutes().ToDebt(),
Severity = Severity.Medium
}
//<Expl>
// The source file{4?:s} containing the declaration{4?:s}
// of the *{0}* {4?is:are} located in the directory
// *{2}* that does not align with the namespace name.{3}
//</Expl>
//<Desc>
// The namespaces hierarchy should be synchronized with the source files
// directory hierarchy — a widely accepted convention; misalignment makes
// code less maintainable and harder to navigate. Matches namespaces whose
// source file locations don't align with the namespace name.
//
// Comparisons are *case-sensitive*; the *justACaseSensitiveIssue* flag
// indicates a pure casing mismatch (slightly lower debt).
//
// Source files out of the project directory are ignored: such linked files
// are shared across projects and already matched by the rule *Avoid
// referencing source file out of the project directory*.
//</Desc>
//<HowToFix>
// Align the namespace with the directory sub-paths containing the source
// files.
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
Source Files Organization: all 6 items
- Avoid referencing source file out of the project directory ND2100
- Avoid duplicating a type definition across assemblies ND2101
- Avoid defining multiple types in a source file ND2102
- Namespace name should correspond to file location ND2103
- Types with source files stored in the same directory, should be declared in the same namespace ND2104
- Types declared in the same namespace, should have their source files stored in the same directory ND2105