-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Adding static analysis tool with dependency checker rules #1755
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
27b408b
c08cd34
b1e1f54
e5f95e7
f03c2ef
0817d6d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.IO; | ||
| using System.Linq; | ||
| using System.Text; | ||
| using System.Threading.Tasks; | ||
|
|
||
| namespace StaticAnalysis | ||
| { | ||
| /// <summary> | ||
| /// Abstract class to implement the logging structure | ||
| /// </summary> | ||
| public abstract class AnalysisLogger | ||
| { | ||
| string _baseDirectory; | ||
|
|
||
| /// <summary> | ||
| /// Create an analysis logger that will write reports to the given directory | ||
| /// </summary> | ||
| /// <param name="baseDirectory"></param> | ||
| public AnalysisLogger(string baseDirectory) | ||
| { | ||
| _baseDirectory = baseDirectory; | ||
| } | ||
|
|
||
| IList<ReportLogger> _loggers = new List<ReportLogger>(); | ||
| protected virtual IList<ReportLogger> Loggers { get { return _loggers; } } | ||
|
|
||
| /// <summary> | ||
| /// Write an error report. | ||
| /// </summary> | ||
| /// <param name="error">The message to write</param> | ||
| public abstract void WriteError(string error); | ||
|
|
||
| public virtual void WriteError(string format, params object[] args) | ||
| { | ||
| WriteError(string.Format(format, args)); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Write an informational message. | ||
| /// </summary> | ||
| /// <param name="message">The message to write</param> | ||
| public abstract void WriteMessage(string message); | ||
|
|
||
| public virtual void WriteMessage(string format, params object[] args) | ||
| { | ||
| WriteMessage(string.Format(format, args)); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Write a warning. | ||
| /// </summary> | ||
| /// <param name="message">The warning text</param> | ||
| public abstract void WriteWarning(string message); | ||
|
|
||
| public virtual void WriteWarning(string format, params object[] args) | ||
| { | ||
| WriteWarning(string.Format(format, args)); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Write a report file to the given file, using the given file contents. | ||
| /// </summary> | ||
| /// <param name="name">The path to the file</param> | ||
| /// <param name="contents">The contents of the report</param> | ||
| public abstract void WriteReport(string name, string contents); | ||
|
|
||
| /// <summary> | ||
| /// Create a logger for a particular report | ||
| /// </summary> | ||
| /// <typeparam name="T">The type of records written to the log</typeparam> | ||
| /// <param name="fileName">The filename (without file path) where the report will be written</param> | ||
| /// <returns>The given logger. Analyzer may write records to this logger and they will be written to the report file.</returns> | ||
| public virtual ReportLogger<T> CreateLogger<T>(string fileName) where T: IReportRecord, new() | ||
| { | ||
| var filePath = Path.Combine(_baseDirectory, fileName); | ||
| var logger = new ReportLogger<T>(filePath, this); | ||
| Loggers.Add(logger); | ||
| return logger; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Write out the report files for each of the added report loggers. | ||
| /// </summary> | ||
| public void WriteReports() | ||
| { | ||
| foreach (var logger in Loggers.Where(l => l.Records.Any())) | ||
| { | ||
| StringBuilder reportText = new StringBuilder(); | ||
| reportText.AppendLine(logger.Records.First().PrintHeaders()); | ||
| foreach (var reportRecord in logger.Records) | ||
| { | ||
| reportText.AppendLine(reportRecord.FormatRecord()); | ||
| } | ||
|
|
||
| WriteReport(logger.FileName, reportText.ToString()); | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| // ---------------------------------------------------------------------------------- | ||
| // | ||
| // 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; | ||
|
|
||
| namespace StaticAnalysis | ||
| { | ||
| /// <summary> | ||
| /// Simple class for logging information | ||
| /// </summary> | ||
| public class ConsoleLogger : AnalysisLogger | ||
| { | ||
|
|
||
| public ConsoleLogger(string baseDirectory) : base(baseDirectory) | ||
| { | ||
| } | ||
|
|
||
| public override void WriteError(string error) | ||
| { | ||
| Console.WriteLine(string.Format("### ERROR {0}", error)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. string.Format is redundant: Same on line 43. |
||
| } | ||
|
|
||
| public override void WriteMessage(string message) | ||
| { | ||
| Console.WriteLine(message); | ||
| } | ||
|
|
||
| public override void WriteWarning(string message) | ||
| { | ||
| Console.WriteLine(string.Format("Warning: {0}", message)); | ||
| } | ||
|
|
||
| public override void WriteReport(string name, string records) | ||
| { | ||
| File.WriteAllText(name, records); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| // ---------------------------------------------------------------------------------- | ||
| // | ||
| // 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 class Decorator<T> | ||
| { | ||
| Action<T> _action; | ||
| string _name; | ||
|
|
||
| protected Decorator(Action<T> action, string name) | ||
| { | ||
| _action = action; | ||
| _name = name; | ||
| Inner = null; | ||
| } | ||
|
|
||
| public static Decorator<T> Create() | ||
| { | ||
| return new Decorator<T>(r => { }, "default"); | ||
| } | ||
|
|
||
| public void Apply(T record) | ||
| { | ||
| _action(record); | ||
| if (Inner != null) | ||
| { | ||
| Inner.Apply(record); | ||
| } | ||
| } | ||
|
|
||
| public void AddDecorator(Action<T> action, string name) | ||
| { | ||
| if (Inner == null) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would add a null check for parameters either here or in ctor
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I think this is a good practice in general |
||
| { | ||
| Inner = new Decorator<T>(action, name); | ||
| } | ||
| else | ||
| { | ||
| Inner.AddDecorator(action, name); | ||
| } | ||
| } | ||
|
|
||
| public void Remove(string name) | ||
| { | ||
| if (Inner != null) | ||
| { | ||
| if (string.Equals(Inner._name, name)) | ||
| { | ||
| Inner = Inner.Inner; | ||
| } | ||
| else | ||
| { | ||
| Inner.Remove(name); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| protected Decorator<T> Inner { get; set; } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| // ---------------------------------------------------------------------------------- | ||
| // | ||
| // 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.Reflection; | ||
|
|
||
| namespace StaticAnalysis.DependencyAnalyzer | ||
| { | ||
| /// <summary> | ||
| /// A class using .Net remoting to load assemblies and retrieve information in a separate app domain | ||
| /// </summary> | ||
| public class AssemblyLoader : MarshalByRefObject | ||
| { | ||
| /// <summary> | ||
| /// Load the assembly in the reflection context by name. Will succeed if the referenced assembly name can | ||
| /// be found using default assembly loading rules (i.e. it is in the current directory or the GAC) | ||
| /// </summary> | ||
| /// <param name="assemblyName">The fullname of the assembly</param> | ||
| /// <returns>Information on the given assembly, if it was loaded successfully, or null if there is an assembly | ||
| /// loading issue. </returns> | ||
| public AssemblyMetadata GetReflectedAssemblyInfo(string assemblyName) | ||
| { | ||
| AssemblyMetadata result = null; | ||
| try | ||
| { | ||
| result = new AssemblyMetadata(Assembly.ReflectionOnlyLoad(assemblyName)); | ||
| } | ||
| catch | ||
| { | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Load the assembly found at the given path in the reflection context and return assembly metadata | ||
| /// </summary> | ||
| /// <param name="assemblyPath">The full path to the assembly file.</param> | ||
| /// <returns>Assembly metadata if the assembly is loaded successfully, or null if there are load errors.</returns> | ||
| public AssemblyMetadata GetReflectedAssemblyFromFile(string assemblyPath) | ||
| { | ||
| AssemblyMetadata result = null; | ||
| try | ||
| { | ||
| return new AssemblyMetadata(Assembly.ReflectionOnlyLoadFrom(assemblyPath)); | ||
| } | ||
| catch | ||
| { | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Create a new AppDomain and create a remote instance of AssemblyLoader we can use there | ||
| /// </summary> | ||
| /// <param name="directoryPath">directory containing assemblies</param> | ||
| /// <param name="testDomain">A new appdomain, where assemblies can be loaded</param> | ||
| /// <returns>A proxy to the AssemblyLoader running in the newly created app domain</returns> | ||
| public static AssemblyLoader Create(string directoryPath, out AppDomain testDomain) | ||
| { | ||
| 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; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| // ---------------------------------------------------------------------------------- | ||
| // | ||
| // 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.Reflection; | ||
| using System.Threading.Tasks; | ||
|
|
||
| namespace StaticAnalysis.DependencyAnalyzer | ||
| { | ||
| /// <summary> | ||
| /// Serializable assembly metadata class, used to return assembly information from a remote AppDomain | ||
| /// </summary> | ||
| [Serializable] | ||
| public class AssemblyMetadata | ||
| { | ||
| AssemblyName _name; | ||
| string _location; | ||
| IList<AssemblyName> _references; | ||
|
|
||
| public AssemblyMetadata(Assembly assembly) | ||
| { | ||
| _name = assembly.GetName(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. null check for assembly |
||
| _location = assembly.Location; | ||
| _references = new List<AssemblyName>(); | ||
| foreach (var child in assembly.GetReferencedAssemblies()) | ||
| { | ||
| _references.Add(child); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Path to the assembly. | ||
| /// </summary> | ||
| public string Location { get { return _location; } } | ||
|
|
||
| /// <summary> | ||
| /// The assembly name | ||
| /// </summary> | ||
| /// <returns>The assembly name for this assembly, including name and version</returns> | ||
| public AssemblyName GetName() | ||
| { | ||
| return _name; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// The list of referenced assemblies | ||
| /// </summary> | ||
| /// <returns>A list of assembly name references for all assemblies referenced in the assembly manifest</returns> | ||
| public IEnumerable<AssemblyName> GetReferencedAssemblies() | ||
| { | ||
| return _references; | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation