From d87460b415dab784a3fd2569bf8f60810526d004 Mon Sep 17 00:00:00 2001 From: PeterForstmeier Date: Tue, 12 Jun 2012 20:57:06 +0200 Subject: [PATCH] Analysis/CodeAnalysis/Src/AnalysisProjectOptionsPanelXaml.xaml - Read FxCop-Rules List --- .../Analysis/CodeAnalysis/CodeAnalysis.csproj | 4 + .../Src/AnalysisProjectOptions.cs | 2 +- .../Src/AnalysisProjectOptionsPanelXaml.xaml | 63 ++++ .../AnalysisProjectOptionsPanelXaml.xaml.cs | 299 ++++++++++++++++++ 4 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 src/AddIns/Analysis/CodeAnalysis/Src/AnalysisProjectOptionsPanelXaml.xaml diff --git a/src/AddIns/Analysis/CodeAnalysis/CodeAnalysis.csproj b/src/AddIns/Analysis/CodeAnalysis/CodeAnalysis.csproj index 726ff82550..56a8a9d0e1 100644 --- a/src/AddIns/Analysis/CodeAnalysis/CodeAnalysis.csproj +++ b/src/AddIns/Analysis/CodeAnalysis/CodeAnalysis.csproj @@ -81,6 +81,10 @@ + + {DDE2A481-8271-4EAC-A330-8FA6A38D13D1} + ICSharpCode.TreeView + {2748AD25-9C63-4E12-877B-4DCE96FBED54} ICSharpCode.SharpDevelop diff --git a/src/AddIns/Analysis/CodeAnalysis/Src/AnalysisProjectOptions.cs b/src/AddIns/Analysis/CodeAnalysis/Src/AnalysisProjectOptions.cs index a55a8fd265..316e7ddd93 100644 --- a/src/AddIns/Analysis/CodeAnalysis/Src/AnalysisProjectOptions.cs +++ b/src/AddIns/Analysis/CodeAnalysis/Src/AnalysisProjectOptions.cs @@ -306,7 +306,7 @@ namespace ICSharpCode.CodeAnalysis public override bool Save() { Set(po.RuleString); - Helper.SetProperty("CodeAnalysisRuleAssemblies", + Helper.SetProperty("CodeAnalysisRuleAssemblies", (po.RuleAssemblies == DefaultRuleAssemblies) ? "" : po.RuleAssemblies, false, Location); diff --git a/src/AddIns/Analysis/CodeAnalysis/Src/AnalysisProjectOptionsPanelXaml.xaml b/src/AddIns/Analysis/CodeAnalysis/Src/AnalysisProjectOptionsPanelXaml.xaml new file mode 100644 index 0000000000..19c4a0681d --- /dev/null +++ b/src/AddIns/Analysis/CodeAnalysis/Src/AnalysisProjectOptionsPanelXaml.xaml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AddIns/Analysis/CodeAnalysis/Src/AnalysisProjectOptionsPanelXaml.xaml.cs b/src/AddIns/Analysis/CodeAnalysis/Src/AnalysisProjectOptionsPanelXaml.xaml.cs index b6b5d9f1d1..22a4ddec2f 100644 --- a/src/AddIns/Analysis/CodeAnalysis/Src/AnalysisProjectOptionsPanelXaml.xaml.cs +++ b/src/AddIns/Analysis/CodeAnalysis/Src/AnalysisProjectOptionsPanelXaml.xaml.cs @@ -7,19 +7,24 @@ */ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Text; +using System.Text.RegularExpressions; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; +using Gui.Dialogs.OptionPanels.ProjectOptions; using ICSharpCode.Core; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Editor; +using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Gui.OptionPanels; using ICSharpCode.SharpDevelop.Project; +using ICSharpCode.TreeView; namespace ICSharpCode.CodeAnalysis { @@ -28,11 +33,21 @@ namespace ICSharpCode.CodeAnalysis /// public partial class AnalysisProjectOptionsPanelXaml : ProjectOptionPanel { + private bool initSuccess; + private bool userCheck; + private Dictionary rules = new Dictionary(); + private List bla = new List(); + public AnalysisProjectOptionsPanelXaml() { InitializeComponent(); + DataContext = this; + bla.Add(new KeyItemPair("Warning","Warning")); + bla.Add(new KeyItemPair("Error","Error")); + bla.Add(new KeyItemPair("None","None")); } + public ProjectProperty RunCodeAnalysis { get { return GetProperty("RunCodeAnalysis", false); } } @@ -41,5 +56,289 @@ namespace ICSharpCode.CodeAnalysis get { return GetProperty("CodeAnalysisRuleAssemblies","",TextBoxEditMode.EditEvaluatedProperty); } } + + public ProjectProperty CodeAnalysisRules { + get { return GetProperty("CodeAnalysisRules","",TextBoxEditMode.EditEvaluatedProperty); } + } + #region Rule Assemblies Property + + string ruleAssemblies; + const string DefaultRuleAssemblies = @"$(FxCopDir)\rules"; + + public string RuleAssemblies { + get { + return ruleAssemblies; + } + set { + if (string.IsNullOrEmpty(value)) { + value = DefaultRuleAssemblies; + } + if (ruleAssemblies != value) { + ruleAssemblies = value; + + if (initSuccess) { +//// OnOptionChanged(EventArgs.Empty); + ReloadRuleList(); + } + } + } + } + #endregion + + #region Rule string Property + + string CreateRuleString() + { + StringBuilder b = new StringBuilder(); + foreach (SharpTreeNode category in ruleTreeView.Items) { + foreach (RuleTreeNode rule in category.Children) { + if (!(bool)rule.IsChecked || rule.isError) { + if (b.Length > 0) + b.Append(';'); + if ((bool)rule.IsChecked) + b.Append('+'); + + else + b.Append('-'); + if (rule.isError) + b.Append('!'); + b.Append(rule.Identifier); + } + } + } + return b.ToString(); + } + + void ReadRuleString() + { + userCheck = false; + foreach (SharpTreeNode cat in ruleTreeView.Root.Children) { + foreach (RuleTreeNode rtn in cat.Children) { + rtn.IsChecked = true; + rtn.isError = false; + } + } + foreach (string rule2 in ruleString.Split(';')) { + string rule = rule2; + if (rule.Length == 0) continue; + bool active = true; + bool error = false; + if (rule.StartsWith("-")) { + active = false; + rule = rule.Substring(1); + } else if (rule.StartsWith("+")) { + rule = rule.Substring(1); + } + if (rule.StartsWith("!")) { + error = true; + rule = rule.Substring(1); + } + RuleTreeNode ruleNode; + if (rules.TryGetValue(rule, out ruleNode)) { + ruleNode.IsChecked = active; + ruleNode.isError = error; + } + } + foreach (SharpTreeNode cat in ruleTreeView.Root.Children) { + bool noneChecked = true; + foreach (RuleTreeNode rtn in cat.Children) { + if ((bool)rtn.IsChecked) { + noneChecked = false; + break; + } + } + cat.IsChecked = !noneChecked; + } + userCheck = true; + } + + + string ruleString = ""; + + public string RuleString { + get { + if (initSuccess) + return CreateRuleString(); + else + return ruleString; + } + set { + ruleString = value; + if (initSuccess) { + ReadRuleString(); + } + } + } + + #endregion + + #region overrides + protected override void Load(MSBuildBasedProject project, string configuration, string platform) + { + base.Load(project, configuration, platform); + RuleString = this.CodeAnalysisRules.Value; + RuleAssemblies = CodeAnalysisRuleAssemblies.Value; + ReloadRuleList(); + } + + + #endregion + + + + #region RuleList + + void ReloadRuleList() + { + ruleTreeView.Root = new SharpTreeNode(); + FxCopWrapper.GetRuleList(GetRuleAssemblyList(true), Callback); + if (ruleTreeView.Root.Children.Count == 0) { + ruleTreeView.Root.Children.Add(new MessageNode(StringParser.Parse("${res:ICSharpCode.CodeAnalysis.ProjectOptions.LoadingRules}"))); + } + } + + + void Callback(List ruleList) + { + if (WorkbenchSingleton.InvokeRequired) { + WorkbenchSingleton.SafeThreadAsyncCall((Action>)Callback, ruleList); + } else { + ruleTreeView.Root = new SharpTreeNode(); + + + rules.Clear(); + if (ruleList == null || ruleList.Count == 0) { + ruleTreeView.Root.Children.Add(new MessageNode(StringParser.Parse("${res:ICSharpCode.CodeAnalysis.ProjectOptions.CannotFindFxCop}"))); + ruleTreeView.Root.Children.Add(new MessageNode(StringParser.Parse("${res:ICSharpCode.CodeAnalysis.ProjectOptions.SpecifyFxCopPath}"))); + } else { + foreach (FxCopCategory cat in ruleList) { + CategoryTreeNode catNode = new CategoryTreeNode(cat,bla); + ruleTreeView.Root.Children.Add(catNode); + foreach (RuleTreeNode ruleNode in catNode.Children) { + rules[ruleNode.Identifier] = ruleNode; + } + } + initSuccess = true; + ReadRuleString(); + } + } + } + + string[] GetRuleAssemblyList(bool replacePath) + { + List list = new List(); + string fxCopPath = FxCopWrapper.FindFxCopPath(); + foreach (string dir in ruleAssemblies.Split(';')) { + if (string.Equals(dir, "$(FxCopDir)\\rules", StringComparison.OrdinalIgnoreCase)) + continue; + if (string.Equals(dir, "$(FxCopDir)/rules", StringComparison.OrdinalIgnoreCase)) + continue; + if (replacePath && !string.IsNullOrEmpty(fxCopPath)) { + list.Add(Regex.Replace(dir, @"\$\(FxCopDir\)", fxCopPath, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase)); + } else { + list.Add(dir); + } + } + return list.ToArray(); + } + + + #endregion + + #region TreeView + + class BaseTree:SharpTreeNode + { + public BaseTree(IEnumerable bla) + { + this.BLA = bla; + } + + public IEnumerable BLA {get;set;} + } + + + class CategoryTreeNode : BaseTree + { + internal FxCopCategory category; + + public CategoryTreeNode(FxCopCategory category,IEnumerable bla):base(bla) + { + this.category = category; + foreach (FxCopRule rule in category.Rules) { + this.Children.Add(new RuleTreeNode(rule,bla)); + } + } + + + public override bool IsCheckable { + get { return true; } + } + + public override object Text { + get { return category.DisplayName; } + } + + + internal int ErrorState { + get { + bool allWarn = true; + bool allErr = true; + foreach (RuleTreeNode tn in Children) { + if (tn.isError) + allWarn = false; + else + allErr = false; + } + if (allErr) + return 1; + else if (allWarn) + return 0; + else + return -1; + } + } + } + + + class RuleTreeNode :BaseTree + { + internal FxCopRule rule; + internal bool isError; + + public RuleTreeNode(FxCopRule rule,IEnumerable bla):base(bla) + { + this.rule = rule; + } + + public override bool IsCheckable { + get { return true; } + } + + public override object Text { + get { return rule.CheckId + " : " + rule.DisplayName; } + } + + public string Identifier { + get { + return rule.CategoryName + "#" + rule.CheckId; + } + } + } + + class MessageNode : SharpTreeNode + { + private string message; + + public MessageNode (string message) + { + this.message = message; + } + + public override object Text { + get { return message; } + } + } + #endregion } } \ No newline at end of file