diff --git a/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs b/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs index 97cff7d30..a88ed7089 100644 --- a/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs +++ b/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs @@ -156,14 +156,21 @@ namespace ICSharpCode.Decompiler.Disassembler writer.WriteReference(Escape(field.Name), field); } + static bool IsValidIdentifierCharacter(char c) + { + return c == '_' || c == '$' || c == '@' || c == '?' || c == '`'; + } + static bool IsValidIdentifier(string identifier) { if (string.IsNullOrEmpty(identifier)) return false; - if (!(char.IsLetter(identifier[0]) || identifier[0] == '_' || identifier[0] == '.')) - return false; + if (!(char.IsLetter(identifier[0]) || IsValidIdentifierCharacter(identifier[0]))) { + // As a special case, .ctor and .cctor are valid despite starting with a dot + return identifier == ".ctor" || identifier == ".cctor"; + } for (int i = 1; i < identifier.Length; i++) { - if (!(char.IsLetterOrDigit(identifier[i]) || identifier[i] == '_' || identifier[i] == '.' || identifier[i] == '`')) + if (!(char.IsLetterOrDigit(identifier[i]) || IsValidIdentifierCharacter(identifier[i]) || identifier[i] == '.')) return false; } return true; @@ -196,7 +203,7 @@ namespace ICSharpCode.Decompiler.Disassembler "vararg", "variant", "vector", "virtual", "void", "wchar", "winapi", "with", "wrapper", // These are not listed as keywords in spec, but ILAsm treats them as such - "property", "type", "flags", "callconv" + "property", "type", "flags", "callconv", "strict" ); static HashSet BuildKeywordList(params string[] keywords) @@ -210,10 +217,13 @@ namespace ICSharpCode.Decompiler.Disassembler public static string Escape(string identifier) { - if (IsValidIdentifier(identifier) && !ilKeywords.Contains(identifier)) + if (IsValidIdentifier(identifier) && !ilKeywords.Contains(identifier)) { return identifier; - else + } else { + // The ECMA specification says that ' inside SQString should be ecaped using an octal escape sequence, + // but we follow Microsoft's ILDasm and use \'. return "'" + NRefactory.CSharp.OutputVisitor.ConvertString(identifier).Replace("'", "\\'") + "'"; + } } public static void WriteTo(this TypeReference type, ITextOutput writer, ILNameSyntax syntax = ILNameSyntax.Signature) diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index 4174f2b11..4e144924e 100644 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -335,7 +335,12 @@ namespace ICSharpCode.Decompiler.Disassembler output.Write(' '); output.Write(DisassemblerHelpers.Escape(na.Name)); output.Write(" = "); - WriteConstant(na.Argument.Value); + if (na.Argument.Value is string) { + // secdecls use special syntax for strings + output.Write("string('{0}')", NRefactory.CSharp.OutputVisitor.ConvertString((string)na.Argument.Value).Replace("'", "\'")); + } else { + WriteConstant(na.Argument.Value); + } } string GetAssemblyQualifiedName(TypeReference type)