diff --git a/BuildTools/tidy.py b/BuildTools/tidy.py index 5f732ce7c..3a0ba3756 100644 --- a/BuildTools/tidy.py +++ b/BuildTools/tidy.py @@ -22,7 +22,7 @@ def main(): if '\\obj\\' in root: continue for filename in files: - if filename.lower().endswith('.cs'): + if filename.lower().endswith('.cs') and not filename.lower().endswith('resources.designer.cs'): if not check(os.path.join(root, filename)): ok = False print('Tidy check: {}'.format('successful' if ok else 'failed')) diff --git a/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs b/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs index 9267c0f99..e5f200486 100644 --- a/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs @@ -329,8 +329,8 @@ namespace ICSharpCode.Decompiler.Tests Tester.RunAndCompareOutput(testFileName, outputFile.PathToAssembly, decompiledOutputFile.PathToAssembly, decompiledCodeFile); - File.Delete(decompiledCodeFile); - File.Delete(decompiledOutputFile.PathToAssembly); + Tester.RepeatOnIOError(() => File.Delete(decompiledCodeFile)); + Tester.RepeatOnIOError(() => File.Delete(decompiledOutputFile.PathToAssembly)); } finally { if (outputFile != null) outputFile.TempFiles.Delete(); @@ -354,8 +354,8 @@ namespace ICSharpCode.Decompiler.Tests Tester.RunAndCompareOutput(testFileName, outputFile.PathToAssembly, decompiledOutputFile.PathToAssembly, decompiledCodeFile); - File.Delete(decompiledCodeFile); - File.Delete(decompiledOutputFile.PathToAssembly); + Tester.RepeatOnIOError(() => File.Delete(decompiledCodeFile)); + Tester.RepeatOnIOError(() => File.Delete(decompiledOutputFile.PathToAssembly)); } finally { if (outputFile != null) outputFile.TempFiles.Delete(); @@ -375,9 +375,9 @@ namespace ICSharpCode.Decompiler.Tests decompiledOutputFile = Tester.CompileCSharp(decompiledCodeFile, options); Tester.RunAndCompareOutput(testFileName, outputFile, decompiledOutputFile.PathToAssembly, decompiledCodeFile); - - File.Delete(decompiledCodeFile); - File.Delete(decompiledOutputFile.PathToAssembly); + + Tester.RepeatOnIOError(() => File.Delete(decompiledCodeFile)); + Tester.RepeatOnIOError(() => File.Delete(decompiledOutputFile.PathToAssembly)); } finally { if (decompiledOutputFile != null) decompiledOutputFile.TempFiles.Delete(); diff --git a/ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs b/ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs index 08a037e95..e09cecda9 100644 --- a/ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs +++ b/ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.VisualBasic; diff --git a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs index 82b98f3db..dfe0d7cb2 100644 --- a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs +++ b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs @@ -518,5 +518,21 @@ namespace ICSharpCode.Decompiler.Tests.Helpers Assert.Fail(b.ToString()); } } + + internal static void RepeatOnIOError(Action action, int numTries = 5) + { + for (int i = 0; i < numTries - 1; i++) { + try { + action(); + return; + } catch (IOException) { + } catch (UnauthorizedAccessException) { + // potential virus scanner problem + } + Thread.Sleep(10); + } + // If the last try still fails, don't catch the exception + action(); + } } } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs index 83a151048..f2cb636dd 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs @@ -1,4 +1,6 @@ -namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty +using System.Threading.Tasks; + +namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { internal class ConstantsTests { @@ -24,6 +26,12 @@ Test((v | 0x123) == 0); } + public void Enum_Flag_Check(TaskCreationOptions v) + { + Test((v & TaskCreationOptions.AttachedToParent) != 0); + Test((v & TaskCreationOptions.AttachedToParent) == 0); + } + private void Test(bool expr) { } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs index 96e96cf66..67bc28561 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs @@ -4,6 +4,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { internal class RefLocalsAndReturns { + public delegate ref T RefFunc(); + public delegate ref readonly T ReadOnlyRefFunc(); + public ref struct RefStruct { private int dummy; diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index ef6870521..8197c4e35 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2014 Daniel Grunwald +// Copyright (c) 2014 Daniel Grunwald // // Permission is hereby granted, free of charge, to any person obtaining a copy of this // software and associated documentation files (the "Software"), to deal in the Software @@ -699,8 +699,8 @@ namespace ICSharpCode.Decompiler.CSharp } // Special case comparisons with enum and char literals - left = AdjustConstantExpressionToType(left, right.Type); - right = AdjustConstantExpressionToType(right, left.Type); + left = TryUniteEqualityOperandType(left, right); + right = TryUniteEqualityOperandType(right, left); if (IsSpecialCasedReferenceComparisonWithNull(left, right)) { // When comparing a string/delegate with null, the C# compiler generates a reference comparison. @@ -763,6 +763,22 @@ namespace ICSharpCode.Decompiler.CSharp .WithRR(rr); } + TranslatedExpression TryUniteEqualityOperandType(TranslatedExpression left, TranslatedExpression right) + { + // Special case for enum flag check "(enum & EnumType.SomeValue) == 0" + // so that the const 0 value is printed as 0 integer and not as enum type, e.g. EnumType.None + if (left.ResolveResult.IsCompileTimeConstant && + left.ResolveResult.Type.IsCSharpPrimitiveIntegerType() && + (left.ResolveResult.ConstantValue as int?) == 0 && + NullableType.GetUnderlyingType(right.Type).Kind == TypeKind.Enum && + right.Expression is BinaryOperatorExpression binaryExpr && + binaryExpr.Operator == BinaryOperatorType.BitwiseAnd) + { + return AdjustConstantExpressionToType(left, compilation.FindType(KnownTypeCode.Int32)); + } else + return AdjustConstantExpressionToType(left, right.Type); + } + bool IsSpecialCasedReferenceComparisonWithNull(TranslatedExpression lhs, TranslatedExpression rhs) { if (lhs.Type.Kind == TypeKind.Null) diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs index c31a53c07..7752d667e 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs @@ -1440,6 +1440,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax decl.AddAnnotation(new TypeResolveResult(d)); } decl.ReturnType = ConvertType(invokeMethod.ReturnType); + if (invokeMethod.ReturnTypeIsRefReadOnly && decl.ReturnType is ComposedType ct && ct.HasRefSpecifier) { + ct.HasReadOnlySpecifier = true; + } decl.Name = d.Name; int outerTypeParameterCount = (d.DeclaringTypeDefinition == null) ? 0 : d.DeclaringTypeDefinition.TypeParameterCount; diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs index 378085fb1..163d58346 100644 --- a/ICSharpCode.Decompiler/DecompilerSettings.cs +++ b/ICSharpCode.Decompiler/DecompilerSettings.cs @@ -139,7 +139,7 @@ namespace ICSharpCode.Decompiler /// Decompile anonymous methods/lambdas. /// [Category("C# 2.0 / VS 2005")] - [Description("Decompile anonymous methods/lambdas")] + [Description("DecompilerSettings.DecompileAnonymousMethodsLambdas")] public bool AnonymousMethods { get { return anonymousMethods; } set { @@ -156,7 +156,7 @@ namespace ICSharpCode.Decompiler /// Decompile anonymous types. /// [Category("C# 3.0 / VS 2008")] - [Description("Decompile anonymous types")] + [Description("DecompilerSettings.DecompileAnonymousTypes")] public bool AnonymousTypes { get { return anonymousTypes; } set { @@ -173,7 +173,7 @@ namespace ICSharpCode.Decompiler /// Use C# 3 lambda syntax if possible. /// [Category("C# 3.0 / VS 2008")] - [Description("Use lambda syntax, if possible")] + [Description("DecompilerSettings.UseLambdaSyntaxIfPossible")] public bool UseLambdaSyntax { get { return useLambdaSyntax; } set { @@ -190,7 +190,7 @@ namespace ICSharpCode.Decompiler /// Decompile expression trees. /// [Category("C# 3.0 / VS 2008")] - [Description("Decompile expression trees")] + [Description("DecompilerSettings.DecompileExpressionTrees")] public bool ExpressionTrees { get { return expressionTrees; } set { @@ -207,7 +207,7 @@ namespace ICSharpCode.Decompiler /// Decompile enumerators. /// [Category("C# 2.0 / VS 2005")] - [Description("Decompile enumerators (yield return)")] + [Description("DecompilerSettings.DecompileEnumeratorsYieldReturn")] public bool YieldReturn { get { return yieldReturn; } set { @@ -224,7 +224,7 @@ namespace ICSharpCode.Decompiler /// Decompile use of the 'dynamic' type. /// [Category("C# 4.0 / VS 2010")] - [Description("Decompile use of the 'dynamic' type")] + [Description("DecompilerSettings.DecompileUseOfTheDynamicType")] public bool Dynamic { get { return dynamic; } set { @@ -241,7 +241,7 @@ namespace ICSharpCode.Decompiler /// Decompile async methods. /// [Category("C# 5.0 / VS 2012")] - [Description("Decompile async methods")] + [Description("DecompilerSettings.DecompileAsyncMethods")] public bool AsyncAwait { get { return asyncAwait; } set { @@ -259,7 +259,7 @@ namespace ICSharpCode.Decompiler /// Only has an effect if is enabled. /// [Category("C# 6.0 / VS 2015")] - [Description("Decompile await in catch/finally blocks")] + [Description("DecompilerSettings.DecompileAwaitInCatchFinallyBlocks")] public bool AwaitInCatchFinally { get { return awaitInCatchFinally; } set { @@ -276,7 +276,7 @@ namespace ICSharpCode.Decompiler /// Decompile [DecimalConstant(...)] as simple literal values. /// [Category("C# 1.0 / VS .NET")] - [Description("Decompile [DecimalConstant(...)] as simple literal values")] + [Description("DecompilerSettings.DecompileDecimalConstantAsSimpleLiteralValues")] public bool DecimalConstants { get { return decimalConstants; } set { @@ -293,7 +293,7 @@ namespace ICSharpCode.Decompiler /// Decompile C# 1.0 'public unsafe fixed int arr[10];' members. /// [Category("C# 1.0 / VS .NET")] - [Description("Decompile C# 1.0 'public unsafe fixed int arr[10];' members")] + [Description("DecompilerSettings.DecompileC10PublicUnsafeFixedIntArr10Members")] public bool FixedBuffers { get { return fixedBuffers; } set { @@ -310,7 +310,7 @@ namespace ICSharpCode.Decompiler /// Use lifted operators for nullables. /// [Category("C# 2.0 / VS 2005")] - [Description("Use lifted operators for nullables")] + [Description("DecompilerSettings.UseLiftedOperatorsForNullables")] public bool LiftNullables { get { return liftNullables; } set { @@ -327,7 +327,7 @@ namespace ICSharpCode.Decompiler /// Decompile C# 6 ?. and ?[] operators. /// [Category("C# 6.0 / VS 2015")] - [Description("Decompile ?. and ?[] operators")] + [Description("DecompilerSettings.DecompileAndOperators")] public bool NullPropagation { get { return nullPropagation; } set { @@ -344,7 +344,7 @@ namespace ICSharpCode.Decompiler /// Decompile automatic properties /// [Category("C# 3.0 / VS 2008")] - [Description("Decompile automatic properties")] + [Description("DecompilerSettings.DecompileAutomaticProperties")] public bool AutomaticProperties { get { return automaticProperties; } set { @@ -361,7 +361,7 @@ namespace ICSharpCode.Decompiler /// Decompile automatic events /// [Category("C# 1.0 / VS .NET")] - [Description("Decompile automatic events")] + [Description("DecompilerSettings.DecompileAutomaticEvents")] public bool AutomaticEvents { get { return automaticEvents; } set { @@ -378,7 +378,7 @@ namespace ICSharpCode.Decompiler /// Decompile using statements. /// [Category("C# 1.0 / VS .NET")] - [Description("Detect using statements")] + [Description("DecompilerSettings.DetectUsingStatements")] public bool UsingStatement { get { return usingStatement; } set { @@ -394,8 +394,8 @@ namespace ICSharpCode.Decompiler /// /// Gets/Sets whether to use braces for single-statement-blocks. /// - [Category("Other")] - [Description("Always use braces")] + [Category("DecompilerSettings.Other")] + [Description("DecompilerSettings.AlwaysUseBraces")] public bool AlwaysUseBraces { get { return alwaysUseBraces; } set { @@ -412,7 +412,7 @@ namespace ICSharpCode.Decompiler /// Decompile foreach statements. /// [Category("C# 1.0 / VS .NET")] - [Description("Detect foreach statements")] + [Description("DecompilerSettings.DetectForeachStatements")] public bool ForEachStatement { get { return forEachStatement; } set { @@ -429,7 +429,7 @@ namespace ICSharpCode.Decompiler /// Decompile lock statements. /// [Category("C# 1.0 / VS .NET")] - [Description("Detect lock statements")] + [Description("DecompilerSettings.DetectLockStatements")] public bool LockStatement { get { return lockStatement; } set { @@ -443,7 +443,7 @@ namespace ICSharpCode.Decompiler bool switchStatementOnString = true; [Category("C# 1.0 / VS .NET")] - [Description("Detect switch on string")] + [Description("DecompilerSettings.DetectSwitchOnString")] public bool SwitchStatementOnString { get { return switchStatementOnString; } set { @@ -457,7 +457,7 @@ namespace ICSharpCode.Decompiler bool usingDeclarations = true; [Category("C# 1.0 / VS .NET")] - [Description("Insert using declarations")] + [Description("DecompilerSettings.InsertUsingDeclarations")] public bool UsingDeclarations { get { return usingDeclarations; } set { @@ -471,7 +471,7 @@ namespace ICSharpCode.Decompiler bool extensionMethods = true; [Category("C# 3.0 / VS 2008")] - [Description("Use extension method syntax")] + [Description("DecompilerSettings.UseExtensionMethodSyntax")] public bool ExtensionMethods { get { return extensionMethods; } set { @@ -485,7 +485,7 @@ namespace ICSharpCode.Decompiler bool queryExpressions = true; [Category("C# 3.0 / VS 2008")] - [Description("Use LINQ expression syntax")] + [Description("DecompilerSettings.UseLINQExpressionSyntax")] public bool QueryExpressions { get { return queryExpressions; } set { @@ -504,7 +504,7 @@ namespace ICSharpCode.Decompiler /// false: EventHandler h = new EventHandler(this.OnClick); /// [Category("C# 2.0 / VS 2005")] - [Description("Use implicit method group conversions")] + [Description("DecompilerSettings.UseImplicitMethodGroupConversions")] public bool UseImplicitMethodGroupConversion { get { return useImplicitMethodGroupConversion; } set { @@ -524,7 +524,7 @@ namespace ICSharpCode.Decompiler /// default: false /// [Category("Other")] - [Description("Always cast targets of explicit interface implementation calls")] + [Description("DecompilerSettings.AlwaysCastTargetsOfExplicitInterfaceImplementationCalls")] public bool AlwaysCastTargetsOfExplicitInterfaceImplementationCalls { get { return alwaysCastTargetsOfExplicitInterfaceImplementationCalls; } set { @@ -541,7 +541,7 @@ namespace ICSharpCode.Decompiler /// Gets/Sets whether to use variable names from debug symbols, if available. /// [Category("Other")] - [Description("Use variable names from debug symbols, if available")] + [Description("DecompilerSettings.UseVariableNamesFromDebugSymbolsIfAvailable")] public bool UseDebugSymbols { get { return useDebugSymbols; } set { @@ -559,7 +559,7 @@ namespace ICSharpCode.Decompiler /// If set to false, might produce non-compilable code. /// [Category("C# 1.0 / VS .NET")] - [Description("Array initializer expressions")] + [Description("DecompilerSettings.ArrayInitializerExpressions")] public bool ArrayInitializers { get { return arrayInitializers; } @@ -579,7 +579,7 @@ namespace ICSharpCode.Decompiler /// Gets/Sets whether to use C# 3.0 object/collection initializers. /// [Category("C# 3.0 / VS 2008")] - [Description("Object/collection initializer expressions")] + [Description("DecompilerSettings.ObjectCollectionInitializerExpressions")] public bool ObjectOrCollectionInitializers { get { return objectCollectionInitializers; } set { @@ -597,7 +597,7 @@ namespace ICSharpCode.Decompiler /// Only has an effect if ObjectOrCollectionInitializers is enabled. /// [Category("C# 6.0 / VS 2015")] - [Description("Dictionary initializer expressions")] + [Description("DecompilerSettings.DictionaryInitializerExpressions")] public bool DictionaryInitializers { get { return dictionaryInitializers; } set { @@ -615,7 +615,7 @@ namespace ICSharpCode.Decompiler /// Only has an effect if ObjectOrCollectionInitializers is enabled. /// [Category("C# 6.0 / VS 2015")] - [Description("Allow extension 'Add' methods in collection initializer expressions")] + [Description("DecompilerSettings.AllowExtensionAddMethodsInCollectionInitializerExpressions")] public bool ExtensionMethodsInCollectionInitializers { get { return extensionMethodsInCollectionInitializers; } set { @@ -632,7 +632,7 @@ namespace ICSharpCode.Decompiler /// Gets/Sets whether to use C# 6.0 string interpolation /// [Category("C# 6.0 / VS 2015")] - [Description("Use string interpolation")] + [Description("DecompilerSettings.UseStringInterpolation")] public bool StringInterpolation { get { return stringInterpolation; } set { @@ -648,8 +648,8 @@ namespace ICSharpCode.Decompiler /// /// Gets/Sets whether to include XML documentation comments in the decompiled code. /// - [Category("Other")] - [Description("Include XML documentation comments in the decompiled code")] + [Category("DecompilerSettings.Other")] + [Description("DecompilerSettings.IncludeXMLDocumentationCommentsInTheDecompiledCode")] public bool ShowXmlDocumentation { get { return showXmlDocumentation; } set { @@ -704,7 +704,7 @@ namespace ICSharpCode.Decompiler /// /// Gets/Sets whether member bodies should be decompiled. /// - [Category("Other")] + [Category("DecompilerSettings.Other")] [Browsable(false)] public bool DecompileMemberBodies { get { return decompileMemberBodies; } @@ -722,7 +722,7 @@ namespace ICSharpCode.Decompiler /// Gets/Sets whether simple calculated getter-only property declarations should use expression body syntax. /// [Category("C# 6.0 / VS 2015")] - [Description("Use expression-bodied member syntax for get-only properties")] + [Description("DecompilerSettings.UseExpressionBodiedMemberSyntaxForGetOnlyProperties")] public bool UseExpressionBodyForCalculatedGetterOnlyProperties { get { return useExpressionBodyForCalculatedGetterOnlyProperties; } set { @@ -739,7 +739,7 @@ namespace ICSharpCode.Decompiler /// Gets/Sets whether out variable declarations should be used when possible. /// [Category("C# 7.0 / VS 2017")] - [Description("Use out variable declarations")] + [Description("DecompilerSettings.UseOutVariableDeclarations")] public bool OutVariables { get { return outVariables; } set { @@ -757,7 +757,7 @@ namespace ICSharpCode.Decompiler /// Only has an effect if is enabled. /// [Category("C# 7.0 / VS 2017")] - [Description("Use discards")] + [Description("DecompilerSettings.UseDiscards")] public bool Discards { get { return discards; } set { @@ -774,7 +774,7 @@ namespace ICSharpCode.Decompiler /// Gets/Sets whether IsByRefLikeAttribute should be replaced with 'ref' modifiers on structs. /// [Category("C# 7.2 / VS 2017.4")] - [Description("IsByRefLikeAttribute should be replaced with 'ref' modifiers on structs")] + [Description("DecompilerSettings.IsByRefLikeAttributeShouldBeReplacedWithRefModifiersOnStructs")] public bool IntroduceRefModifiersOnStructs { get { return introduceRefModifiersOnStructs; } set { @@ -792,7 +792,7 @@ namespace ICSharpCode.Decompiler /// and with the 'in' modifier on parameters. /// [Category("C# 7.2 / VS 2017.4")] - [Description("IsReadOnlyAttribute should be replaced with 'readonly'/'in' modifiers on structs/parameters")] + [Description("DecompilerSettings.IsReadOnlyAttributeShouldBeReplacedWithReadonlyInModifiersOnStructsParameters")] public bool IntroduceReadonlyAndInModifiers { get { return introduceReadonlyAndInModifiers; } set { @@ -810,7 +810,7 @@ namespace ICSharpCode.Decompiler /// is replaced with "T : unmanaged" constraints. /// [Category("C# 7.3 / VS 2017.7")] - [Description("IsUnmanagedAttribute on type parameters should be replaced with 'unmanaged' constraints")] + [Description("DecompilerSettings.IsUnmanagedAttributeOnTypeParametersShouldBeReplacedWithUnmanagedConstraints")] public bool IntroduceUnmanagedConstraint { get { return introduceUnmanagedConstraint; } set { @@ -827,7 +827,7 @@ namespace ICSharpCode.Decompiler /// Gets/Sets whether C# 7.3 stackalloc initializers should be used. /// [Category("C# 7.3 / VS 2017.7")] - [Description("Use stackalloc initializer syntax")] + [Description("DecompilerSettings.UseStackallocInitializerSyntax")] public bool StackAllocInitializers { get { return stackAllocInitializers; } set { @@ -845,7 +845,7 @@ namespace ICSharpCode.Decompiler /// should be used for System.ValueTuple. /// [Category("C# 7.0 / VS 2017")] - [Description("Use tuple type syntax")] + [Description("DecompilerSettings.UseTupleTypeSyntax")] public bool TupleTypes { get { return tupleTypes; } set { @@ -863,7 +863,7 @@ namespace ICSharpCode.Decompiler /// should be used in the decompiled output. /// [Category("C# 7.0 / VS 2017")] - [Description("Use implicit conversions between tuple types")] + [Description("DecompilerSettings.UseImplicitConversionsBetweenTupleTypes")] public bool TupleConversions { get { return tupleConversions; } set { @@ -880,7 +880,7 @@ namespace ICSharpCode.Decompiler /// Gets/Sets whether tuple comparisons should be detected. /// [Category("C# 7.3 / VS 2017.7")] - [Description("Detect tuple comparisons")] + [Description("DecompilerSettings.DetectTupleComparisons")] public bool TupleComparisons { get { return tupleComparisons; } set { @@ -897,7 +897,7 @@ namespace ICSharpCode.Decompiler /// Gets/Sets whether named arguments should be used. /// [Category("C# 4.0 / VS 2010")] - [Description("Use named arguments")] + [Description("DecompilerSettings.UseNamedArguments")] public bool NamedArguments { get { return namedArguments; } set { @@ -914,7 +914,7 @@ namespace ICSharpCode.Decompiler /// Gets/Sets whether C# 7.2 non-trailing named arguments should be used. /// [Category("C# 7.2 / VS 2017.4")] - [Description("Use non-trailing named arguments")] + [Description("DecompilerSettings.UseNonTrailingNamedArguments")] public bool NonTrailingNamedArguments { get { return nonTrailingNamedArguments; } set { @@ -931,7 +931,7 @@ namespace ICSharpCode.Decompiler /// Gets/Sets whether optional arguments should be removed, if possible. /// [Category("C# 4.0 / VS 2010")] - [Description("Remove optional arguments, if possible")] + [Description("DecompilerSettings.RemoveOptionalArgumentsIfPossible")] public bool OptionalArguments { get { return optionalArguments; } set { @@ -949,7 +949,7 @@ namespace ICSharpCode.Decompiler /// Note: this language feature is currently not implemented and this setting is always false. /// [Category("C# 7.0 / VS 2017")] - [Description("Introduce local functions (NOT IMPLEMENTED!)")] + [Description("DecompilerSettings.IntroduceLocalFunctionsNOTIMPLEMENTED")] [Browsable(false)] public bool LocalFunctions { get { return localFunctions; } @@ -968,7 +968,7 @@ namespace ICSharpCode.Decompiler /// Gets/Sets whether C# 8.0 nullable reference types are enabled. /// [Category("C# 8.0 / VS 2019")] - [Description("Nullable reference types")] + [Description("DecompilerSettings.NullableReferenceTypes")] public bool NullableReferenceTypes { get { return nullableReferenceTypes; } set { @@ -981,8 +981,8 @@ namespace ICSharpCode.Decompiler bool showDebugInfo; - [Category("Other")] - [Description("Show info from debug symbols, if available")] + [Category("DecompilerSettings.Other")] + [Description("DecompilerSettings.ShowInfoFromDebugSymbolsIfAvailable")] [Browsable(false)] public bool ShowDebugInfo { get { return showDebugInfo; } @@ -1000,7 +1000,7 @@ namespace ICSharpCode.Decompiler /// /// Gets/Sets whether the decompiler can assume that 'ldlen; conv.i4.ovf' does not throw an overflow exception. /// - [Category("VB-specific options")] + [Category("DecompilerSettings.VBSpecificOptions")] [Browsable(false)] public bool AssumeArrayLengthFitsIntoInt32 { get { return assumeArrayLengthFitsIntoInt32; } @@ -1017,7 +1017,7 @@ namespace ICSharpCode.Decompiler /// /// Gets/Sets whether to use increment and decrement operators /// - [Category("VB-specific options")] + [Category("DecompilerSettings.VBSpecificOptions")] [Browsable(false)] public bool IntroduceIncrementAndDecrement { get { return introduceIncrementAndDecrement; } @@ -1034,7 +1034,7 @@ namespace ICSharpCode.Decompiler /// /// Gets/Sets whether to use assignment expressions such as in while ((count = Do()) != 0) ; /// - [Category("VB-specific options")] + [Category("DecompilerSettings.VBSpecificOptions")] [Browsable(false)] public bool MakeAssignmentExpressions { get { return makeAssignmentExpressions; } @@ -1051,8 +1051,8 @@ namespace ICSharpCode.Decompiler #region Options to aid F# decompilation bool removeDeadCode = false; - [Category("F#-specific options")] - [Description("Remove dead and side effect free code (use with caution!)")] + [Category("DecompilerSettings.FSpecificOptions")] + [Description("DecompilerSettings.RemoveDeadAndSideEffectFreeCodeUseWithCaution")] public bool RemoveDeadCode { get { return removeDeadCode; } set { @@ -1094,8 +1094,8 @@ namespace ICSharpCode.Decompiler bool applyWindowsRuntimeProjections = true; - [Category("Other")] - [Description("Apply Windows Runtime projections on loaded assemblies")] + [Category("DecompilerSettings.Other")] + [Description("DecompilerSettings.ApplyWindowsRuntimeProjectionsOnLoadedAssemblies")] public bool ApplyWindowsRuntimeProjections { get { return applyWindowsRuntimeProjections; } set { diff --git a/ILSpy.AddIn/Utils.cs b/ILSpy.AddIn/Utils.cs index ae5ee4bca..20fa53e0b 100644 --- a/ILSpy.AddIn/Utils.cs +++ b/ILSpy.AddIn/Utils.cs @@ -146,7 +146,7 @@ namespace ICSharpCode.ILSpy.AddIn } } - public static object[] GetProperties(Properties properties, params string[] names) + public static object[] GetProperties(EnvDTE.Properties properties, params string[] names) { var values = new object[names.Length]; foreach (object p in properties) { @@ -166,7 +166,7 @@ namespace ICSharpCode.ILSpy.AddIn return values; } - public static List<(string, object)> GetAllProperties(Properties properties) + public static List<(string, object)> GetAllProperties(EnvDTE.Properties properties) { var result = new List<(string, object)>(); for (int i = 0; i < properties.Count; i++) { diff --git a/ILSpy.BamlDecompiler/Handlers/Records/StaticResourceIdHandler.cs b/ILSpy.BamlDecompiler/Handlers/Records/StaticResourceIdHandler.cs new file mode 100644 index 000000000..c52dcc771 --- /dev/null +++ b/ILSpy.BamlDecompiler/Handlers/Records/StaticResourceIdHandler.cs @@ -0,0 +1,53 @@ +// Copyright (c) 2019 Siegfried Pammer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using ILSpy.BamlDecompiler.Baml; +using ILSpy.BamlDecompiler.Xaml; + +namespace ILSpy.BamlDecompiler.Handlers +{ + class StaticResourceIdHandler : IHandler + { + public BamlRecordType Type => BamlRecordType.StaticResourceId; + + public BamlElement Translate(XamlContext ctx, BamlNode node, BamlElement parent) + { + var record = (StaticResourceIdRecord)((BamlRecordNode)node).Record; + + BamlNode found = node; + XamlResourceKey key; + do { + key = XamlResourceKey.FindKeyInAncestors(found.Parent, out found); + } while (key != null && record.StaticResourceId >= key.StaticResources.Count); + + if (key == null) + throw new Exception("Cannot find StaticResource @" + node.Record.Position); + + var resNode = key.StaticResources[record.StaticResourceId]; + + var handler = (IDeferHandler)HandlerMap.LookupHandler(resNode.Type); + var resElem = handler.TranslateDefer(ctx, resNode, parent); + + parent.Children.Add(resElem); + resElem.Parent = parent; + + return resElem; + } + } +} diff --git a/ILSpy.BamlDecompiler/Handlers/Records/StaticResourceStartHandler.cs b/ILSpy.BamlDecompiler/Handlers/Records/StaticResourceStartHandler.cs new file mode 100644 index 000000000..ad627f3de --- /dev/null +++ b/ILSpy.BamlDecompiler/Handlers/Records/StaticResourceStartHandler.cs @@ -0,0 +1,52 @@ +// Copyright (c) 2019 Siegfried Pammer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using ILSpy.BamlDecompiler.Baml; +using ILSpy.BamlDecompiler.Xaml; + +namespace ILSpy.BamlDecompiler.Handlers +{ + class StaticResourceStartHandler : IHandler, IDeferHandler + { + public BamlRecordType Type => BamlRecordType.StaticResourceStart; + + public BamlElement Translate(XamlContext ctx, BamlNode node, BamlElement parent) + { + var record = (StaticResourceStartRecord)((BamlBlockNode)node).Record; + var key = XamlResourceKey.FindKeyInSiblings(node); + + key.StaticResources.Add(node); + return null; + } + + public BamlElement TranslateDefer(XamlContext ctx, BamlNode node, BamlElement parent) + { + var record = (StaticResourceStartRecord)((BamlBlockNode)node).Record; + var doc = new BamlElement(node); + var elemType = ctx.ResolveType(record.TypeId); + doc.Xaml = new XElement(elemType.ToXName(ctx)); + doc.Xaml.Element.AddAnnotation(elemType); + parent.Xaml.Element.Add(doc.Xaml.Element); + HandlerMap.ProcessChildren(ctx, (BamlBlockNode)node, doc); + return doc; + } + } +} diff --git a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj index 67d4706f2..87269f706 100644 --- a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj +++ b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj @@ -97,6 +97,8 @@ + + diff --git a/ILSpy.sln b/ILSpy.sln index 21c5ca663..58bdc2b3e 100644 --- a/ILSpy.sln +++ b/ILSpy.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2026 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28803.202 MinimumVisualStudioVersion = 15.0 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}" ProjectSection(SolutionItems) = preProject diff --git a/ILSpy/AboutPage.cs b/ILSpy/AboutPage.cs index 5bd1b40e8..168d75b71 100644 --- a/ILSpy/AboutPage.cs +++ b/ILSpy/AboutPage.cs @@ -33,11 +33,12 @@ using System.Xml.Linq; using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.Decompiler; +using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; namespace ICSharpCode.ILSpy { - [ExportMainMenuCommand(Menu = "_Help", Header = "_About", MenuOrder = 99999)] + [ExportMainMenuCommand(Menu = nameof(Resources._Help), Header = nameof(Resources._About), MenuOrder = 99999)] sealed class AboutPage : SimpleCommand { [Import] @@ -57,7 +58,7 @@ namespace ICSharpCode.ILSpy public static void Display(DecompilerTextView textView) { AvalonEditTextOutput output = new AvalonEditTextOutput(); - output.WriteLine("ILSpy version " + RevisionClass.FullVersion); + output.WriteLine(Resources.ILSpyVersion + RevisionClass.FullVersion); output.AddUIElement( delegate { StackPanel stackPanel = new StackPanel(); @@ -71,7 +72,7 @@ namespace ICSharpCode.ILSpy } CheckBox checkBox = new CheckBox(); checkBox.Margin = new Thickness(4); - checkBox.Content = "Automatically check for updates every week"; + checkBox.Content = Resources.AutomaticallyCheckUpdatesEveryWeek; UpdateSettings settings = new UpdateSettings(ILSpySettings.Load()); checkBox.SetBinding(CheckBox.IsCheckedProperty, new Binding("AutomaticUpdateCheckEnabled") { Source = settings }); return new StackPanel { @@ -118,12 +119,12 @@ namespace ICSharpCode.ILSpy static void AddUpdateCheckButton(StackPanel stackPanel, DecompilerTextView textView) { Button button = new Button(); - button.Content = "Check for updates"; + button.Content = Resources.CheckUpdates; button.Cursor = Cursors.Arrow; stackPanel.Children.Add(button); button.Click += delegate { - button.Content = "Checking..."; + button.Content = Resources.Checking; button.IsEnabled = false; GetLatestVersionAsync().ContinueWith( delegate (Task task) { @@ -152,19 +153,19 @@ namespace ICSharpCode.ILSpy }); stackPanel.Children.Add( new TextBlock { - Text = "You are using the latest release.", + Text = Resources.UsingLatestRelease, VerticalAlignment = VerticalAlignment.Bottom }); } else if (currentVersion < availableVersion.Version) { stackPanel.Children.Add( new TextBlock { - Text = "Version " + availableVersion.Version + " is available.", + Text = string.Format(Resources.VersionAvailable, availableVersion.Version ), Margin = new Thickness(0,0,8,0), VerticalAlignment = VerticalAlignment.Bottom }); if (availableVersion.DownloadUrl != null) { Button button = new Button(); - button.Content = "Download"; + button.Content = Resources.Download; button.Cursor = Cursors.Arrow; button.Click += delegate { MainWindow.OpenLink(availableVersion.DownloadUrl); @@ -172,7 +173,7 @@ namespace ICSharpCode.ILSpy stackPanel.Children.Add(button); } } else { - stackPanel.Children.Add(new TextBlock { Text = "You are using a nightly build newer than the latest release." }); + stackPanel.Children.Add(new TextBlock { Text = Resources.UsingNightlyBuildNewerThanLatestRelease }); } } diff --git a/ILSpy/Analyzers/AnalyzeCommand.cs b/ILSpy/Analyzers/AnalyzeCommand.cs index 05772294d..72117338b 100644 --- a/ILSpy/Analyzers/AnalyzeCommand.cs +++ b/ILSpy/Analyzers/AnalyzeCommand.cs @@ -20,11 +20,12 @@ using System; using System.Linq; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TreeNodes; namespace ICSharpCode.ILSpy.Analyzers { - [ExportContextMenuEntry(Header = "Analyze", Icon = "images/Search.png", Category = "Analyze", InputGestureText = "Ctrl+R", Order = 100)] + [ExportContextMenuEntry(Header = nameof(Resources.Analyze), Icon = "images/Search.png", Category = nameof(Resources.Analyze), InputGestureText = "Ctrl+R", Order = 100)] internal sealed class AnalyzeCommand : SimpleCommand, IContextMenuEntry { public bool IsVisible(TextViewContext context) diff --git a/ILSpy/Analyzers/Builtin/MethodOverriddenByAnalyzer.cs b/ILSpy/Analyzers/Builtin/MethodOverriddenByAnalyzer.cs index 95004dff6..4d65b8f91 100644 --- a/ILSpy/Analyzers/Builtin/MethodOverriddenByAnalyzer.cs +++ b/ILSpy/Analyzers/Builtin/MethodOverriddenByAnalyzer.cs @@ -44,9 +44,9 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin IEnumerable AnalyzeType(IMethod analyzedEntity, ITypeDefinition type) { - if (!analyzedEntity.DeclaringType.GetAllBaseTypeDefinitions() + if (!type.GetAllBaseTypeDefinitions() .Any(t => t.MetadataToken == analyzedEntity.DeclaringTypeDefinition.MetadataToken - && t.ParentModule.PEFile == type.ParentModule.PEFile)) + && t.ParentModule.PEFile == analyzedEntity.ParentModule.PEFile)) yield break; foreach (var method in type.Methods) { diff --git a/ILSpy/App.xaml.cs b/ILSpy/App.xaml.cs index c1f7d649d..088224b3c 100644 --- a/ILSpy/App.xaml.cs +++ b/ILSpy/App.xaml.cs @@ -234,6 +234,7 @@ namespace ICSharpCode.ILSpy } } ILSpy.MainWindow.Instance.TextView.ShowText(output); + e.Handled = true; } } } diff --git a/ILSpy/Commands/BrowseBackCommand.cs b/ILSpy/Commands/BrowseBackCommand.cs index d3a6c9ee2..a79f11855 100644 --- a/ILSpy/Commands/BrowseBackCommand.cs +++ b/ILSpy/Commands/BrowseBackCommand.cs @@ -17,10 +17,11 @@ // DEALINGS IN THE SOFTWARE. using System.Windows.Input; +using ICSharpCode.ILSpy.Properties; namespace ICSharpCode.ILSpy { - [ExportToolbarCommand(ToolTip = "Back", ToolbarIcon = "Images/Back.png", ToolbarCategory = "Navigation", ToolbarOrder = 0)] + [ExportToolbarCommand(ToolTip = nameof(Resources.Back), ToolbarIcon = "Images/Back.png", ToolbarCategory = nameof(Resources.Navigation), ToolbarOrder = 0)] sealed class BrowseBackCommand : CommandWrapper { public BrowseBackCommand() diff --git a/ILSpy/Commands/BrowseForwardCommand.cs b/ILSpy/Commands/BrowseForwardCommand.cs index 47674bc40..583ddede1 100644 --- a/ILSpy/Commands/BrowseForwardCommand.cs +++ b/ILSpy/Commands/BrowseForwardCommand.cs @@ -17,10 +17,11 @@ // DEALINGS IN THE SOFTWARE. using System.Windows.Input; +using ICSharpCode.ILSpy.Properties; namespace ICSharpCode.ILSpy { - [ExportToolbarCommand(ToolTip = "Forward", ToolbarIcon = "Images/Forward.png", ToolbarCategory = "Navigation", ToolbarOrder = 1)] + [ExportToolbarCommand(ToolTip = nameof(Resources.Forward), ToolbarIcon = "Images/Forward.png", ToolbarCategory = nameof(Resources.Navigation), ToolbarOrder = 1)] sealed class BrowseForwardCommand : CommandWrapper { public BrowseForwardCommand() diff --git a/ILSpy/Commands/CheckForUpdatesCommand.cs b/ILSpy/Commands/CheckForUpdatesCommand.cs index 87d0a6e99..179e26b6f 100644 --- a/ILSpy/Commands/CheckForUpdatesCommand.cs +++ b/ILSpy/Commands/CheckForUpdatesCommand.cs @@ -17,9 +17,11 @@ // DEALINGS IN THE SOFTWARE. +using ICSharpCode.ILSpy.Properties; + namespace ICSharpCode.ILSpy { - [ExportMainMenuCommand(Menu = "_Help", Header = "_Check for Updates", MenuOrder = 5000)] + [ExportMainMenuCommand(Menu = nameof(Resources._Help), Header = nameof(Resources._CheckUpdates), MenuOrder = 5000)] sealed class CheckForUpdatesCommand : SimpleCommand { public override void Execute(object parameter) diff --git a/ILSpy/Commands/DecompileAllCommand.cs b/ILSpy/Commands/DecompileAllCommand.cs index e54d88877..9cf8cbc11 100644 --- a/ILSpy/Commands/DecompileAllCommand.cs +++ b/ILSpy/Commands/DecompileAllCommand.cs @@ -23,11 +23,12 @@ using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using ICSharpCode.Decompiler; +using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; namespace ICSharpCode.ILSpy { - [ExportMainMenuCommand(Menu = "_File", Header = "DEBUG -- Decompile All", MenuCategory = "Open", MenuOrder = 2.5)] + [ExportMainMenuCommand(Menu = nameof(Resources._File), Header = nameof(Resources.DEBUGDecompile), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)] sealed class DecompileAllCommand : SimpleCommand { public override bool CanExecute(object parameter) @@ -67,7 +68,7 @@ namespace ICSharpCode.ILSpy } } - [ExportMainMenuCommand(Menu = "_File", Header = "DEBUG -- Decompile 100x", MenuCategory = "Open", MenuOrder = 2.6)] + [ExportMainMenuCommand(Menu = nameof(Resources._File), Header = nameof(Resources.DEBUGDecompile100x), MenuCategory = nameof(Resources.Open), MenuOrder = 2.6)] sealed class Decompile100TimesCommand : SimpleCommand { public override void Execute(object parameter) diff --git a/ILSpy/Commands/DisassembleAllCommand.cs b/ILSpy/Commands/DisassembleAllCommand.cs index 32a7fc997..74af340a1 100644 --- a/ILSpy/Commands/DisassembleAllCommand.cs +++ b/ILSpy/Commands/DisassembleAllCommand.cs @@ -22,10 +22,10 @@ using System; using System.Diagnostics; using System.Threading.Tasks; using ICSharpCode.ILSpy.TextView; - +using ICSharpCode.ILSpy.Properties; namespace ICSharpCode.ILSpy { - [ExportMainMenuCommand(Menu = "_File", Header = "DEBUG -- Disassemble All", MenuCategory = "Open", MenuOrder = 2.5)] + [ExportMainMenuCommand(Menu = nameof(Resources._File), Header = nameof(Resources.DEBUGDisassemble), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)] sealed class DisassembleAllCommand : SimpleCommand { public override bool CanExecute(object parameter) diff --git a/ILSpy/Commands/ExitCommand.cs b/ILSpy/Commands/ExitCommand.cs index f6a215d22..a3be28e72 100644 --- a/ILSpy/Commands/ExitCommand.cs +++ b/ILSpy/Commands/ExitCommand.cs @@ -15,11 +15,11 @@ // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. - +using ICSharpCode.ILSpy.Properties; namespace ICSharpCode.ILSpy { - [ExportMainMenuCommand(Menu = "_File", Header = "E_xit", MenuOrder = 99999, MenuCategory = "Exit")] + [ExportMainMenuCommand(Menu = nameof(Resources._File), Header = nameof(Resources.E_xit), MenuOrder = 99999, MenuCategory = nameof(Resources.Exit))] sealed class ExitCommand : SimpleCommand { public override void Execute(object parameter) diff --git a/ILSpy/Commands/ExportCommandAttribute.cs b/ILSpy/Commands/ExportCommandAttribute.cs index 989131bcb..2c8f3962f 100644 --- a/ILSpy/Commands/ExportCommandAttribute.cs +++ b/ILSpy/Commands/ExportCommandAttribute.cs @@ -30,6 +30,7 @@ namespace ICSharpCode.ILSpy string ToolbarCategory { get; } object Tag { get; } double ToolbarOrder { get; } + } [MetadataAttribute] @@ -58,7 +59,6 @@ namespace ICSharpCode.ILSpy string MenuCategory { get; } string InputGestureText { get; } bool IsEnabled { get; } - double MenuOrder { get; } } diff --git a/ILSpy/Commands/GeneratePdbContextMenuEntry.cs b/ILSpy/Commands/GeneratePdbContextMenuEntry.cs index e2897fa73..a632ee27a 100644 --- a/ILSpy/Commands/GeneratePdbContextMenuEntry.cs +++ b/ILSpy/Commands/GeneratePdbContextMenuEntry.cs @@ -28,7 +28,7 @@ using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; using Microsoft.Win32; - +using ICSharpCode.ILSpy.Properties; namespace ICSharpCode.ILSpy { [ExportContextMenuEntry(Header = "Generate portable PDB")] @@ -87,7 +87,7 @@ namespace ICSharpCode.ILSpy } } - [ExportMainMenuCommand(Menu = "_File", Header = "Generate portable PDB", MenuCategory = "Save")] + [ExportMainMenuCommand(Menu = nameof(Resources._File), Header = nameof(Resources.GeneratePortable), MenuCategory = "Save")] class GeneratePdbMainMenuEntry : SimpleCommand { public override bool CanExecute(object parameter) diff --git a/ILSpy/Commands/OpenCommand.cs b/ILSpy/Commands/OpenCommand.cs index 4fdad2bb9..0f5e86ca9 100644 --- a/ILSpy/Commands/OpenCommand.cs +++ b/ILSpy/Commands/OpenCommand.cs @@ -17,11 +17,12 @@ // DEALINGS IN THE SOFTWARE. using System.Windows.Input; +using ICSharpCode.ILSpy.Properties; namespace ICSharpCode.ILSpy { - [ExportToolbarCommand(ToolTip = "Open", ToolbarIcon = "Images/Open.png", ToolbarCategory = "Open", ToolbarOrder = 0)] - [ExportMainMenuCommand(Menu = "_File", Header = "_Open...", MenuIcon = "Images/Open.png", MenuCategory = "Open", MenuOrder = 0)] + [ExportToolbarCommand(ToolTip = nameof(Resources.Open), ToolbarIcon = "Images/Open.png", ToolbarCategory = nameof(Resources.Open), ToolbarOrder = 0)] + [ExportMainMenuCommand(Menu = nameof(Resources._File), Header = nameof(Resources._Open), MenuIcon = "Images/Open.png", MenuCategory = nameof(Resources.Open), MenuOrder = 0)] sealed class OpenCommand : CommandWrapper { public OpenCommand() diff --git a/ILSpy/Commands/OpenFromGacCommand.cs b/ILSpy/Commands/OpenFromGacCommand.cs index 258a182e3..8f7f008e7 100644 --- a/ILSpy/Commands/OpenFromGacCommand.cs +++ b/ILSpy/Commands/OpenFromGacCommand.cs @@ -16,10 +16,10 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. - +using ICSharpCode.ILSpy.Properties; namespace ICSharpCode.ILSpy { - [ExportMainMenuCommand(Menu = "_File", Header = "Open from _GAC...", MenuIcon = "Images/AssemblyListGAC.png", MenuCategory = "Open", MenuOrder = 1)] + [ExportMainMenuCommand(Menu = nameof(Resources._File), Header = nameof(Resources.OpenFrom_GAC), MenuIcon = "Images/AssemblyListGAC.png", MenuCategory = nameof(Resources.Open), MenuOrder = 1)] sealed class OpenFromGacCommand : SimpleCommand { public override void Execute(object parameter) diff --git a/ILSpy/Commands/OpenListCommand.cs b/ILSpy/Commands/OpenListCommand.cs index b4bb05cac..e5fe22139 100644 --- a/ILSpy/Commands/OpenListCommand.cs +++ b/ILSpy/Commands/OpenListCommand.cs @@ -17,9 +17,11 @@ // DEALINGS IN THE SOFTWARE. +using ICSharpCode.ILSpy.Properties; + namespace ICSharpCode.ILSpy { - [ExportMainMenuCommand(Menu = "_File", Header = "Open _List...", MenuIcon = "Images/AssemblyList.png", MenuCategory = "Open", MenuOrder = 1.7)] + [ExportMainMenuCommand(Menu = nameof(Resources._File), Header = nameof(Resources.Open_List), MenuIcon = "Images/AssemblyList.png", MenuCategory = nameof(Resources.Open), MenuOrder = 1.7)] sealed class OpenListCommand : SimpleCommand { public override void Execute(object parameter) diff --git a/ILSpy/Commands/RefreshCommand.cs b/ILSpy/Commands/RefreshCommand.cs index 6f3312b5f..96e421882 100644 --- a/ILSpy/Commands/RefreshCommand.cs +++ b/ILSpy/Commands/RefreshCommand.cs @@ -17,11 +17,12 @@ // DEALINGS IN THE SOFTWARE. using System.Windows.Input; +using ICSharpCode.ILSpy.Properties; namespace ICSharpCode.ILSpy { - [ExportToolbarCommand(ToolTip = "Reload all assemblies", ToolbarIcon = "Images/Refresh.png", ToolbarCategory = "Open", ToolbarOrder = 2)] - [ExportMainMenuCommand(Menu = "_File", Header = "_Reload", MenuIcon = "Images/Refresh.png", MenuCategory = "Open", MenuOrder = 2)] + [ExportToolbarCommand(ToolTip = nameof(Resources.RefreshCommand_ReloadAssemblies), ToolbarIcon = "Images/Refresh.png", ToolbarCategory = nameof(Resources.Open), ToolbarOrder = 2)] + [ExportMainMenuCommand(Menu = nameof(Resources._File), Header = nameof(Resources._Reload), MenuIcon = "Images/Refresh.png", MenuCategory = nameof(Resources.Open), MenuOrder = 2)] sealed class RefreshCommand : CommandWrapper { public RefreshCommand() diff --git a/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs b/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs index 2570a0a7d..e67515444 100644 --- a/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs +++ b/ILSpy/Commands/RemoveAssembliesWithLoadErrors.cs @@ -19,10 +19,11 @@ using System; using System.Collections.Generic; using System.Linq; +using ICSharpCode.ILSpy.Properties; namespace ICSharpCode.ILSpy { - [ExportMainMenuCommand(Menu = "_File", Header = "_Remove Assemblies with load errors", MenuCategory = "Remove", MenuOrder = 2.6)] + [ExportMainMenuCommand(Menu = nameof(Resources._File), Header = nameof(Resources._RemoveAssembliesWithLoadErrors), MenuCategory = nameof(Resources.Remove), MenuOrder = 2.6)] class RemoveAssembliesWithLoadErrors : SimpleCommand { public override bool CanExecute(object parameter) diff --git a/ILSpy/Commands/SaveCommand.cs b/ILSpy/Commands/SaveCommand.cs index f195fccf8..22da9c57c 100644 --- a/ILSpy/Commands/SaveCommand.cs +++ b/ILSpy/Commands/SaveCommand.cs @@ -17,10 +17,11 @@ // DEALINGS IN THE SOFTWARE. using System.Windows.Input; +using ICSharpCode.ILSpy.Properties; namespace ICSharpCode.ILSpy { - [ExportMainMenuCommand(Menu = "_File", Header = "_Save Code...", MenuIcon = "Images/SaveFile.png", MenuCategory = "Save", MenuOrder = 0)] + [ExportMainMenuCommand(Menu = nameof(Resources._File), Header = nameof(Resources._SaveCode), MenuIcon = "Images/SaveFile.png", MenuCategory = nameof(Resources.Save), MenuOrder = 0)] sealed class SaveCommand : CommandWrapper { public SaveCommand() diff --git a/ILSpy/Commands/ShowDebugSteps.cs b/ILSpy/Commands/ShowDebugSteps.cs index c04c36594..d7b12f155 100644 --- a/ILSpy/Commands/ShowDebugSteps.cs +++ b/ILSpy/Commands/ShowDebugSteps.cs @@ -1,8 +1,10 @@ #if DEBUG +using ICSharpCode.ILSpy.Properties; + namespace ICSharpCode.ILSpy.Commands { - [ExportMainMenuCommand(Menu = "_View", Header = "_Show debug steps", MenuOrder = 5000)] + [ExportMainMenuCommand(Menu = nameof(Resources._View), Header = nameof(Resources._ShowDebugSteps), MenuOrder = 5000)] class ShowDebugSteps : SimpleCommand { public override void Execute(object parameter) diff --git a/ILSpy/Commands/SortAssemblyListCommand.cs b/ILSpy/Commands/SortAssemblyListCommand.cs index a161d373b..b205cc03a 100644 --- a/ILSpy/Commands/SortAssemblyListCommand.cs +++ b/ILSpy/Commands/SortAssemblyListCommand.cs @@ -18,12 +18,13 @@ using System; using System.Collections.Generic; +using ICSharpCode.ILSpy.Properties; using ICSharpCode.TreeView; namespace ICSharpCode.ILSpy { - [ExportMainMenuCommand(Menu = "_View", Header = "Sort assembly _list by name", MenuIcon = "Images/Sort.png", MenuCategory = "View")] - [ExportToolbarCommand(ToolTip = "Sort assembly list by name", ToolbarIcon = "Images/Sort.png", ToolbarCategory = "View")] + [ExportMainMenuCommand(Menu = nameof(Resources._View), Header = nameof(Resources.SortAssembly_listName), MenuIcon = "Images/Sort.png", MenuCategory = nameof(Resources.View))] + [ExportToolbarCommand(ToolTip = nameof(Resources.SortAssemblyListName), ToolbarIcon = "Images/Sort.png", ToolbarCategory = nameof(Resources.View))] sealed class SortAssemblyListCommand : SimpleCommand, IComparer { public override void Execute(object parameter) @@ -38,8 +39,8 @@ namespace ICSharpCode.ILSpy } } - [ExportMainMenuCommand(Menu = "_View", Header = "_Collapse all tree nodes", MenuIcon = "Images/CollapseAll.png", MenuCategory = "View")] - [ExportToolbarCommand(ToolTip = "Collapse all tree nodes", ToolbarIcon = "Images/CollapseAll.png", ToolbarCategory = "View")] + [ExportMainMenuCommand(Menu = nameof(Resources._View), Header = nameof(Resources._CollapseTreeNodes), MenuIcon = "Images/CollapseAll.png", MenuCategory = nameof(Resources.View))] + [ExportToolbarCommand(ToolTip = nameof(Resources.CollapseTreeNodes), ToolbarIcon = "Images/CollapseAll.png", ToolbarCategory = nameof(Resources.View))] sealed class CollapseAllCommand : SimpleCommand { public override void Execute(object parameter) diff --git a/ILSpy/ContextMenuEntry.cs b/ILSpy/ContextMenuEntry.cs index 0bde81f81..f2a94ae09 100644 --- a/ILSpy/ContextMenuEntry.cs +++ b/ILSpy/ContextMenuEntry.cs @@ -219,7 +219,7 @@ namespace ICSharpCode.ILSpy needSeparatorForCategory = false; } MenuItem menuItem = new MenuItem(); - menuItem.Header = entryPair.Metadata.Header; + menuItem.Header = MainWindow.GetResourceString( entryPair.Metadata.Header); menuItem.InputGestureText = entryPair.Metadata.InputGestureText; if (!string.IsNullOrEmpty(entryPair.Metadata.Icon)) { menuItem.Icon = new Image { diff --git a/ILSpy/Controls/ResourceObjectTable.xaml b/ILSpy/Controls/ResourceObjectTable.xaml index f994c2aaa..d7258815e 100644 --- a/ILSpy/Controls/ResourceObjectTable.xaml +++ b/ILSpy/Controls/ResourceObjectTable.xaml @@ -2,6 +2,7 @@ @@ -27,7 +28,7 @@ -