diff --git a/tools/StaticAnalysis/AppDomainHelpers.cs b/tools/StaticAnalysis/AppDomainHelpers.cs
new file mode 100644
index 000000000000..cdf32c4cc754
--- /dev/null
+++ b/tools/StaticAnalysis/AppDomainHelpers.cs
@@ -0,0 +1,47 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+
+namespace StaticAnalysis
+{
+ public static class AppDomainHelpers
+ {
+ ///
+ /// Create a new AppDomain and create a remote instance of AssemblyLoader we can use there
+ ///
+ /// directory containing assemblies
+ /// A new AppDomain, where assemblies can be loaded
+ /// A proxy to the AssemblyLoader running in the newly created app domain
+ public static T CreateProxy(string directoryPath, out AppDomain testDomain) where T:MarshalByRefObject
+ {
+ if (string.IsNullOrWhiteSpace(directoryPath))
+ {
+ throw new ArgumentException("directoryPath");
+ }
+
+ var setup = new AppDomainSetup();
+ setup.ApplicationBase = directoryPath;
+ setup.ApplicationName = "TestDomain";
+ setup.ApplicationTrust = AppDomain.CurrentDomain.ApplicationTrust;
+ setup.DisallowApplicationBaseProbing = false;
+ setup.DisallowCodeDownload = false;
+ setup.DisallowBindingRedirects = false;
+ setup.DisallowPublisherPolicy = false;
+ testDomain = AppDomain.CreateDomain("TestDomain", null, setup);
+ return testDomain.CreateInstanceFromAndUnwrap(typeof(T).Assembly.Location,
+ typeof(T).FullName) as T;
+ }
+ }
+}
diff --git a/tools/StaticAnalysis/DependencyAnalyzer/AssemblyLoader.cs b/tools/StaticAnalysis/DependencyAnalyzer/AssemblyLoader.cs
index 15cd6731a4c8..8b98a38c3f0f 100644
--- a/tools/StaticAnalysis/DependencyAnalyzer/AssemblyLoader.cs
+++ b/tools/StaticAnalysis/DependencyAnalyzer/AssemblyLoader.cs
@@ -71,31 +71,5 @@ public AssemblyMetadata GetReflectedAssemblyFromFile(string assemblyPath)
return result;
}
-
- ///
- /// Create a new AppDomain and create a remote instance of AssemblyLoader we can use there
- ///
- /// directory containing assemblies
- /// A new AppDomain, where assemblies can be loaded
- /// A proxy to the AssemblyLoader running in the newly created app domain
- public static AssemblyLoader Create(string directoryPath, out AppDomain testDomain)
- {
- if (string.IsNullOrWhiteSpace(directoryPath))
- {
- throw new ArgumentException("directoryPath");
- }
-
- var setup = new AppDomainSetup();
- setup.ApplicationBase = directoryPath;
- setup.ApplicationName = "TestDomain";
- setup.ApplicationTrust = AppDomain.CurrentDomain.ApplicationTrust;
- setup.DisallowApplicationBaseProbing = false;
- setup.DisallowCodeDownload = false;
- setup.DisallowBindingRedirects = false;
- setup.DisallowPublisherPolicy = false;
- testDomain = AppDomain.CreateDomain("TestDomain", null, setup);
- return testDomain.CreateInstanceFromAndUnwrap(typeof(AssemblyLoader).Assembly.Location,
- typeof(AssemblyLoader).FullName) as AssemblyLoader;
- }
}
}
diff --git a/tools/StaticAnalysis/DependencyAnalyzer/DependencyAnalyzer.cs b/tools/StaticAnalysis/DependencyAnalyzer/DependencyAnalyzer.cs
index 829b78e3e343..62f8ee2786ff 100644
--- a/tools/StaticAnalysis/DependencyAnalyzer/DependencyAnalyzer.cs
+++ b/tools/StaticAnalysis/DependencyAnalyzer/DependencyAnalyzer.cs
@@ -209,7 +209,7 @@ private void ProcessDirectory(string directoryPath)
{
var savedDirectory = Directory.GetCurrentDirectory();
Directory.SetCurrentDirectory(directoryPath);
- _loader = AssemblyLoader.Create(directoryPath, out _testDomain);
+ _loader = AppDomainHelpers.CreateProxy(directoryPath, out _testDomain);
foreach (var file in Directory.GetFiles(directoryPath).Where(file => file.EndsWith(".dll")))
{
AssemblyRecord assembly = CreateAssemblyRecord(file);
diff --git a/tools/StaticAnalysis/HelpAnalyzer/CmdletHelpMetadata.cs b/tools/StaticAnalysis/HelpAnalyzer/CmdletHelpMetadata.cs
new file mode 100644
index 000000000000..6f2dc31d0f93
--- /dev/null
+++ b/tools/StaticAnalysis/HelpAnalyzer/CmdletHelpMetadata.cs
@@ -0,0 +1,32 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+
+namespace StaticAnalysis.HelpAnalyzer
+{
+ [Serializable]
+ public class CmdletHelpMetadata
+ {
+ ///
+ /// The cmdlet name
+ ///
+ public string CmdletName { get; set; }
+
+ ///
+ /// The class name implementing the cmdlet
+ ///
+ public string ClassName { get; set; }
+ }
+}
diff --git a/tools/StaticAnalysis/HelpAnalyzer/CmdletHelpParser.cs b/tools/StaticAnalysis/HelpAnalyzer/CmdletHelpParser.cs
new file mode 100644
index 000000000000..c1d7d1e0476f
--- /dev/null
+++ b/tools/StaticAnalysis/HelpAnalyzer/CmdletHelpParser.cs
@@ -0,0 +1,85 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Xml.Linq;
+
+namespace StaticAnalysis.HelpAnalyzer
+{
+ ///
+ /// Parse the cmdlet help file
+ ///
+ public class CmdletHelpParser
+ {
+ public const string MamlSchemaUri = "http://schemas.microsoft.com/maml/2004/10";
+ public const string MamlDevSchemaUri = "http://schemas.microsoft.com/maml/dev/2004/10";
+ public const string CommandSchemaUri = "http://schemas.microsoft.com/maml/dev/command/2004/10";
+ public static IList GetHelpTopics(string helpPath, ReportLogger logger)
+ {
+ IList cmdlets = new List();
+ try
+ {
+ XDocument document = XDocument.Parse(File.ReadAllText(helpPath));
+ var root = document.Root;
+ foreach (var command in root.GetChildElements("command"))
+ {
+ if (command.ContainsChildElement("details"))
+ {
+ var details = command.GetChildElement("details");
+ if (details.ContainsChildElement("name"))
+ {
+ cmdlets.Add(details.GetChildElement("name").Value.Trim());
+ }
+ else
+ {
+ logger.LogRecord(new HelpIssue
+ {
+ HelpFile = helpPath,
+ Severity = 0,
+ Description = string.Format("Missing command:name element for file {0}", helpPath),
+ Remediation = "Correct the xml format of the help file"
+ });
+
+ }
+ }
+ else
+ {
+
+ logger.LogRecord(new HelpIssue
+ {
+ HelpFile = helpPath,
+ Severity = 0,
+ Description = string.Format("Missing command:details element for file {0}", helpPath),
+ Remediation = "Correct the xml format of the help file"
+ });
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ logger.LogRecord(new HelpIssue
+ {
+ HelpFile = helpPath,
+ Severity = 0,
+ Description = string.Format("Parsing error for help file {0}: {1}", helpPath, e.ToString()),
+ Remediation = "Correct the xml format of the help file"
+ });
+ }
+
+ return cmdlets;
+ }
+ }
+}
diff --git a/tools/StaticAnalysis/HelpAnalyzer/CmdletLoader.cs b/tools/StaticAnalysis/HelpAnalyzer/CmdletLoader.cs
new file mode 100644
index 000000000000..4d79e1275739
--- /dev/null
+++ b/tools/StaticAnalysis/HelpAnalyzer/CmdletLoader.cs
@@ -0,0 +1,57 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Management.Automation;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using StaticAnalysis.help;
+
+namespace StaticAnalysis.HelpAnalyzer
+{
+ public class CmdletLoader : MarshalByRefObject
+ {
+ ///
+ /// Get cmdlets from the given assembly
+ ///
+ ///
+ ///
+ public IList GetCmdlets(string assemblyPath)
+ {
+ IList result = new List();
+ try
+ {
+ var assembly = Assembly.LoadFrom(assemblyPath);
+ foreach (var type in assembly.GetCmdletTypes())
+ {
+ var cmdlet = type.GetAttribute();
+ result.Add(
+ new CmdletHelpMetadata
+ {
+ ClassName = type.FullName,
+ CmdletName = string.Format("{0}-{1}", cmdlet.VerbName, cmdlet.NounName)
+ });
+ }
+ }
+ catch
+ {
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/tools/StaticAnalysis/HelpAnalyzer/HelpAnalyzer.cs b/tools/StaticAnalysis/HelpAnalyzer/HelpAnalyzer.cs
new file mode 100644
index 000000000000..dbbeabfb237f
--- /dev/null
+++ b/tools/StaticAnalysis/HelpAnalyzer/HelpAnalyzer.cs
@@ -0,0 +1,103 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace StaticAnalysis.HelpAnalyzer
+{
+ ///
+ /// Static analyzer for PowerShell Help
+ ///
+ public class HelpAnalyzer : IStaticAnalyzer
+ {
+ public HelpAnalyzer()
+ {
+ Name = "Help Analyzer";
+ }
+ public AnalysisLogger Logger { get; set; }
+ public string Name { get; private set; }
+
+ private AppDomain _appDomain;
+
+ ///
+ /// Given a set of directory paths containing PowerShell module folders, analyze the help
+ /// in the module folders and report any issues
+ ///
+ ///
+ public void Analyze(IEnumerable scopes)
+ {
+ var savedDirectory = Directory.GetCurrentDirectory();
+ var processedHelpFiles = new List();
+ var helpLogger = Logger.CreateLogger("HelpIssues.csv");
+ foreach (var baseDirectory in scopes.Where(s => Directory.Exists(Path.GetFullPath(s))))
+ {
+ foreach (var directory in Directory.EnumerateDirectories(Path.GetFullPath(baseDirectory)))
+ {
+ var helpFiles = Directory.EnumerateFiles(directory, "*.dll-Help.xml")
+ .Where(f => !processedHelpFiles.Contains(Path.GetFileName(f),
+ StringComparer.OrdinalIgnoreCase)).ToList();
+ if (helpFiles.Any())
+ {
+ Directory.SetCurrentDirectory(directory);
+ foreach (var helpFile in helpFiles)
+ {
+ var cmdletFile = helpFile.Substring(0, helpFile.Length - "-Help.xml".Length);
+ var helpFileName = Path.GetFileName(helpFile);
+ var cmdletFileName = Path.GetFileName(cmdletFile);
+ if (File.Exists(cmdletFile) )
+ {
+ processedHelpFiles.Add(helpFileName);
+ helpLogger.Decorator.AddDecorator((h) =>
+ {
+ h.HelpFile = helpFileName;
+ h.Assembly = cmdletFileName;
+ }, "Cmdlet");
+ var proxy = AppDomainHelpers.CreateProxy(directory, out _appDomain);
+ var cmdlets = proxy.GetCmdlets(cmdletFile);
+ var helpRecords = CmdletHelpParser.GetHelpTopics(helpFile, helpLogger);
+ ValidateHelpRecords(cmdlets, helpRecords, helpLogger);
+ helpLogger.Decorator.Remove("Cmdlet");
+ AppDomain.Unload(_appDomain);
+ }
+ }
+
+ Directory.SetCurrentDirectory(savedDirectory);
+ }
+ }
+ }
+ }
+
+ private void ValidateHelpRecords(IList cmdlets, IList helpRecords,
+ ReportLogger helpLogger)
+ {
+ foreach (var cmdlet in cmdlets)
+ {
+ if (!helpRecords.Contains(cmdlet.CmdletName, StringComparer.OrdinalIgnoreCase))
+ {
+ helpLogger.LogRecord(new HelpIssue
+ {
+ Target = cmdlet.ClassName,
+ Severity = 1,
+ Description = string.Format("Help missing for cmdlet {0} implemented by class {1}",
+ cmdlet.CmdletName, cmdlet.ClassName),
+ Remediation = string.Format("Add Help record for cmdlet {0} to help file.", cmdlet.CmdletName)
+ });
+ }
+ }
+ }
+ }
+}
diff --git a/tools/StaticAnalysis/HelpAnalyzer/HelpIssue.cs b/tools/StaticAnalysis/HelpAnalyzer/HelpIssue.cs
new file mode 100644
index 000000000000..a35c80aafd31
--- /dev/null
+++ b/tools/StaticAnalysis/HelpAnalyzer/HelpIssue.cs
@@ -0,0 +1,50 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+
+namespace StaticAnalysis.HelpAnalyzer
+{
+ public class HelpIssue : IReportRecord
+ {
+ ///
+ /// The assembly containing the help issue
+ ///
+ public string Assembly { get; set; }
+ ///
+ /// The associated help file.
+ ///
+ public string HelpFile { get; set; }
+ ///
+ /// The target of the report (cmdlet name, etc..)
+ ///
+ public string Target { get; set; }
+ public string Description { get; set; }
+ public string Remediation { get; set; }
+ public int Severity { get; set; }
+ public string PrintHeaders()
+ {
+ return "\"Assembly\",\"HelpFile\",\"Target\",\"Severity\",\"Description\",\"Remediation\"";
+ }
+
+ public string FormatRecord()
+ {
+ return string.Format("\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\"",
+ Assembly, HelpFile, Target, Severity, Description, Remediation);
+ }
+ }
+}
diff --git a/tools/StaticAnalysis/HelpAnalyzer/ReflectionExtensions.cs b/tools/StaticAnalysis/HelpAnalyzer/ReflectionExtensions.cs
new file mode 100644
index 000000000000..0156997106b7
--- /dev/null
+++ b/tools/StaticAnalysis/HelpAnalyzer/ReflectionExtensions.cs
@@ -0,0 +1,64 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Management.Automation;
+using System.Reflection;
+
+namespace StaticAnalysis.help
+
+{
+ public static class ReflectionExtensions
+ {
+ public static T GetAttribute(this Type decoratedType) where T : Attribute
+ {
+ return decoratedType.GetTypeInfo().GetCustomAttribute(typeof(T), true) as T;
+ }
+
+ public static T GetAttribute(this PropertyInfo decoratedProperty) where T : Attribute
+ {
+ return decoratedProperty.GetCustomAttribute(typeof(T), true) as T;
+ }
+
+ public static IEnumerable GetAttributes(this Type decoratedType) where T : Attribute
+ {
+ return decoratedType.GetTypeInfo().GetCustomAttributes(typeof(T), false).Select(a => a as T);
+ }
+
+ public static IEnumerable GetAttributes(this PropertyInfo decoratedProeprty) where T : Attribute
+ {
+ return decoratedProeprty.GetCustomAttributes(typeof(T), false).Select(a => a as T);
+ }
+
+ public static bool HasAttribute(this Type decoratedType) where T : Attribute
+ {
+ return decoratedType.GetTypeInfo().CustomAttributes.Any(d => d.AttributeType == typeof (T));
+
+ }
+
+ public static bool HasAttribute(this PropertyInfo decoratedProperty) where T : Attribute
+ {
+ return decoratedProperty.CustomAttributes.Any(d => d.AttributeType == typeof(T));
+
+ }
+
+ public static IEnumerable GetCmdletTypes(this Assembly assembly)
+ {
+ return assembly.GetTypes().Where(t => t.HasAttribute());
+ }
+
+ }
+}
diff --git a/tools/StaticAnalysis/HelpAnalyzer/XmlExtensions.cs b/tools/StaticAnalysis/HelpAnalyzer/XmlExtensions.cs
new file mode 100644
index 000000000000..f2d562a48c3f
--- /dev/null
+++ b/tools/StaticAnalysis/HelpAnalyzer/XmlExtensions.cs
@@ -0,0 +1,128 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace StaticAnalysis
+{
+ public static class XmlExtensions
+ {
+ ///
+ /// Get all child elements with the given name
+ ///
+ /// The element to search
+ /// The child element name to search for
+ /// An enumeration of child elements with the given name, or null if none
+ /// are found.
+ public static IEnumerable GetChildElements(this XElement parent, string name)
+ {
+ return parent.Descendants().Where(e => String.Equals(e.Name.LocalName, name));
+ }
+
+ ///
+ /// Get all child elements with the given name that satisfy the given predicate
+ ///
+ /// The element to search
+ /// The child element name to search for
+ /// The additional condition to satisfy
+ /// An enumeration of child elements with the given name that satisfy the predicate,
+ /// or null if none are found.
+ public static IEnumerable GetChildElements(this XElement parent, string name,
+ Func predicate )
+ {
+ return parent.Descendants().Where(e => String.Equals(e.Name.LocalName, name)
+ && predicate(e));
+ }
+
+ ///
+ /// Get the first child element with the given name
+ ///
+ /// The element to search
+ /// The child element name to search for
+ /// The child element with the given name, or null if none are found.
+ public static XElement GetChildElement(this XElement parent, string name)
+ {
+ return parent.Descendants().FirstOrDefault(e => String.Equals(e.Name.LocalName, name));
+ }
+
+ ///
+ /// Get the first child element with the given name that satisfies the given predicate
+ ///
+ /// The element to search
+ /// The child element name to search for
+ /// Additional conditions over the desired child element
+ ///
+ public static XElement GetChildElement(this XElement parent, string name,
+ Func predicate )
+ {
+ return parent.Descendants().FirstOrDefault(e => String.Equals(e.Name.LocalName, name)
+ && predicate(e));
+ }
+
+ ///
+ /// Determines if the given element contains a child element of the given name
+ ///
+ /// The element to search
+ /// The child element name to search for
+ /// true if the given child element exists, otherwise false
+ public static bool ContainsChildElement(this XElement element, string name)
+ {
+ return element.Descendants().Any(e => string.Equals(e.Name.LocalName, name));
+ }
+
+ ///
+ /// Determines if the given element contains a child element of the given name that satisfies
+ /// the specified predicate
+ ///
+ /// The element to search
+ /// The child element name to search for
+ /// An additional condition on descendant elements
+ /// true if the given child element exists, otherwise false
+ public static bool ContainsChildElement(this XElement element, string name,
+ Func predicate)
+ {
+ return element.Descendants().Any(e => string.Equals(e.Name.LocalName, name)
+ && predicate(e));
+ }
+
+ ///
+ /// Determines if the given element contains a child element with any of the provided names
+ ///
+ /// The element to search
+ /// The child element names to search for
+ /// true if any of the given child elements exists, otherwise false
+ public static bool ContainsChildElement(this XElement element, IEnumerable names)
+ {
+ return names.Any(element.ContainsChildElement);
+ }
+
+ ///
+ /// Determines if the given element contains a child element with any of the provided names that
+ /// satisfies the given predicate
+ ///
+ /// The element to search
+ /// The child element names to search for
+ /// An additional condition to check on descendant elements
+ /// True if any child element has the specified name and satisfies the specified
+ /// predicate.
+ public static bool ContainsChildElement(this XElement element, IEnumerable names,
+ Func predicate )
+ {
+ return names.Any( n => element.ContainsChildElement(n, predicate));
+ }
+ }
+}
diff --git a/tools/StaticAnalysis/Program.cs b/tools/StaticAnalysis/Program.cs
index e4c94f164179..9f989039b0b1 100644
--- a/tools/StaticAnalysis/Program.cs
+++ b/tools/StaticAnalysis/Program.cs
@@ -16,13 +16,18 @@
using System.Collections.Generic;
using System.IO;
-namespace StaticAnalysis.DependencyAnalyzer
+namespace StaticAnalysis
{
///
/// Runner for all static analysis tools.
///
public class Program
{
+ static readonly IList Analyzers = new List()
+ {
+ new HelpAnalyzer.HelpAnalyzer(),
+ new DependencyAnalyzer.DependencyAnalyzer()
+ };
public static void Main(string[] args)
{
if (args == null || args.Length < 1)
@@ -58,11 +63,15 @@ public static void Main(string[] args)
reportsDirectory);
}
- var analyzer = new DependencyAnalyzer { Logger = logger };
- logger.WriteMessage("Executing analyzer: {0}", analyzer.Name);
- analyzer.Analyze(directories);
+ foreach (var analyzer in Analyzers)
+ {
+ analyzer.Logger = logger;
+ logger.WriteMessage("Executing analyzer: {0}", analyzer.Name);
+ analyzer.Analyze(directories);
+ logger.WriteMessage("Processing complete for analyzer: {0}", analyzer.Name);
+ }
+
logger.WriteReports();
- logger.WriteMessage("Processing complete for analyzer: {0}", analyzer.Name);
}
}
}
diff --git a/tools/StaticAnalysis/StaticAnalysis.csproj b/tools/StaticAnalysis/StaticAnalysis.csproj
index cb94c8f63485..21a772b5b05c 100644
--- a/tools/StaticAnalysis/StaticAnalysis.csproj
+++ b/tools/StaticAnalysis/StaticAnalysis.csproj
@@ -34,6 +34,10 @@
+
+ packages\System.Management.Automation_PowerShell_3.0.6.3.9600.17400\lib\net40\System.Management.Automation.dll
+ True
+
@@ -42,6 +46,7 @@
+
@@ -53,12 +58,22 @@
+
+
+
+
+
+
+
+
+
+