Create a gist now

Instantly share code, notes, and snippets.

anonymous /gist:11404067
Created Apr 29, 2014

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using NDepend;
using NDepend.Analysis;
using NDepend.CodeModel;
using NDepend.CodeQuery;
using NDepend.Path;
namespace RulesRunner {
class Program {
[STAThread]
static void Main() {
// Special AssemblyResolve for NDepend.API that is defined in $NDependInstallDir$\Lib
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolverHelper.AssemblyResolveHandler;
MainSub();
}
const string NDEPEND_PROJECT_FILE_PATH = @"C:\NDepend\6.Current\AnalysisResultOfThisVersion\NDependIn.ndproj";
// Don't show more than 10 matches per rule violated
const int MAX_NB_MATCH_TO_SHOW_PER_RULE = 10;
static void MainSub() {
var projectFilePath = NDEPEND_PROJECT_FILE_PATH.ToAbsoluteFilePath();
Console.WriteLine("*** Load NDepend Project from {" + projectFilePath.ToString() + @"}***");
var provider = new NDependServicesProvider();
var projectManager = provider.ProjectManager;
var project = projectManager.LoadProject(projectFilePath);
Console.WriteLine("*** Run Analysis on Project {" + project .Properties.Name+ @"}***");
var analysisResult = project.RunAnalysis(
// Comment this two line to avoid analysis verbosity
analysisLog => Console.WriteLine(analysisLog.Category.ToString() + ": "+ analysisLog.Description),
progressLog => Console.WriteLine(progressLog.EstimatedPercentageDone.ToString() + "%"));
var codeBase = analysisResult.CodeBase;
// TODO: Use the method CreateCompareContextWithOlder(this ICodeBase newer, ICodeBase older) : ICompareContext
// defined in NDepend.CodeModel.ExtensionMethodsHelpers
// to run rules in older/newer compare context
Console.WriteLine("*** Compile All Queries and Rules***");
var queriesSet = project.CodeQueries.CodeQueriesSet;
var allActiveQueriesString = queriesSet.AllQueriesRecursive
.Where(IsQueryActive)
.Select(q => q.QueryString).ToArray();
var allActiveQueriesCompiled = allActiveQueriesString.CompileMany(codeBase);
Console.WriteLine("*** Compute JustMyCode ***");
var justMyCode = queriesSet.ComputeJustMyCode(codeBase);
Console.WriteLine("*** Run All Rules ***");
var rulesViolated = new List<IQueryExecutionSuccessResult>();
foreach (var queryCompiled in allActiveQueriesCompiled) {
if (queryCompiled.HasErrors) { continue; }
if (queryCompiled.KindOfCodeQueryExpression != KindOfCodeQueryExpression.Rule) { continue; }
var queryResult = queryCompiled.QueryCompiledSuccess.Execute(justMyCode, TimeSpan.FromSeconds(2));
if (queryResult.Status != QueryExecutionStatus.Success) { continue; }
var successResult = queryResult.SuccessResult;
if(!successResult.IsARuleViolated) { continue; }
rulesViolated.Add(successResult);
}
Console.WriteLine("*** " + rulesViolated.Count + " Rules Violated ***");
foreach(var ruleViolated in rulesViolated) {
var ruleName = GetQueryName(ruleViolated.OriginalQueryString);
var matchedCodeElements = ruleViolated.MatchedCodeElements;
var nbMatch = matchedCodeElements.Count;
var codeElementKind = ruleViolated.ColumnsNames[0];
// TODO Use ruleViolated.Records to get not only code elements matched but also all query result row data
//
// Show at most MAX_NB_MATCH_TO_SHOW_PER_RULE metches per rule violated
//
Console.WriteLine("");
Console.WriteLine(" - Rule violated: {" + ruleName + "} " + nbMatch + " " + codeElementKind + " violated");
var nbMatchToShow = Math.Min(MAX_NB_MATCH_TO_SHOW_PER_RULE, nbMatch);
for (var i = 0; i < nbMatchToShow; i++) {
var match = matchedCodeElements[i];
var name = match.Name;
var memberMatched = match as IMember; // IMember is supported by IType, IMethod, IField
if (memberMatched != null) {
// Show more verbose FullName for members
name = memberMatched.FullName;
}
Console.WriteLine(" " + name);
}
var nbMatchNotShown = nbMatch - nbMatchToShow;
if (nbMatchNotShown > 0) {
Console.WriteLine(" ... (" + nbMatchNotShown.ToString() + " " + codeElementKind + " not shown)");
}
}
}
//
// These methods will be provided out-of-the-box by the API in future versions!
//
private static bool IsQueryActive(IQuery query) {
Debug.Assert(query != null);
if(!query.IsActive) { return false; }
var parentGroup = query.Parent;
while (true) {
if (!parentGroup.IsActive) { return false; }
parentGroup = parentGroup.Parent as IGroup;
if(parentGroup == null) { break; }
}
return true;
}
private static string GetQueryName(string queryString) {
Debug.Assert(!string.IsNullOrEmpty(queryString));
const string NAME_START = "<Name>";
var indexStart = queryString.IndexOf(NAME_START);
if (indexStart == -1) { goto GET_FIRST_N_CHARS; }
indexStart += NAME_START.Length;
const string NAME_END = "</Name>";
var indexEnd = queryString.IndexOf(NAME_END);
if (indexEnd == -1) { goto GET_FIRST_N_CHARS; }
if(indexEnd < indexStart) { goto GET_FIRST_N_CHARS; }
return queryString.Substring(indexStart, indexEnd - indexStart);
GET_FIRST_N_CHARS:
return queryString.Substring(0, Math.Min(50, queryString.Length));
}
}
//
// Special treatment for NDepend.API and NDepend.Core because they are defined in $NDependInstallDir$\Lib
//
internal static class AssemblyResolverHelper {
internal static Assembly AssemblyResolveHandler(object sender, ResolveEventArgs args) {
var assemblyName = new AssemblyName(args.Name);
Debug.Assert(assemblyName != null);
var assemblyNameString = assemblyName.Name;
Debug.Assert(assemblyNameString != null);
if (assemblyNameString != "NDepend.API" &&
assemblyNameString != "NDepend.Core") {
return null;
}
string binPath =
System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) +
System.IO.Path.DirectorySeparatorChar +
"Lib" +
System.IO.Path.DirectorySeparatorChar;
const string extension = ".dll";
var assembly = Assembly.LoadFrom(binPath + assemblyNameString + extension);
return assembly;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment