Discard generated Types from JustMyCode

JustMyCode Definition ND3002 Defining JustMyCode

A notmycode query: matched types (and their methods and fields) are removed from the JustMyCode code base view used by most default queries and rules.

It matches several well-identified generated types, like the ones tagged System.CodeDom.Compiler.GeneratedCodeAttribute. Enrich it to discard your own generated types.

notmycode queries run before other queries and rules; modifying one re-runs the queries relying on JustMyCode. Several notmycode types queries cumulate. Documentation: https://www.ndepend.com/docs/cqlinq-syntax#NotMyCode

CQLinq source

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

// <Name>Discard generated Types from JustMyCode</Name>
// <Id>ND3002:DiscardGeneratedTypesFromJustMyCode</Id>

notmycode

// Define some sets to quickly test EntityFramework generated types
let efContexts = Application.Types.Where(t => 
  t.DeriveFrom("System.Data.Entity.DbContext".AllowNoMatch()) &&
  t.SourceDecls.Count(
           sd => sd.SourceFile.FileName.EndsWithAny(
                 ".context.cs", ".context.vb", StringComparison.OrdinalIgnoreCase)) 
       == 1).ToHashSetEx()
let efEntities = Application.Types.UsedByAny(efContexts).ToHashSetEx()
let efMigrations = Application.Types.Where(t => 
   t.DeriveFrom("System.Data.Entity.Migrations.DbMigration".AllowNoMatch()) || 
   t.DeriveFrom("Microsoft.EntityFrameworkCore.Migrations.Migration".AllowNoMatch())).ToHashSetEx()
let efModelSnapshots = Application.Types.Where(t => t.DeriveFrom(
     "Microsoft.EntityFrameworkCore.Infrastructure.ModelSnapshot".AllowNoMatch())).ToHashSetEx()

let unityContext = ThirdParty.Assemblies.Any(a => a.Name.StartsWith("UnityEngine"))

