This article describes the operation of a method-based static code analyzer for .NET that constructs in-memory method call networks of compiled assemblies. You will also see a concrete application of static code analysis to generate a website providing easy insights on a sample application.
- codeanalyzerandtodosample.zip
- CodeAnalyzer and Sample Solution.sln
- Generate.cmd
- Generator
- Output
- Blank.html
- co_CreateToDoItem(int,string,Nullable[DateTime])_ToDoItem.html
- co_DeleteToDoItem(int)_void.html
- co_FindUserByName(string)_User.html
- co_GetToDoItem(int)_ToDoItem.html
- co_GetUser(int)_User.html
- co_ListAllToDoItems()_IEnumerable[ToDoItem].html
- co_ListAllUsers()_IEnumerable[User].html
- co_ListDoneItemsForUser(int)_IEnumerable[ToDoItem].html
- co_ListToDoItemsForUser(int)_IEnumerable[ToDoItem].html
- co_ListUsersMatching(string)_IEnumerable[User].html
- co_MarkToDoItemDone(int)_void.html
- co_UpdateToDoItem(int,string,Nullable[DateTime])_void.html
- CodeModel.css
- CodeModel.js
- Content.html
- Index.html
- IndexTop.html
- so_CreateToDoItem(int,string,Nullable[DateTime])_ToDoItem.html
- so_DeleteToDoItem(int)_void.html
- so_FindUserByName(string)_User.html
- so_GetUser(int)_User.html
- so_ListAllUsers()_List[User].html
- so_ListDoneItemsForUser(int)_List[ToDoItem].html
- so_ListToDoItemsForUser(int)_List[ToDoItem].html
- so_ListUsersMatching(string)_List[User].html
- so_MarkToDoItemDone(int)_void.html
- so_UpdateToDoItem(int,string,Nullable[DateTime])_ToDoItem.html
- ui_CreateNewToDoItemClicked(object,System.Windows.RoutedEventArgs)_void.html
- ui_DeleteClicked(object,System.Windows.RoutedEventArgs)_void.html
- ui_InitializeComponent()_void.html
- ui_MarkDoneClicked(object,System.Windows.RoutedEventArgs)_void.html
- ui_RefreshToDoItems()_void.html
- ui_SaveClicked(object,System.Windows.RoutedEventArgs)_void.html
- ui_ToDoItemSelected(object,System.Windows.Controls.SelectionChangedEventArgs)_void.html
- ui_UserSelected(object,System.Windows.Controls.SelectionChangedEventArgs)_void.html
- ui_WindowLoaded(object,System.Windows.RoutedEventArgs)_void.html
- SampleApp
- LocalTestRun.testrunconfig
- ToDoApplication
- ToDoContract
- ToDoSample.vsmdi
- ToDoService
- ToDoUnitTests
- StaticCodeAnalyzer
- Arebis.CodeAnalysis.Static
- Arebis.Common
|
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Arebis.Reflection;
using System.Xml;
using System.IO;
using System.Text.RegularExpressions;
using Arebis.CodeAnalysis.Static;
using System.Threading;
using Arebis.CodeAnalysis.Static.Processors;
using System.Diagnostics;
namespace Arebis.CodeAnalysis.Static
{
/// <summary>
/// A StaticCodeAnalyzer constructs a codemodel containing an
/// in-memory method call networks for code analysis.
/// </summary>
public class StaticCodeAnalyzer
{
/// <summary>
/// Process the given session and return a codemodel containing
/// the in-memory method call network.
/// </summary>
public CodeModel Process(StaticCodeAnalyzerSession session)
{
List<ModelAssembly> massemblies = new List<ModelAssembly>();
List<ModelType> mtypes = new List<ModelType>();
Dictionary<string, ModelMethod> mmethods = new Dictionary<string, ModelMethod>();
ILanguageInfo languageInfo = session.LanguageInfo;
IAnalyzerFilter analyzerFilter = session.AnalyzerFilter;
// Retrieve all methods and constructors:
foreach (Assembly asm in session.Assemblies)
{
if ((analyzerFilter != null)
&& (!analyzerFilter.ProcessAssembly(asm)))
continue;
ModelAssembly masm = new ModelAssembly(asm, languageInfo);
massemblies.Add(masm);
foreach (Type type in asm.GetTypes())
{
if ((analyzerFilter != null)
&& (!analyzerFilter.ProcessType(type)))
continue;
ModelType mtype = new ModelType(masm, type, languageInfo);
mtypes.Add(mtype);
foreach (MethodBase mb in type.GetConstructors(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
{
if ((analyzerFilter != null)
&& (!analyzerFilter.ProcessMethod(mb)))
continue;
mmethods[GetMethodKey(mb)] = new ModelMethod(mtype, mb, languageInfo);
}
foreach (MethodBase mb in type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly))
{
if ((analyzerFilter != null)
&& (!analyzerFilter.ProcessMethod(mb)))
continue;
mmethods[GetMethodKey(mb)] = new ModelMethod(mtype, mb, languageInfo);
}
}
}
// Build network of method calls:
foreach (ModelMethod m in mmethods.Values)
{
try
{
MethodBodyReader reader = new MethodBodyReader(m.MethodBase);
foreach (MethodBase calledmb in reader.GetCalledMethods(true, true))
{
ModelMethod calledm = FindMethod(mmethods, calledmb);
if (calledm != null)
{
m.CallsMethods.Add(calledm);
}
}
}
catch (InvalidOperationException ex)
{
Debug.WriteLine(ex.Message);
}
}
// Construct a code model:
CodeModel codeModel = new CodeModel(
massemblies,
mtypes,
mmethods.Values);
// Apply processors:
foreach (IProcessor processor in session.Processors)
{
processor.Process(codeModel);
}
// Construct & return a code model:
return codeModel;
}
#region Private implementation
private static ModelMethod FindMethod(Dictionary<string, ModelMethod> methods, MethodBase methodBase)
{
ModelMethod result;
if (methods.TryGetValue(GetMethodKey(methodBase), out result))
return result;
else
return null;
}
private static string GetMethodKey(MethodBase methodBase)
{
StringBuilder key = new StringBuilder(64);
key.Append(methodBase.DeclaringType);
key.Append('.');
key.Append(methodBase.Name);
foreach(ParameterInfo param in methodBase.GetParameters())
{
key.Append('(');
key.Append(param.ParameterType);
}
return key.ToString();
}
#endregion
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.