diff --git a/.gitignore b/.gitignore
index 3499559..60b7e8d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,6 @@ bin/
obj/
*.mdb
.git/
-
+NDependOut/
+.nuget/
+.nuget
diff --git a/NOCQ.ndproj b/NOCQ.ndproj
new file mode 100644
index 0000000..e22296d
--- /dev/null
+++ b/NOCQ.ndproj
@@ -0,0 +1,4069 @@
+
+
+ D:\varanas\NDependOut
+
+ NOCQ
+ NOCQ.Application
+
+
+ mscorlib
+ System.ComponentModel.Composition
+ System
+ System.Core
+ Newtonsoft.Json
+ Microsoft.CSharp
+ AE.Net.Mail
+ csredis
+
+
+ D:\varanas\src\NOCQ\bin\Debug
+ D:\varanas\src\NOCQ.Application\bin\Debug
+ C:\Windows\Microsoft.NET\Framework\v4.0.30319
+ C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Types too big - critical
+warnif count > 0 from t in JustMyCode.Types where
+ t.NbLinesOfCode > 500
+ // We've commented # IL Instructions, because with LINQ syntax, a few lines of code can compile to hundreds of IL instructions.
+ // || t.NbILInstructions > 3000
+ orderby t.NbLinesOfCode descending
+select new { t, t.NbLinesOfCode, t.NbILInstructions,
+ t.Methods, t.Fields }
+
+// Types where NbLinesOfCode > 500 are extremely complex
+// and should be split in a smaller group of types.
+// See the definition of the NbLinesOfCode metric here
+// http://www.ndepend.com/Metrics.aspx#NbLinesOfCode
+
+// In average, a line of code is compiled to around
+// 6 IL instructions. This is why the code metric
+// NbILInstructions is used here, in case the
+// code metric NbLinesOfCode is un-available because
+// of missing assemblies corresponding PDB files.
+// See the definition of the NbILInstructions metric here
+// http://www.ndepend.com/Metrics.aspx#NbILInstructions
+
+]]>
+ Methods too complex - critical
+warnif count > 0 from m in JustMyCode.Methods where
+ m.ILCyclomaticComplexity > 40 &&
+ m.ILNestingDepth > 5
+ orderby m.ILCyclomaticComplexity descending,
+ m.ILNestingDepth descending
+select new { m, m.ILCyclomaticComplexity, m.ILNestingDepth }
+
+// Methods with ILCyclomaticComplexity > 40 and ILNestingDepth > 4
+// are really too complex and should be split
+// in smaller methods, or even types.
+// See the definition of the ILCyclomaticComplexity metric here
+// http://www.ndepend.com/Metrics.aspx#ILCC
+// See the definition of the ILNestingDepth metric here
+// http://www.NDepend.com/Metrics.aspx#ILNestingDepth]]>
+ Methods with too many parameters - critical
+warnif count > 0 from m in JustMyCode.Methods where
+ m.NbParameters > 8
+ orderby m.NbParameters descending
+select new { m, m.NbParameters }
+
+// Methods with more than 8 parameters might be painful to call
+// and might degrade performance. You should prefer using
+// additional properties/fields to the declaring type to
+// handle numerous states. Another alternative is to provide
+// a class or structure dedicated to handle arguments passing
+// (for example see the class System.Diagnostics.ProcessStartInfo
+// and the method System.Diagnostics.Process.Start(ProcessStartInfo))
+// See the definition of the NbParameters metric here
+// http://www.ndepend.com/Metrics.aspx#NbParameters
+]]>
+ Quick summary of methods to refactor
+warnif count > 0 from m in JustMyCode.Methods where
+ // Code Metrics' definitions
+ m.NbLinesOfCode > 30 || // http://www.ndepend.com/Metrics.aspx#NbLinesOfCode
+ // We've commented # IL Instructions, because with LINQ syntax, a few lines of code can compile to hundreds of IL instructions.
+ // m.NbILInstructions > 200 || // http://www.ndepend.com/Metrics.aspx#NbILInstructions
+ m.CyclomaticComplexity > 20 || // http://www.ndepend.com/Metrics.aspx#CC
+ m.ILCyclomaticComplexity > 50 || // http://www.ndepend.com/Metrics.aspx#ILCC
+ m.ILNestingDepth > 5 || // http://www.ndepend.com/Metrics.aspx#ILNestingDepth
+ m.NbParameters > 5 || // http://www.ndepend.com/Metrics.aspx#NbParameters
+ m.NbVariables > 8 || // http://www.ndepend.com/Metrics.aspx#NbVariables
+ m.NbOverloads > 6 // http://www.ndepend.com/Metrics.aspx#NbOverloads
+
+select new { m, m.NbLinesOfCode, m.NbILInstructions, m.CyclomaticComplexity,
+ m.ILCyclomaticComplexity, m.ILNestingDepth,
+ m.NbParameters, m.NbVariables, m.NbOverloads } ]]>
+ Methods too big
+warnif count > 0 from m in JustMyCode.Methods where
+ m.NbLinesOfCode > 30
+ // We've commented # IL Instructions, because with LINQ syntax, a few lines of code can compile to hundreds of IL instructions.
+ // || m.NbILInstructions > 200
+ orderby m.NbLinesOfCode descending,
+ m.NbILInstructions descending
+select new { m, m.NbLinesOfCode, m.NbILInstructions }
+
+// Methods where NbLinesOfCode > 30 or NbILInstructions > 200
+// are extremely complex and should be split in smaller methods.
+// See the definition of the NbLinesOfCode metric here
+// http://www.ndepend.com/Metrics.aspx#NbLinesOfCode]]>
+ Methods too complex
+warnif count > 0 from m in JustMyCode.Methods where
+ m.CyclomaticComplexity > 20 ||
+ m.ILCyclomaticComplexity > 40 ||
+ m.ILNestingDepth > 5
+ orderby m.CyclomaticComplexity descending,
+ m.ILCyclomaticComplexity descending,
+ m.ILNestingDepth descending
+select new { m, m.CyclomaticComplexity,
+ m.ILCyclomaticComplexity,
+ m.ILNestingDepth }
+
+// Methods where CyclomaticComplexity > 20
+// or ILCyclomaticComplexity > 40
+// or ILNestingDepth > 4
+// are hard to understand and maintain
+// and should be split in smaller methods.
+// See the definition of the complexity metrics here:
+// http://www.ndepend.com/Metrics.aspx#CC
+// http://www.ndepend.com/Metrics.aspx#ILCC
+// http://www.NDepend.com/Metrics.aspx#ILNestingDepth]]>
+ Methods potentially poorly commented
+warnif count > 0 from m in JustMyCode.Methods where
+ m.PercentageComment < 20 &&
+ m.NbLinesOfCode > 20
+ orderby m.PercentageComment ascending
+select new { m, m.PercentageComment, m.NbLinesOfCode, m.NbLinesOfComment }
+
+// Methods where %Comment < 20 and that have
+// at least 20 lines of code might need to be more commented.
+// See the definition of the Comments metric here
+// http://www.ndepend.com/Metrics.aspx#PercentageComment
+// http://www.ndepend.com/Metrics.aspx#NbLinesOfComment ]]>
+ Methods with too many parameters
+warnif count > 0 from m in JustMyCode.Methods where
+ m.NbParameters > 5
+ orderby m.NbParameters descending
+select new { m, m.NbParameters }
+
+// Methods where NbParameters > 5 might be painful to call
+// and might degrade performance. You should prefer using
+// additional properties/fields to the declaring type to
+// handle numerous states. Another alternative is to provide
+// a class or structure dedicated to handle arguments passing
+// (for example see the class System.Diagnostics.ProcessStartInfo
+// and the method System.Diagnostics.Process.Start(ProcessStartInfo))
+// See the definition of the NbParameters metric here
+// http://www.ndepend.com/Metrics.aspx#NbParameters]]>
+ Methods with too many local variables
+warnif count > 0 from m in JustMyCode.Methods where
+ m.NbVariables > 15
+ orderby m.NbVariables descending
+select new { m, m.NbVariables }
+
+// Methods where NbVariables > 8 are hard to understand and maintain.
+// Methods where NbVariables > 15 are extremely complex
+// and should be split in smaller methods.
+// See the definition of the Nbvariables metric here
+// http://www.ndepend.com/Metrics.aspx#Nbvariables]]>
+ Methods with too many overloads
+warnif count > 0 from m in JustMyCode.Methods where
+ m.NbOverloads > 6 &&
+ !m.IsOperator // Don't report operator overload
+ orderby m.NbOverloads descending
+select new { m, m.NbOverloads }
+
+// Methods where NbOverloads > 6 might
+// be a problem to maintain and provoke higher coupling
+// than necessary.
+// This might also reveal a potential misused of the
+// C# and VB.NET language that since C#3 and VB9 support
+// object initialization. This feature helps reducing the number
+// of constructors of a class.
+// See the definition of the NbOverloads metric here
+// http://www.ndepend.com/Metrics.aspx#NbOverloads]]>
+ Types with too many methods
+warnif count > 0 from t in JustMyCode.Types where
+ t.Methods.Count() > 20
+ orderby t.Methods.Count() descending
+select new { t, t.InstanceMethods, t.StaticMethods }
+
+// Types where Methods.Count() > 20 might be hard to
+// understand and maintain
+// but there might be cases where it is relevant
+// to have a high number of methods.
+// For example, the System.Windows.Forms.DataGridView
+// standard class has more than 1000 methods.
+]]>
+ Types with too many fields
+warnif count > 0 from t in JustMyCode.Types where
+ t.Fields.Count() > 20 &&
+ !t.IsEnumeration
+ orderby t.Fields.Count() descending
+select new { t, t.InstanceFields, t.StaticFields, t.SizeOfInst }
+
+// Types where Fields.Count() > 20 and not IsEnumeration
+// might be hard to understand and maintain
+// but there might be cases where it is relevant
+// to have a high number of fields.
+// For example, the System.Windows.Forms.Control
+// standard class has more than 200 fields.]]>
+ Types with poor cohesion
+warnif count > 0 from t in JustMyCode.Types where
+ (t.LCOM > 0.8 || t.LCOMHS > 0.95) &&
+ t.NbFields > 10 &&
+ t.NbMethods >10
+ orderby t.LCOM descending, t.LCOMHS descending
+select new { t, t.LCOM, t.LCOMHS,
+ t.NbMethods, t.NbFields }
+
+// Types where LCOM > 0.8 and NbFields > 10
+// and NbMethods >10 might be problematic.
+// However, it is very hard to avoid such
+// non-cohesive types. The LCOMHS metric
+// is often considered as more efficient to
+// detect non-cohesive types.
+// See the definition of the LCOM metric here
+// http://www.ndepend.com/Metrics.aspx#LCOM]]>
+
+
+ From now, all methods added or refactored should respect basic quality principles
+warnif count > 0 from m in JustMyCode.Methods where
+
+// *** Only new or modified methods since Baseline for Comparison ***
+ (m.WasAdded() || m.CodeWasChanged()) &&
+
+// Low Quality methods// Metrics' definitions
+( m.NbLinesOfCode > 30 || // http://www.ndepend.com/Metrics.aspx#NbLinesOfCode
+ m.NbILInstructions > 200 || // http://www.ndepend.com/Metrics.aspx#NbILInstructions
+ m.CyclomaticComplexity > 20 || // http://www.ndepend.com/Metrics.aspx#CC
+ m.ILCyclomaticComplexity > 50 || // http://www.ndepend.com/Metrics.aspx#ILCC
+ m.ILNestingDepth > 4 || // http://www.ndepend.com/Metrics.aspx#ILNestingDepth
+ m.NbParameters > 5 || // http://www.ndepend.com/Metrics.aspx#NbParameters
+ m.NbVariables > 8 || // http://www.ndepend.com/Metrics.aspx#NbVariables
+ m.NbOverloads > 6 )
+select new { m, m.NbLinesOfCode, m.NbILInstructions, m.CyclomaticComplexity,
+ m.ILCyclomaticComplexity, m.ILNestingDepth,
+ m.NbParameters, m.NbVariables, m.NbOverloads } // http://www.ndepend.com/Metrics.aspx#NbOverloads
+
+
+// This rule warns if a method with
+// low-quality has been added or refactored.
+// With NDepend and such rule, you can
+// Ensure Quality From Now! as explained here:
+// http://codebetter.com/blogs/patricksmacchia/archive/2008/01/01/ensure-the-quality-of-the-code-that-will-be-developed-this-year.aspx
+]]>
+ From now, all types added or refactored should respect basic quality principles
+warnif count > 0 from t in JustMyCode.Types where
+
+// *** Only match new or modified types since Baseline for Comparison ***
+(t.WasAdded() || t.CodeWasChanged()) &&
+
+// Eliminate interfaces, enumerations or types only with constant fields
+// by making sure we are matching type with code.
+t.NbLinesOfCode > 10 &&
+
+// Low Quality types Metrics' definitions are available here:
+// http://www.ndepend.com/Metrics.aspx#MetricsOnTypes
+( // Types with too many methods
+ t.NbMethods > 20 ||
+
+ // Types with too many fields
+ t.NbFields > 20 ||
+
+ // Complex Types that use more than 50 other types
+ t.NbTypesUsed > 50
+)
+select new { t, t.Methods, t.Fields, t.TypesUsed }
+
+
+// This rule warns if a type with
+// low-quality has been added or refactored.
+// With NDepend and such rule, you can
+// Ensure Quality From Now! as explained here:
+// http://codebetter.com/blogs/patricksmacchia/archive/2008/01/01/ensure-the-quality-of-the-code-that-will-be-developed-this-year.aspx
+]]>
+ From now, all types added or refactored should be 100% covered by tests
+warnif count > 0 from t in JustMyCode.Types where
+
+ // Match methods new or modified since Baseline for Comparison...
+ (t.WasAdded() || t.CodeWasChanged()) &&
+
+ // ...that are not 100% covered by tests
+ t.PercentageCoverage < 100
+
+ let methodsCulprit = t.Methods.Where(m => m.PercentageCoverage < 100)
+
+select new { t, t.PercentageCoverage, methodsCulprit }
+
+// Having types 100% covered by tests is a good idea because
+// the small portion of code hard to cover, is also the
+// portion of code that is the most likely to contain bugs.]]>
+ Avoid decreasing code coverage by tests of types
+// To visualize changes in code, right-click a matched type and select:
+// - Compare older and newer versions of source file
+// - Compare older and newer versions disassembled with Reflector
+
+warnif count > 0
+from t in JustMyCode.Types where
+ t.IsPresentInBothBuilds() &&
+ t.PercentageCoverage < t.OlderVersion().PercentageCoverage
+
+select new { t,
+ OldCov = t.OlderVersion().PercentageCoverage,
+ NewCov = t.PercentageCoverage,
+ OldLoc = t.OlderVersion().NbLinesOfCode,
+ NewLoc = t.NbLinesOfCode,
+}
+]]>
+ Types that used to be 100% covered but not anymore
+warnif count > 0
+from t in JustMyCode.Types where
+ t.IsPresentInBothBuilds() &&
+ t.OlderVersion().PercentageCoverage == 100 &&
+ t.PercentageCoverage < 100
+let culpritMethods = t.Methods.Where(m => m.PercentageCoverage < 100)
+select new {t, t.PercentageCoverage, culpritMethods }]]>
+ Avoid making complex methods even more complex (Source CC)
+// To visualize changes in code, right-click a matched method and select:
+// - Compare older and newer versions of source file
+// - Compare older and newer versions disassembled with Reflector
+
+warnif count > 0
+from m in JustMyCode.Methods where
+ !m.IsAbstract &&
+ m.IsPresentInBothBuilds() &&
+ m.CodeWasChanged()
+
+let oldCC = m.OlderVersion().CyclomaticComplexity
+where oldCC > 6 && m.CyclomaticComplexity > oldCC
+
+select new { m,
+ oldCC ,
+ newCC = m.CyclomaticComplexity ,
+ oldLoc = m.OlderVersion().NbLinesOfCode,
+ newLoc = m.NbLinesOfCode,
+}
+]]>
+ Avoid making complex methods even more complex (IL CC)
+// To visualize changes in code, right-click a matched method and select:
+// - Compare older and newer versions of source file
+// - Compare older and newer versions disassembled with Reflector
+
+warnif count > 0
+from m in JustMyCode.Methods where
+ !m.IsAbstract &&
+ m.IsPresentInBothBuilds() &&
+ m.CodeWasChanged()
+
+let oldCC = m.OlderVersion().ILCyclomaticComplexity
+where oldCC > 10 && m.ILCyclomaticComplexity > oldCC
+
+select new { m,
+ oldCC ,
+ newCC = m.ILCyclomaticComplexity ,
+ oldLoc = m.OlderVersion().NbLinesOfCode,
+ newLoc = m.NbLinesOfCode,
+}
+
+]]>
+ Avoid making large methods even larger
+// To visualize changes in code, right-click a matched method and select:
+// - Compare older and newer versions of source file
+// - Compare older and newer versions disassembled with Reflector
+
+warnif count > 0
+from m in JustMyCode.Methods where
+ !m.IsAbstract &&
+ m.IsPresentInBothBuilds() &&
+ m.CodeWasChanged() &&
+ // Eliminate constructors from match, since they get larger
+ // as soons as some fields initialization are added.
+ !m.IsConstructor &&
+ !m.IsClassConstructor
+
+let oldLoc = m.OlderVersion().NbLinesOfCode
+where oldLoc > 15 && m.NbLinesOfCode > oldLoc
+
+select new { m,
+ oldLoc,
+ newLoc = m.NbLinesOfCode,
+}
+
+]]>
+ Avoid adding methods to a type that already had many methods
+// To visualize changes in code, right-click a matched type and select:
+// - Compare older and newer versions of source file
+// - Compare older and newer versions disassembled with Reflector
+
+warnif count > 0
+from t in JustMyCode.Types where
+ t.IsPresentInBothBuilds() &&
+ t.Methods.Count() > t.OlderVersion().Methods.Count() &&
+ t.OlderVersion().Methods.Count() > 10
+
+let newMethods = t.Methods.Where(m => m.WasAdded())
+let removedMethods = t.OlderVersion().Methods.Where(m => m.WasRemoved())
+
+select new { t,
+ oldNbMethods = t.OlderVersion().NbMethods,
+ newNbMethods = t.NbMethods,
+ newMethods,
+ removedMethods }]]>
+ Avoid transforming an immutable type into a mutable one
+// Users of an immutable type often rely on the fact that the type is immutable.
+// If an immutable type becomes mutable, there are chances that this will break its users.
+warnif count > 0
+from t in Application.Types where
+ t.IsPresentInBothBuilds() &&
+ t.OlderVersion().IsImmutable &&
+ !t.IsImmutable &&
+ // Don't take account of immutable types transformed into static types (not deemed as immtable)
+ !t.IsStatic
+let culpritFields = t.Fields.Where(f => f.IsImmutable)
+select new {t, culpritFields }]]>
+ Avoid transforming an immutable field into a mutable one
+// Users of an immutable field often rely on the fact that the type is immutable.
+// If an immutable field becomes mutable, there are chances that this will break its users.
+warnif count > 0
+from f in Application.Fields where
+ f.IsPresentInBothBuilds() &&
+ f.OlderVersion().IsImmutable &&
+ !f.IsImmutable
+select f]]>
+ Avoid adding instance fields to a type that already had many instance fields
+// To visualize changes in code, right-click a matched type and select:
+// - Compare older and newer versions of source file
+// - Compare older and newer versions disassembled with Reflector
+
+warnif count > 0
+from t in JustMyCode.Types where
+ t.IsPresentInBothBuilds() &&
+ !t.IsStatic
+
+let oldNbInstanceFields = t.OlderVersion().InstanceFields
+let newNbInstanceFields = t.InstanceFields
+where
+ newNbInstanceFields.Count() > oldNbInstanceFields .Count() &&
+ oldNbInstanceFields.Count() > 6
+
+let newInstanceFields = t.InstanceFields.Where(f => f.WasAdded())
+
+select new { t,
+ oldCount = oldNbInstanceFields.Count() ,
+ newCount = newNbInstanceFields.Count() ,
+ newInstanceFields }]]>
+
+
+ Base class should not use derivatives
+warnif count > 0
+from baseClass in JustMyCode.Types
+where baseClass.IsClass && baseClass.NbChildren > 0 // <-- for optimization!
+let derivedClassesUsed = baseClass.DerivedTypes.UsedBy(baseClass)
+where derivedClassesUsed.Count() > 0
+select new { baseClass, derivedClassesUsed }]]>
+ Class shouldn't be too deep in inheritance tree
+warnif count > 0 from t in JustMyCode.Types
+where t.IsClass
+let baseClasses = t.BaseClasses.ExceptThirdParty()
+
+// Warn for classes with 3 or more base classes.
+// Notice that we don't count third-party classes
+// because this rule concerns your code design,
+// not third-party libraries consumed design.
+where baseClasses.Count() >= 3
+
+select new { t, baseClasses,
+ // The metric value DepthOfInheritance takes account
+ // of third-party base classes
+ t.DepthOfInheritance }
+
+// Branches too long in the derivation should be avoided.
+// See the definition of the DepthOfInheritance metric here
+// http://www.ndepend.com/Metrics.aspx#DIT
+]]>
+ Class with no descendant should be sealed if possible
+warnif count > 0 from t in JustMyCode.Types where
+ t.IsClass &&
+ t.NbChildren ==0 &&
+ !t.IsSealed &&
+ !t.IsStatic
+ // && !t.IsPublic <-- You might want to add this condition
+ // if you are developing a framework
+ // with classes that are intended to be
+ // sub-classed by your clients.
+ orderby t.NbLinesOfCode descending
+select new { t, t.NbLinesOfCode }]]>
+ Overrides of Method() should call base.Method()
+// Overrides of Method() should refine the behavior of base.Method().
+// If base.Method() is not called, the base behavior is not refined but it is replaced.
+// Violations of this rule are a sign of design flaw,
+// especially if the design provides valid reasons
+// that advocates that the base behavior must be replaced and not refined.
+//
+// Discussions on this topic are available here:
+// http://stackoverflow.com/questions/1107022/should-i-call-the-base-class-implementation-when-overriding-a-method-in-c-sharp
+// http://stackoverflow.com/questions/2945147/make-sure-base-method-gets-called-in-c-sharp
+
+warnif count > 0
+from t in Types // Take account of third-party types too
+
+// Bother only classes with descendant
+where t.IsClass && t.NbChildren > 0
+
+from mBase in t.InstanceMethods
+where mBase.IsVirtual &&
+ !mBase.IsThirdParty &&
+ !mBase.IsAbstract &&
+ !mBase.IsExplicitInterfaceImpl
+from mOverride in mBase.OverridesDirectDerived
+where !mOverride.IsUsing(mBase)
+select new { mOverride, shouldCall = mBase, definedInBaseClass = mBase.ParentType }
+]]>
+ Do not hide base class methods
+// To fix a violation of this rule, remove or rename the method, or change the parameter signature
+// so that the method does not hide the base method.
+
+// More on hiding vs. virtual usefulness here:
+// http://www.artima.com/intv/nonvirtual.html
+// http://blogs.msdn.com/b/ericlippert/archive/2008/05/21/method-hiding-apologia.aspx
+
+warnif count > 0
+
+// Define a lookup table indexing methods by their name including parameters signature.
+let lookup = Methods.Where(m => !m.IsConstructor && !m.IsStatic && !m.IsGeneratedByCompiler)
+ .ToLookup(m1 => m1.Name)
+
+from t in Application.Types
+where !t.IsStatic && t.IsClass &&
+ // Discard classes deriving directly from System.Object
+ t.DepthOfInheritance > 1
+where t.BaseClasses.Any()
+
+// For each methods not overriding any methods (new slot),
+// let's check if it hides by name some methods defined in base classe.
+from m in t.InstanceMethods
+where m.IsNewSlot && !m.IsExplicitInterfaceImpl && !m.IsGeneratedByCompiler
+
+// Notice how lookup is used to quickly retrieve methods with same name as m.
+// This makes the query 10 times faster than iterating each base methods to check their name.
+let baseMethodsHidden = lookup[m.Name].Where(m1 => m1 != m && t.DeriveFrom(m1.ParentType))
+
+where baseMethodsHidden.Count() > 0
+select new { m, baseMethodsHidden }]]>
+ A stateless class or structure might be turned into a static type
+// This rule indicates stateless types that might
+// eventually be turned into static classes.
+warnif count > 0 from t in JustMyCode.Types where
+ !t.IsStatic &&
+ !t.IsGeneric &&
+ t.InstanceFields.Count() == 0 &&
+
+ // Don't match:
+ // --> types that implement some interfaces.
+ t.NbInterfacesImplemented == 0 &&
+
+ // --> or classes that have sub-classes children.
+ t.NbChildren == 0 &&
+
+ // --> or classes that have a base class
+ ((t.IsClass && t.DepthOfDeriveFrom("System.Object".AllowNoMatch()) == 1) ||
+ t.IsStructure)
+
+
+select t
+
+]]>
+ Non-static classes should be instantiated or turned to static
+// Notice that classes only instantiated through reflection, like plug-in root classes
+// are matched by this rules.
+warnif count > 0
+from t in JustMyCode.Types
+where t.IsClass &&
+ //!t.IsPublic && // if you are developing a framework,
+ // you might not want to match public classes
+ !t.IsStatic &&
+ !t.IsAttributeClass && // Attributes class are never seen as instantiated
+ !t.DeriveFrom("System.MarshalByRefObject".AllowNoMatch()) // Types instantiated through remoting infrastructure
+
+// find the first constructor of t called
+let ctorCalled = t.Constructors.FirstOrDefault(ctor => ctor.NbMethodsCallingMe > 0)
+
+// match t if none of its constructors is called.
+where ctorCalled == null
+select new { t, t.Visibility }]]>
+ Methods should be declared static if possible
+warnif count > 0
+
+// When an instance method can be safely declared as static you should declare it as static.
+// Since it doesn't use any instance data and method of its type and base-types,
+// you should consider if such a method could be moved to a static utility class
+// or if it is strongly related enough to its current declaring type to stay in it.
+//
+// Turning an instance method into a static method is a micro performance optimization
+// since a static method is a bit cheaper to invoke than an instance method.
+
+from t in JustMyCode.Types.Where(t =>
+ !t.IsStatic && !t.IsInterface &&
+ !t.IsEnumeration && !t.IsDelegate &&
+ !t.IsGeneratedByCompiler)
+
+let methodsThatCanBeMadeStatic =
+ from m in t.InstanceMethods
+
+ // An instance method can be turned to static if it is not virtual,
+ // not using the this reference and also, not using
+ // any of its class or base classes instance fields or instance methods.
+ where !m.IsAbstract && !m.IsVirtual &&
+ !m.AccessThis && !m.IsExplicitInterfaceImpl &&
+
+ // Optimization: Using FirstOrDefault() avoid to check all members,
+ // as soon as one member is found
+ // we know the method m cannot be made static.
+ m.MembersUsed.FirstOrDefault(
+ mUsed => !mUsed.IsStatic &&
+ (mUsed.ParentType == t ||
+ t.DeriveFrom(mUsed.ParentType))
+ ) == null
+ select m
+
+from m in methodsThatCanBeMadeStatic
+let staticFieldsUsed = m.ParentType.StaticFields.UsedBy(m).Where(f => !f.IsGeneratedByCompiler)
+select new { m, staticFieldsUsed }]]>
+ Constructor should not call a virtual methods
+
+// Returns constructor of a non-sealed type calling virtual methods.
+// In such a situation, if a derived class overrides the method,
+// then the override method will be called before the derived constructor.
+// This makes the class fragile to derive from.
+//
+// Violations reported can be solved by re-designing object initialisation
+// or by marking the parent class as sealed, if possible.
+
+warnif count > 0
+from t in Application.Types where
+ t.IsClass &&
+ !t.IsGeneratedByCompiler &&
+ !t.IsSealed
+
+from ctor in t.Constructors
+let virtualMethodsCalled = from mCalled in ctor.MethodsCalled
+ where mCalled.IsVirtual &&
+ (mCalled.ParentType == t ||
+ t.DeriveFrom(mCalled.ParentType))
+ select mCalled
+where virtualMethodsCalled.Count() > 0
+
+select new { ctor ,
+ virtualMethodsCalled,
+ // If there is no derived type, it might be
+ // an opportunity to mark t as sealed.
+ t.DerivedTypes }]]>
+ Avoid the Singleton pattern
+warnif count > 0
+from t in Application.Types
+where !t.IsStatic && !t.IsAbstract && (t.IsClass || t.IsStructure)
+
+// All ctors of a singleton are private
+where t.Constructors.Where(ctor => !ctor.IsPrivate).Count() == 0
+
+// A singleton contains one static field of its parent type, to reference the unique instance
+let staticFieldInstances = t.StaticFields.WithFieldType(t)
+where staticFieldInstances.Count() == 1
+select new { t, staticFieldInstance = staticFieldInstances.First() }
+
+// The Singleton pattern consists in syntactically enforcing that a class
+// has just one unique instance.
+// At first glance, this pattern looks appealing and it is widely used.
+// However, we discourage you from using singleton classes because experience
+// shows that singletons often result in less testable and less maintainable code.
+// More details available in these discussions:
+// http://codebetter.com/patricksmacchia/2011/05/04/back-to-basics-usage-of-static-members/
+// http://adamschepis.com/blog/2011/05/02/im-adam-and-im-a-recovering-singleton-addict/
+]]>
+ Don't assign static fields from instance methods
+// Assigning static fields from instance methods leads to
+// poorly maintainable and non thread-safe code.
+// It is advised to assign static fields inline or from class constructor.
+warnif count > 0
+from f in Application.Fields where
+ f.IsStatic &&
+ !f.IsLiteral &&
+ !f.IsInitOnly &&
+ !f.IsGeneratedByCompiler &&
+ // Contract API define such a insideContractEvaluation static field
+ f.Name != "insideContractEvaluation"
+let assignedBy = f.MethodsAssigningMe.Where(m => !m.IsStatic)
+where assignedBy .Count() > 0
+select new { f, assignedBy }]]>
+ Avoid empty interfaces
+warnif count > 0 from t in JustMyCode.Types where
+ t.IsInterface &&
+ t.NbMethods == 0
+select new { t, t.TypesThatImplementMe }
+
+// Interfaces define members that provide a behavior
+// or usage contract. The functionality described by
+// the interface can be adopted by any type,
+// regardless of where the type appears in the
+// inheritance hierarchy. A type implements an
+// interface by providing implementations for the
+// interface's members. An empty interface does not
+// define any members, and as such, does not define
+// a contract that can be implemented.
+
+// If your design includes empty interfaces that
+// types are expected to implement, you are probably
+// using an interface as a marker, or a way of
+// identifying a group of types. If this identification
+// will occur at runtime, the correct way to accomplish
+// this is to use a custom attribute. Use the presence
+// or absence of the attribute, or the attribute's
+// properties, to identify the target types. If the
+// identification must occurs at compile time, then using
+// an empty interface is acceptable.]]>
+ Avoid types initialization cycles
+warnif count > 0
+
+// The class constructor (also called static constructor, and named cctor in IL code)
+// of a type, if any, is executed by the CLR at runtime, the first time the type is used.
+// A cctor doesn't need to be explicitely declared in C# or VB.NET, to exist in compiled IL code.
+// Having a static field inline initialization is enought to have
+// the cctor implicitely declared in the parent class or structure.
+//
+// If the cctor of a type t1 is using the type t2 and if the cctor of t2 is using t1,
+// some type initialization unexpected and hard-to-diagnose buggy behavior can occur.
+// Such a cyclic chain of initialization is not necessarily limited to two types
+// and can embrace N types in the general case.
+// More information on types initialization cycles can be found here:
+// http://msmvps.com/blogs/jon_skeet/archive/2012/04/07/1808561.aspx
+
+// The present code rule enumerates types initialization cycles.
+// Some false positives can appear if some lambda expressions are defined
+// in cctors or in methods called by cctors. In such situation, this rule
+// considers these lambda expressions as executed at type initialization time,
+// while it is not necessarily the case.
+
+// Types initialization cycle can only happen between types of an assembly.
+from assembly in Application.Assemblies
+
+let cctorSuspects = assembly.ChildMethods.Where(
+ m => m.IsClassConstructor &&
+ // Optimization: types involved in a type cycle necessarily don't have type level.
+ m.ParentType.Level == null)
+
+where cctorSuspects.Count() > 1
+let typesSuspects = cctorSuspects.ParentTypes().ToHashSet()
+
+//
+// dicoTmp associates to each type suspect T, a set of types from typesSuspects
+// that contains at least a method or a field used directly or indirectly by the cctor of T.
+//
+let dicoTmp = cctorSuspects.ToDictionary(
+ cctor => cctor.ParentType,
+ cctor => ((IMember)cctor).ToEnumerable().FillIterative(
+ members => from m in members
+ from mUsed in (m is IMethod) ? (m as IMethod).MembersUsed : new IMember[0]
+ where mUsed.ParentAssembly == assembly
+ select mUsed)
+ .DefinitionDomain
+ .Select(m => m.ParentType) // Don't need .Distinct() here, because of ToHashSet() below.
+ .Except(cctor.ParentType)
+ .Intersect(typesSuspects)
+ .ToHashSet()
+)
+
+//
+// dico associates to each type suspect T, the set of types initialized (directly or indirectly)
+// by the initialization of T. This second step is needed, because if a cctor of a type T1
+// calls a member of a type T2, not only the cctor of T1 triggers the initialization of T2,
+// but also it triggers the initialization of all types that are initialized by T2 initialization.
+//
+let dico = typesSuspects.Where(t => dicoTmp[t].Count() > 0).ToDictionary(
+ typeSuspect => typeSuspect,
+ typeSuspect => typeSuspect.ToEnumerable().FillIterative(
+ types => from t in types
+ from tUsed in dicoTmp[t]
+ select tUsed)
+ .DefinitionDomain
+ .Except(typeSuspect)
+ .ToHashSet()
+)
+
+
+//
+// Now that dico is prepared, detect the cctor cycles
+//
+from t in dico.Keys
+
+ // Thanks to the work done to build dico, it is now pretty easy
+ // to spot types involved in an initialization cyle with t!
+ let usersAndUseds = from tTmp in dico[t]
+ where dico.ContainsKey(tTmp) && dico[tTmp].Contains(t)
+ select tTmp
+ where usersAndUseds.Count() > 0
+
+ // Here we've found type(s) both using and used by the suspect type.
+ // A cycle involving the type t is found!
+ let typeInitCycle = usersAndUseds.Append(t)
+
+
+ // Compute methodsCalled and fieldsUsed, useful to explore
+ // how a cctor involved in a type initialization cycle, triggers other type initialization.
+ let methodsCalledDepth = assembly.ChildMethods.DepthOfIsUsedBy(t.ClassConstructor)
+ let fieldsUsedDepth = assembly.ChildFields.DepthOfIsUsedBy(t.ClassConstructor)
+
+ let methodsCalled = methodsCalledDepth.DefinitionDomain.OrderBy(m => methodsCalledDepth[m]).ToArray()
+ let fieldsUsed = fieldsUsedDepth.DefinitionDomain.OrderBy(f => fieldsUsedDepth[f]).ToArray()
+
+// Use the tick box to: Group cctors methods By parent types
+select new { t.ClassConstructor,
+ cctorsCycle= typeInitCycle.Select(tTmp => tTmp.ClassConstructor),
+
+ // methodsCalled and fieldsUsed are members used directly and indirectly by the cctor.
+ // Export these members to the dependency graph (right click the cell Export/Append ... to the Graph)
+ // and see how the cctor trigger the initialization of other types
+ methodsCalled,
+ fieldsUsed
+}]]>
+
+
+ Avoid custom delegates
+
+// Prefer using one of the standard generic delegate type in
+// Predicate Func Action
+// instead of creating your own delegate type.
+// Not only the code using these custom delegates will become clearer,
+// but you'll be relieved from the maintenance of these delegate types.
+//
+// Notice that delegate that are consumed by DllImport extern methods
+// must not be converted, else this could provoke marshalling issues.
+
+warnif count > 0
+from t in Application.Types where t.IsDelegate
+
+let invokeMethod = (from m in t.Methods where m.SimpleName == "Invoke" select m).Single()
+let signature1 = invokeMethod.Name.Substring(invokeMethod.SimpleName.Length, invokeMethod.Name.Length - invokeMethod.SimpleName.Length)
+
+// 'ref' and 'out' parameters canot be supported
+where !signature1.Contains("&")
+
+let signature2 = signature1.Replace("(","<").Replace(")",">")
+let signature3 = signature2 == "<>" ? "" : signature2
+let resultTypeName = invokeMethod.ReturnType == null ? "????" :
+ invokeMethod.ReturnType.FullName == "System.Void" ? "" :
+ invokeMethod.ReturnType.Name
+let replaceWith = resultTypeName == "Boolean" ?
+ "Predicate" + signature3 : resultTypeName == "" ?
+ "Action" + signature3 :
+ "Func" + signature3.Replace(">", "," + resultTypeName + ">")
+
+
+select new { t, replaceWith }]]>
+ Types with disposable instance fields must be disposable
+warnif count > 0
+
+let iDisposable = ThirdParty.Types.WithFullName("System.IDisposable").FirstOrDefault()
+where iDisposable != null // iDisposable can be null if the code base doesn't use at all System.IDisposable
+
+from t in Application.Types where
+ !t.Implement(iDisposable) &&
+ !t.IsGeneratedByCompiler
+
+let instanceFieldsDisposable =
+ t.InstanceFields.Where(f => f.FieldType != null &&
+ f.FieldType.Implement(iDisposable))
+
+where instanceFieldsDisposable.Count() > 0
+select new { t, instanceFieldsDisposable }]]>
+ Disposable types with unmanaged resources should declare finalizer
+// warnif count > 0
+let iDisposable = ThirdParty.Types.WithFullName("System.IDisposable").SingleOrDefault()
+where iDisposable != null // iDisposable can be null if the code base doesn't use at all System.IDisposable
+
+let disposableTypes = Application.Types.ThatImplement(iDisposable)
+let unmanagedResourcesFields = disposableTypes.ChildFields().Where(f =>
+ !f.IsStatic &&
+ f.FieldType != null &&
+ f.FieldType.FullName.EqualsAny("System.IntPtr","System.UIntPtr","System.Runtime.InteropServices.HandleRef")).ToHashSet()
+let disposableTypesWithUnmanagedResource = unmanagedResourcesFields.ParentTypes()
+
+from t in disposableTypesWithUnmanagedResource
+where !t.HasFinalizer
+let unmanagedResourcesTypeFields = unmanagedResourcesFields.Intersect(t.InstanceFields)
+select new { t, unmanagedResourcesTypeFields }]]>
+ Classes that are candidate to be turned into structures
+//
+// CAUTION: Before applying this rule, make sure to understand
+// the implication of transforming a class into a structure.
+// http://msdn.microsoft.com/en-us/library/aa664471(v=vs.71).aspx
+//
+// Int32, Double or Boolean are structures and not classes.
+// Structure are particularly suited to implement lightweight values.
+// Hence a class is candidate to be turned into a structure
+// when its instances are lightweight values.
+//
+warnif count > 0 from t in JustMyCode.Types where
+ t.IsClass &&
+ !t.IsGeneratedByCompiler &&
+ !t.IsStatic &&
+ t.SizeOfInst > 0 &&
+ t.SizeOfInst <= 16 && // Structure instance must not be too big,
+ // else it degrades performance.
+
+ t.NbChildren == 0 && // Must not have children
+
+ // Must not implement interfaces to avoid boxing mismatch
+ // when structures implements interfaces.
+ t.InterfacesImplemented.Count() == 0 &&
+
+ // Must have no base class
+ t.DepthOfDeriveFrom("System.Object".AllowNoMatch()) == 1
+
+select new { t, t.SizeOfInst, t.InstanceFields } // Must derive directly from System.Object
+
+ // && t.IsSealed <-- You might want to add this condition
+ // to restraint the set.
+ // && t.IsImmutable <-- Structures should be immutable type.
+ // && t.!IsPublic <-- You might want to add this condition if
+ // you are developping a framework with classes
+ // that are intended to be sub-classed by
+ // your clients.
+ ]]>
+ Avoid namespaces with few types
+warnif count > 0 from n in JustMyCode.Namespaces
+let types = n.ChildTypes.Where(t => !t.IsGeneratedByCompiler)
+where
+ types.Count() < 5
+ orderby types.Count() ascending
+select new { n, types }
+
+// Make sure that there is a logical organization
+// to each of your namespaces, and that there is a
+// valid reason for putting types in a sparsely
+// populated namespace. Namespaces should contain
+// types that are used together in most scenarios.
+// When their applications are mutually exclusive,
+// types should be located in separate namespaces]]>
+ Nested types should not be visible
+warnif count > 0 from t in JustMyCode.Types where
+ t.IsNested &&
+ !t.IsGeneratedByCompiler &&
+ !t.IsPrivate
+select new { t, t.NbLinesOfCode, t.Visibility }
+
+
+// A nested type is a type declared within the
+// scope of another type. Nested types are useful
+// for encapsulating private implementation details
+// of the containing type. Used for this purpose,
+// nested types should not be externally visible.
+// Do not use externally visible nested types for
+// logical grouping or to avoid name collisions;
+// instead, use namespaces.]]>
+ Declare types in namespaces
+warnif count > 0 from n in Application.Namespaces where
+ n.Name == ""
+select new { n, n.ChildTypes, n.NbLinesOfCode }
+
+// Types are declared within namespaces to
+// prevent name collisions, and as a way of
+// organizing related types in an object hierarchy.
+// Types outside any named namespace are in a
+// global namespace that cannot be referenced
+// in code. If an anonymous namespace can be found,
+// it means that it contains types outside of namespaces.]]>
+ Empty static constructor can be discarded
+warnif count > 0 from m in Application.Methods where
+ m.IsClassConstructor &&
+ m.NbLinesOfCode == 0
+select m
+ ]]>
+ Instances size shouldn't be too big
+warnif count > 0 from t in JustMyCode.Types where
+ t.SizeOfInst > 64
+ orderby t.SizeOfInst descending
+select new { t, t.SizeOfInst, t.InstanceFields }
+
+// Types where SizeOfInst > 64 might degrade performance
+// (depending on the number of instances created at runtime)
+// and might be hard to maintain. However it is not a rule
+// since sometime there is no alternative (the size of
+// instances of the System.Net.NetworkInformation.SystemIcmpV6Statistics
+// standard class is 2064 bytes).
+// Notice that a class with a large SizeOfInst value
+// doesn't necessarily have a lot of instance fields.
+// It might derive from a class with a large SizeOfInst value.
+// See the definition of the SizeOfInst metric here
+// http://www.ndepend.com/Metrics.aspx#SizeOfInst]]>
+ Boxing/unboxing should be avoided
+warnif percentage > 5 from m in Application.Methods where
+ m.IsUsingBoxing ||
+ m.IsUsingUnboxing
+select new { m, m.NbLinesOfCode, m.IsUsingBoxing, m.IsUsingUnboxing }
+
+// Thanks to generics, boxing and unboxing should be rare.]]>
+ Attribute classes should be sealed
+warnif count > 0 from t in Application.Types where
+ t.IsAttributeClass &&
+ !t.IsSealed &&
+ !t.IsAbstract &&
+ t.IsPublic
+select new { t, t.NbLinesOfCode }
+
+// The .NET Framework class library provides methods
+// for retrieving custom attributes. By default,
+// these methods search the attribute inheritance
+// hierarchy; for example System.Attribute.GetCustomAttribute
+// searches for the specified attribute type, or any
+// attribute type that extends the specified attribute
+// type. Sealing the attribute eliminates the search
+// through the inheritance hierarchy, and can improve
+// performance.]]>
+ Don't use obsolete types, methods or fields
+warnif count > 0
+let obsoleteTypes = Types.Where(t => t.IsObsolete)
+let obsoleteMethods = Methods.Where(m => m.IsObsolete).ToHashSet()
+let obsoleteFields = Fields.Where(f => f.IsObsolete)
+
+from m in JustMyCode.Methods.UsingAny(obsoleteTypes).Union(
+ JustMyCode.Methods.UsingAny(obsoleteMethods)).Union(
+ JustMyCode.Methods.UsingAny(obsoleteFields))
+let obsoleteTypesUsed = obsoleteTypes.UsedBy(m)
+
+// Optimization: MethodsCalled + Intersect() is faster than using obsoleteMethods.UsedBy()
+let obsoleteMethodsUsed = m.MethodsCalled.Intersect(obsoleteMethods)
+let obsoleteFieldsUsed = obsoleteFields.UsedBy(m)
+select new { m, obsoleteTypesUsed, obsoleteMethodsUsed, obsoleteFieldsUsed }]]>
+ Don't forget to implement methods that throw NotImplementedException
+warnif count > 0
+from m in Application.Methods
+where m.CreateA("System.NotImplementedException".AllowNoMatch())
+select m]]>
+ Equals() should be overridden by types implementing the '==' operator
+warnif count > 0
+from m in Application.Methods where
+ m.IsOperator &&
+ m.SimpleName == "op_Equality"
+let equalsMethod = m.ParentType.InstanceMethods.Where(m0 => m0.Name == "Equals(Object)").SingleOrDefault()
+where equalsMethod == null
+select m
+]]>
+
+
+ Avoid namespaces mutually dependent
+warnif count > 0
+// Foreach pair of namespace mutually dependent, this rule lists pairs.
+// The pair { first, second } is formatted to show first namespace shouldn't use the second namespace.
+// The first/second order is inferred from the number of types used by each other.
+// The first namespace is using fewer types of the second.
+// It means the first namespace is certainly at a lower level in the architecture than the second.
+//
+// To explore the coupling between two namespaces mutually dependent:
+// 1) export the first namespace to the vertical header of the dependency matrix
+// 2) export the second namespace to the horizontal header of the dependency matrix
+// 3) double-click the black cell
+// 4) in the matrix command bar, click the button: Remove empty Row(s) en Column(s)
+// At this point, the dependency matrix shows types involved into the coupling.
+//
+// Following this rule is useful to avoid namespaces dependency cycles.
+// More on this in our white books relative to partitioning code.
+// http://www.ndepend.com/WhiteBooks.aspx
+
+
+// Optimization: restraint application assemblies set
+// If some namespaces are mutually dependent
+// - They must be declared in the same assembly
+// - The parent assembly must ContainsNamespaceDependencyCycle
+from assembly in Application.Assemblies.Where(a => a.ContainsNamespaceDependencyCycle != null && a.ContainsNamespaceDependencyCycle.Value)
+
+// hashset is used to avoid reporting both A <-> B and B <-> A
+let hashset = new HashSet()
+
+// Optimization: restraint namespaces set
+// If a namespace doesn't have a Level value, it must be in a dependency cycle
+// or it must be using directly or indirectly a dependency cycle.
+let namespacesSuspect = assembly.ChildNamespaces.Where(n => n.Level == null)
+
+from nA in namespacesSuspect
+
+// Select namespaces mutually dependent with nA
+let unused = hashset.Add(nA) // Populate hashset
+let namespacesMutuallyDependentWith_nA = nA.NamespacesUsed.Using(nA)
+ .Except(hashset) // <-- avoid reporting both A <-> B and B <-> A
+where namespacesMutuallyDependentWith_nA.Count() > 0
+
+from nB in namespacesMutuallyDependentWith_nA
+
+// nA and nB are mutually dependent
+// First select the one that shouldn't use the other.
+// The first namespace is inferred from the fact that it is using less types of the second.
+let typesOfBUsedByA = nB.ChildTypes.UsedBy(nA)
+let typesOfAUsedByB = nA.ChildTypes.UsedBy(nB)
+let first = (typesOfBUsedByA.Count() > typesOfAUsedByB.Count()) ? nB : nA
+let second = (first == nA) ? nB : nA
+let typesOfFirstUsedBySecond = (first == nA) ? typesOfAUsedByB : typesOfBUsedByA
+let typesOfSecondUsedByFirst = (first == nA) ? typesOfBUsedByA : typesOfAUsedByB
+select new { first, shouldntUse = second, typesOfFirstUsedBySecond, typesOfSecondUsedByFirst }
+]]>
+ Avoid namespaces dependency cycles
+warnif count > 0
+// This query lists all application namespace dependency cycles.
+// Each row shows a different cycle, prefixed with a namespace entangled in the cycle.
+//
+// To browse a cycle on the dependency graph or the dependency matrix, right click
+// a cycle cell and export the matched namespaces to the dependency graph or matrix!
+//
+// In the matrix, dependency cycles are represented with red squares and black cells.
+// To easily browse dependency cycles, the Matrix comes with an option:
+// --> Display Direct and Indirect Dependencies
+//
+// Read our white books relative to partitioning code,
+// to know more about namespaces dependency cycles, and why avoiding them
+// is a simple but efficient solution to architecture for your code base.
+// http://www.ndepend.com/WhiteBooks.aspx
+
+
+// Optimization: restraint application assemblies set
+// If some namespaces are mutually dependent
+// - They must be declared in the same assembly
+// - The parent assembly must ContainsNamespaceDependencyCycle
+from assembly in Application.Assemblies
+ .Where(a => a.ContainsNamespaceDependencyCycle != null &&
+ a.ContainsNamespaceDependencyCycle.Value)
+
+// Optimization: restraint namespaces set
+// A namespace involved in a cycle necessarily have a null Level.
+let namespacesSuspect = assembly.ChildNamespaces.Where(n => n.Level == null)
+
+// hashset is used to avoid iterating again on namespaces already caught in a cycle.
+let hashset = new HashSet()
+
+
+from suspect in namespacesSuspect
+ // By commenting in this line, the query matches all namespaces involved in a cycle.
+ where !hashset.Contains(suspect)
+
+ // Define 2 code metrics
+ // - Namespaces depth of is using indirectly the suspect namespace.
+ // - Namespaces depth of is used by the suspect namespace indirectly.
+ // Note: for direct usage the depth is equal to 1.
+ let namespacesUserDepth = namespacesSuspect.DepthOfIsUsing(suspect)
+ let namespacesUsedDepth = namespacesSuspect.DepthOfIsUsedBy(suspect)
+
+ // Select namespaces that are both using and used by namespaceSuspect
+ let usersAndUsed = from n in namespacesSuspect where
+ namespacesUserDepth[n] > 0 &&
+ namespacesUsedDepth[n] > 0
+ select n
+
+ where usersAndUsed.Count() > 0
+
+ // Here we've found namespace(s) both using and used by the suspect namespace.
+ // A cycle involving the suspect namespace is found!
+ let cycle = usersAndUsed.Append(suspect)
+
+ // Fill hashset with namespaces in the cycle.
+ // .ToArray() is needed to force the iterating process.
+ let unused1 = (from n in cycle let unused2 = hashset.Add(n) select n).ToArray()
+
+select new { suspect, cycle }
+]]>
+ Avoid partitioning the code base through many small library Assemblies
+warnif count > 10
+from a in Application.Assemblies where
+ ( a.NbLinesOfCode < 1000 ||
+ a.NbILInstructions < 7000 ) &&
+ a.FilePath.FileExtension.ToLower() == ".dll"
+select new { a, a.NbLinesOfCode, a.NbILInstructions }
+
+// Each .NET Assembly represents one or several physical file.
+// Having too many library .NET Assemblies is a symptom of
+// considering physical .NET Assemblies as logical components.
+// We advise having less, and bigger, .NET Assemblies
+// and using the concept of namespaces to define logical components.
+// Benefits are:
+// - Much faster compilation time
+// (compilation time divided by 10 wouldn't be surprising)
+// - Faster startup time for your program
+// - Easier deploiement thanks to less files to manage.
+// - If you are developing a Framework,
+// less .NET assemblies to reference and manage for your users
+//
+// More on this in our white books relative to partitioning code.
+// http://www.ndepend.com/WhiteBooks.aspx ]]>
+ UI layer shouldn't use directly DB types
+warnif count > 0
+
+// UI layer is made of types in namespaces using a UI framework
+let uiTypes = Application.Namespaces.UsingAny(Assemblies.WithNameIn("PresentationFramework", "System.Windows", "System.Windows.Forms", "System.Web")).ChildTypes()
+
+// You can easily customize this line to define what are DB types.
+let dbTypes = ThirdParty.Assemblies.WithNameIn("System.Data", "EntityFramework", "NHibernate").ChildTypes()
+ // Ideally even DataSet and associated, usage should be forbidden from UI layer:
+ // http://stackoverflow.com/questions/1708690/is-list-better-than-dataset-for-ui-layer-in-asp-net
+ .Except(ThirdParty.Types.WithNameIn("DataSet", "DataTable", "DataRow"))
+
+from uiType in uiTypes.UsingAny(dbTypes)
+let dbTypesUsed = dbTypes.Intersect(uiType.TypesUsed)
+select new { uiType, dbTypesUsed }]]>
+ UI layer shouldn't use directly DAL layer
+warnif count > 0
+
+// UI layer is made of types in namespaces using a UI framework
+let uiTypes = Application.Namespaces.UsingAny(Assemblies.WithNameIn("PresentationFramework", "System.Windows", "System.Windows.Forms", "System.Web")).ChildTypes()
+
+// Exclude commonly used DataSet and associated, from ADO.Net types
+// You can easily customize this line to define what are DB types.
+let dbTypes = ThirdParty.Assemblies.WithNameIn("System.Data", "EntityFramework", "NHibernate").ChildTypes()
+ .Except(ThirdParty.Types.WithNameIn("DataSet", "DataTable", "DataRow"))
+
+// DAL layer is made of types in namespaces using a DB framework
+// .ToHashSet() results to faster execution of dalTypes.Intersect(uiType.TypesIUse).
+let dalTypes = Application.Namespaces.UsingAny(dbTypes).ChildTypes().ToHashSet()
+
+from uiType in uiTypes.UsingAny(dalTypes)
+let dalTypesUsed = dalTypes.Intersect(uiType.TypesUsed)
+select new {
+ uiType,
+ // if dalTypesUsed is empty, it means that the uiType is part of the DAL
+ dalTypesUsed
+}]]>
+ Assemblies with poor cohesion (RelationalCohesion)
+warnif count > 0 from a in Application.Assemblies where
+ a.NbTypes > 20 && // Relational Cohesion metrics is relevant only if there are several types
+ (a.RelationalCohesion < 1.5 ||
+ a.RelationalCohesion > 4.0)
+select new { a, a.NbTypes, a.RelationalCohesion }
+
+// As classes inside an assembly should be strongly related,
+// the cohesion should be high. On the other hand, a value
+// which is too high may indicate over-coupling. A good range
+// for RelationalCohesion is 1.5 to 4.0.
+// See the definition of the RelationalCohesion metric here
+// http://www.ndepend.com/Metrics.aspx#RelationalCohesion]]>
+ Assemblies that don't satisfy the Abstractness/Instability principle
+warnif percentage > 15 from a in Application.Assemblies where
+ a.NormDistFromMainSeq > 0.7
+ orderby a.NormDistFromMainSeq descending
+select new { a, a.NormDistFromMainSeq }
+
+// See the definition of the NormDistFromMainSeq metric here
+// http://www.ndepend.com/Metrics.aspx#DitFromMainSeq]]>
+ Example of custom rule to check for dependency
+
+// To define a rule that warns if a particular dependency exist or not,
+// from a code element A to a code element B
+// A and B being an Assembly Namespace Type Method or Field,
+// A and B not necessarily two Assemblies or two Namespaces...
+// you can first, right click the cell in the Dependency Matrix
+// with B in row and A in column,
+// or right-click the concerned arrow in the Dependency Graph
+// from A to B, and choose to:
+// "Generate a code rule that warns if this dependency exists"
+//
+// The generated rule will look like the one below.
+// It is now up to you to adapt this rule to check your needs.
+
+warnif count > 0 from a in Assemblies
+where
+a.IsUsing("Foo1.Foo2".AllowNoMatch().MatchNamespace()) &&
+(a.Name == @"Foo3")
+select new { a, a.NbLinesOfCode }
+// the assembly Foo3
+// shouldn't use directly
+// the namespace Foo3.Foo4
+// because (TODO insert your reason)
+]]>
+ Higher cohesion - lower coupling
+// It is deemed as a good software architecture practice to clearly separate
+// 'abstract' namespaces containing only abstractions (interfaces, enumerations, delegates)
+// from other 'concrete' namespaces, that contains classes and structures.
+//
+// Typically, the more concrete namespaces rely on abstract namespaces *only*,
+// the more Decoupled is the architecture, and the more Cohesive are
+// classes inside concrete namespaces.
+//
+// The following code query, define sets of abstract and concrete namespaces
+// and shows for each concrete namespaces, which concrete and abstract namespaces are used.
+//
+// This query can be adapted to a rule, depending on how much you want
+// your code architecture being decoupled.
+//
+
+let abstractNamespaces = JustMyCode.Namespaces.Where(
+ n => n.ChildTypes.Where(t => !t.IsInterface && !t.IsEnumeration && !t.IsDelegate).Count() == 0
+).ToHashSet()
+
+let concreteNamespaces = JustMyCode.Namespaces.Except(abstractNamespaces).ToHashSet()
+
+from n in concreteNamespaces
+let namespacesUsed = n.NamespacesUsed.ExceptThirdParty()
+let concreteNamespacesUsed = namespacesUsed.Except(abstractNamespaces)
+let abstractNamespacesUsed = namespacesUsed.Except(concreteNamespaces)
+select new { n, concreteNamespacesUsed , abstractNamespacesUsed }]]>
+
+
+ API Breaking Changes: Types
+// This rule warns if a publicly visible type is
+// not publicly visible anymore or if it has been removed.
+// Such type can break the code of your clients.
+
+warnif count > 0 from t in codeBase.OlderVersion().Application.Types
+where t.IsPubliclyVisible &&
+
+ // The type has been removed and its parent assembly hasn't been removed ...
+ ( (t.WasRemoved() && !t.ParentAssembly.WasRemoved()) ||
+
+ // ... or the type is not publicly visible anymore
+ !t.WasRemoved() && !t.NewerVersion().IsPubliclyVisible)
+
+select new { t,
+ NewVisibility = (t.WasRemoved() ? " " : t.NewerVersion().Visibility.ToString()) }
+]]>
+ API Breaking Changes: Methods
+// This rule warns if a publicly visible method is
+// not publicly visible anymore or if it has been removed.
+// Such method can break the code of your clients.
+
+warnif count > 0 from m in codeBase.OlderVersion().Application.Methods
+where m.IsPubliclyVisible &&
+
+ // The method has been removed and its parent type hasn't been removed ...
+ ( (m.WasRemoved() && !m.ParentType.WasRemoved()) ||
+
+ // ... or the method is not publicly visible anymore
+ !m.WasRemoved() && !m.NewerVersion().IsPubliclyVisible)
+
+select new { m,
+ NewVisibility = (m.WasRemoved() ? " " : m.NewerVersion().Visibility.ToString()) }]]>
+ API Breaking Changes: Fields
+// This rule warns if a publicly visible field is
+// not publicly visible anymore or if it has been removed.
+// Such field can break the code of your clients.
+
+warnif count > 0 from f in codeBase.OlderVersion().Application.Fields
+where f.IsPubliclyVisible &&
+
+ // The field has been removed and its parent type hasn't been removed ...
+ ( (f.WasRemoved() && !f.ParentType.WasRemoved()) ||
+
+ // ... or the field is not publicly visible anymore
+ !f.WasRemoved() && !f.NewerVersion().IsPubliclyVisible)
+
+select new { f,
+ NewVisibility = (f.WasRemoved() ? " " : f.NewerVersion().Visibility.ToString()) }]]>
+ API Breaking Changes: Interfaces and Abstract Classes
+// This rule warns if a publicly visible interface or abstract class
+// has been changed and contains new abstract methods or
+// if some abstract methods have been removed.
+// This can break the code of clients
+// that implement such interface or derive from such abstract class.
+
+warnif count > 0 from tNewer in Application.Types where
+ (tNewer.IsInterface || tNewer.IsClass && tNewer.IsAbstract) &&
+ tNewer.IsPubliclyVisible &&
+ tNewer.IsPresentInBothBuilds()
+
+let tOlder = tNewer.OlderVersion() where tOlder.IsPubliclyVisible
+
+let methodsRemoved = tOlder.Methods.Where(m => m.IsAbstract && m.WasRemoved())
+let methodsAdded = tNewer.Methods.Where(m => m.IsAbstract && m.WasAdded())
+
+where methodsAdded.Count() > 0 || methodsRemoved.Count() > 0
+select new { tNewer, methodsAdded, methodsRemoved }]]>
+ Broken serializable types
+// Find breaking changes in types marked with SerializableAttribute.
+warnif count > 0
+
+from t in Application.Types where
+
+ // Collect types tagged with SerializableAttribute
+ t.HasAttribute("System.SerializableAttribute".AllowNoMatch()) &&
+ !t.IsDelegate &&
+ t.IsPresentInBothBuilds() &&
+ t.HasAttribute(t)
+
+ // Find newer and older versions of NonSerializedAttribute
+ let newNonSerializedAttribute = ThirdParty.Types.WithFullName("System.NonSerializedAttribute").SingleOrDefault()
+ let oldNonSerializedAttribute = newNonSerializedAttribute == null ? null : newNonSerializedAttribute.OlderVersion()
+
+ // Find added or removed fields not marked with NonSerializedAttribute
+ let addedInstanceField = from f in t.InstanceFields where
+ f.WasAdded() &&
+ (newNonSerializedAttribute == null || !f.HasAttribute(newNonSerializedAttribute))
+ select f
+ let removedInstanceField = from f in t.OlderVersion().InstanceFields where
+ f.WasRemoved() &&
+ (oldNonSerializedAttribute == null || !f.HasAttribute(oldNonSerializedAttribute))
+ select f
+ where addedInstanceField.Count() > 0 || removedInstanceField.Count() > 0
+
+select new { t, addedInstanceField, removedInstanceField }
+
+// From http://msdn.microsoft.com/library/system.serializableattribute.aspx :
+// All the public and private fields in a type that are marked by the
+// SerializableAttribute are serialized by default, unless the type
+// implements the ISerializable interface to override the serialization process.
+// The default serialization process excludes fields that are marked
+// with the NonSerializedAttribute attribute.]]>
+ Avoid transforming immutable types into mutable types
+
+// Immutability is a strong property on a type.
+// Breaking immutability can result in serious problem for an algorithm consummer
+// that has been written taking account of the type immutability.
+
+// To visualize changes in code, right-click a matched type and select:
+// - Compare older and newer versions of source file
+// - Compare older and newer versions disassembled with Reflector
+
+warnif count > 0
+from t in Application.Types where
+ t.IsPresentInBothBuilds() &&
+ !t.IsStatic &&
+ !t.IsImmutable &&
+ t.OlderVersion().IsImmutable
+
+let mutableFields = from f in t.InstanceFields where !f.IsImmutable select f
+
+select new { t, mutableFields }
+
+]]>
+ Avoid changing enumerations Flags status
+
+// Being tagged with the Flags attribute is a strong property for an enumeration.
+// Changing the Flags status of an enumeration has significant impact for its client.
+warnif count > 0
+
+let oldFlags = codeBase.OlderVersion().ThirdParty.Types.WithFullName("System.FlagsAttribute").SingleOrDefault()
+let newFlags = ThirdParty.Types.WithFullName("System.FlagsAttribute").SingleOrDefault()
+where oldFlags != null && newFlags != null
+
+from t in Application.Types where
+ t.IsEnumeration &&
+ t.IsPresentInBothBuilds()
+let isFlags = t.HasAttribute(newFlags)
+let wasFlags = t.OlderVersion().HasAttribute(oldFlags)
+where isFlags != wasFlags
+select new { t, isFlags, wasFlags }
+]]>
+ API: New publicly visible types
+// List types that are new in the public surface of your assemblies
+
+from t in Application.Types
+where t.IsPubliclyVisible &&
+
+ // The type has been removed and its parent assembly hasn't been removed ...
+ ( (t.WasAdded() && !t.ParentAssembly.WasAdded()) ||
+
+ // ... or the type existed but was not publicly visible
+ !t.WasAdded() && !t.OlderVersion().IsPubliclyVisible)
+
+select new { t,
+ OldVisibility = (t.WasAdded() ? " " : t.OlderVersion().Visibility.ToString()) }]]>
+ API: New publicly visible methods
+// List methods that are new in the public surface of your assemblies
+
+from m in Application.Methods
+where m.IsPubliclyVisible &&
+
+ // The method has been removed and its parent assembly hasn'm been removed ...
+ ( (m.WasAdded() && !m.ParentType.WasAdded()) ||
+
+ // ... or the t existed but was not publicly visible
+ !m.WasAdded() && !m.OlderVersion().IsPubliclyVisible)
+
+select new { m,
+ OldVisibility = (m.WasAdded() ? " " : m.OlderVersion().Visibility.ToString()) }]]>
+ API: New publicly visible fields
+// List fields that are new in the public surface of your assemblies
+
+from f in Application.Fields
+where f.IsPubliclyVisible &&
+
+ // The method has been removed and its parent assembly hasn'f been removed ...
+ ( (f.WasAdded() && !f.ParentType.WasAdded()) ||
+
+ // ... or the t existed but was not publicly visible
+ !f.WasAdded() && !f.OlderVersion().IsPubliclyVisible)
+
+select new { f,
+ OldVisibility = (f.WasAdded() ? " " : f.OlderVersion().Visibility.ToString()) }]]>
+
+
+ New assemblies
+from a in Application.Assemblies where a.WasAdded()
+select new { a, a.NbLinesOfCode }
+
+]]>
+ Assemblies removed
+from a in codeBase.OlderVersion().Application.Assemblies where a.WasRemoved()
+select new { a, a.NbLinesOfCode }]]>
+ Assemblies where code was changed
+from a in Application.Assemblies where a.CodeWasChanged()
+select new { a, a.NbLinesOfCode,
+ oldNbLinesOfCode = a.OlderVersion().NbLinesOfCode.GetValueOrDefault() ,
+ delta = (int) a.NbLinesOfCode.GetValueOrDefault() - a.OlderVersion().NbLinesOfCode.GetValueOrDefault() }]]>
+ New namespaces
+from n in Application.Namespaces where
+ !n.ParentAssembly.WasAdded() &&
+ n.WasAdded()
+select new { n, n.NbLinesOfCode }
+]]>
+ Namespaces removed
+from n in codeBase.OlderVersion().Application.Namespaces where
+ !n.ParentAssembly.WasRemoved() &&
+ n.WasRemoved()
+select new { n, n.NbLinesOfCode }
+]]>
+ Namespaces where code was changed
+from n in Application.Namespaces where n.CodeWasChanged()
+select new { n, n.NbLinesOfCode,
+ oldNbLinesOfCode = n.OlderVersion().NbLinesOfCode.GetValueOrDefault() ,
+ delta = (int) n.NbLinesOfCode.GetValueOrDefault() - n.OlderVersion().NbLinesOfCode.GetValueOrDefault() }]]>
+ New types
+from t in Application.Types where
+ !t.ParentNamespace.WasAdded() &&
+ t.WasAdded()
+select new { t, t.NbLinesOfCode }
+]]>
+ Types removed
+from t in codeBase.OlderVersion().Application.Types where
+ !t.ParentNamespace.WasRemoved() &&
+ t.WasRemoved()
+select new { t, t.NbLinesOfCode }
+]]>
+ Types where code was changed
+// To visualize changes in code, right-click a matched type and select:
+// - Compare older and newer versions of source file
+// - Compare older and newer versions disassembled with Reflector
+
+from t in Application.Types where t.CodeWasChanged()
+//select new { t, t.NbLinesOfCode }
+select new { t, t.NbLinesOfCode,
+ oldNbLinesOfCode = t.OlderVersion().NbLinesOfCode ,
+ delta = (int?) t.NbLinesOfCode - t.OlderVersion().NbLinesOfCode }
+/*from t in Application.Types where t.CodeWasChanged() && t.IsPresentInBothBuild
+select new { t, t.NbLinesOfCode,
+ oldNbLinesOfCode = t.OlderVersion().NbLinesOfCode ,
+ delta = (int) t.NbLinesOfCode - t.OlderVersion().NbLinesOfCode }*/]]>
+ Heuristic to find types moved from one namespace or assembly to another
+let typesRemoved = codeBase.OlderVersion().Types.Where(t => t.WasRemoved())
+let typesAdded = Types.Where(t => t.WasAdded())
+
+from tMoved in typesAdded.Join(
+ typesRemoved,
+ t => t.Name,
+ t => t.Name,
+ (tNewer, tOlder) => new { tNewer,
+ OlderParentNamespace = tOlder.ParentNamespace,
+ OlderParentAssembly = tOlder.ParentAssembly } )
+select tMoved]]>
+ Types directly using one or several types changed
+let typesChanged = Application.Types.Where(t => t.CodeWasChanged()).ToHashSet()
+
+from t in JustMyCode.Types.UsingAny(typesChanged) where
+ !t.CodeWasChanged() &&
+ !t.WasAdded()
+let typesChangedUsed = t.TypesUsed.Intersect(typesChanged)
+select new { t, typesChangedUsed }]]>
+ Types indirectly using one or several types changed
+let typesChanged = Application.Types.Where(t => t.CodeWasChanged()).ToHashSet()
+
+// 'depth' represents a code metric defined on types using
+// directly or indirectly any type where code was changed.
+let depth = JustMyCode.Types.DepthOfIsUsingAny(typesChanged)
+
+from t in depth.DefinitionDomain where
+ !t.CodeWasChanged() &&
+ !t.WasAdded()
+
+let typesChangedDirectlyUsed = t.TypesUsed.Intersect(typesChanged)
+let depthOfUsingTypesChanged = depth[t]
+orderby depthOfUsingTypesChanged
+
+select new { t, depthOfUsingTypesChanged, typesChangedDirectlyUsed }]]>
+ New methods
+from m in Application.Methods where
+ !m.ParentType.WasAdded() &&
+ m.WasAdded()
+select new { m, m.NbLinesOfCode }
+]]>
+ Methods removed
+from m in codeBase.OlderVersion().Application.Methods where
+ !m.ParentType.WasRemoved() &&
+ m.WasRemoved()
+select new { m, m.NbLinesOfCode }
+]]>
+ Methods where code was changed
+// To visualize changes in code, right-click a matched method and select:
+// - Compare older and newer versions of source file
+// - Compare older and newer versions disassembled with Reflector
+
+from m in Application.Methods where m.CodeWasChanged()
+select new { m, m.NbLinesOfCode,
+ oldNbLinesOfCode = m.OlderVersion().NbLinesOfCode ,
+ delta = (int?) m.NbLinesOfCode - m.OlderVersion().NbLinesOfCode }]]>
+ Methods directly calling one or several methods changed
+let methodsChanged = Application.Methods.Where(m => m.CodeWasChanged()).ToHashSet()
+
+from m in JustMyCode.Methods.UsingAny(methodsChanged ) where
+ !m.CodeWasChanged() &&
+ !m.WasAdded()
+let methodsChangedCalled = m.MethodsCalled.Intersect(methodsChanged)
+select new { m, methodsChangedCalled }]]>
+ Methods indirectly calling one or several methods changed
+let methodsChanged = Application.Methods.Where(m => m.CodeWasChanged()).ToHashSet()
+
+// 'depth' represents a code metric defined on methods using
+// directly or indirectly any method where code was changed.
+let depth = JustMyCode.Methods.DepthOfIsUsingAny(methodsChanged)
+
+from m in depth.DefinitionDomain where
+ !m.CodeWasChanged() &&
+ !m.WasAdded()
+
+let methodsChangedDirectlyUsed = m.MethodsCalled.Intersect(methodsChanged)
+let depthOfUsingMethodsChanged = depth[m]
+orderby depthOfUsingMethodsChanged
+
+select new { m, depthOfUsingMethodsChanged, methodsChangedDirectlyUsed }]]>
+ New fields
+from f in Application.Fields where
+ !f.ParentType.WasAdded() &&
+ f.WasAdded()
+select new { f }
+]]>
+ Fields removed
+from f in codeBase.OlderVersion().Application.Fields where
+ !f.ParentType.WasRemoved() &&
+ f.WasRemoved()
+select new { f }
+]]>
+ Third party types that were not used and that are now used
+from t in ThirdParty.Types where t.IsUsedRecently()
+select new { t, t.Methods, t.Fields, t.TypesUsingMe }
+]]>
+ Third party types that were used and that are not used anymore
+from t in codeBase.OlderVersion().Types where t.IsNotUsedAnymore()
+select new { t, t.Methods, t.Fields, TypesThatUsedMe = t.TypesUsingMe }
+]]>
+ Third party methods that were not used and that are now used
+from m in ThirdParty.Methods where
+ m.IsUsedRecently() &&
+ !m.ParentType.IsUsedRecently()
+select new { m, m.MethodsCallingMe }]]>
+ Third party methods that were used and that are not used anymore
+from m in codeBase.OlderVersion().Methods where
+ m.IsNotUsedAnymore() &&
+ !m.ParentType.IsNotUsedAnymore()
+select new { m, MethodsThatCalledMe = m.MethodsCallingMe}]]>
+ Third party fields that were not used and that are now used
+from f in ThirdParty.Fields where
+ f.IsUsedRecently() &&
+ !f.ParentType.IsUsedRecently()
+select new { f, f.MethodsUsingMe }]]>
+ Third party fields that were used and that are not used anymore
+from f in codeBase.OlderVersion().Fields where
+ f.IsNotUsedAnymore() &&
+ !f.ParentType.IsNotUsedAnymore()
+select new { f, MethodsThatUsedMe = f.MethodsUsingMe }]]>
+
+
+ C.R.A.P method code metric
+// Change Risk Analyzer and Predictor (i.e. CRAP) code metric
+// This code metric helps in pinpointing overly complex and untested code.
+// Reference: http://www.artima.com/weblogs/viewpost.jsp?thread=215899
+// Formula: CRAP(m) = comp(m)^2 * (1 – cov(m)/100)^3 + comp(m)
+warnif count > 0
+from m in JustMyCode.Methods
+
+// Don't match too short methods
+where m.NbLinesOfCode > 10
+
+let CC = m.CyclomaticComplexity
+let uncov = (100 - m.PercentageCoverage) / 100f
+let CRAP = (CC * CC * uncov * uncov * uncov) + CC
+where CRAP != null && CRAP > 30
+orderby CRAP descending, m.NbLinesOfCode descending
+select new { m, CRAP, CC, uncoveredPercentage = uncov*100, m.NbLinesOfCode }]]>
+ Complex methods partially covered by tests should be 100% covered
+warnif count > 0 from m in JustMyCode.Methods
+ where
+ // These metrics' definitions are available here:
+ // http://www.ndepend.com/Metrics.aspx#MetricsOnMethods
+ ( m.NbLinesOfCode > 30 ||
+ m.ILCyclomaticComplexity > 50 ||
+ m.ILNestingDepth > 4 ||
+ m.NbVariables > 8) &&
+
+ // Take care only of complex methods
+ // already partially covered, but not completely covered.
+ m.PercentageCoverage > 0 &&
+ m.PercentageCoverage < 100
+
+ orderby m.NbLinesOfCodeNotCovered ascending,
+ m.NbLinesOfCode descending
+select new { m, m.PercentageCoverage, m.NbLinesOfCode,
+ m.NbLinesOfCodeCovered, m.NbLinesOfCodeNotCovered,
+ m.ILCyclomaticComplexity, m.ILNestingDepth, m.NbVariables } ]]>
+ Method changed poorly covered
+from m in Application.Methods where
+ m.PercentageCoverage < 30 &&
+ m.CodeWasChanged()
+ orderby m.NbLinesOfCode descending,
+ m.NbLinesOfCodeNotCovered ,
+ m.PercentageCoverage
+select new { m, m.PercentageCoverage, m.NbLinesOfCode,
+ m.NbLinesOfCodeNotCovered }
+]]>
+ Method added poorly covered
+from m in Application.Methods where
+ m.NbLinesOfCode > 0 &&
+ m.PercentageCoverage < 30 &&
+ m.WasAdded()
+ orderby m.NbLinesOfCode descending,
+ m.NbLinesOfCodeNotCovered ,
+ m.PercentageCoverage
+select new { m, m.PercentageCoverage, m.NbLinesOfCode,
+ m.NbLinesOfCodeNotCovered }
+]]>
+ Types 95% to 99% covered
+from t in Application.Types where
+ t.PercentageCoverage >= 95 &&
+ t.PercentageCoverage <= 99 &&
+ !t.IsGeneratedByCompiler
+
+ let methodsCulprit = t.Methods.Where(m => m.PercentageCoverage < 100)
+
+ orderby t.NbLinesOfCode descending ,
+ t.NbLinesOfCodeNotCovered ,
+ t.PercentageCoverage
+select new { t, t.PercentageCoverage, t.NbLinesOfCode,
+ t.NbLinesOfCodeNotCovered, methodsCulprit }
+
+// Having types 100% covered by tests is a good idea because
+// the small portion of code hard to cover, is also the
+// portion of code that is the most likely to contain bugs.
+]]>
+ Namespaces 95% to 99% covered
+from n in Application.Namespaces where
+ n.PercentageCoverage >= 95 &&
+ n.PercentageCoverage <= 99
+
+ let methodsCulprit = n.ChildMethods.Where(m => m.PercentageCoverage < 100)
+
+ orderby n.NbLinesOfCode descending ,
+ n.NbLinesOfCodeNotCovered ,
+ n.PercentageCoverage
+select new { n, n.PercentageCoverage, n.NbLinesOfCode,
+ n.NbLinesOfCodeNotCovered, methodsCulprit }
+
+// Having types 100% covered by tests is a good idea because
+// the small portion of code hard to cover, is also the
+// portion of code that is the most likely to contain bugs.]]>
+ Types tagged with FullCoveredAttribute should be 100% covered
+warnif count > 0
+from t in Application.Types where
+ t.HasAttribute ("NDepend.Attributes.FullCoveredAttribute".AllowNoMatch()) &&
+ t.PercentageCoverage < 100
+
+let notFullCoveredMethods = t.Methods.Where(
+ m => m.NbLinesOfCode> 0 &&
+ m.PercentageCoverage < 100 &&
+ !m.HasAttribute("NDepend.Attributes.UncoverableByTestAttribute".AllowNoMatch()))
+
+orderby t.NbLinesOfCodeNotCovered descending
+
+select new { t, t.PercentageCoverage, t.NbLinesOfCodeNotCovered, notFullCoveredMethods,
+ t.NbLinesOfCode, t.NbLinesOfCodeCovered }
+
+// By using a FullCoveredAttribute, you can signify to developers
+// that a class is, and must remain in the future, 100% covered by tests.
+// If you don't want to link NDepend.API.dll,
+// you can use your own attribute and adapt this rule.
+
+// Having types 100% covered by tests is a good idea because
+// the small portion of code hard to cover, is also the
+// portion of code that is the most likely to contain bugs.
+]]>
+ Types 100% covered should be tagged with FullCoveredAttribute
+warnif count > 0 from t in JustMyCode.Types where
+ !t.HasAttribute ("NDepend.Attributes.FullCoveredAttribute".AllowNoMatch()) &&
+ t.PercentageCoverage == 100 &&
+ !t.IsGeneratedByCompiler
+select new { t, t.NbLinesOfCode }
+
+// By using a FullCoveredAttribute, you can signify to developers
+// that a class is, and must remain in the future, 100% covered by tests.
+// If you don't want to link NDepend.API.dll, you can use your own attribute and adapt this rule.
+
+// Having types 100% covered by tests is a good idea because
+// the small portion of code hard to cover, is also the
+// portion of code that is the most likely to contain bugs.
+]]>
+ Types not covered at all
+from t in Application.Types where
+ t.PercentageCoverage == 0
+ orderby t.NbLinesOfCode descending
+select new { t, t.NbLinesOfCode }
+]]>
+ Namespaces not covered at all
+from n in Application.Namespaces where
+ n.PercentageCoverage == 0
+ orderby n.NbLinesOfCode descending
+select new { n, n.NbLinesOfCode}
+]]>
+ Test Methods
+
+// We advise to not include test assemblies in code analyzed by NDepend.
+// But if you wish the current query to run properly,
+// you'll need to consider test assemblies in your list of application assemblies analyzed by NDepend..
+
+let testAttr = ThirdParty.Types.WithNameIn("TestAttribute", "TestCaseAttribute")
+let testMethods = Methods.TaggedWithAnyAttributes(testAttr)
+from m in testMethods
+select m
+]]>
+ Methods directly called by test Methods
+
+// Lists all methods directly called by tests methods.
+// Overrides of virtual and absract methods, called through polymorphism, are not listed.
+// Methods solely invoked through a delegate are not listed.
+// Methods solely invoked through reflection are not listed.
+
+// We advise to not include test assemblies in code analyzed by NDepend.
+// But if you wish the current query to run properly,
+// you'll need to consider test assemblies in your list of application assemblies analyzed by NDepend..
+
+let testAttr = ThirdParty.Types.WithNameIn("TestAttribute", "TestCaseAttribute")
+let testMethods = Methods.TaggedWithAnyAttributes(testAttr).ToHashSet()
+
+// --- Uncomment this line if your test methods are in dedicated test assemblies ---
+//let testAssemblies = testMethods.ParentAssemblies().ToHashSet()
+
+from m in Application.Methods.UsedByAny(testMethods)
+
+// --- Uncomment this line if your test methods are in dedicated test assemblies ---
+//where !testAssemblies.Contains(m.ParentAssembly)
+
+select new { m ,
+ calledByTests = m.MethodsCallingMe.Intersect(testMethods ),
+ // --- Uncomment this line if your project import some coverage data ---
+ // m.PercentageCoverage
+}]]>
+ Methods directly and indirectly called by test Methods
+
+// Lists all methods called directly or indirectly by tests methods.
+// Overrides of virtual and absract methods, called through polymorphism, are not listed.
+// Methods solely invoked through a delegate are not listed.
+// Methods solely invoked through reflection are not listed.
+
+// We advise to not include test assemblies in code analyzed by NDepend.
+// But if you wish the current query to run properly,
+// you'll need to consider test assemblies in your list of application assemblies analyzed by NDepend.
+
+let testAttr = from t in ThirdParty.Types.WithNameIn("TestAttribute", "TestCaseAttribute") select t
+let testMethods = Methods.TaggedWithAnyAttributes(testAttr)
+
+// --- Uncomment this line if your test methods are in dedicated test assemblies ---
+// let testAssemblies = testMethods.ParentAssemblies().ToHashSet()
+
+let depthOfCalledByTest = Application.Methods.DepthOfIsUsedByAny(testMethods)
+from pair in depthOfCalledByTest
+where pair.Value > 0
+orderby pair.Value ascending
+// --- Uncomment this line if your test methods are in dedicated test assemblies ---
+//&& !testAssemblies.Contains(pair.CodeElement.ParentAssembly)
+
+select new {
+ method = pair.CodeElement,
+ // (depthOfCalledByTests == 1) means that the method is directly called by tests
+ // (depthOfCalledByTests == 2) means that the method is directly called by a method directly called by tests
+ // ...
+ depthOfCalledByTests = pair.Value,
+ // --- Uncomment this line if your project import some coverage data ---
+ // m.PercentageCoverage
+}]]>
+
+
+ Potentially dead Types
+warnif count > 0
+// Filter procedure for types that should'nt be considered as dead
+let canTypeBeConsideredAsDeadProc = new Func(
+ t => !t.IsPublic && // Public types might be used by client applications of your assemblies.
+ t.Name != "Program" &&
+ !t.IsGeneratedByCompiler &&
+
+ // If you don't want to link NDepend.API.dll, you can use your own IsNotDeadCodeAttribute and adapt this rule.
+ !t.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
+
+ // Exclude static types that define only const fields
+ // because they cannot be seen as used in IL code.
+ !(t.IsStatic && t.NbMethods == 0 && !t.Fields.Where(f => !f.IsLiteral).Any()))
+
+
+// Select types unused
+let typesUnused =
+ from t in JustMyCode.Types where
+ t.NbTypesUsingMe == 0 && canTypeBeConsideredAsDeadProc(t)
+ select t
+
+// Dead types = types used only by unused types (recursive)
+let deadTypesMetric = typesUnused.FillIterative(
+types => from t in codeBase.Application.Types.UsedByAny(types).Except(types)
+ where canTypeBeConsideredAsDeadProc(t) &&
+ t.TypesUsingMe.Intersect(types).Count() == t.NbTypesUsingMe
+ select t)
+
+from t in deadTypesMetric.DefinitionDomain
+select new { t, t.TypesUsingMe, depth = deadTypesMetric[t] }]]>
+ Potentially dead Methods
+warnif count > 0
+// Filter procedure for methods that should'nt be considered as dead
+let canMethodBeConsideredAsDeadProc = new Func(
+ m => !m.IsPubliclyVisible && // Public methods might be used by client applications of your assemblies.
+ !m.IsEntryPoint && // Main() method is not used by-design.
+ !m.IsExplicitInterfaceImpl && // The IL code never explicitely calls explicit interface methods implementation.
+ !m.IsClassConstructor && // The IL code never explicitely calls class constructors.
+ !m.IsFinalizer && // The IL code never explicitely calls finalizers.
+ !m.IsVirtual && // Only check for non virtual method that are not seen as used in IL.
+ !(m.IsConstructor && // Don't take account of protected ctor that might be call by a derived ctors.
+ m.IsProtected) &&
+ !m.IsEventAdder && // The IL code never explicitely calls events adder/remover.
+ !m.IsEventRemover &&
+ !m.IsGeneratedByCompiler &&
+ !m.ParentType.IsDelegate &&
+
+ // Methods tagged with these two attributes are called by the serialization infrastructure.
+ !m.HasAttribute("System.Runtime.Serialization.OnSerializingAttribute".AllowNoMatch()) &&
+ !m.HasAttribute("System.Runtime.Serialization.OnDeserializedAttribute".AllowNoMatch()) &&
+
+ // If you don't want to link NDepend.API.dll, you can use your own IsNotDeadCodeAttribute and adapt this rule.
+ !m.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()))
+
+// Get methods unused
+let methodsUnused =
+ from m in JustMyCode.Methods where
+ m.NbMethodsCallingMe == 0 &&
+ canMethodBeConsideredAsDeadProc(m)
+ select m
+
+// Dead methods = methods used only by unused methods (recursive)
+let deadMethodsMetric = methodsUnused.FillIterative(
+ methods => // Unique loop, just to let a chance to build the hashset.
+ from o in (new object()).ToEnumerable()
+ // Use a hashet to make Intersect calls much faster!
+ let hashset = methods.ToHashSet()
+ from m in codeBase.Application.Methods.UsedByAny(methods).Except(methods)
+ where canMethodBeConsideredAsDeadProc(m) &&
+ // Select methods called only by methods already considered as dead
+ hashset.Intersect(m.MethodsCallingMe).Count() == m.NbMethodsCallingMe
+ select m)
+
+from m in JustMyCode.Methods.Intersect(deadMethodsMetric.DefinitionDomain)
+select new { m, m.MethodsCallingMe, depth = deadMethodsMetric[m] }]]>
+ Potentially dead Fields
+warnif count > 0
+from f in JustMyCode.Fields where
+ f.NbMethodsUsingMe == 0 &&
+ !f.IsPublic && // Although not recommended, public fields might be used by client applications of your assemblies.
+ !f.IsLiteral && // The IL code never explicitely uses literal fields.
+ !f.IsEnumValue && // The IL code never explicitely uses enumeration value.
+ f.Name != "value__" && // Field named 'value__' are relative to enumerations and the IL code never explicitely uses them.
+ !f.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
+ !f.IsGeneratedByCompiler
+ // If you don't want to link NDepend.API.dll, you can use your own IsNotDeadCodeAttribute and adapt this rule.
+select f]]>
+ Wrong usage of IsNotDeadCodeAttribute
+
+// This IsNotDeadCodeAttribute can be used to signify that
+// despite a member could be removed without provoking any syntax error
+// (we also say it is dead code), your intention is to not remove this member.
+// Default 'Dead Code' code rules take account of this attribute.
+// IsNotDeadCodeAttribute is defined in NDepend.API.dll
+// If you don't want to link NDepend.API.dll, you can use
+// your own IsNotDeadCodeAttribute and adapt this rule.
+warnif count == 1
+
+let tAttr = Types.WithFullName("NDepend.Attributes.IsNotDeadCodeAttribute").FirstOrDefault()
+where tAttr != null
+
+// Get types that do a wrong usage of IsNotDeadCodeAttribute
+let types = from t in Application.Types where
+ t.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
+
+ ( // types used don't need to be tagged with IsNotDeadCodeAttribute!
+ t.NbTypesUsingMe > 0 ||
+
+ // Static types that define only const fields cannot be seen as used in IL code.
+ // They don't need to be tagged with IsNotDeadCodeAttribute.
+ (t.IsStatic && t.NbMethods == 0 && !t.Fields.Where(f => !f.IsLiteral).Any())
+ )
+ select t
+
+// Get methods that do a wrong usage of IsNotDeadCodeAttribute
+let methods = from m in Application.Methods where
+ m.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
+ m.NbMethodsCallingMe > 0
+ select m
+
+// Get fields that do a wrong usage of IsNotDeadCodeAttribute
+let fields = from f in Application.Fields where
+ f.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
+ f.NbMethodsUsingMe > 0
+ select f
+
+where types.Count() > 0 || methods.Count() > 0 || fields.Count() > 0
+select new { tAttr, types , methods, fields }]]>
+
+
+ Methods that could have a lower visibility
+warnif count > 0 from m in JustMyCode.Methods where
+ m.Visibility != m.OptimalVisibility &&
+ !m.HasAttribute("NDepend.Attributes.CannotDecreaseVisibilityAttribute".AllowNoMatch()) &&
+ !m.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
+ // If you don't want to link NDepend.API.dll, you can use your own attributes and adapt this rule.
+
+ // Eliminate default constructor from the result.
+ // Whatever the visibility of the declaring class,
+ // default constructors are public and introduce noise
+ // in the current rule.
+ !( m.IsConstructor && m.IsPublic && m.NbParameters == 0) &&
+
+ // Don't decrease the visibility of Main() methods.
+ !m.IsEntryPoint
+
+select new { m,
+ m.Visibility ,
+ CouldBeDeclared = m.OptimalVisibility,
+ m.MethodsCallingMe }]]>
+ Types that could have a lower visibility
+warnif count > 0 from t in JustMyCode.Types where
+
+ t.Visibility != t.OptimalVisibility &&
+
+ // If you don't want to link NDepend.API.dll, you can use your own attributes and adapt this rule.
+ !t.HasAttribute("NDepend.Attributes.CannotDecreaseVisibilityAttribute".AllowNoMatch()) &&
+ !t.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
+
+ // Static types that define only const fields cannot be seen as used in IL code.
+ // They don't have to be tagged with CannotDecreaseVisibilityAttribute.
+ !( t.IsStatic &&
+ !t.Methods.Any(m => !m.IsClassConstructor) &&
+ !t.Fields.Any(f => !f.IsLiteral && !(f.IsStatic && f.IsInitOnly))) &&
+
+ // A type used by an interface that has the same visibility
+ // cannot have its visibility decreased, else a compilation error occurs!
+ !t.TypesUsingMe.Any(tUser =>
+ tUser.IsInterface &&
+ tUser.Visibility == t.Visibility)
+
+select new { t, t.Visibility ,
+ CouldBeDeclared = t.OptimalVisibility,
+ t.TypesUsingMe }
+]]>
+ Fields that could have a lower visibility
+warnif count > 0 from f in JustMyCode.Fields where
+ f.Visibility != f.OptimalVisibility &&
+ !f.HasAttribute("NDepend.Attributes.CannotDecreaseVisibilityAttribute".AllowNoMatch()) &&
+ !f.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch())
+ // If you don't want to link NDepend.API.dll, you can use your own attributes and adapt this rule.
+
+select new { f,
+ f.Visibility ,
+ CouldBeDeclared = f.OptimalVisibility,
+ f.MethodsUsingMe }]]>
+ Types that could be declared as private, nested in a parent type
+// The conditions for a type to be nested into a parent type
+// is that the parent type is the only type using it,
+// and that the parent type is declared in the same namespace.
+//
+// Declaring a type as private into a parent type helps enforcing encapsulation.
+// But since nested private types are hardly testable, this rule might
+// not be applied for types used directly by tests.
+
+warnif count > 0
+from t in Application.Types
+where !t.IsGeneratedByCompiler &&
+ !t.IsNested &&
+ !t.IsPubliclyVisible &&
+ // Only one type user...
+ t.TypesUsingMe.Count() == 1
+let couldBeNestedIn = t.TypesUsingMe.Single()
+where !couldBeNestedIn.IsGeneratedByCompiler &&
+ // ...declared in the same namespace
+ couldBeNestedIn.ParentNamespace == t.ParentNamespace
+select new { t, couldBeNestedIn }]]>
+ Avoid publicly visible constant fields
+
+// Match constant fields which are visible outside their parent assembly.
+// Such field, when used outside its parent assembly,
+// has its constant value hard-coded into the client assembly.
+// Changing the field's value requires to recompile all assemblies
+// that use the field.
+
+// Declare the field as static readonly instead. This way, the value can be
+// safely changed, without the need to recompile client assemblies.
+
+warnif count > 0
+from f in Application.Fields
+where f.IsLiteral && f.IsPubliclyVisible
+ && !f.IsEnumValue // This situation also applies to enumeration values
+ // but to avoid too many false positives, per default
+ // this rule doesn't match these particular fields.
+select f]]>
+ Fields should be declared as private
+// Fields should be considered as implementation details
+// and as a consequence they should be declared as private.
+// When a field is private, the caller cannot get
+// inappropriate direct access to the field.
+
+warnif count > 0 from f in Application.Fields where
+ !f.IsPrivate &&
+
+ // These conditions filter cases where fields
+ // doesn't represent state that should be encapsulated.
+ !f.IsGeneratedByCompiler &&
+ !f.IsSpecialName &&
+ !f.IsInitOnly &&
+ !f.IsLiteral &&
+ !f.IsEnumValue
+
+// A non-private field assigned from outside its class,
+// usually leads to complicated field state management.
+let outsideMethodsAssigningMe =
+ f.MethodsAssigningMe.Where(m => m.ParentType != f.ParentType)
+
+select new { f,
+ f.Visibility,
+ outsideMethodsAssigningMe }]]>
+ Constructors of abstract classes should be declared as protected or private
+// Constructors of an abstract class can be accessed only from its class and derived class.
+// Declaring such a constructor with another visibility level is useless and potentially misleading.
+
+// Notice that if a constructor of an abstract class is declared as private,
+// it can only be accessed from derived classes nested in the abstract class.
+
+warnif count > 0
+from t in Application.Types where
+ t.IsClass &&
+ t.IsAbstract
+let ctors = t.Constructors.Where(c => !c.IsProtected && !c.IsPrivate)
+where ctors.Count() > 0
+select new { t, ctors }
+]]>
+ Avoid public methods not publicly visible
+// Matched methods are declared public but are not publicly visible by assemblies consumers.
+// Their visibility level must be decreased.
+
+warnif count > 0
+from m in JustMyCode.Methods where
+ !m.IsPubliclyVisible && m.IsPublic &&
+
+ // Eliminate virtual methods
+ !m.IsVirtual &&
+ // Eliminate interface and delegate types
+ !m.ParentType.IsInterface &&
+ !m.ParentType.IsDelegate &&
+ // Eliminate default constructors
+ !(m.IsConstructor && m.NbParameters == 0) &&
+ // Eliminate operators that must be declared public
+ !m.IsOperator &&
+ // Eliminate methods generated by compiler
+ !m.IsGeneratedByCompiler
+select m]]>
+ Methods that should be declared as 'public' in C#, 'Public' in VB.NET
+// The condition 'ShouldBePublic' shows code elements
+// declared as 'internal\Friend' that are used outside
+// of their assembly thanks to the Attribute
+// System.Runtime.CompilerServices.InternalsVisibleToAttribute
+
+from m in Application.Methods where
+ m.ShouldBePublic
+let usedInAssemblies = m.MethodsCallingMe.ParentAssemblies().Except(m.ParentAssembly)
+select new { m, m.ParentAssembly, usedInAssemblies, m.MethodsCallingMe }
+]]>
+ Wrong usage of CannotDecreaseVisibilityAttribute
+
+// The CannotDecreaseVisibilityAttribute can be used to signify that despite
+// a member could have a lower visibility without provoking any syntax error,
+// your intention is to not change this member visibility.
+// Default Visibility code rules take account of this attribute.
+// CannotDecreaseVisibilityAttribute is defined in NDepend.API.dll
+// If you don't want to link NDepend.API.dll, you can use
+// your own CannotDecreaseVisibilityAttribute and adapt this rule.
+
+warnif count == 1
+
+let tAttr = Types.WithFullName("NDepend.Attributes.CannotDecreaseVisibilityAttribute").FirstOrDefault()
+where tAttr != null
+
+// Get types that do a wrong usage of CannotDecreaseVisibilityAttribute
+let types = from t in Application.Types where
+ t.HasAttribute("NDepend.Attributes.CannotDecreaseVisibilityAttribute".AllowNoMatch()) &&
+ ( t.Visibility == t.OptimalVisibility ||
+
+ // Static types that define only const fields cannot be seen as used in IL code.
+ // They don't need to be tagged with CannotDecreaseVisibilityAttribute.
+ (t.IsStatic && t.NbMethods == 0 && !t.Fields.Where(f => !f.IsLiteral).Any())
+ )
+ select t
+
+// Get methods that do a wrong usage of CannotDecreaseVisibilityAttribute
+let methods = from m in Application.Methods where
+ m.HasAttribute("NDepend.Attributes.CannotDecreaseVisibilityAttribute".AllowNoMatch()) &&
+ m.Visibility == m.OptimalVisibility
+ select m
+
+// Get fields that do a wrong usage of CannotDecreaseVisibilityAttribute
+let fields = from f in Application.Fields where
+ f.HasAttribute("NDepend.Attributes.CannotDecreaseVisibilityAttribute".AllowNoMatch()) &&
+ f.Visibility == f.OptimalVisibility
+ select f
+
+where types.Count() > 0 || methods.Count() > 0 || fields.Count() > 0
+select new { tAttr, types , methods, fields }]]>
+ Event handler methods should be declared private
+warnif count > 0
+from m in Application.Methods where
+ !m.IsPrivate &&
+
+ // A method is considered as event handler if...
+ m.NbParameters==2 && // ...it has two parameters..
+ m.Name.Contains("Object") && // ...of types Object...
+ m.Name.Contains("EventArgs") && // ...and EventArgs
+
+ // Discard special cases
+ !m.ParentType.IsDelegate &&
+ !m.IsGeneratedByCompiler
+
+select new { m,m.Visibility }
+// This rule implementation relies on the facts that:
+// -> A method name contains the type of its parameters.
+// -> All EventArgs derived types have the suffix "EventArgs".]]>
+
+
+ Fields should be marked as ReadOnly when possible
+warnif count > 0
+from f in JustMyCode.Fields where
+ f.IsImmutable &&
+ !f.IsInitOnly &&
+ !f.IsGeneratedByCompiler &&
+ !f.IsEventDelegateObject
+select new { f, f.SizeOfInst }
+
+// A field that matches the condition IsImmutable
+// is a field that is assigned only by constructors
+// of its class.
+// For an instance field, this means its value
+// will remain constant throught the lifetime
+// of the object.
+// For a static field, this means its value will
+// remain constant throught the lifetime of the
+// program.
+// In both cases, such field can safely be marked
+// with the C# readonly keyword
+// (ReadOnly in VB.NET).
+
+// The condition IsInitOnly matches fields that
+// are marked with the C# readonly keyword
+// (ReadOnly in VB.NET).
+
+
+
+]]>
+ Structures should be immutable
+warnif count > 0 from t in Application.Types where
+ t.IsStructure &&
+ !t.IsImmutable
+
+let mutableFields = t.Fields.Where(f => !f.IsImmutable)
+
+select new { t, t.NbLinesOfCode, mutableFields }
+
+// It is deemed as a good practice to make
+// your structure immutable.
+// An object is immutable if its state doesn’t
+// change once the object has been created.
+// Consequently, a structure is immutable if
+// its instances are immutable.
+// Immutable types naturally simplify code by
+// limiting side-effects.
+// See some explanations on immutability and
+// how NDepend supports it here:
+// http://codebetter.com/blogs/patricksmacchia/archive/2008/01/13/immutable-types-understand-them-and-use-them.aspx
+]]>
+ Property Getters should be immutable
+warnif count > 0 from m in Application.Methods where
+ m.IsPropertyGetter &&
+ ( ( !m.IsStatic && m.ChangesObjectState) ||
+ ( m.IsStatic && m.ChangesTypeState) )
+
+let fieldsAssigned = m.FieldsAssigned
+
+select new { m, m.NbLinesOfCode, fieldsAssigned }
+
+// This rule might be violated in the case of object lazy initialized
+// when the property getter is accessed the first time.
+// But in general, the callers of a property
+// doesn't expect to change any state through the call.
+ ]]>
+ Avoid static fields with a mutable field type
+warnif count > 0
+from f in Application.Fields
+where f.IsStatic && !f.IsEnumValue && !f.IsGeneratedByCompiler && !f.IsLiteral
+let fieldType = f.FieldType
+where fieldType != null &&
+ !fieldType.IsThirdParty &&
+ !fieldType.IsInterface &&
+ !fieldType.IsImmutable
+select new { f,
+ mutableFieldType = fieldType ,
+ isFieldImmutable = f.IsImmutable,
+ isFieldIsReadOnly = f.IsInitOnly }
+
+// As explained in this blog post
+// http://codebetter.com/patricksmacchia/2011/05/04/back-to-basics-usage-of-static-members
+// static fields should be used to hold only constant and immutable states.
+]]>
+ A field must not be assigned from outside its parent hierarchy types
+warnif count > 0
+from f in JustMyCode.Fields.Where(f =>
+ !f.IsPrivate && !f.IsGeneratedByCompiler &&
+ !f.IsImmutable && !f.IsEnumValue)
+
+let methodsAssignerOutsideOfMyType = f.MethodsAssigningMe.Where(
+ m =>!m.IsGeneratedByCompiler &&
+ m.ParentType != f.ParentType &&
+ !m.ParentType.DeriveFrom(f.ParentType) )
+
+where methodsAssignerOutsideOfMyType.Count() > 0
+select new { f, methodsAssignerOutsideOfMyType }]]>
+ Don't assign a field from many methods
+warnif count > 0
+from f in JustMyCode.Fields where
+ !f.IsEnumValue &&
+ !f.IsImmutable &&
+ !f.IsInitOnly &&
+ !f.IsGeneratedByCompiler &&
+ !f.IsEventDelegateObject &&
+ (f.IsPrivate || f.IsProtected) // Don't match fields assigned outside their classes.
+
+// The threshold 4 is arbitrary and it should avoid matching too many fields.
+// Threshold is even lower for static fields because this reveals situations even more complex.
+where f.MethodsAssigningMe.Count() >= (!f.IsStatic ? 4 : 2)
+select new { f,
+ f.MethodsAssigningMe,
+ f.MethodsReadingMeButNotAssigningMe,
+ f.MethodsUsingMe,
+ f.ParentType }
+
+// A field assigned from many methods is a symptom of bug-prone code.
+// This situation makes harder to anticipate the field state during runtime.
+// The code is then hard to read, hard to debug and hard to maintain.
+// Hard-to-solve bugs due to corrupted state are often the consequence of fields anarchically assigned.
+//
+// The situation is even more complex if the field is static.
+// Indeed, this potentially involves global random accesses from different parts of the application.
+// This is why this rule provides a lower threshold for static fields.
+//
+// If the object containing such field is meant to be used from multiple threads,
+// there are alarming chances that the code is unmaintainable and bugged.
+// When multiple threads are involved, the rule of thumb is to use immutable objects.
+//
+// If the field type is a reference type (interfaces, classes, strings, delegates)
+// corrupted state might result in a NullReferenceException.
+// If the field type is a value type (number, boolean, structure)
+// corrupted state might result in wrong result not even signaled by an exception sent.
+//
+// There is no straight advice to refactor the number of methods responsible for assigning a field.
+// Solutions often involve rethinking and then rewriting a complex algorithm.
+// Such field can sometime become just a variable accessed locally by a method or a closure.
+// Sometime, just rethinking the life-time and the role of the parent object allows the field to become immutable
+// (i.e assigned only by the constructor).
+
+]]>
+ Do not declare read only mutable reference types
+warnif count > 0 from f in JustMyCode.Fields where
+ f.IsInitOnly &&
+ !f.ParentType.IsPrivate &&
+ !f.IsPrivate &&
+ f.FieldType != null &&
+ f.FieldType.IsClass &&
+ !f.FieldType.IsThirdParty &&
+ !f.FieldType.IsImmutable
+select new { f, f.FieldType, FieldVisibility = f.Visibility }
+
+// This rule is violated when a public or internal
+// type contains a public or internal read-only field
+// that is a mutable reference type.
+//
+// This situation provides the wrong impression that the
+// value can't change, when actually it's only the field
+// value that can't change, rather than the object.
+//
+// To fix a violation of this rule, remove the read-only
+// modifier or, if a breaking change is acceptable,
+// replace the field with an immutable type.
+//
+// An object is immutable if its state doesn’t
+// change once the object has been created.
+// Consequently, a class or a structure is
+// immutable if its instances are immutable.
+// Immutable types naturally simplify code by
+// limiting side-effects.
+]]>
+ Array fields should not be read only
+warnif count > 0 from f in Application.Fields where
+ f.IsInitOnly &&
+ f.IsPubliclyVisible &&
+ f.FieldType != null &&
+ f.FieldType.FullName == "System.Array"
+select new { f, FieldVisibility = f.Visibility }
+
+// This rule is violated when a publicly visible field
+// that holds an array, is declared read-only.
+//
+// This situation represents a security vulnerability.
+// Because the field is read-only it cannot be changed to refer
+// to a different array. However, the elements of the array
+// that are stored in a read-only field can be changed.
+// Code that makes decisions or performs operations that are
+// based on the elements of a read-only array that can be publicly
+// accessed might contain an exploitable security vulnerability.
+//
+// To fix the security vulnerability that is identified by ,
+// this rule do not rely on the contents of a read-only array
+// that can be publicly accessed. It is strongly recommended
+// that you use one of the following procedures:
+//
+// -> Replace the array with a strongly typed collection
+// that cannot be changed. For more information,
+// see System.Collections.Generic.IReadOnlyList
+// System.Collections.Generic.IReadOnlyCollection
+// System.Collections.ReadOnlyCollectionBase.
+//
+// -> Replace the public field with a method that returns a clone
+// of a private array. Because your code does not rely on
+// the clone, there is no danger if the elements are modified.
+]]>
+ Types immutable should be tagged with ImmutableAttribute
+from t in Application.Types where
+ !t.HasAttribute ("NDepend.Attributes.ImmutableAttribute".AllowNoMatch()) &&
+ t.IsImmutable
+select new { t, t.NbLinesOfCode }
+
+// Types matched by this query are immutable but
+// are not tagged with the ImmutableAttribute.
+// The benefit of tagging them with the ImmutableAttribute
+// is that the rule 'Regression on immutable types'
+// will warn when the immutability of a type gets broken.
+
+// NDepend.Attributes.ImmutableAttribute is defined in the
+// redistributable assembly $NDependInstallDir$\Lib\NDepend.API.dll
+// You can define your own attribute to tag 'immutable' types.
+]]>
+ Methods tagged with PureAttribute must be pure
+warnif count > 0 from m in Application.Methods where
+ ( m.HasAttribute ("NDepend.Attributes.PureAttribute".AllowNoMatch()) ||
+ m.HasAttribute ("System.Diagnostics.Contract.PureAttribute".AllowNoMatch()) ) &&
+ ( m.ChangesObjectState || m.ChangesTypeState ) &&
+ m.NbLinesOfCode > 0
+
+let fieldsAssigned = m.FieldsAssigned
+
+select new { m, m.NbLinesOfCode, fieldsAssigned }
+
+// A method is pure if its execution doesn’t change
+// the value of any instance or static field.
+// Pure methods naturally simplify code by limiting
+// side-effects.
+// See some explanations on immutability - purity and
+// how NDepend supports it here:
+// http://codebetter.com/blogs/patricksmacchia/archive/2008/01/13/immutable-types-understand-them-and-use-them.aspx
+
+// NDepend.Attributes.PureAttribute is defined in the
+// redistributable assembly $NDependInstallDir$\Lib\NDepend.API.dll
+// You can define your own attribute to tag 'pure' methods
+// or you can use as well System.Diagnostics.Contract.PureAttribute
+// introduced with .NET v4.0.
+
+]]>
+ Pure methods should be tagged with PureAttribute
+from m in Application.Methods where
+ !m.HasAttribute ("NDepend.Attributes.PureAttribute".AllowNoMatch()) &&
+ !m.HasAttribute ("System.Diagnostics.Contract.PureAttribute".AllowNoMatch()) &&
+ !m.ChangesObjectState && !m.ChangesTypeState &&
+ m.NbLinesOfCode > 0
+select new { m, m.NbLinesOfCode }
+
+// Methods matched by this query are pure but
+// are not tagged with the PureAttribute.
+// The benefit of tagging them with the PureAttribute
+// is that the rule 'Regression on pure methods'
+// will warn when the purity of a method gets broken.
+
+// NDepend.Attributes.PureAttribute is defined in the
+// redistributable assembly $NDependInstallDir$\Lib\NDepend.API.dll
+// You can define your own attribute to tag 'pure' methods
+// or you can use as well System.Diagnostics.Contract.PureAttribute
+// introduced with .NET v4.0.]]>
+
+
+ Instance fields should be prefixed with a 'm_'
+warnif count > 0 from f in Application.Fields where
+ !f.NameLike (@"^m_") &&
+ !f.IsStatic &&
+ !f.IsLiteral &&
+ !f.IsGeneratedByCompiler &&
+ !f.IsSpecialName &&
+ !f.IsEventDelegateObject
+select new { f, f.SizeOfInst }
+
+// This naming convention provokes debate.
+// Don't hesitate to customize the regex of
+// NameLike to your preference.]]>
+ Static fields should be prefixed with a 's_'
+warnif count > 0 from f in Application.Fields where
+ !f.NameLike (@"^s_") &&
+ f.IsStatic &&
+ !f.IsLiteral &&
+ !f.IsGeneratedByCompiler &&
+ !f.IsSpecialName &&
+ !f.IsEventDelegateObject
+select new { f, f.SizeOfInst }
+
+// This naming convention provokes debate.
+// Don't hesitate to customize the regex of
+// NameLike to your preference.
+]]>
+ Interface name should begin with a 'I'
+warnif count > 0 from t in Application.Types where
+t.IsInterface
+
+// Discard outter type(s) name prefix for nested types
+let name = !t.IsNested ? t.Name : t.Name.Substring(t.Name.LastIndexOf('+') + 1, t.Name.Length - t.Name.LastIndexOf('+') - 1)
+
+where name[0] != 'I'
+select t
+]]>
+ Abstract base class should be suffixed with 'Base'
+warnif count > 0 from t in Application.Types where
+ t.IsAbstract &&
+ t.IsClass &&
+
+ // equivalent to: DepthOfDeriveFrom "System.Object" == 1
+ t.DepthOfInheritance == 1 &&
+
+ ((!t.IsGeneric && !t.NameLike (@"Base$")) ||
+ ( t.IsGeneric && !t.NameLike (@"Base<")))
+select new { t, t.DepthOfInheritance }]]>
+ Exception class name should be suffixed with 'Exception'
+warnif count > 0 from t in Application.Types where
+ t.IsExceptionClass &&
+ !t.NameLike (@"Exception$") &&
+ !t.NameLike (@"ExceptionBase$") // Allow the second suffix Base
+ // for base exception classes.
+select new { t, t.NbLinesOfCode }
+
+// The name of an exception class should end with 'Exception'.]]>
+ Attribute class name should be suffixed with 'Attribute'
+warnif count > 0 from t in Application.Types where
+ t.IsAttributeClass &&
+ !t.NameLike (@"Attribute$")
+select new { t, t.NbLinesOfCode }
+]]>
+ Types name should begin with an Upper character
+warnif count > 0 from t in JustMyCode.Types where
+ // The name of a type should begin with an Upper letter.
+ !t.SimpleNameLike (@"^[A-Z]") &&
+
+ // Except if it is generated by compiler or ...
+ !t.IsSpecialName &&
+ !t.IsGeneratedByCompiler
+
+
+select new { t, t.NbLinesOfCode }]]>
+ Methods name should begin with an Upper character
+warnif count > 0 from m in JustMyCode.Methods where
+ !m.NameLike (@"^[A-Z]") &&
+ !m.IsSpecialName &&
+ !m.IsGeneratedByCompiler
+select m
+
+// The name of a regular method should
+// begin with an Upper letter.]]>
+ Do not name enum values 'Reserved'
+warnif count > 0 from f in Application.Fields where
+ f.IsEnumValue &&
+ f.NameLike (@"Reserved")
+select new { f, f.SizeOfInst }
+
+// This rule assumes that an enumeration member
+// with a name that contains "reserved"
+// is not currently used but is a placeholder to
+// be renamed or removed in a future version.
+// Renaming or removing a member is a breaking
+// change. You should not expect users to ignore
+// a member just because its name contains
+// "reserved" nor can you rely on users to read or
+// abide by documentation. Furthermore, because
+// reserved members appear in object browsers
+// and smart integrated development environments,
+// they can cause confusion as to which members
+// are actually being used.
+
+// Instead of using a reserved member, add a
+// new member to the enumeration in the future
+// version.
+// In most cases, the addition of the new
+// member is not a breaking change, as long as the
+// addition does not cause the values of the
+// original members to change.]]>
+ Avoid types with name too long
+warnif count > 0 from t in Application.Types
+where !t.IsGeneratedByCompiler
+
+where t.SimpleName.Length > 35
+select new { t, t.SimpleName }
+
+ ]]>
+ Avoid methods with name too long
+warnif count > 0 from m in Application.Methods where
+ !m.IsExplicitInterfaceImpl &&
+ !m.IsGeneratedByCompiler &&
+ ((!m.IsSpecialName && m.SimpleName.Length > 35) ||
+ // Property getter/setter are prefixed with "get_" "set_" of length 4.
+ ( m.IsSpecialName && m.SimpleName.Length - 4 > 35))
+
+select new { m, m.SimpleName }
+
+// The regex matches methods with name longer
+// than 35 characters.
+// Method Name doesn't contain the type and namespace
+// prefix, FullName does.
+// The regex computes the method name length from
+// the beginning until the first open parenthesis
+// or first lower than (for generic methods).
+// Explicit Interface Implementation methods are
+// discarded because their names are prefixed
+// with the interface name.
+ ]]>
+ Avoid fields with name too long
+warnif count > 0 from f in Application.Fields where
+ !f.IsGeneratedByCompiler &&
+ f.Name.Length > 35
+select f
+
+// The regex matches fields with name longer
+// than 35 characters.
+// Field Name doesn't contain the type and
+// namespace prefix, FullName does.
+ ]]>
+ Avoid having different types with same name
+// Such practice typically creates confusion,
+// and type naming collision inside a source file.
+
+warnif count > 0
+
+// 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)
+
+ // 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)
+
+orderby types.Count() descending
+
+select new { t = types.First(),
+ // In the 'types' column, make sure to group matched types
+ // by parent assemblies and parent namespaces, to get a result
+ // more readable.
+ types
+ }]]>
+ Avoid prefixing type name with parent namespace name
+
+// For example a type named "RuntimeEnvironment"
+// declared in a namespace named "Foo.Runtime"
+// should be named "Environment"
+
+from n in Application.Namespaces where n.Name.Length > 0
+from t in n.ChildTypes
+where
+ !t.IsGeneratedByCompiler &&
+ !t.IsNested &&
+ t.Name.IndexOf(n.SimpleName) == 0
+select new { t, namespaceName = n.SimpleName }]]>
+ Avoid naming types and namespaces with the same identifier
+
+// Not only this can provoke compiler resolution collision,
+// but also, this makes code less maintainable because
+// concepts are not concisely identified.
+
+warnif count > 0
+let hashsetShortNames = Namespaces.Where(n => n.Name.Length > 0).Select(n => n.SimpleName).ToHashSet()
+
+from t in JustMyCode.Types
+where hashsetShortNames.Contains(t.Name)
+select new { t, namespaces = Namespaces.Where(n => n.SimpleName == t.Name) }]]>
+ Don't call your method Dispose
+// Methods shouldn't be called Dispose,
+// this syntax is reserved for System.IDisposable type usage.
+from m in Application.Methods.WithSimpleName("Dispose")
+where !m.ParentType.Implement("System.IDisposable".AllowNoMatch())
+select m]]>
+ Methods prefixed with 'Try' should return a boolean
+// and such TryXXX method can eventually have out parameters to return results.
+// Get inspired from the API design of:
+// System.Int32.TryParse(int,out string):bool
+warnif count > 0
+from m in Application.Methods where
+ m.SimpleNameLike("^Try") &&
+ m.ReturnType != null &&
+ m.ReturnType.FullName != "System.Boolean"
+select new { m, m.ReturnType }]]>
+
+
+ Avoid referencing source file out of Visual Studio project directory
+
+// A source file located outside of the VS project directory can be add through:
+// > Add > Existing Items... > Add As Link
+//
+// Don't use this possibility to share code accross several assemblies.
+// This provoques type duplication at binary level.
+// Hence maintainability is degraded and subtle versioning bug can appear.
+// Prefer sharing types through classic libraries.
+//
+// This practice can be tolerated for certain types shared accross executable assemblies.
+// Such type can be responsible for particular and not shareable startup related concerns,
+// such as registering custom assembly resolving handlers or
+// checking the .NET Framework version before loading any custom library.
+warnif count > 0
+
+from a in Application.Assemblies
+where a.VisualStudioProjectFilePath != null
+let vsProjDirPathLower = a.VisualStudioProjectFilePath.ParentDirectoryPath.ToString().ToLower()
+
+from t in a.ChildTypes
+where JustMyCode.Contains(t) && t.SourceFileDeclAvailable
+
+from decl in t.SourceDecls
+let sourceFilePathLower = decl.SourceFile.FilePath.ToString().ToLower()
+where sourceFilePathLower .IndexOf(vsProjDirPathLower) != 0
+select new { t, sourceFilePathLower , projectFilePath = a.VisualStudioProjectFilePath.ToString() }]]>
+ Avoid duplicating a type definition across assemblies
+// Prefer to factorize type definition in a library assembly.
+warnif count > 0
+
+let groups = Application.Types
+ .Where(t => !t.IsGeneratedByCompiler)
+ .GroupBy(t => t.FullName)
+from @group in groups
+where @group.Count() > 1
+
+select new { t = @group.First(),
+ // In the 'types' column, make sure to group matched types by parent assemblies.
+ typesDefs = @group.ToArray()
+ }]]>
+ Avoid defining multiple types in a source file
+warnif count > 0
+
+// Build a lookup indexed by source files, values being a sequence of types defined in the source file.
+let lookup = Application.Types.Where(t =>
+ t.SourceFileDeclAvailable &&
+ // except nested types and types generated by compilers!
+ !t.IsGeneratedByCompiler &&
+ !t.IsNested)
+ // It could make sense to not apply this rule for enumerations.
+ // && !t.IsEnumeration)
+
+ // We use multi-key, since a type can be declared in multiple source files.
+ .ToMultiKeyLookup(t => t.SourceDecls.Select(d => d.SourceFile))
+
+from @group in lookup where @group.Count() > 1
+ let sourceFile = @group.Key
+
+ // CQLinq doesn't let indexing result with sourceFile
+ // so we choose a typeIndex in types,
+ // preferably the type that has the file name.
+ let typeWithSourceFileName = @group.FirstOrDefault(t => t.SimpleName == sourceFile.FileNameWithoutExtension)
+ let typeIndex = typeWithSourceFileName ?? @group.First()
+
+select new { typeIndex,
+ types = @group as IEnumerable,
+ sourceFile.FilePathString }]]>
+ Namespace name should correspond to file location
+
+// For a good code organization,
+// do mirror the namespaces hierarchy and the source files directories tree.
+
+warnif count > 0
+from n in Application.Namespaces
+
+// Replace dots by spaces in namespace name
+let dirCorresponding = n.Name.Replace('.', ' ')
+
+// Look at source file decl of JustMyCode type's declared in n
+from t in n.ChildTypes
+where JustMyCode.Contains(t) && t.SourceFileDeclAvailable
+from decl in t.SourceDecls
+let sourceFilePath = decl.SourceFile.FilePath.ToString()
+
+// Replace dots and path separators by spaces in source files names
+where !sourceFilePath.Replace('.',' ').Replace('\\',' ').Contains(dirCorresponding)
+
+select new { t, dirCorresponding , sourceFilePath } ]]>
+ Types with source files stored in the same directory, should be declared in the same namespace
+warnif count > 0
+
+// Group JustMyCode types in a lookup
+// where groups are keyed with directories that contain the types' source file(s).
+// Note that a type can be contained in several groups
+// if it is declared in several source files stored in different directories.
+let lookup = JustMyCode.Types.Where(t => t.SourceFileDeclAvailable)
+ .ToMultiKeyLookup(
+ t => t.SourceDecls.Select(
+ decl => decl.SourceFile.FilePath.ParentDirectoryPath).Distinct()
+ )
+
+
+from groupOfTypes in lookup
+let parentNamespaces = groupOfTypes.ParentNamespaces()
+
+// Select group of types (with source files stored in the same directory) ...
+// ... but contained in several namespaces
+where parentNamespaces.Count() > 1
+
+// mainNamespaces is the namespace that contains many types
+// declared in the directory groupOfTypes .key
+let mainNamespace = groupOfTypes
+ .ToLookup(t => t.ParentNamespace)
+ .OrderByDescending(g => g.Count()).First().Key
+
+// Select types with source files stored in the same directory,
+// but contained in namespaces different than mainNamespace.
+let typesOutOfMainNamespace = groupOfTypes
+ .Where(t => t.ParentNamespace != mainNamespace )
+
+ // Filter types declared on several source files that contain generated methods
+ // because typically such type contains one or several partial definitions generated.
+ // These partially generated types would be false positive for the present rule.
+ .Where(t => t.SourceDecls.Count() == 1 ||
+ t.Methods.Count(m => JustMyCode.Contains(m)) == 0)
+where typesOutOfMainNamespace.Count() > 0
+
+select new { mainNamespace,
+
+ // Typically a type in typesOutOfMainNamespace ...
+ // 1) ... is contained in the wrong namespace but its source file(s) is stored in the right directory.
+ // --> In such situation the type should be contained in mainNamespace.
+ // 2) ... is contained in the right namespace but its source file(s) is stored in the wrong directory
+ // --> In such situation the source file of type must be moved to the parent namespace directory.
+ // 3) ... is declared in multiple source files, stored in different directories.
+ // --> It would be preferable that all source files are stored in a single directory.
+ typesOutOfMainNamespace }
+
+]]>
+ Types declared in the same namespace, should have their source files stored in the same directory
+warnif count > 0
+from @namespace in Application.Namespaces
+
+// Group types of @namespace in a lookup
+// where groups are keyed with directories that contain the types' source file(s).
+// Note that a type can be contained in several groups
+// if it is declared in several source files stored in different directories.
+let lookup = @namespace.ChildTypes.Where(t => t.SourceFileDeclAvailable && JustMyCode.Contains(t))
+ .ToMultiKeyLookup(
+ t => t.SourceDecls.Select(
+ decl => decl.SourceFile.FilePath.ParentDirectoryPath).Distinct()
+ )
+
+// Are types of @namespaces declared in more than one directory?
+where lookup.Count > 1
+
+// Infer the main folder, preferably the one that has the same name as the namespace.
+let dirs = lookup.Select(types => types.Key)
+let mainDirNullable = dirs.Where(d => d.DirectoryName == @namespace.SimpleName).FirstOrDefault()
+let mainDir = mainDirNullable ?? dirs.First()
+
+// Types declared out of mainDir, are types in group of types declared in a directory different than mainDir!
+let typesDeclaredOutOfMainDir = lookup.Where(types => types.Key != mainDir)
+ .SelectMany(types => types)
+
+ // Filter types declared on several source files that contain generated methods
+ // because typically such type contains one or several partial definitions generated.
+ // These partially generated types would be false positive for the present rule.
+ .Where(t => t.SourceDecls.Count() == 1 ||
+ t.Methods.Count(m => JustMyCode.Contains(m)) == 0)
+
+where typesDeclaredOutOfMainDir.Count() > 0
+
+select new { @namespace,
+
+ // Typically a type in typesDeclaredOutOfMainDir ...
+ // 1) ... is contained in the wrong namespace but its source file(s) is stored in the right directory.
+ // --> In such situation the type parent namespace should be the namespace corresponding to the directory.
+ // 2) ... is contained in the right namespace but its source file(s) is stored in the wrong directory
+ // --> In such situation the type source file should be moved to mainDir.
+ // 3) ... is declared in multiple source files, stored in different directories.
+ // --> It would be preferable that all source files are stored in a single directory.
+ typesDeclaredOutOfMainDir ,
+
+ mainDir = mainDir.ToString() }]]>
+
+
+
+ Mark ISerializable types with SerializableAttribute
+from t in Application.Types where
+ t.IsPublic &&
+ !t.IsDelegate &&
+ t.Implement ("System.Runtime.Serialization.ISerializable".AllowNoMatch()) &&
+ !t.HasAttribute ("System.SerializableAttribute".AllowNoMatch())
+select new { t, t.NbLinesOfCode }
+
+// To be recognized by the CLR as serializable,
+// types must be marked with the SerializableAttribute
+// attribute even if the type uses a custom
+// serialization routine through implementation of
+// the ISerializable interface.]]>
+ Mark assemblies with assembly version
+warnif count > 0 from a in Application.Assemblies where
+ !a.HasAttribute ("System.Reflection.AssemblyVersionAttribute".AllowNoMatch())
+select a
+
+// The identity of an assembly is composed of
+// the following information:
+// - Assembly name
+// - Version number
+// - Culture
+// - Public key (for strong-named assemblies).
+// The .NET Framework uses the version number
+// to uniquely identify an assembly, and to bind
+// to types in strong-named assemblies. The
+// version number is used together with version
+// and publisher policy. By default, applications
+// run only with the assembly version with
+// which they were built.]]>
+ Mark assemblies with CLSCompliant
+warnif count > 0 from a in Application.Assemblies where
+ !a.HasAttribute ("System.CLSCompliantAttribute".AllowNoMatch())
+select a
+
+// The Common Language Specification (CLS) defines
+// naming restrictions, data types, and rules to which
+// assemblies must conform if they are to be used
+// across programming languages. Good design dictates
+// that all assemblies explicitly indicate CLS
+// compliance with CLSCompliantAttribute. If the
+// attribute is not present on an assembly, the
+// assembly is not compliant.]]>
+ Mark assemblies with ComVisible
+warnif count > 0 from a in Application.Assemblies where
+ !a.HasAttribute ("System.Runtime.InteropServices.ComVisibleAttribute".AllowNoMatch())
+select a
+
+// The ComVisibleAttribute attribute determines
+// how COM clients access managed code. Good design
+// dictates that assemblies explicitly indicate
+// COM visibility. COM visibility can be set for
+// an entire assembly and then overridden for
+// individual types and type members. If the
+// attribute is not present, the contents of
+// the assembly are visible to COM clients.]]>
+ Mark attributes with AttributeUsageAttribute
+warnif count > 0 from t in Application.Types where
+ t.DeriveFrom ("System.Attribute".AllowNoMatch()) &&
+ !t.HasAttribute ("System.AttributeUsageAttribute".AllowNoMatch())
+select t
+
+// When defining a custom attribute, mark it using
+// AttributeUsageAttribute to indicate where in the
+// source code the custom attribute can be applied.
+// An attribute's meaning and intended usage will
+// determine its valid locations in code. For example,
+// if you are defining an attribute that identifies
+// the person responsible for maintaining and enhancing
+// each type in a library, and responsibility is
+// always assigned at the type level, compilers should
+// allow the attribute on classes, enumerations,
+// and interfaces, but should not allow it on methods,
+// events, or properties. Organizational policies and
+// procedures would dictate whether the attribute
+// should be allowed on assemblies.]]>
+ Remove calls to GC.Collect()
+warnif count > 0
+
+let gcCollectMethods = ThirdParty.Methods.WithFullNameIn(
+ "System.GC.Collect()",
+ "System.GC.Collect(Int32)",
+ "System.GC.Collect(Int32,GCCollectionMode)")
+
+from m in Application.Methods.UsingAny(gcCollectMethods)
+select m
+
+// It is preferrable to avoid calling GC.Collect()
+// explicitely in order to avoid some performance pitfall.
+// More in information on this here:
+// http://blogs.msdn.com/ricom/archive/2004/11/29/271829.aspx]]>
+ Don't call GC.Collect() without calling GC.WaitForPendingFinalizers()
+warnif count > 0
+
+let gcCollectMethods = ThirdParty.Methods.WithFullNameIn(
+ "System.GC.Collect()",
+ "System.GC.Collect(Int32)",
+ "System.GC.Collect(Int32,GCCollectionMode)")
+
+from m in Application.Methods.UsingAny(gcCollectMethods) where
+ !m.IsUsing ("System.GC.WaitForPendingFinalizers()".AllowNoMatch())
+select new { m, m.NbLinesOfCode }
+
+// It is preferrable to avoid calling GC.Collect()
+// explicitely in order to avoid some performance
+// pitfall. But if you wish to call GC.Collect(),
+// you must do it this way:
+// GC.Collect();
+// GC.WaitForPendingFinalizers();
+// GC.Collect();
+// To make sure that finalizer got executed, and
+// object with finalizer got cleaned properly.]]>
+ Enum Storage should be Int32
+warnif count > 0 from f in Fields where
+ f.Name == @"value__" &&
+ !f.FieldTypeIs ("System.Int32".AllowNoMatch()) &&
+ !f.IsThirdParty
+select new { f, f.SizeOfInst, f.FieldType }
+
+// An enumeration is a value type that defines
+// a set of related named constants. By default,
+// the System.Int32 data type is used to store
+// the constant value. Even though you can change
+// this underlying type, it is not necessary or
+// recommended for most scenarios. Note that there
+// is no significant performance gain in using
+// a data type smaller than Int32. If you cannot
+// use the default data type, you should use one
+// of the CLS-compliant integral types, Byte,
+// Int16, Int32, or Int64, to ensure that all of
+// the enumeration's values are representable in
+// CLS-compliant programming languages.]]>
+ Do not raise too general exception types
+warnif count > 0 from m in Application.Methods where
+ // Test for non-constructor, else this rule
+ // would warn on ctor of classes that derive
+ // from these exception types.
+ !m.IsConstructor && (
+
+ m.CreateA("System.Exception".AllowNoMatch()) ||
+ m.CreateA("System.ApplicationException".AllowNoMatch()) ||
+ m.CreateA("System.SystemException".AllowNoMatch()) )
+select m
+]]>
+ Do not raise reserved exception types
+warnif count > 0
+
+let reservedExceptions = ThirdParty.Types.WithFullNameIn(
+ "System.ExecutionEngineException",
+ "System.IndexOutOfRangeException",
+ "System.NullReferenceException",
+ "System.OutOfMemoryException",
+ "System.StackOverflowException",
+ "System.InvalidProgramException",
+ "System.AccessViolationException",
+ "System.CannotUnloadAppDomainException",
+ "System.BadImageFormatException",
+ "System.DataMisalignedException")
+
+from m in Application.Methods.ThatCreateAny(reservedExceptions)
+let reservedExceptionsCreated = reservedExceptions.Where(t => m.IsUsing(t))
+select new { m, reservedExceptionsCreated }]]>
+ Use integral or string argument for indexers
+from m in Application.Methods where
+m.IsIndexerGetter &&
+ !( (m.Name == @"get_Item(String)") ||
+ m.NameLike (@"get_Item\(Int") ||
+ m.NameLike (@"get_Item\(Byte") ||
+ m.NameLike (@"get_Item\(SByte") )
+select m
+
+// Indexers, that is, indexed properties,
+// should use integer or string types for the index.
+// These types are typically used for indexing
+// data structures and increase the usability of
+// the library. Use of the Object type should be
+// restricted to those cases where the specific
+// integer or string type cannot be specified at
+// design time. If the design requires other
+// types for the index, reconsider whether the
+// type represents a logical data store. If it
+// does not represent a logical data store,
+// use a method.]]>
+ Uri fields should be of type System.Uri
+warnif count > 0 from f in Application.Fields where
+ (f.NameLike (@"Uri$") ||
+ f.NameLike (@"Url$")) &&
+ !f.FieldTypeIs ("System.Uri".AllowNoMatch())
+select new { f, f.FieldType }
+
+// A field which name end with 'Uri' is deemed
+// as representing a uri. Such field should be of
+// type System.Uri.]]>
+ Types should not extend System.ApplicationException
+warnif count > 0 from t in Application.Types where
+ t.DeriveFrom("System.ApplicationException".AllowNoMatch())
+select t
+
+// For .NET Framework version 1, it was
+// recommended to derive new exceptions from
+// ApplicationException. The recommendation has
+// changed and new exceptions should derive
+// from System.Exception or one of its
+// subclasses in the System namespace.]]>
+
+
+ Collection properties should be read only
+
+// A writable collection property allows a user to replace the collection with
+// a completely different collection. A read-only property stops the collection
+// from being replaced but still allows the individual members to be set.
+// If replacing the collection is a goal, the preferred design pattern is to
+// include a method to remove all the elements from the collection
+// (with a call to the ICollection.Clear() method) and then re-populate the collection.
+
+warnif count > 0
+
+// First find collectionTypes
+let collectionInterfaces = ThirdParty.Types.WithFullNameIn(
+ "System.Collections.ICollection", "System.Collections.Generic.ICollection")
+where collectionInterfaces.Count() > 0
+let collectionTypes = Types.ThatImplementAny(collectionInterfaces)
+ .Union(collectionInterfaces).ToHashSet()
+
+// Then find all property setters that have an associated
+// getter that returns a collection type.
+from propGetter in Application.Methods.Where(
+ m => m.IsPropertyGetter &&
+ m.ReturnType != null &&
+ collectionTypes.Contains(m.ReturnType))
+
+let propSetter = propGetter.ParentType.Methods.WithSimpleName(
+ propGetter.SimpleName.Replace("get_","set_"))
+ .SingleOrDefault()
+
+where propSetter != null &&
+ !propSetter.IsPrivate
+
+select new { propSetter, propGetter.ReturnType }]]>
+ Don't use .NET 1.x HashTable and ArrayList
+warnif count > 0
+let forbiddenTypes = ThirdParty.Types.WithFullNameIn("System.Collections.HashTable", "System.Collections.ArrayList")
+where forbiddenTypes.Count() > 0
+from m in Application.Methods.ThatCreateAny(forbiddenTypes)
+select m
+
+// You can be forced to use HashTable or ArrayList
+// because you are using third party code that requires
+// working with these classes or because you are
+// coding with .NET 1.x.]]>
+ Caution with List.Contains()
+let containsMethods = ThirdParty.Methods.WithFullNameIn(
+ "System.Collections.Generic.List.Contains(T)",
+ "System.Collections.Generic.IList.Contains(T)",
+ "System.Collections.ArrayList.Contains(Object)")
+
+from m in Application.Methods.UsingAny(containsMethods)
+select m
+
+// The cost of checking if a list contains an
+// object is proportional to the size of the list
+// (O(N) operation). For large lists and/or frequent
+// calls to Contains(), prefer using the
+// System.Collections.Generic.HashSet class
+// where calls to Contains() takes a constant
+// time (O(0) operation).]]>
+ Prefer return collection abstraction instead of implementation
+let implTypes = ThirdParty.Types.WithFullNameIn(
+ "System.Collections.Generic.List",
+ "System.Collections.Generic.HashSet",
+ "System.Collections.Generic.Dictionary")
+
+from m in Application.Methods.WithReturnTypeIn(implTypes)
+select new { m, m.ReturnType }
+
+// Most of the time, clients of a method doesn't
+// need to know the exact implementation of the
+// collection returned. It is preferrable to return
+// a collection interface such as IList,
+// ICollection or IEnumerable.]]>
+
+
+ P/Invokes should be static and not be visible
+warnif count > 0 from m in Application.Methods where
+ !m.IsThirdParty &&
+ (m.HasAttribute ("System.Runtime.InteropServices.DllImportAttribute".AllowNoMatch())) &&
+ ( m.IsPublic ||
+ !m.IsStatic)
+select new { m, m.Visibility, m.IsStatic }
+
+// Methods marked with the DllImportAttribute
+// attribute (or methods defined using the
+// Declare keyword in Visual Basic) use
+// Platform Invocation Services to access unmanaged
+// code. Such methods should not be exposed. Keeping
+// these methods private or internal ensures
+// that your library cannot be used to breach
+// security by allowing callers access to
+// unmanaged APIs they could not call otherwise.]]>
+ Move P/Invokes to NativeMethods class
+warnif count > 0 from m in Application.Methods where
+ m.HasAttribute ("System.Runtime.InteropServices.DllImportAttribute".AllowNoMatch()) &&
+ m.ParentType.Name != "NativeMethods"
+select m
+
+// Platform Invocation methods, such as those marked
+// with the System.Runtime.InteropServices.DllImportAttribute
+// attribute, or methods defined by using the Declare
+// keyword in Visual Basic, access unmanaged code.
+// These methods should be in one of the following classes:
+//
+// - NativeMethods - This class does not suppress stack
+// walks for unmanaged code permission.
+// (System.Security.SuppressUnmanagedCodeSecurityAttribute
+// must not be applied to this class.)
+// This class is for methods that can be used
+// anywhere because a stack walk will be performed.
+//
+// - SafeNativeMethods - This class suppresses
+// stack walks for unmanaged code permission.
+// (System.Security.SuppressUnmanagedCodeSecurityAttribute
+// is applied to this class.)
+// This class is for methods that are safe
+// for anyone to call. Callers of these methods
+// are not required to do a full security review
+// to ensure that the usage is secure because
+// the methods are harmless for any caller.
+//
+// - UnsafeNativeMethods - This class suppresses
+// stack walks for unmanaged code permission.
+// (System.Security.SuppressUnmanagedCodeSecurityAttribute
+// is applied to this class.) This class is for
+// methods that are potentially dangerous. Any
+// caller of these methods must do a full security
+// review to ensure that the usage is secure because
+// no stack walk will be performed.
+]]>
+ NativeMethods class should be static and internal
+warnif count > 0 from t in Application.Types.WithNameIn(
+ @"NativeMethods", "SafeNativeMethods", "UnsafeNativeMethods") where
+ t.IsPublic || !t.IsStatic
+select new { t, t.Visibility, t.IsStatic }
+
+// Native Methods' classes are declared as internal
+// (Friend, in Visual Basic) and static.
+]]>
+
+
+ Method non-synchronized that read mutable states
+from m in Application.Methods where
+ (m.ReadsMutableObjectState || m.ReadsMutableTypeState) &&
+ !m.IsUsing ("System.Threading.Monitor".AllowNoMatch()) &&
+ !m.IsUsing ("System.Threading.ReaderWriterLock".AllowNoMatch())
+select new { m, mutableFieldsUsed = m.FieldsUsed.Where(f => !f.IsImmutable) }
+
+// Mutable object states are instance fields that
+// can be modifed throught the lifetime of the object.
+// Mutable type states are static fields that can be
+// modifed throught the lifetime of the program.
+// This query lists methods that read mutable state
+// without synchronizing access. In the case of
+// multi-threaded program, doing so can lead to
+// state corruption.]]>
+ Don't create threads explicitely
+warnif count > 0 from m in Application.Methods where
+ m.CreateA ("System.Threading.Thread".AllowNoMatch())
+select m
+
+// Prefer using the thread pool instead of
+// creating manually your own thread.
+// Threads are costly objects.
+// They take approximately 200,000 cycles to
+// create and about 100,000 cycles to destroy.
+// By default they reserve 1 megabyte of virtual
+// memory for its stack and use 2,000-8,000
+// cycles for each context switch.
+// As a consequence, it is preferrable to let
+// the thread pool recycle threads.
+
+// Creating custom thread can also be the
+// sign of flawed design, where tasks and
+// threads have affinity. It is preferrable
+// to code tasks that can be ran on any thread.]]>
+ Don't use dangerous threading methods
+warnif count > 0
+
+let wrongMethods = ThirdParty.Methods.WithFullNameIn(
+
+ // Usage of Thread.Abort() is dangerous.
+ // More information on this here:
+ // http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation
+ "System.Threading.Thread.Abort()",
+ "System.Threading.Thread.Abort(Object)",
+
+ // Usage of Thread.Sleep() is a sign of
+ // flawed design. More information on this here:
+ // http://msmvps.com/blogs/peterritchie/archive/2007/04/26/thread-sleep-is-a-sign-of-a-poorly-designed-program.aspx
+ "System.Threading.Thread.Sleep(Int32)",
+
+ // Suspend() and Resume() are dangerous threading methods, marked as obsolete.
+ // More information on workaround here:
+ // http://stackoverflow.com/questions/382173/what-are-alternative-ways-to-suspend-and-resume-a-thread
+ "System.Threading.Thread.Suspend()",
+ "System.Threading.Thread.Resume()"
+)
+
+from m in Application.Methods.UsingAny(wrongMethods)
+select new { m, calls = m.MethodsCalled.Intersect(wrongMethods) }
+
+]]>
+ Monitor TryEnter/Exit must be both called within the same method
+// Else you expose yourself to complex error-prone scenarios.
+warnif count > 0
+
+let enterMethods = ThirdParty.Methods.WithFullNameWildcardMatchIn(
+ "System.Threading.Monitor.Enter(*",
+ "System.Threading.Monitor.TryEnter(*")
+
+from m in Application.Methods.UsingAny(enterMethods) where
+ !m.IsUsing ("System.Threading.Monitor.Exit(Object)".AllowNoMatch())
+select new { m, enterMethodsCalled = m.MethodsCalled.Intersect(enterMethods) }]]>
+ ReaderWriterLock Acquire[Reader/Writer]Lock/ReleaseLock must be both called within the same method
+// Else you expose yourself to complex error-prone scenarios.
+warnif count > 0
+
+let acquireLockMethods = ThirdParty.Methods.WithFullNameWildcardMatch(
+ "System.Threading.ReaderWriterLock.AcquireReaderLock(*")
+
+from m in Application.Methods.UsingAny(acquireLockMethods) where
+ !m.IsUsing ("System.Threading.ReaderWriterLock.ReleaseReaderLock()".AllowNoMatch()) &&
+ !m.IsUsing ("System.Threading.ReaderWriterLock.ReleaseLock()".AllowNoMatch())
+select new { m, acquireLockMethods = m.MethodsCalled.Intersect(acquireLockMethods) }]]>
+ Don't tag instance fields with ThreadStaticAttribute
+// The ThreadStaticAttribute is designed to only works when it tags static fields.
+warnif count > 0
+from f in Application.Fields
+where !f.IsStatic &&
+ f.HasAttribute ("System.ThreadStaticAttribute".AllowNoMatch())
+select new { f, f.SizeOfInst }]]>
+
+
+ Method should not return concrete XmlNode
+warnif count > 0
+
+let concreteXmlTypes = ThirdParty.Types.WithFullNameIn(
+ "System.Xml.XmlDocument",
+ "System.Xml.XmlAttribute",
+ "System.Xml.XmlDocumentFragment",
+ "System.Xml.XmlEntity",
+ "System.Xml.XmlLinkedNode",
+ "System.Xml.XmlNotation",
+ "System.Xml.XmlNode")
+
+from m in Application.Methods.WithReturnTypeIn(concreteXmlTypes)
+select new { m, m.ReturnType }
+
+// The class System.Xml.XmlNode implements the interface
+// System.Xml.Xpath.IXPathNavigable. It is preferrable
+// to return this interface instead of a concrete class.
+]]>
+ Types should not extend System.Xml.XmlDocument
+warnif count > 0 from t in Application.Types where
+ t.DeriveFrom("System.Xml.XmlDocument".AllowNoMatch())
+select t
+
+// Do not create a subclass of XmlDocument if you want
+// to create an XML view of an underlying object
+// model or data source.]]>
+
+
+ Float and Date Parsing must be culture aware
+warnif count > 0
+from m in ThirdParty.Types.WithFullNameIn(
+ "System.DateTime",
+ "System.Single",
+ "System.Double",
+ "System.Decimal").ChildMethods()
+
+ where m.NbParameters > 0 &&
+ (m.SimpleName == "Parse" ||
+ m.SimpleName == "ToString") &&
+ !m.Name.Contains("IFormatProvider")
+select new { m, m.MethodsCallingMe }]]>
+
+
+ Public methods returning a reference needs a contract to ensure that a non-null reference is returned
+
+// Contracts are useful to decrease ambiguity between callers and callees.
+// Not ensuring that a reference returned is not-null leaves ambiguity for the caller.
+// Contract.Ensures(Contract.Result<***ReturnType***>() != null, "returned object is not null");
+
+// We advise to use the {TryXXX} pattern exposed in the System.Int32.TryParse() method for example
+// if you need to express that a method might return a null reference.
+
+warnif count > 0
+from a in Application.Assemblies where a.IsUsing ("Microsoft.Contracts".AllowNoMatch().MatchAssembly())
+let ensureMethod = a.ChildMethods.WithFullName("System.Diagnostics.Contracts.__ContractsRuntime.Ensures(Boolean,String,String)").SingleOrDefault()
+where ensureMethod != null
+
+from m in a.ChildMethods where
+ m.IsPubliclyVisible &&
+ !m.IsAbstract &&
+ m.ReturnType != null &&
+ // Identify that the return type is a reference type
+ (m.ReturnType.IsClass || m.ReturnType.IsInterface) &&
+ !m.IsUsing(ensureMethod )
+
+select new { m, ReturnTypeReference = m.ReturnType }]]>
+
+
+ Third-Party Assemblies Used
+ThirdParty.Assemblies.Select(a => a)]]>
+ Third-Party Namespaces Used
+ThirdParty.Namespaces.Select(n => n)]]>
+ Third-Party Types Used
+ThirdParty.Types.Select(t => t)]]>
+ Third-Party Methods Used
+ThirdParty.Methods.Select(m => m)]]>
+ Third-Party Fields Used
+ThirdParty.Fields.Select(f => f)]]>
+
+
+
+
+
+Application.Assemblies.Sum(a => a.NbLinesOfCode)]]>
+
+JustMyCode.Methods.Sum(m => m.NbLinesOfCode)
+
+// JustMyCode is defined by code queries prefixed with 'notmycode'
+// in the group 'Defining JustMyCode'.
+]]>
+
+Application.Methods.Where(m => !JustMyCode.Contains(m))
+ .Sum(m => m.NbLinesOfCode)
+
+// JustMyCode is defined by code queries prefixed with 'notmycode'
+// in the group 'Defining JustMyCode'.
+]]>
+
+( from a in Application.Assemblies
+ let nbLocAdded = !a.IsPresentInBothBuilds()
+ ? a.NbLinesOfCode
+ : (a.NbLinesOfCode != null && a.OlderVersion().NbLinesOfCode != null)
+ ? a.NbLinesOfCode - (int)a.OlderVersion().NbLinesOfCode
+ : 0
+ select nbLocAdded)
+.Sum(loc => loc)
+
+// A value is computed by this Trend Metric query
+// only if a Baseline for Comparison is provided.
+// See Project Properties > Analysis > Baseline for Comparison
+]]>
+
+Application.Assemblies.SelectMany(
+ a => a.SourceDecls.Select(sd => sd.SourceFile.FilePathString.ToLower()))
+.Distinct()
+.Count()
+
+// If a value 0 is obtained, it means that at analysis time,
+// assemblies PDB files were not available.
+// http://www.ndepend.com/Doc_CI_Inputs.aspx
+]]>
+
+Application.Assemblies.Sum(a => a.NbILInstructions)
+]]>
+
+Application.Methods.Where(m => !JustMyCode.Contains(m))
+ .Sum(m => m.NbILInstructions)
+
+// JustMyCode is defined by code queries prefixed with 'notmycode'
+// in the group 'Defining JustMyCode'.
+]]>
+
+Application.Assemblies.Sum(a => a.NbLinesOfComment)
+
+// So far comments are only extracted from C# source code.
+]]>
+
+Application.Assemblies.Count()
+
+]]>
+
+Application.Namespaces.Count()]]>
+
+Application.Types.Count()]]>
+
+Application.Types.Where(t => t.IsPubliclyVisible).Count()]]>
+
+Application.Types.Count(t => t.IsClass && !t.IsGeneratedByCompiler)
+]]>
+
+Application.Types.Count(t => t.IsClass && t.IsAbstract)
+
+]]>
+
+Application.Types.Count(t => t.IsInterface)]]>
+
+Application.Types.Count(t => t.IsStructure)]]>
+
+Application.Methods.Count(m => !m.IsGeneratedByCompiler)]]>
+
+Application.Methods.Count(m => m.IsAbstract)]]>
+
+Application.Methods.Count(m => !m.IsAbstract && !m.IsGeneratedByCompiler)
+]]>
+
+Application.Fields.Count(f =>
+ !f.IsEnumValue &&
+ !f.IsGeneratedByCompiler &&
+ !f.IsLiteral &&
+ !f.ParentType.IsEnumeration)
+
+]]>
+
+
+
+JustMyCode.Methods
+ .Max(m => m.NbLinesOfCode)
+ .ToEnumerable().Sum(loc => loc)
+
+// Here is the code query to get the (JustMyCode) method with largest # Lines of Code
+// JustMyCode.Methods.OrderByDescending(m => m.NbLinesOfCode).Take(1).Select(m => new {m, m.NbLinesOfCode})
+]]>
+
+Application.Methods.Where(m => m.NbLinesOfCode > 0)
+ .Average(m => m.NbLinesOfCode)]]>
+
+Application.Methods.Where(m => m.NbLinesOfCode >= 3)
+ .Average(m => m.NbLinesOfCode)
+]]>
+
+JustMyCode.Types
+ .Max(t => t.NbLinesOfCode)
+ .ToEnumerable().Sum(loc => loc)
+
+// Here is the code query to get the (JustMyCode) type with largest # Lines of Code
+// JustMyCode.Types.OrderByDescending(t => t.NbLinesOfCode).Take(1).Select(t => new {t, t.NbLinesOfCode})
+
+]]>
+
+Application.Types.Where(t => t.NbLinesOfCode > 0)
+ .Average(t => t.NbLinesOfCode)]]>
+
+Application.Methods
+ .Max(m => m.CyclomaticComplexity)
+ .ToEnumerable().Sum(loc => loc)
+
+// Here is the code query to get the most complex method, according to Cyclomatic Complexity
+// Application.Methods.OrderByDescending(m => m.CyclomaticComplexity).Take(1).Select(m => new {m, m.CyclomaticComplexity})
+]]>
+
+Application.Methods.Where(m => m.NbLinesOfCode> 0)
+ .Average(m => m.CyclomaticComplexity)]]>
+
+Application.Methods
+ .Max(m => m.ILCyclomaticComplexity)
+ .ToEnumerable().Sum(loc => loc)
+
+// Here is the code query to get the most complex method, according to Cyclomatic Complexity computed from IL code.
+// Application.Methods.OrderByDescending(m => m.ILCyclomaticComplexity).Take(1).Select(m => new {m, m.CyclomaticComplexity})
+]]>
+
+Application.Methods.Where(m => m.NbILInstructions> 0)
+ .Average(m => m.ILCyclomaticComplexity)
+]]>
+
+Application.Methods
+ .Max(m => m.ILNestingDepth)
+ .ToEnumerable().Sum(loc => loc)
+
+// Here is the code query to get the method with highest ILNestingDepth.
+// Application.Methods.OrderByDescending(m => m.ILNestingDepth).Take(1).Select(m => new {m, m.ILNestingDepth})
+]]>
+
+Application.Methods.Where(m => m.NbILInstructions> 0)
+ .Average(m => m.ILNestingDepth)
+]]>
+
+Application.Types
+ .Max(t => t.NbMethods)
+ .ToEnumerable().Sum(loc => loc)
+
+// Here is the code query to get the (JustMyCode) type with largest # of Methods
+// JustMyCode.Types.OrderByDescending(t => t.NbMethods).Take(1).Select(t => new {t, t.Methods})
+
+]]>
+
+Application.Types.Average(t => t.NbMethods)]]>
+
+Application.Types.Where(t => t.IsInterface)
+ .Max(t => t.NbMethods)
+ .ToEnumerable().Sum(loc => loc)
+
+// Here is the code query to get the (JustMyCode) type with largest # of Methods
+// JustMyCode.Types.OrderByDescending(t => t.NbMethods).Take(1).Select(t => new {t, t.Methods})]]>
+
+JustMyCode.Types.Where(t => t.IsInterface)
+ .Average(t => t.NbMethods)
+]]>
+
+
+
+((float)Application.Assemblies.Sum(a => a.NbLinesOfCodeCovered) /
+ Application.Assemblies.Sum(a => a.NbLinesOfCode)
+ * 100f)
+.ToEnumerable().Sum()
+]]>
+
+Application.Assemblies.Sum(a => a.NbLinesOfCodeCovered)]]>
+
+Application.Assemblies.Sum(a => a.NbLinesOfCodeNotCovered)]]>
+
+Application.Types.Where(t => t.PercentageCoverage == 100)
+ .Sum(t => t.NbLinesOfCodeCovered)]]>
+
+Application.Methods.Where(m => m.PercentageCoverage == 100)
+ .Sum(m => m.NbLinesOfCodeCovered)]]>
+
+// Change Risk Analyzer and Predictor (i.e. CRAP) code metric
+// This code metric helps in pinpointing overly complex and untested code.
+// Reference: http://www.artima.com/weblogs/viewpost.jsp?thread=215899
+// Formula: CRAP(m) = comp(m)^2 * (1 - cov(m)/100)^3 + comp(m)
+
+(from m in JustMyCode.Methods
+
+// Don't match too short methods
+where m.NbLinesOfCode > 10
+
+let CC = m.CyclomaticComplexity
+let uncov = (100 - m.PercentageCoverage) / 100f
+let CRAP = (CC * CC * uncov * uncov * uncov) + CC
+where CRAP != null && CRAP > 30 select CRAP)
+.Max(CRAP => CRAP)
+
+// To list methods with highest C.R.A.P scores, please refer to the default rule:
+// Test and Code Coverage > C.R.A.P method code metric
+]]>
+
+// Change Risk Analyzer and Predictor (i.e. CRAP) code metric
+// This code metric helps in pinpointing overly complex and untested code.
+// Reference: http://www.artima.com/weblogs/viewpost.jsp?thread=215899
+// Formula: CRAP(m) = comp(m)^2 * (1 - cov(m)/100)^3 + comp(m)
+
+(from m in JustMyCode.Methods
+
+// Don't match too short methods
+where m.NbLinesOfCode > 10
+
+let CC = m.CyclomaticComplexity
+let uncov = (100 - m.PercentageCoverage) / 100f
+let CRAP = (CC * CC * uncov * uncov * uncov) + CC
+where CRAP != null && CRAP > 30 select CRAP)
+.Average(CRAP => CRAP)
+
+// To list methods with highest C.R.A.P scores, please refer to the default rule:
+// Test and Code Coverage > C.R.A.P method code metric
+]]>
+
+
+
+ThirdParty.Assemblies.Count()]]>
+
+ThirdParty.Namespaces.Count()]]>
+
+ThirdParty.Types.Count()]]>
+
+ThirdParty.Methods.Count()]]>
+
+ThirdParty.Fields.Count()]]>
+
+
+
+ Discard generated Assemblies from JustMyCode
+// --- Make sure to make this query richer to discard generated assemblies from NDepend rules results---
+notmycode
+from a in Application.Assemblies where
+// Assemblies generated for Xsl IL compilation for example are tagged with this attribute
+a.HasAttribute ("System.CodeDom.Compiler.GeneratedCodeAttribute".AllowNoMatch())
+select new { a, a.NbILInstructions }]]>
+ Discard generated Types from JustMyCode
+// --- Make sure to make this query richer to discard generated types from NDepend rules results ---
+notmycode
+from t in Application.Types where
+
+ // Resources, Settings, or typed DataSet generated types for example, are tagged with this attribute
+ t.HasAttribute ("System.CodeDom.Compiler.GeneratedCodeAttribute".AllowNoMatch()) ||
+
+ // This attributes identifies a type or member that is not part of the user code for an application.
+ t.HasAttribute ("System.Diagnostics.DebuggerNonUserCodeAttribute".AllowNoMatch()) ||
+
+ // Delegate types are always generated
+ t.IsDelegate ||
+
+ // Discard ASP.NET page types generated by aspnet_compiler.exe
+ // See: http://www.ndepend.com/FAQ.aspx#ASPNET
+ t.ParentNamespace.Name.EqualsAny("ASP", "__ASP") ||
+
+ // Discard generated type ContractException
+ t.Name == "__ContractsRuntime+ContractException" ||
+ t.FullName == "System.Diagnostics.Contracts.RuntimeContractsAttribute" ||
+ t.FullName == "System.Diagnostics.Contracts.__ContractsRuntime" ||
+
+ // Discard all types declared in a folder path containing the word "generated"
+ (t.SourceFileDeclAvailable &&
+ t.SourceDecls.All(s => s.SourceFile.FilePath.ParentDirectoryPath.ToString().ToLower().Contains("generated")))
+
+select new { t, t.NbLinesOfCode }]]>
+ Discard generated and designer Methods from JustMyCode
+// --- Make sure to make this query richer to discard generated methods from NDepend rules results ---
+notmycode
+
+//
+// First define source files paths to discard
+//
+from a in Application.Assemblies
+where a.SourceFileDeclAvailable
+let asmSourceFilesPaths = a.SourceDecls.Select(s => s.SourceFile.FilePath)
+
+let sourceFilesPathsToDiscard = (
+ from filePath in asmSourceFilesPaths
+ let filePathLower= filePath.ToString().ToLower()
+ where
+ filePathLower.EndsWithAny(
+ ".g.cs", // Popular pattern to name generated files.
+ ".g.vb",
+ ".xaml", // notmycode WPF xaml code
+ ".designer.cs", // notmycode C# Windows Forms designer code
+ ".designer.vb") // notmycode VB.NET Windows Forms designer code
+ ||
+ // notmycode methods in source files in a directory containing generated
+ filePathLower.Contains("generated")
+ select filePath
+).ToHashSet()
+
+//
+// Second: discard methods in sourceFilesPathsToDiscard
+//
+from m in a.ChildMethods
+where (m.SourceFileDeclAvailable &&
+ sourceFilesPathsToDiscard.Contains(m.SourceDecls.First().SourceFile.FilePath)) ||
+ // Generated methods might be tagged with this attribute
+ m.HasAttribute ("System.CodeDom.Compiler.GeneratedCodeAttribute".AllowNoMatch()) ||
+
+ // This attributes identifies a type or member that is not part of the user code for an application.
+ m.HasAttribute ("System.Diagnostics.DebuggerNonUserCodeAttribute".AllowNoMatch())
+
+select new { m, m.NbLinesOfCode }]]>
+ Discard generated Fields from JustMyCode
+// --- Make sure to make this query richer to discard generated fields from NDepend rules results ---
+notmycode
+from f in Application.Fields where
+ f.HasAttribute ("System.CodeDom.Compiler.GeneratedCodeAttribute".AllowNoMatch()) ||
+
+ // Eliminate "components" generated in Windows Form Conrol context
+ f.Name == "components" && f.ParentType.DeriveFrom("System.Windows.Forms.Control".AllowNoMatch())
+select f]]>
+
+
+ Most used types (Rank)
+(from t in Application.Types orderby t.Rank descending
+ select new { t, t.Rank }).Take(50)
+
+// TypeRank values are computed by applying
+// the Google PageRank algorithm on the
+// graph of types' dependencies. Types with
+// high Rank are the most used ones.
+// See the definition of the TypeRank metric here:
+// http://www.ndepend.com/Metrics.aspx#TypeRank]]>
+ Most used methods (Rank)
+(from m in Application.Methods orderby m.Rank descending
+ select new { m, m.Rank }).Take(50)
+
+// MethodRank values are computed by applying
+// the Google PageRank algorithm on the graph of
+// methods' dependencies. Methods with high Rank
+// are the most used ones. See the definition of
+// the MethodRank metric here:
+// http://www.ndepend.com/Metrics.aspx#MethodRank]]>
+ Most used namespaces (#NamespacesUsingMe )
+(from n in Namespaces orderby n.NbNamespacesUsingMe descending
+ select new { n, n.NamespacesUsingMe }).Take(50)]]>
+ Most used types (#TypesUsingMe )
+(from t in Types orderby t.NbTypesUsingMe descending
+ select new { t, t.TypesUsingMe }).Take(50)]]>
+ Most used methods (#MethodsCallingMe )
+(from m in Methods orderby m.NbMethodsCallingMe descending
+ select new { m, m.MethodsCallingMe }).Take(50)]]>
+ Namespaces that use many other namespaces (#NamespacesUsed )
+(from n in Application.Namespaces orderby n.NbNamespacesUsed descending
+ select new { n, n.NamespacesUsed }).Take(50)]]>
+ Types that use many other types (#TypesUsed )
+(from t in Application.Types orderby t.NbTypesUsed descending
+ select new { t, t.TypesUsed }).Take(50)]]>
+ Methods that use many other methods (#MethodsCalled )
+(from m in Application.Methods orderby m.NbMethodsCalled descending
+ select new { m, m.MethodsCalled }).Take(50)]]>
+ High-level to low-level assemblies (Level)
+from a in Application.Assemblies orderby a.Level descending
+select new { a, a.Level }
+
+// Classify assemblies by their Level values.
+// See the definition of the AssemblyLevel metric here:
+// http://www.ndepend.com/Metrics.aspx#Level]]>
+ High-level to low-level namespaces (Level)
+from n in Application.Namespaces orderby n.Level descending
+select new { n, n.Level }
+
+// Classify namespaces by their Level values.
+// See the definition of the NamespaceLevel metric here:
+// http://www.ndepend.com/Metrics.aspx#Level]]>
+ High-level to low-level types (Level)
+from t in Application.Types orderby t.Level descending
+select new { t, t.Level }
+
+// Classify types by their Level values.
+// See the definition of the TypeLevel metric here:
+// http://www.ndepend.com/Metrics.aspx#Level]]>
+ High-level to low-level methods (Level)
+from m in Application.Methods orderby m.Level descending
+select new { m, m.Level }
+
+// Classify methods by their Level values.
+// See the definition of the MethodLevel metric here:
+// http://www.ndepend.com/Metrics.aspx#Level]]>
+
+
+ Check that the assembly Asm1 is not using the assembly Asm2
+warnif count > 0 from a in Application.Assemblies where
+ a.IsUsing ("Asm2".AllowNoMatch().MatchAssembly()) &&
+ (a.Name == @"Asm1")
+select a
+]]>
+ Check that the namespace N1.N2 is not using the namespace N3.N4.N5
+warnif count > 0 from n in Application.Namespaces where
+ n.IsUsing ("N3.N4.N5".AllowNoMatch().MatchAssembly()) &&
+ (n.Name == @"N1.N2")
+select n
+]]>
+ Check that the assembly Asm1 is only using the assemblies Asm2, Asm3 or mscorlib
+warnif count > 0 from a in Application.Assemblies where
+ ( !a.IsUsing ("Asm2".AllowNoMatch().MatchAssembly()) ||
+ !a.IsUsing ("Asm3".AllowNoMatch().MatchAssembly()) ||
+ !a.IsUsing ("mscorlib".MatchAssembly()) ||
+ a.AssembliesUsed.Count() != 3) // Must not be used more than 3 assemblies
+&&
+ (a.Name == @"Asm1")
+select new { a, a.AssembliesUsed }
+]]>
+ Check that the namespace N1.N2 is only using the namespaces N3.N4, N5 or System
+warnif count > 0 from n in Application.Namespaces where
+ ( !n.IsUsing("N3.N4".AllowNoMatch().MatchNamespace()) ||
+ !n.IsUsing("N5".AllowNoMatch().MatchNamespace()) ||
+ !n.IsUsing("System".MatchNamespace()) ||
+ n.NamespacesUsed.Count() != 3) // Must not be used more than 3 assemblies
+ // AsmCe = Efferent Coupling for assembly
+&&
+ (n.Name == @"N1.N2")
+select new { n, n.NamespacesUsed }
+]]>
+ Check that AsmDrawing is the only assembly that is using System.Drawing
+warnif count> 0 from a in Application.Assemblies where
+ a.IsUsing ("System.Drawing".AllowNoMatch().MatchAssembly()) &&
+ !(a.Name == @"AsmDrawing")
+select a
+]]>
+ Check that only 3 assemblies are using System.Drawing
+warnif count != 3 from a in Application.Assemblies where
+ a.IsUsing ("System.Drawing".AllowNoMatch().MatchAssembly())
+select a
+]]>
+ Check that all methods that call Foo.Fct1() also call Foo.Fct2(Int32)
+warnif count > 0 from m in Application.Methods where
+ m.IsUsing ("Foo.Fct1()".AllowNoMatch()) &&
+ !m.IsUsing ("Foo.Fct2(Int32)".AllowNoMatch())
+select m
+]]>
+ Check that all types that derive from Foo, also implement IFoo
+warnif count > 0 from t in Application.Types where
+ t.DeriveFrom ("Foo".AllowNoMatch().MatchType()) &&
+ !t.Implement ("IFoo".AllowNoMatch().MatchType())
+select t
+]]>
+ Check that all types that has the attribute FooAttribute are declared in the namespace N1.N2*
+warnif count > 0 from t in
+ Application.Namespaces.WithNameWildcardMatchNotIn("N1.N2*").ChildTypes()
+ where
+ t.HasAttribute ("FooAttribute".AllowNoMatch())
+select t]]>
+ Check that all synchronization objects are only used from the namespaces under MyNamespace.Sync
+warnif count > 0 from n in Application.Namespaces
+ where
+ (n.IsUsing ("System.Threading.Monitor".AllowNoMatch()) ||
+ n.IsUsing ("System.Threading.ReaderWriterLock".AllowNoMatch()) ||
+ n.IsUsing ("System.Threading.Mutex".AllowNoMatch()) ||
+ n.IsUsing ("System.Threading.EventWaitHandle".AllowNoMatch()) ||
+ n.IsUsing ("System.Threading.Semaphore".AllowNoMatch()) ||
+ n.IsUsing ("System.Threading.Interlocked".AllowNoMatch()))
+ && !n.NameLike (@"^MyNamespace.Sync")
+select n
+]]>
+
+ Check that the assembly Asm is 100% covered by tests
+warnif count > 0 from a in Application.Assemblies where
+ (a.Name == @"Asm") &&
+ a.PercentageCoverage < 100
+select new { a, a.PercentageCoverage }
+
+
+// To run this rule properly coverage data
+// must be gathered from NCover™ or Visual Studio™ Coverage.
+// This can be done throught the menu:
+// NDepend -> Coverage -> Import Coverage Files
+// This can be done at analysis time throught the menu:
+// Project Properties -> Analysis -> Code Coverage
+// More information on how to import coverage data here:
+// http://www.ndepend.com/Coverage.aspx
+
+]]>
+ Check that the namespace N1.N2 is 100% covered by tests
+warnif count > 0 from n in Application.Namespaces where
+ (n.Name == @"N1.N2") &&
+ n.PercentageCoverage < 100
+select new { n, n.PercentageCoverage }
+
+
+// To run this rule properly coverage data
+// must be gathered from NCover™ or Visual Studio™ Coverage.
+// This can be done throught the menu:
+// NDepend -> Coverage -> Import Coverage Files
+// This can be done at analysis time throught the menu:
+// Project Properties -> Analysis -> Code Coverage
+// More information on how to import coverage data here:
+// http://www.ndepend.com/Coverage.aspx
+
+]]>
+ Check that the class Namespace.Foo is 100% covered by tests
+warnif count > 0 from t in Application.Types where
+ (t.FullName == @"Namespace.Foo") &&
+ t.PercentageCoverage < 100
+select new { t, t.PercentageCoverage }
+
+
+// To run this rule properly coverage data
+// must be gathered from NCover™ or Visual Studio™ Coverage.
+// This can be done throught the menu:
+// NDepend -> Coverage -> Import Coverage Files
+// This can be done at analysis time throught the menu:
+// Project Properties -> Analysis -> Code Coverage
+// More information on how to import coverage data here:
+// http://www.ndepend.com/Coverage.aspx
+
+]]>
+ Check that the class Namespace.Foo.Method(Int32) is 100% covered by tests
+warnif count > 0 from t in Application.Types where
+ (t.FullName == @"Namespace.Foo.Method(Int32)") &&
+ t.PercentageCoverage < 100
+select new { t, t.PercentageCoverage }
+
+
+// To run this rule properly coverage data
+// must be gathered from NCover™ or Visual Studio™ Coverage.
+// This can be done throught the menu:
+// NDepend -> Coverage -> Import Coverage Files
+// This can be done at analysis time throught the menu:
+// Project Properties -> Analysis -> Code Coverage
+// More information on how to import coverage data here:
+// http://www.ndepend.com/Coverage.aspx
+
+]]>
+
+
+ Check that all types that derive from Foo, has a name that ends up with Foo
+warnif count > 0 from t in Application.Types where
+ t.DeriveFrom ("Foo".AllowNoMatch().MatchType()) &&
+ !t.NameLike (@"Foo$")
+select new { t, t.NbLinesOfCode }
+]]>
+ Check that all namespaces begins with CompanyName.ProductName
+warnif count > 0 from n in Application.Namespaces where
+ !n.NameLike (@"^CompanyName.ProductName")
+select new { n, n.NbLinesOfCode } ]]>
+
+
+
+
+
\ No newline at end of file
diff --git a/NOCQ.sln b/NOCQ.sln
index b10310e..38a986d 100644
--- a/NOCQ.sln
+++ b/NOCQ.sln
@@ -1,10 +1,19 @@
-Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual Studio 2010
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.30501.0
+MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NOCQ", "src\NOCQ\NOCQ.csproj", "{83651B7D-B58F-46B8-BFE2-BCC0A6C92C7A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NOCQ.Application", "src\NOCQ.Application\NOCQ.Application.csproj", "{DF8CD7EA-76FC-4B57-B24A-52C6373A8EDF}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NOCQ.UnitTest", "src\NOCQ.UnitTest\NOCQ.UnitTest.csproj", "{D9435B3A-C005-49C2-9C0D-B87330B006D7}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{37EF7652-8519-4B19-89DB-9C9916F53908}"
+ ProjectSection(SolutionItems) = preProject
+ .nuget\packages.config = .nuget\packages.config
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -19,8 +28,18 @@ Global
{DF8CD7EA-76FC-4B57-B24A-52C6373A8EDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DF8CD7EA-76FC-4B57-B24A-52C6373A8EDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DF8CD7EA-76FC-4B57-B24A-52C6373A8EDF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D9435B3A-C005-49C2-9C0D-B87330B006D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D9435B3A-C005-49C2-9C0D-B87330B006D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D9435B3A-C005-49C2-9C0D-B87330B006D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D9435B3A-C005-49C2-9C0D-B87330B006D7}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = src\NOCQ.Application\NOCQ.Application.csproj
EndGlobalSection
+ GlobalSection(NDepend) = preSolution
+ Project = ".\NOCQ.ndproj"
+ EndGlobalSection
EndGlobal
diff --git a/NOCQ.v12.suo b/NOCQ.v12.suo
new file mode 100644
index 0000000..dbedcda
Binary files /dev/null and b/NOCQ.v12.suo differ
diff --git a/src/NOCQ.UnitTest/Class1.cs b/src/NOCQ.UnitTest/Class1.cs
new file mode 100644
index 0000000..a01af0b
--- /dev/null
+++ b/src/NOCQ.UnitTest/Class1.cs
@@ -0,0 +1,18 @@
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace NOCQ.UnitTest
+{
+ [TestFixture]
+ public class Class1
+ {
+ public static void Success()
+ {
+ Assert.Pass();
+ }
+ }
+}
diff --git a/src/NOCQ.UnitTest/NOCQ.UnitTest.csproj b/src/NOCQ.UnitTest/NOCQ.UnitTest.csproj
new file mode 100644
index 0000000..219da77
--- /dev/null
+++ b/src/NOCQ.UnitTest/NOCQ.UnitTest.csproj
@@ -0,0 +1,59 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {D9435B3A-C005-49C2-9C0D-B87330B006D7}
+ Library
+ Properties
+ NOCQ.UnitTest
+ NOCQ.UnitTest
+ v4.5
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\..\packages\NUnit.2.6.3\lib\nunit.framework.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/NOCQ.UnitTest/Properties/AssemblyInfo.cs b/src/NOCQ.UnitTest/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..1a40912
--- /dev/null
+++ b/src/NOCQ.UnitTest/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("NOCQ.UnitTest")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("NOCQ.UnitTest")]
+[assembly: AssemblyCopyright("Copyright © 2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("1e338b42-4312-4561-9d92-91057b434f5d")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/NOCQ.UnitTest/packages.config b/src/NOCQ.UnitTest/packages.config
new file mode 100644
index 0000000..d4e241a
--- /dev/null
+++ b/src/NOCQ.UnitTest/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file