#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

241 lines
7.9 KiB

// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Microsoft.Win32;
using ICSharpCode.Core;
namespace ICSharpCode.CodeAnalysis
{
public static class FxCopWrapper
{
static Dictionary<string[], List<FxCopCategory>> ruleDict = new Dictionary<string[], List<FxCopCategory>>(new ArrayHashCodeProvider());
class ArrayHashCodeProvider : IEqualityComparer<string[]>
{
public bool Equals(string[] x, string[] y)
{
if (x == y) return true;
if (x == null || y == null) return false;
if (x.Length != y.Length) return false;
for (int i = 0; i < x.Length; i++) {
if (StringComparer.OrdinalIgnoreCase.Equals(x[i], y[i])) return false;
}
return true;
}
public int GetHashCode(string[] obj)
{
int hashcode = 0;
foreach (string e in obj) {
hashcode ^= StringComparer.OrdinalIgnoreCase.GetHashCode(e);
}
return hashcode;
}
}
class Request
{
public string[] ruleAssemblies;
public Action<List<FxCopCategory>> callback;
public Request(string[] ruleAssemblies, Action<List<FxCopCategory>> callback)
{
this.ruleAssemblies = ruleAssemblies;
this.callback = callback;
}
}
/// <summary>
/// Gets the rules supported by the current FxCop version. The rules are loaded on a separate
/// thread, the callback is fired when the action has completed.
/// Warning: the callback might be fired on the current thread if the rules are already loaded,
/// or on another thread!
/// </summary>
public static void GetRuleList(string[] ruleAssemblies, Action<List<FxCopCategory>> callback)
{
if (ruleAssemblies == null)
throw new ArgumentNullException("ruleAssemblies");
List<FxCopCategory> rules = null;
lock (ruleDict) {
if (!ruleDict.TryGetValue(ruleAssemblies, out rules)) {
// Start the thread:
System.Threading.ThreadPool.QueueUserWorkItem(RunGetRuleList, new Request(ruleAssemblies, callback));
}
}
if (rules != null) {
callback(rules);
}
}
public static string FindFxCopPath()
{
string fxCopPath = PropertyService.Get("CodeAnalysis.FxCopPath");
if (fxCopPath.Length > 0 && File.Exists(Path.Combine(fxCopPath, "FxCopCommon.dll"))) {
return fxCopPath;
}
// Code duplication: FxCop.cs in ICSharpCode.Build.Tasks
fxCopPath = FromRegistry(Registry.CurrentUser.OpenSubKey(@"Software\Classes\FxCopProject\Shell\Open\Command"));
if (fxCopPath.Length > 0 && File.Exists(Path.Combine(fxCopPath, "FxCopCommon.dll"))) {
return fxCopPath;
}
fxCopPath = FromRegistry(Registry.ClassesRoot.OpenSubKey(@"FxCopProject\Shell\Open\Command"));
if (fxCopPath.Length > 0 && File.Exists(Path.Combine(fxCopPath, "FxCopCommon.dll"))) {
return fxCopPath;
}
return null;
}
static string FromRegistry(RegistryKey key)
{
// Code duplication: FxCop.cs in ICSharpCode.Build.Tasks
if (key == null) return string.Empty;
using (key) {
string cmd = key.GetValue("").ToString();
int pos;
if (cmd.StartsWith("\""))
pos = cmd.IndexOf('"', 1);
else
pos = cmd.IndexOf(' ');
try {
if (cmd.StartsWith("\""))
return Path.GetDirectoryName(cmd.Substring(1, pos - 1));
else
return Path.GetDirectoryName(cmd.Substring(0, pos));
} catch (ArgumentException ex) {
LoggingService.Warn(cmd);
LoggingService.Warn(ex);
return string.Empty;
}
}
}
static void RunGetRuleList(object state)
{
Request request = (Request)state;
LoggingService.Debug("Trying to find FxCop rules");
string fxCopPath = FindFxCopPath();
List<FxCopCategory> rules;
if (fxCopPath != null) {
try {
rules = GetRuleListAndSort(fxCopPath, request.ruleAssemblies);
} catch (Exception ex) {
LoggingService.Warn(ex);
rules = new List<FxCopCategory>();
}
} else {
rules = new List<FxCopCategory>();
}
LoggingService.Debug("Finished getting FxCop rules, invoking callback");
request.callback(rules);
}
static List<FxCopCategory> GetRuleListAndSort(string fxCopPath, string[] ruleAssemblies)
{
AppDomainSetup setup = new AppDomainSetup();
setup.DisallowCodeDownload = true;
setup.ApplicationBase = fxCopPath;
AppDomain domain = AppDomain.CreateDomain("FxCop Rule Loading Domain", AppDomain.CurrentDomain.Evidence, setup);
string[][] ruleTextList;
try {
ruleTextList = (string[][])AppDomainLaunchHelper.LaunchInAppDomain(domain, typeof(FxCopWrapper), "GetRuleListInCurrentAppDomain", fxCopPath, ruleAssemblies);
} finally {
AppDomain.Unload(domain);
}
FxCopRule[] ruleList = new FxCopRule[ruleTextList.Length];
for (int i = 0; i < ruleTextList.Length; i++) {
ruleList[i] = new FxCopRule(ruleTextList[i][0], ruleTextList[i][1],
ruleTextList[i][2], ruleTextList[i][3],
ruleTextList[i][4]);
}
Array.Sort(ruleList);
List<FxCopCategory> rules = new List<FxCopCategory>();
lock (ruleDict) {
FxCopCategory cat = null;
foreach (FxCopRule rule in ruleList) {
if (cat == null || cat.Name != rule.CategoryName) {
cat = new FxCopCategory(rule.CategoryName);
rules.Add(cat);
}
cat.Rules.Add(rule);
}
ruleDict[ruleAssemblies] = rules;
}
return rules;
}
// We don't want to reference the FxCop assembly
static object CallMethod(object instance, string name, params object[] args)
{
return instance.GetType().InvokeMember(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, instance, args);
}
static object CallMethod(Type type, string name, BindingFlags flags, object instance, params object[] args)
{
return type.InvokeMember(name, flags | BindingFlags.Public | BindingFlags.InvokeMethod,
null, instance, args);
}
static object GetProp(object instance, string name)
{
return instance.GetType().InvokeMember(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty,
null, instance, null);
}
static string GetSProp(object instance, string name)
{
object v = GetProp(instance, name);
if (v == null)
return string.Empty;
else
return v.ToString();
}
public static string[][] GetRuleListInCurrentAppDomain(string fxCopPath, string[] ruleAssemblies)
{
Assembly asm = Assembly.LoadFrom(Path.Combine(fxCopPath, "FxCopCommon.dll"));
Type fxCopOM = asm.GetType("Microsoft.FxCop.Common.FxCopOM");
CallMethod(fxCopOM, "Initialize", BindingFlags.Static, null);
object engines = fxCopOM.InvokeMember("Engines", BindingFlags.Public | BindingFlags.Static | BindingFlags.GetProperty, null, null, null);
((System.Collections.Specialized.StringCollection)GetProp(engines, "RuleDirectories"))
.AddRange(ruleAssemblies);
object project = asm.CreateInstance("Microsoft.FxCop.Common.Project");
fxCopOM.InvokeMember("Project", BindingFlags.Public | BindingFlags.Static | BindingFlags.SetProperty,
null, null, new object[] { project });
object exceptionList = CallMethod(project, "Initialize");
foreach (Exception ex in ((IEnumerable)exceptionList)) {
LoggingService.Warn(ex);
}
IEnumerable ruleList = (IEnumerable)GetProp(GetProp(project, "AllRules"), "Values");
List<string[]> rules = new List<string[]>();
foreach (object ruleContainer in ruleList) {
object rule = GetProp(ruleContainer, "IRule");
rules.Add(new string[] {
GetSProp(rule, "CheckId"),
GetSProp(rule, "Name"),
GetSProp(rule, "Category"),
GetSProp(rule, "Description"),
GetSProp(rule, "Url")
});
}
return rules.ToArray();
}
}
}