Skip to content

Commit

Permalink
Merge pull request #170 from EdHarvey/Analysis
Browse files Browse the repository at this point in the history
Analyzer & Ux Enhancements
  • Loading branch information
dgrunwald committed May 20, 2011
2 parents faf3a29 + 4c2e64e commit e04f6f7
Show file tree
Hide file tree
Showing 26 changed files with 547 additions and 299 deletions.
110 changes: 62 additions & 48 deletions ILSpy/CSharpLanguage.cs
Expand Up @@ -47,12 +47,12 @@ public class CSharpLanguage : Language
string name = "C#";
bool showAllMembers = false;
Predicate<IAstTransform> transformAbortCondition = null;

public CSharpLanguage()
{
}
#if DEBUG

#if DEBUG
internal static IEnumerable<CSharpLanguage> GetDebugLanguages()
{
DecompilerContext context = new DecompilerContext(ModuleDefinition.CreateModule("dummy", ModuleKind.Dll));
Expand All @@ -71,52 +71,55 @@ internal static IEnumerable<CSharpLanguage> GetDebugLanguages()
showAllMembers = true
};
}
#endif

public override string Name {
#endif

public override string Name
{
get { return name; }
}

public override string FileExtension {

public override string FileExtension
{
get { return ".cs"; }
}

public override string ProjectFileExtension {

public override string ProjectFileExtension
{
get { return ".csproj"; }
}

public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: method.DeclaringType, isSingleMember: true);
codeDomBuilder.AddMethod(method);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
}

public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: property.DeclaringType, isSingleMember: true);
codeDomBuilder.AddProperty(property);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
}

public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: field.DeclaringType, isSingleMember: true);
codeDomBuilder.AddField(field);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
}

public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, TypeToString(ev.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: ev.DeclaringType, isSingleMember: true);
codeDomBuilder.AddEvent(ev);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
}

public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: type);
Expand All @@ -131,7 +134,7 @@ void RunTransformsAndGenerateCode(AstBuilder astBuilder, ITextOutput output, Dec
AddXmlDocTransform.Run(astBuilder.CompilationUnit);
astBuilder.GenerateCode(output);
}

public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{
if (options.FullDecompilation && options.SaveAsProjectDirectory != null) {
Expand All @@ -150,7 +153,7 @@ public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput outp
}
}
}

