~halega/+junk/sharpdevelop

« back to all changes in this revision

Viewing changes to src/Libraries/ICSharpCode.Build.Tasks/Project/FxCop.cs

  • Committer: sk
  • Date: 2011-09-10 05:17:57 UTC
  • Revision ID: halega@halega.com-20110910051757-qfouz1llya9m6boy
4.1.0.7915 Release Candidate 1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
 
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
 
3
 
 
4
using System;
 
5
using System.Globalization;
 
6
using System.IO;
 
7
using System.Text;
 
8
using System.Xml;
 
9
 
 
10
using Microsoft.Build.Framework;
 
11
using Microsoft.Build.Utilities;
 
12
using Microsoft.Win32;
 
13
 
 
14
namespace ICSharpCode.Build.Tasks
 
15
{
 
16
        public sealed class FxCop : ToolTask
 
17
        {
 
18
                string realLogFile;
 
19
                
 
20
                public string LogFile { get; set; }
 
21
                public string InputAssembly { get; set; }
 
22
                public string[] Rules { get; set; }
 
23
                public string[] RuleAssemblies { get; set; }
 
24
                public string[] ReferencePaths { get; set;}
 
25
                public ITaskItem[] Dictionary { get; set;}
 
26
                
 
27
                protected override string ToolName {
 
28
                        get {
 
29
                                return "FxCopCmd.exe";
 
30
                        }
 
31
                }
 
32
                
 
33
                public override bool Execute()
 
34
                {
 
35
                        if (string.IsNullOrEmpty(ToolPath)) {
 
36
                                string path = FindFxCopPath();
 
37
                                Log.LogMessage(MessageImportance.High, Resources.RunningCodeAnalysis);
 
38
                                if (path != null) {
 
39
                                        ToolPath = path;
 
40
                                } else {
 
41
                                        Log.LogError(Resources.CannotFindFxCop);
 
42
                                        return false;
 
43
                                }
 
44
                        }
 
45
                        realLogFile = LogFile ?? Path.GetTempFileName();
 
46
                        try {
 
47
                                bool result = base.Execute();
 
48
                                if (File.Exists(realLogFile)) {
 
49
                                        try {
 
50
                                                #if DEBUG
 
51
                                                Console.WriteLine(File.ReadAllText(realLogFile));
 
52
                                                #endif
 
53
                                                XmlDocument doc = new XmlDocument();
 
54
                                                doc.Load(realLogFile);
 
55
                                                foreach (XmlNode node in doc.DocumentElement.SelectNodes(".//Exception")) {
 
56
                                                        XmlElement el = node as XmlElement;
 
57
                                                        if (el == null) continue;
 
58
                                                        
 
59
                                                        result = false;
 
60
                                                        string checkId = el.GetAttribute("CheckId");
 
61
                                                        string keyword = el.GetAttribute("Keyword");
 
62
                                                        string message = el["ExceptionMessage"].InnerText;
 
63
                                                        if (checkId.Length > 0) {
 
64
                                                                Log.LogError(null, null, keyword, "", 0, 0, 0, 0,
 
65
                                                                             "{0} : {2} ({1}): {3}", keyword, el.GetAttribute("Category"), checkId, el.GetAttribute("Target"), message);
 
66
                                                        } else {
 
67
                                                                Log.LogError(keyword + " : " + message);
 
68
                                                        }
 
69
                                                }
 
70
                                                foreach (XmlNode node in doc.DocumentElement.SelectNodes(".//Message")) {
 
71
                                                        XmlElement el = node as XmlElement;
 
72
                                                        if (el == null) continue;
 
73
                                                        result &= LogMessage(el);
 
74
                                                }
 
75
                                        } catch (XmlException e) {
 
76
                                                Log.LogError(Resources.CannotReadFxCopLogFile + " " + e.Message);
 
77
                                        }
 
78
                                }
 
79
                                return result;
 
80
                        } finally {
 
81
                                if (LogFile == null) {
 
82
                                        File.Delete(realLogFile);
 
83
                                }
 
84
                        }
 
85
                }
 
86
                
 
87
                /// <summary>
 
88
                /// Logs a message.
 
89
                /// </summary>
 
90
                /// <returns>True for warning, false for error.</returns>
 
91
                bool LogMessage(XmlElement message)
 
92
                {
 
93
                        bool isWarning = true;
 
94
                        string checkId = message.GetAttribute("CheckId");
 
95
                        if (message.HasAttribute("TypeName")) {
 
96
                                checkId = checkId + ":" + message.GetAttribute("TypeName");
 
97
                        }
 
98
                        string category = message.GetAttribute("Category");
 
99
                        foreach (XmlNode node in message.SelectNodes(".//Issue")) {
 
100
                                XmlElement issueEl = node as XmlElement;
 
101
                                if (issueEl == null) continue;
 
102
                                
 
103
                                if ("true".Equals(message.GetAttribute("BreaksBuild"), StringComparison.OrdinalIgnoreCase)) {
 
104
                                        isWarning = false;
 
105
                                }
 
106
                                string issueText = issueEl.InnerText;
 
107
                                string issuePath = issueEl.GetAttribute("Path");
 
108
                                string issueFile = issueEl.GetAttribute("File");
 
109
                                string issueLine = issueEl.GetAttribute("Line");
 
110
                                int issueLineNumber = 0;
 
111
                                string issueFullFile = null;
 
112
                                
 
113
                                // Try to find additional information about this type
 
114
                                string memberName = null;
 
115
                                string typeName = null;
 
116
                                XmlNode parent = message.ParentNode;
 
117
                                while (parent != null) {
 
118
                                        if (parent.Name == "Type") {
 
119
                                                if (typeName == null) {
 
120
                                                        typeName = ((XmlElement)parent).GetAttribute("Name");
 
121
                                                } else {
 
122
                                                        typeName = ((XmlElement)parent).GetAttribute("Name") + "+" + typeName;
 
123
                                                }
 
124
                                        } else if (parent.Name == "Namespace" && typeName != null) {
 
125
                                                typeName = ((XmlElement)parent).GetAttribute("Name") + "." + typeName;
 
126
                                        } else if (parent.Name == "Member" && memberName == null) {
 
127
                                                memberName = ((XmlElement)parent).GetAttribute("Name");
 
128
                                                // first, strip the # inserted by FxCop
 
129
                                                if (memberName.StartsWith("#"))
 
130
                                                        memberName = memberName.Substring(1);
 
131
                                                // second, translate .ctor to #ctor
 
132
                                                if (memberName.StartsWith(".ctor") || memberName.StartsWith(".cctor"))
 
133
                                                        memberName = "#" + memberName.Substring(1);
 
134
                                        }
 
135
                                        parent = parent.ParentNode;
 
136
                                }
 
137
                                if (issuePath.Length > 0 && issueLine.Length > 0 && issueFile.Length > 0) {
 
138
                                        issueFullFile = Path.Combine(issuePath, issueFile);
 
139
                                        issueLineNumber = int.Parse(issueLine, CultureInfo.InvariantCulture);
 
140
                                } else if (typeName != null) {
 
141
                                        issueFullFile = "positionof#" + typeName + "#" + memberName;
 
142
                                }
 
143
                                
 
144
                                string data = typeName + "|" + memberName;
 
145
                                
 
146
                                if (message.HasAttribute("Id")) {
 
147
                                        data = data + "|" + message.GetAttribute("Id");
 
148
                                }
 
149
                                
 
150
                                if (isWarning) {
 
151
                                        Log.LogWarning(data, checkId, category, issueFullFile, issueLineNumber, 0, 0, 0, issueText);
 
152
                                } else {
 
153
                                        Log.LogError(data, checkId, category, issueFullFile, issueLineNumber, 0, 0, 0, issueText);
 
154
                                }
 
155
                        }
 
156
                        return isWarning;
 
157
                }
 
158
                
 
159
                string FindFxCopPath()
 
160
                {
 
161
                        // Code duplication: FxCopWrapper.cs in CodeAnalysis addin
 
162
                        string fxCopPath = null;
 
163
                        using (RegistryKey key = Registry.LocalMachine.OpenSubKey(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Setup\EDev")) {
 
164
                                if (key != null) {
 
165
                                        fxCopPath = key.GetValue("FxCopDir") as string;
 
166
                                }
 
167
                        }
 
168
                        if (IsFxCopPath(fxCopPath)) {
 
169
                                return fxCopPath;
 
170
                        }
 
171
                        using (RegistryKey key = Registry.LocalMachine.OpenSubKey(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Setup\EDev")) {
 
172
                                if (key != null) {
 
173
                                        fxCopPath = key.GetValue("FxCopDir") as string;
 
174
                                }
 
175
                        }
 
176
                        if (IsFxCopPath(fxCopPath)) {
 
177
                                return fxCopPath;
 
178
                        }
 
179
 
 
180
                        fxCopPath = FromRegistry(Registry.ClassesRoot.OpenSubKey(@"FxCop.Project.9.0\Shell\Open\Command"));
 
181
                        if (IsFxCopPath(fxCopPath)) {
 
182
                                return fxCopPath;
 
183
                        }
 
184
                        fxCopPath = FromRegistry(Registry.CurrentUser.OpenSubKey(@"Software\Classes\FxCopProject\Shell\Open\Command"));
 
185
                        if (IsFxCopPath(fxCopPath)) {
 
186
                                return fxCopPath;
 
187
                        }
 
188
                        fxCopPath = FromRegistry(Registry.ClassesRoot.OpenSubKey(@"FxCopProject\Shell\Open\Command"));
 
189
                        if (IsFxCopPath(fxCopPath)) {
 
190
                                return fxCopPath;
 
191
                        }
 
192
                        return null;
 
193
                }
 
194
                
 
195
                bool IsFxCopPath(string fxCopPath)
 
196
                {
 
197
                        return !string.IsNullOrEmpty(fxCopPath) && File.Exists(Path.Combine(fxCopPath, ToolName));
 
198
                }
 
199
                
 
200
                string FromRegistry(RegistryKey key)
 
201
                {
 
202
                        // Code duplication: FxCopWrapper.cs in CodeAnalysis addin
 
203
                        if (key == null) return string.Empty;
 
204
                        using (key) {
 
205
                                string cmd = key.GetValue("").ToString();
 
206
                                int pos;
 
207
                                if (cmd.StartsWith("\""))
 
208
                                        pos = cmd.IndexOf('"', 1);
 
209
                                else
 
210
                                        pos = cmd.IndexOf(' ');
 
211
                                try {
 
212
                                        if (cmd.StartsWith("\""))
 
213
                                                return Path.GetDirectoryName(cmd.Substring(1, pos - 1));
 
214
                                        else
 
215
                                                return Path.GetDirectoryName(cmd.Substring(0, pos));
 
216
                                } catch (ArgumentException ex) {
 
217
                                        Log.LogWarning(cmd);
 
218
                                        Log.LogWarningFromException(ex);
 
219
                                        return string.Empty;
 
220
                                }
 
221
                        }
 
222
                }
 
223
                
 
224
                protected override string GenerateFullPathToTool()
 
225
                {
 
226
                        return Path.Combine(ToolPath.Trim('"'), ToolName);
 
227
                }
 
228
                
 
229
                static void AppendSwitch(StringBuilder b, string @switch, string val)
 
230
                {
 
231
                        if (!string.IsNullOrEmpty(val)) {
 
232
                                b.Append(" /");
 
233
                                b.Append(@switch);
 
234
                                b.Append(':');
 
235
                                if (val[0] == '"') {
 
236
                                        b.Append(val);
 
237
                                } else {
 
238
                                        b.Append('"');
 
239
                                        b.Append(val);
 
240
                                        b.Append('"');
 
241
                                }
 
242
                        }
 
243
                }
 
244
                
 
245
                //protected override string GenerateResponseFileCommands()
 
246
                protected override string GenerateCommandLineCommands()
 
247
                {
 
248
                        // using a response file fails when the a path contains spaces, but using the command line
 
249
                        // works fine (FxCop bug?)
 
250
                        
 
251
                        StringBuilder b = new StringBuilder();
 
252
                        AppendSwitch(b, "o", realLogFile);
 
253
                        AppendSwitch(b, "f", InputAssembly);
 
254
                        if (ReferencePaths != null) {
 
255
                                foreach (string path in ReferencePaths) {
 
256
                                        AppendSwitch(b, "d", Path.GetDirectoryName(path));
 
257
                                }
 
258
                        }
 
259
                        if (RuleAssemblies != null) {
 
260
                                foreach (string asm in RuleAssemblies) {
 
261
                                        if (asm.StartsWith("\\")) {
 
262
                                                AppendSwitch(b, "r", ToolPath + asm);
 
263
                                        } else {
 
264
                                                AppendSwitch(b, "r", asm);
 
265
                                        }
 
266
                                }
 
267
                        }
 
268
                        if (Rules != null) {
 
269
                                foreach (string rule in Rules) {
 
270
                                        AppendSwitch(b, "ruleid", rule);
 
271
                                }
 
272
                        }
 
273
                        if (Dictionary != null) {
 
274
                                foreach (ITaskItem dic in Dictionary) {
 
275
                                        AppendSwitch(b, "dic", dic.ItemSpec);
 
276
                                }
 
277
                        }
 
278
                        #if DEBUG
 
279
                        Console.WriteLine(b.ToString());
 
280
                        #endif
 
281
                        return b.ToString();
 
282
                }
 
283
        }
 
284
}