Skip to content

Commit

Permalink
Update MSBuild project generator
Browse files Browse the repository at this point in the history
  • Loading branch information
ElektroKill committed Apr 17, 2024
1 parent d164a7d commit 60a79af
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 76 deletions.
2 changes: 1 addition & 1 deletion dnSpy/dnSpy.Decompiler/MSBuild/MSBuildProjectCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public void Create() {
maxProgress++;
progressListener.SetMaxProgress(maxProgress);

Parallel.ForEach(GetJobs(), opts, job => {
Parallel.ForEach(jobs, opts, job => {
options.CancellationToken.ThrowIfCancellationRequested();
try {
job.Create(ctx);
Expand Down
21 changes: 20 additions & 1 deletion dnSpy/dnSpy.Decompiler/MSBuild/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ void CreateEmptyAppXamlFile() {
if ((Options.Module.Characteristics & Characteristics.Dll) != 0)
return;

var file = Files.OfType<TypeProjectFile>().Where(a => DotNetUtils.IsSystemWindowsApplication(a.Type)).FirstOrDefault();
var file = Files.OfType<TypeProjectFile>().FirstOrDefault(a => DotNetUtils.IsSystemWindowsApplication(a.Type));
Debug2.Assert(file is not null);
if (file is null)
return;
Expand Down Expand Up @@ -454,9 +454,28 @@ bool DecompileType(TypeDef type) {
if (type.Namespace == "XamlGeneratedNamespace" && type.Name == "GeneratedInternalTypeHelper")
return false;

// Don't include attribute types added by the compiler.
// if (type.BaseType is not null && type.BaseType.Name == "Attribute" && type.CustomAttributes.IsDefined("Microsoft.CodeAnalysis.EmbeddedAttribute")) {
// if (type.Namespace == "Microsoft.CodeAnalysis" && type.Name == "EmbeddedAttribute")
// return false;
// if (type.Namespace == "System.Runtime.CompilerServices" && attributeNames.Contains(type.Name))
// return false;
// }

return true;
}

static readonly HashSet<string> attributeNames = new HashSet<string> {
"IsReadOnlyAttribute",
"IsByRefLikeAttribute",
"IsUnmanagedAttribute",
"NullableAttribute",
"NullableContextAttribute",
"NativeIntegerAttribute",
"RefSafetyRulesAttribute",
"ScopedRefAttribute",
};

IEnumerable<ProjectFile> CreateSatelliteFiles(string rsrcName, FilenameCreator filenameCreator, ProjectFile nonSatFile) {
foreach (var satMod in satelliteAssemblyFinder.GetSatelliteAssemblies(Options.Module)) {
var satFile = TryCreateSatelliteFile(satMod, rsrcName, filenameCreator, nonSatFile);
Expand Down
72 changes: 1 addition & 71 deletions dnSpy/dnSpy.Decompiler/MSBuild/ResXProjectFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,10 @@ sealed class ResXProjectFile : ProjectFile {
public string TypeFullName { get; }
public bool IsSatelliteFile { get; set; }

readonly ModuleDef module;
readonly ResourceElementSet resourceElementSet;
readonly Dictionary<IAssembly, IAssembly> newToOldAsm;

public ResXProjectFile(ModuleDef module, string filename, string typeFullName, ResourceElementSet resourceElementSet) {
this.module = module;
this.filename = filename;
TypeFullName = typeFullName;
this.resourceElementSet = resourceElementSet;
Expand All @@ -51,7 +49,7 @@ public ResXProjectFile(ModuleDef module, string filename, string typeFullName, R
}

public override void Create(DecompileContext ctx) {
using (var writer = new ResXResourceFileWriter(Filename, TypeNameConverter, HasTypeConverterForByteArray)) {
using (var writer = new ResXResourceFileWriter(Filename, TypeNameConverter)) {
foreach (var resourceElement in resourceElementSet.ResourceElements) {
ctx.CancellationToken.ThrowIfCancellationRequested();
writer.AddResourceData(resourceElement);
Expand All @@ -69,73 +67,5 @@ string TypeNameConverter(Type type) {
return type.AssemblyQualifiedName ?? throw new ArgumentException();
return $"{type.FullName}, {oldAsm.FullName}";
}

bool HasTypeConverterForByteArray(string typeFullName) {
var typeDef = TypeNameParser.ParseReflection(module, typeFullName, null)?.ResolveTypeDef();

while (typeDef is not null) {
var attribute = typeDef.CustomAttributes.Find("System.ComponentModel.TypeConverterAttribute");
if (attribute is not null && attribute.ConstructorArguments.Count == 1 && attribute.ConstructorArguments[0].Value is ClassOrValueTypeSig typeSig) {
var converter = typeSig.TypeDefOrRef.ResolveTypeDef();
var (canConvertToMethod, canConvertFromMethod) = FindCanConvertMethods(converter);

if (canConvertToMethod is not null && canConvertFromMethod is not null) {
bool canConvertToHasByteArray = ContainsByteArrayReference(canConvertToMethod);
bool canConvertFromHasByteArray = ContainsByteArrayReference(canConvertFromMethod);
if (canConvertFromHasByteArray && canConvertToHasByteArray)
return true;
}

return false;
}

typeDef = typeDef.BaseType.ResolveTypeDef();
}

return false;
}

static (MethodDef? canConvertToMethod, MethodDef? canConvertFromMethod) FindCanConvertMethods(TypeDef type) {
MethodDef? canConvertToMethod = null;
MethodDef? canConvertFromMethod = null;
foreach (var method in type.Methods) {
if (!method.MethodSig.HasThis)
continue;
if (method.MethodSig.Params.Count != 2)
continue;
if (method.ReturnType.GetElementType() != ElementType.Boolean)
continue;

if (method.Name == "CanConvertTo")
canConvertToMethod ??= method;
else if (method.Name == "CanConvertFrom")
canConvertFromMethod ??= method;
else {
foreach (var methodOverride in method.Overrides) {
var overridenMethod = methodOverride.MethodDeclaration.ResolveMethodDef();
if (overridenMethod.Name == "CanConvertTo")
canConvertToMethod ??= method;
else if (overridenMethod.Name == "CanConvertFrom")
canConvertFromMethod ??= method;
}
}
}

return (canConvertToMethod, canConvertFromMethod);
}

static bool ContainsByteArrayReference(MethodDef method) {
if (!method.HasBody)
return false;
for (var i = 0; i < method.Body.Instructions.Count; i++) {
var instr = method.Body.Instructions[i];
if (instr.OpCode.Code == Code.Ldtoken && instr.Operand is TypeSpec typeSpec &&
typeSpec.TypeSig is SZArraySig arraySig &&
arraySig.Next.GetElementType() == ElementType.U1) {
return true;
}
}
return false;
}
}
}
4 changes: 1 addition & 3 deletions dnSpy/dnSpy.Decompiler/MSBuild/ResXResourceFileWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,11 @@ public ResXResourceInfo(string valueString) {
}

readonly Func<Type, string> typeNameConverter;
readonly Func<string, bool> hasByteArrayConverter;
readonly XmlTextWriter writer;
bool written;

public ResXResourceFileWriter(string fileName, Func<Type, string> typeNameConverter, Func<string, bool> hasByteArrayConverter) {
public ResXResourceFileWriter(string fileName, Func<Type, string> typeNameConverter) {
this.typeNameConverter = typeNameConverter;
this.hasByteArrayConverter = hasByteArrayConverter;
writer = new XmlTextWriter(fileName, Encoding.UTF8) {
Formatting = Formatting.Indented,
Indentation = 2
Expand Down

0 comments on commit 60a79af

Please sign in to comment.