#region WriteProjectFile
void WriteProjectFile(TextWriter writer, IEnumerable<Tuple<string, string>> files, ModuleDefinition module)
{
Expand Down Expand Up @@ -178,20 +181,20 @@ void WriteProjectFile(TextWriter writer, IEnumerable<Tuple<string, string>> file
w.WriteStartElement("Project", ns);
w.WriteAttributeString("ToolsVersion", "4.0");
w.WriteAttributeString("DefaultTargets", "Build");

w.WriteStartElement("PropertyGroup");
w.WriteElementString("ProjectGuid", Guid.NewGuid().ToString().ToUpperInvariant());

w.WriteStartElement("Configuration");
w.WriteAttributeString("Condition", " '$(Configuration)' == '' ");
w.WriteValue("Debug");
w.WriteEndElement(); // </Configuration>

w.WriteStartElement("Platform");
w.WriteAttributeString("Condition", " '$(Platform)' == '' ");
w.WriteValue(platformName);
w.WriteEndElement(); // </Platform>

switch (module.Kind) {
case ModuleKind.Windows:
w.WriteElementString("OutputType", "WinExe");
Expand All @@ -203,7 +206,7 @@ void WriteProjectFile(TextWriter writer, IEnumerable<Tuple<string, string>> file
w.WriteElementString("OutputType", "Library");
break;
}

w.WriteElementString("AssemblyName", module.Assembly.Name.Name);
switch (module.Runtime) {
case TargetRuntime.Net_1_0:
Expand All @@ -222,31 +225,31 @@ void WriteProjectFile(TextWriter writer, IEnumerable<Tuple<string, string>> file
break;
}
w.WriteElementString("WarningLevel", "4");

w.WriteEndElement(); // </PropertyGroup>

w.WriteStartElement("PropertyGroup"); // platform-specific
w.WriteAttributeString("Condition", " '$(Platform)' == '" + platformName + "' ");
w.WriteElementString("PlatformTarget", platformName);
w.WriteEndElement(); // </PropertyGroup> (platform-specific)

w.WriteStartElement("PropertyGroup"); // Debug
w.WriteAttributeString("Condition", " '$(Configuration)' == 'Debug' ");
w.WriteElementString("OutputPath", "bin\\Debug\\");
w.WriteElementString("DebugSymbols", "true");
w.WriteElementString("DebugType", "full");
w.WriteElementString("Optimize", "false");
w.WriteEndElement(); // </PropertyGroup> (Debug)

w.WriteStartElement("PropertyGroup"); // Release
w.WriteAttributeString("Condition", " '$(Configuration)' == 'Release' ");
w.WriteElementString("OutputPath", "bin\\Release\\");
w.WriteElementString("DebugSymbols", "true");
w.WriteElementString("DebugType", "pdbonly");
w.WriteElementString("Optimize", "true");
w.WriteEndElement(); // </PropertyGroup> (Release)


w.WriteStartElement("ItemGroup"); // References
foreach (AssemblyNameReference r in module.AssemblyReferences) {
if (r.Name != "mscorlib") {
Expand All @@ -257,7 +260,7 @@ void WriteProjectFile(TextWriter writer, IEnumerable<Tuple<string, string>> file
}
}
w.WriteEndElement(); // </ItemGroup> (References)

foreach (IGrouping<string, string> gr in (from f in files group f.Item2 by f.Item1 into g orderby g.Key select g)) {
w.WriteStartElement("ItemGroup");
foreach (string file in gr.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)) {
Expand All @@ -267,16 +270,16 @@ void WriteProjectFile(TextWriter writer, IEnumerable<Tuple<string, string>> file
}
w.WriteEndElement();
}

w.WriteStartElement("Import");
w.WriteAttributeString("Project", "$(MSBuildToolsPath)\\Microsoft.CSharp.targets");
w.WriteEndElement();

w.WriteEndDocument();
}
}
#endregion

#region WriteCodeFilesInProject
bool IncludeTypeWhenDecompilingProject(TypeDefinition type, DecompilationOptions options)
{
Expand All @@ -286,11 +289,11 @@ bool IncludeTypeWhenDecompilingProject(TypeDefinition type, DecompilationOptions
return false;
return true;
}

IEnumerable<Tuple<string, string>> WriteCodeFilesInProject(AssemblyDefinition assembly, DecompilationOptions options, HashSet<string> directories)
{
var files = assembly.MainModule.Types.Where(t => IncludeTypeWhenDecompilingProject(t, options)).GroupBy(
delegate (TypeDefinition type) {
delegate(TypeDefinition type) {
string file = TextView.DecompilerTextView.CleanUpName(type.Name) + this.FileExtension;
if (string.IsNullOrEmpty(type.Namespace)) {
return file;
Expand All @@ -305,7 +308,7 @@ bool IncludeTypeWhenDecompilingProject(TypeDefinition type, DecompilationOptions
Parallel.ForEach(
files,
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
delegate (IGrouping<string, TypeDefinition> file) {
delegate(IGrouping<string, TypeDefinition> file) {
using (StreamWriter w = new StreamWriter(Path.Combine(options.SaveAsProjectDirectory, file.Key))) {
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentModule: assembly.MainModule);
foreach (TypeDefinition type in file) {
Expand All @@ -319,7 +322,7 @@ bool IncludeTypeWhenDecompilingProject(TypeDefinition type, DecompilationOptions
return files.Select(f => Tuple.Create("Compile", f.Key));
}
#endregion

#region WriteResourceFilesInProject
IEnumerable<Tuple<string, string>> WriteResourceFilesInProject(LoadedAssembly assembly, DecompilationOptions options, HashSet<string> directories)
{
Expand All @@ -333,7 +336,8 @@ bool IncludeTypeWhenDecompilingProject(TypeDefinition type, DecompilationOptions
IEnumerable<DictionaryEntry> rs = null;
try {
rs = new ResourceSet(s).Cast<DictionaryEntry>();
} catch (ArgumentException) {
}
catch (ArgumentException) {
}
if (rs != null && rs.All(e => e.Value is Stream)) {
foreach (var pair in rs) {
Expand All @@ -351,7 +355,8 @@ bool IncludeTypeWhenDecompilingProject(TypeDefinition type, DecompilationOptions
string xaml = null;
try {
xaml = decompiler.DecompileBaml(ms, assembly.FileName, new ConnectMethodDecompiler(assembly), new AssemblyResolver(assembly));
} catch (XamlXmlWriterException) {} // ignore XAML writer exceptions
}
catch (XamlXmlWriterException) { } // ignore XAML writer exceptions
if (xaml != null) {
File.WriteAllText(Path.Combine(options.SaveAsProjectDirectory, Path.ChangeExtension(fileName, ".xaml")), xaml);
yield return Tuple.Create("Page", Path.ChangeExtension(fileName, ".xaml"));
Expand All @@ -372,12 +377,13 @@ bool IncludeTypeWhenDecompilingProject(TypeDefinition type, DecompilationOptions
}
yield return Tuple.Create("EmbeddedResource", fileName);
}
} finally {
}
finally {
if (bamlDecompilerAppDomain != null)
AppDomain.Unload(bamlDecompilerAppDomain);
}
}

string GetFileNameForResource(string fullName, HashSet<string> directories)
{
string[] splitName = fullName.Split('.');
Expand All @@ -393,7 +399,7 @@ string GetFileNameForResource(string fullName, HashSet<string> directories)
return fileName;
}
#endregion

AstBuilder CreateAstBuilder(DecompilationOptions options, ModuleDefinition currentModule = null, TypeDefinition currentType = null, bool isSingleMember = false)
{
if (currentModule == null)
Expand All @@ -417,19 +423,19 @@ public override string TypeToString(TypeReference type, bool includeNamespace, I
if (includeNamespace)
options |= ConvertTypeOptions.IncludeNamespace;
AstType astType = AstBuilder.ConvertType(type, typeAttributes, options);

StringWriter w = new StringWriter();
if (type.IsByReference) {
ParameterDefinition pd = typeAttributes as ParameterDefinition;
if (pd != null && (!pd.IsIn && pd.IsOut))
w.Write("out ");
else
w.Write("ref ");

if (astType is ComposedType && ((ComposedType)astType).PointerRank > 0)
((ComposedType)astType).PointerRank--;
}

astType.AcceptVisitor(new OutputVisitor(w, new CSharpFormattingOptions()), null);
return w.ToString();
}
Expand Down Expand Up @@ -464,12 +470,20 @@ public override string FormatPropertyName(PropertyDefinition property, bool? isI
} else
return property.Name;
}

public override bool ShowMember(MemberReference member)
{
return showAllMembers || !AstBuilder.MemberIsHidden(member, new DecompilationOptions().DecompilerSettings);
}


public override MemberReference GetOriginalCodeLocation(MemberReference member)
{
if (showAllMembers || !DecompilerSettingsPanel.CurrentDecompilerSettings.AnonymousMethods)
return member;
else
return ICSharpCode.ILSpy.TreeNodes.Analyzer.Helpers.GetOriginalCodeLocation(member);
}

public override string GetTooltip(MemberReference member)
{
MethodDefinition md = member as MethodDefinition;
Expand All @@ -490,12 +504,12 @@ public override string GetTooltip(MemberReference member)
b.RunTransformations();
foreach (var attribute in b.CompilationUnit.Descendants.OfType<AttributeSection>())
attribute.Remove();

StringWriter w = new StringWriter();
b.GenerateCode(new PlainTextOutput(w));
return Regex.Replace(w.ToString(), @"\s+", " ").TrimEnd();
}

return base.GetTooltip(member);
}
}
Expand Down
7 changes: 4 additions & 3 deletions ILSpy/ILSpy.csproj
Expand Up @@ -144,21 +144,22 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="TreeNodes\Analyzer\AnalyzeContextMenuEntry.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventAccessorsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventOverridesTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedInterfacePropertyImplementedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedInterfaceMethodImplementedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedInterfaceEventImplementedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyAccessorTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeExposedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeExtensionMethodsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeInstantiationsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventAccessorTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedVirtualMethodUsedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\Helpers.cs" />
<Compile Include="TreeNodes\Analyzer\ScopedWhereUsedAnalyzer.cs" />
<Compile Include="TreeNodes\IMemberTreeNode.cs" />
<Compile Include="TreeNodes\XamlResourceNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyAccessorsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyOverridesTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyTreeNode.cs" />
<Compile Include="XmlDoc\AddXmlDocTransform.cs" />
Expand Down Expand Up @@ -243,6 +244,7 @@
</ItemGroup>
<ItemGroup>
<Resource Include="Images\Class.png" />
<Resource Include="Images\StaticClass.png" />
<Resource Include="Images\Delegate.png" />
<Resource Include="Images\Enum.png" />
<Resource Include="Images\Field.png" />
Expand Down Expand Up @@ -310,6 +312,5 @@
<Name>ICSharpCode.TreeView</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>

0 comments on commit e04f6f7

Please sign in to comment.