from t in Application.Types where

  // Don't consider anonymous types as JustMyCode  
  // C# and VB.NET anonymous types generated by the compiler satisfies these conditions
  (t.IsGeneratedByCompiler && 
   t.ParentNamespace.Name.Length == 0 &&
   t.SimpleNameLike("AnonymousType")) ||

  // Types generated by the compiler for collections
  (t.IsGeneratedByCompiler &&
   t.Name.EndsWith("z__ReadOnlyArray<T>")) ||

  // Don't consider Attribute classes as my code, to avoid reporting issues 
  // that comes from the fact that attribute are not explicitly instantiated in code,
  // this provokes coverage or dead code issues.
   t.IsAttributeClass ||
   
  // Resources, Settings, or typed DataSet generated types for example, are tagged with this attribute
  t.HasAttribute ("System.CodeDom.Compiler.GeneratedCodeAttribute".AllowNoMatch()) ||

  // This attribute identifies classes compiled by the Razor infrastructure
  t.HasAttribute ("Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemMetadataAttribute".AllowNoMatch()) ||

  // This attribute identifies a type or member that is not part of the user code for an application.
  t.HasAttribute ("System.Diagnostics.DebuggerNonUserCodeAttribute".AllowNoMatch()) ||

  // These attributes identify a type that is defined with COM, elsewhere, so consider it not-my-code.
  t.HasAttribute ("System.Runtime.InteropServices.GuidAttribute".AllowNoMatch()) ||
  t.HasAttribute ("System.Runtime.InteropServices.TypeIdentifierAttribute".AllowNoMatch()) ||

  // Discard ASP.NET page types generated by aspnet_compiler.exe
  // See: https://www.ndepend.com/FAQ.aspx#ASPNET
  t.ParentNamespace.Name.EqualsAny("ASP", "__ASP") ||

  // Discard ASP.NET special types
  (t.SimpleNameEqualsAny("Startup","BundleConfig","RouteConfig") && 
   ThirdParty.Assemblies.WithNameWildcardMatchIn("System.Web*", "Microsoft.AspNetCore*").Any()) ||

  // Discard Blazor and Razor special types
  (t.SimpleNameEqualsAny("_Imports", "TypeInference")) ||

  // Discard xUnit generated type
  (t.SimpleNameEqualsAny("SelfRegisteredExtensions", "XunitAutoGeneratedEntryPoint")) ||

  // Discard DataSet classes and their nested types
  (t.DeriveFrom("System.Data.DataSet".AllowNoMatch()) && 
   t.HasAttribute("System.ComponentModel.DesignerCategoryAttribute".AllowNoMatch())) ||
  (t.IsNested && t.ParentType != null && 
   t.ParentType.DeriveFrom("System.Data.DataSet".AllowNoMatch()) && 
   t.ParentType.HasAttribute("System.ComponentModel.DesignerCategoryAttribute".AllowNoMatch())) ||

  // Discard DataSet TableAdapterManager classes their nested types
   (t.SimpleNameEquals("TableAdapterManager") && 
    t.DeriveFrom("System.ComponentModel.Component".AllowNoMatch())) ||
   (t.IsNested && t.ParentType != null && 
    t.ParentType.SimpleNameEquals("TableAdapterManager") && 
    t.ParentType.DeriveFrom("System.ComponentModel.Component".AllowNoMatch())) ||

  // Discard Xamarin form generated types that contain the method LoadDataTemplate()
 (t.IsNested && 
  t.SimpleName.StartsWith("<InitializeComponent>") && 
  t.Methods.Count(m => m.SimpleNameEquals("LoadDataTemplate")) == 1 &&
  t.ParentAssembly.AssembliesUsed.Count(a => a.Name.StartsWithAny("Xamarin", "Mono.Android")) > 0)  ||

  // Discard Xamarin Resource types
 (t.IsNested && 
  t.ParentType != null && 
  t.ParentType.Name == "Resource" && 
  t.ParentAssembly.AssembliesUsed.Count(a => a.Name.StartsWithAny("Xamarin", "Mono.Android")) > 0) ||

  // Discard Entity Framework generated DB context types and entities types used by DB context types!
  efContexts.Contains(t) ||
  efEntities.Contains(t) ||
  efMigrations.Contains(t) ||
  efModelSnapshots.Contains(t) ||

  // Discard types generated for code contract
  t.FullName.StartsWith("System.Diagnostics.Contracts.__ContractsRuntime") ||
  t.FullName == "System.Diagnostics.Contracts.RuntimeContractsAttribute" ||

  // Discard all types declared in a folder path containing the word "generated"
  (t.SourceFileDeclAvailable &&
   (t.SourceDecls.All(s => 
        s.SourceFile.FilePath.ParentDirectoryPath.ToString()
         .IndexOf("generated", StringComparison.OrdinalIgnoreCase) >= 0) ||
    t.SourceDecls.FirstOrDefault(s =>
        s.SourceFile.FilePathString.EndsWith(
          ".cshtml", StringComparison.OrdinalIgnoreCase)) != null)) ||

  // Discard types declared only in generated source files.
  // Typically the default output of Roslyn source generators.
  (t.SourceFileDeclAvailable &&
   t.SourceDecls.All(s =>
        s.SourceFile.FileName.EndsWithAny(
          ".g.cs", ".g.vb", ".generated.cs", ".generated.vb",
          StringComparison.OrdinalIgnoreCase))) ||

  // Discard a type with no source declaration, in an assembly that has sources, when its namespace
  // holds types tagged with GeneratedCodeAttribute: the output of a Roslyn source generator that does
  // not tag all its types and whose generated files are not on disk. An assembly analyzed without
  // its PDB files has no source at all: its types are not concerned.
  (!t.SourceFileDeclAvailable &&
   t.ParentAssembly.SourceFileDeclAvailable &&
   t.ParentNamespace.ChildTypes.Any(nt =>
        nt.HasAttribute("System.CodeDom.Compiler.GeneratedCodeAttribute".AllowNoMatch()))) ||

  // Types created by the test infrastructure
  t.FullName == "AutoGeneratedProgram" ||

  // Discard special types generated by the Roslyn compiler that are typically used by several methods
  // and as a consequence, cannot be merged in application code through the option
  //   NDepend Project Properties > Analysis > Merge Code Generated by Compiler into Application Code
  (t.IsGeneratedByCompiler && t.IsNested && t.SimpleName.StartsWith("<")) ||

  // Discard unity generated type
  (unityContext && (t.FullNameContainsAny("UnitySourceGenerated","Readme")))

select t

//<Desc>
// A **notmycode** query: matched types (and their methods and fields) are
// removed from the *JustMyCode* code base view used by most default queries
// and rules.
//
// It matches several well-identified generated types, like the ones tagged
// *System.CodeDom.Compiler.GeneratedCodeAttribute*. Enrich it to discard
// your own generated types.
//
// *notmycode* queries run before other queries and rules; modifying one
// re-runs the queries relying on *JustMyCode*. Several *notmycode* types
// queries cumulate. Documentation:
// https://www.ndepend.com/docs/cqlinq-syntax#NotMyCode
//</Desc>

Defining JustMyCode: all 7 items