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!
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.
"System.IDisposable" is found, always returns false."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();
}