Some Simple Nitriqular Tasks

Tags: tools, nitriq

Since Nitriq is a new tool, I thought that it might be useful to share a few simple, real-world-style queries that demonstrate what you can expect Nitriq queries to look like.

  • This will filter out automatically generated names and generic type parameters from the lists. You can replace Types with Methods as well.

    var results = Types.Where(t => !t.Name.Like("<.*>.__.*") && t.FullName[0] != '.');

    Nitriq’s simplified regular expression queries make it very easy to find identifier names – ordinarily, you’d have to use a RegEx object, or roll your own extension method to hide those details.

  • We can find all recursive methods:

    var results = Methods.Where(method => method.Calls.Contains(method));

    Normally, you’d have to examine individual methods to see whether or not they were recursive, but because Nitriq gives you access to all of the methods that a method calls, we only need to find methods that call themselves and we’re done. In one line, we’ve found every recursive method. Nitriq also gives access to all of the methods that call a given method via the CalledBy property, and makes it easy to find out where instance variables are set and where their values are used.

  • As another example of using the method call information provided by Nitriq, we can find all public methods that are only called within the class in which they are defined:

    var results = Methods
        .Where(m => m.IsPublic && m.CalledBy.All(m2 => m.Type.TypeId == m2.Type.TypeId));
  • Sometimes even the name of a type can provide us with information about what might be wrong with it. Oftentimes, a method name with a conjunction indicates that the method could be violating the single responsibility principle. This query will find all methods that contain some such conjunctions in PascalCase:

    var results = Methods
        .Where(method => method.Name.Like(".*And.*|.*Then.*|.*Or.*", false));

    The ‘false’ we’ve passed in makes the query case-sensitive so that methods like HideHeadInSand() don’t trigger the rule.

  • Find all methods that return or take in System.Object:

    var objectType = Types.Where(t => t.FullName == "System.Object").Single();
    var results = Methods
        .Where(m => m.ParameterTypes.Contains(objectType) || m.ReturnType == objectType);

    C# has excellent type-safety, but inappropriate use of object negates many of these benefits. It often indicates a place where another approach, such as generics, should be preferred.

  • Find excessively commented methods:

    var results = Methods.Where(m => m.PercentComment > 10);

    Depending on how your religion treats comments, you may want to tweak this value, but methods with more than a few lines of comments tend to indicate either a case where an old implementation has been commented out as a poor substitute for version control, or an futile attempt to shoehorn clarity into a muddled method.

  • As Scott recently discussed in his amazingly alliterative post, Copious Cyclomatic Complexity Creates Confusing Code, excessive cyclomatic complexity can be strongly indicative of potential faults. This little snippet gives you the average cyclomatic complexity of all of the methods in each type.

    Func<BfType, System.Collections.Generic.IEnumerable<BfMethod>>
        cyclomaticMethods = t => t.Methods.Where(m => m.Cyclomatic > 0);
    
    var results = Types.Select(
        t => new {
            TypeId = t.TypeId,
            TypeName = t.Name,
            AverageCyclomatic = 
                cyclomaticMethods(t).Any() ? 
                cyclomaticMethods(t).Average(m => m.Cyclomatic) : 0
        }
    );
  • For today’s final example, we can see a few other neat features while we find circular dependencies:

    var inTypePairs = Types
        .SelectMany(t => t.InTypes.Select(
            u => new { TypeId = t.TypeId, TypeName = t.FullName, DependentOn = u.FullName })
        )
        .Where(t => t.TypeName != t.DependentOn);
    var reverseTypePairs = Types
        .SelectMany(t => t.InTypes.Select(
            u => new { TypeId = u.TypeId, TypeName = u.FullName, DependentOn = t.FullName })
        );
    var results = inTypePairs.Intersect(reverseTypePairs);

    Nitriq exposes the types that a type depends on as InTypes, and the types that depend on a type as OutTypes. This allows us to see a list of all types such that have circular dependencies, which, although allowed within a namespace, might not be ideal, especially if the two types really belong in different modules. This query selects a list of pairs (Type, InType) for each of a Type’s InTypes. It also selects the reverse pairs (InType, Type), and performs an intersection between the two list.

    Dependencies This query is also doing something different than all of the previous queries: here, we’re selecting an anonymous type, instead of one of the Bf- types ‘native’ to Nitriq. Nitriq is smart enough to show the fields of an anonymous type with the appropriate column headings, as you can see to the right.

 

I haven’t really delved deeply into what you can do with Nitriq here, but I hope that I’ve at least demonstrated how easy it is to accomplish many real-world queries.

Add a Comment