Domanda

Is it possible to use to port a CQLinq query to a simple C# LINQ query?

I am creating a code analyzer tool using NDepend API, and I would like to use the CQLinq queries.

Some are easy to port. For example,

from m in Methods
where m.ILCyclomaticComplexity > 10 
orderby m.ILCyclomaticComplexity descending
select new { m }

is easily ported to

using NDepend.CodeModel;
using NDepend.CodeQuery;

public List<IMethod> GetUnitTestFromType(ICodeBase codeBase)
{
    var complexMethods = (from m in codeBase.Application.Methods
                      where m.ILCyclomaticComplexity > 10
                      orderby m.ILCyclomaticComplexity descending
                      select m).ToList();
    return complexMethods;
} 

But I would like to use the more powerfull CQLinq methods, i.e. AllowNoMatch()

from t in codeBase.Application.Types
where t.Implement("System.IDisposable".AllowNoMatch())
select t;

In fact, It would be great to directly use the CQLinq query. How?

I can see there is a NDepend.CodeQuery namespace with methods like CreateQuery, Compile and Execute. Can anybody show me an exaple of usage?

Thanks!

È stato utile?

Soluzione

Indeed CQLinq offers a number of convenient extension methods defined in the namespace NDepend.Reserved.CQLinq. These extension methods gets special treatment at CQLinq post-compilation time and per-se are not available in C#.

When you write in a CQLinq query: t.Implement("System.IDisposable".AllowNoMatch())

...the special ExtensionMethodsCQLinqDependency.Implement() extension methods is resolved. The CQLinq post-C#-compilation/pre-execution step try to resolve the type specified as a string ( "System.IDisposable".AllowNoMatch() ) once before executing and infers a predicate on IType.

  • If no type full named "System.IDisposable" is found, always returns false.
  • If a type full named "System.IDisposable" is found, returns true. for types implementing it.

In the documentation of ExtensionMethodsCQLinqDependency.Implement(), it is stated that This method can only be called in a ICQLinqExecutionContext, otherwise the method NDepend.CodeModel.IType.NDepend.CodeModel.IType.Implement must be called instead.

Hence by using the NDepend.API you have to do the CQLinq post-compilation work yourself, but it is pretty immediate:

var iDisposable = codebase.Types.SingleOrDefault(t.FullName == "System.IDisposable");
if(iDisposable == null) {
  return new IType[0];
}
return from t in codeBase.Application.Types
       where t.Implement(iDisposable)
       select t;

I can see there is a NDepend.CodeQuery namespace with methods like CreateQuery, Compile and Execute. Can anybody show me an exaple of usage?

Indeed with NDepend.API you can compile a CQLinq query string, execute it and use the result. A sample usage is available in OSS Power Tools Query code with CQLinq, $NDependRedistributable$\NDepend.PowerTools\CodeQueryConsole\CodeQueryConsolePowerTool.cs

     var codeBase = analysisResult.CodeBase;
     Func<string, IQueryCompiled> compileQueryProc = queryString => queryString.Compile( codeBase);

     // ... but if we can get a compareContext, then compile and execute the query against the compareContext
     ICompareContext compareContext;
     if (ProjectAnalysisUtils.TryGetCompareContextDefinedByBaseline(analysisResult, out compareContext)) {
        Debug.Assert(compareContext != null);
        compileQueryProc = queryString => queryString.Compile(compareContext);
     }

...
       IQueryCompiled queryCompiled;
       using (var queryEditSession = new QueryEditSession(queriesPreviouslyEdited)) {
           var queryString = queryEditSession.GetQueryString();
COMPILE_QUERY:
           Console.BackgroundColor = ConsoleColor.Black;
           Console.ForegroundColor = ConsoleColor.White;
           if (queryString == null) { break; }

           // Try compile query
           queryCompiled = compileQueryProc(queryString);
           var queryCompiledError = queryCompiled.QueryCompiledError;
           if (queryCompiledError != null) {
              queryString = queryEditSession.ShowCompilatioErrorsAndThenGetQueryString(queryCompiledError);
              goto COMPILE_QUERY;
           }
        }

        // Execute query compiled
        var queryCompiledSuccess = queryCompiled.QueryCompiledSuccess;
        Debug.Assert(queryCompiledSuccess != null);
        var result = queryCompiledSuccess.Execute();
        if (result.Status != QueryExecutionStatus.Success) {
           var exception = result.Exception;
           // The error must be an Exception thrown by the query, since we don't use the Execute(...) overload with time-out!
           Debug.Assert(exception != null);
           DisplayQueryThrowAnException(exception);
           continue;
        }

        QueryExecutionResultDisplayer.Go(result.SuccessResult);
        Console.WriteLine();
     }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top