Browse Source

Merge branch 'master' of https://github.com/icsharpcode/ILSpy into local-functions

pull/1586/head
Siegfried Pammer 6 years ago
parent
commit
8bfd17404b
  1. 2
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 28
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.cs
  3. 2
      ICSharpCode.Decompiler/CSharp/OutputVisitor/FormattingOptionsFactory.cs
  4. 2
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs
  5. 4
      ICSharpCode.Decompiler/CSharp/Resolver/MethodGroupResolveResult.cs
  6. 1
      ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs
  7. 42
      ICSharpCode.Decompiler/CSharp/Resolver/RenameCallbackArguments.cs
  8. 6
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AssignmentExpression.cs
  9. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/UnaryOperatorExpression.cs
  10. 2
      ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/ExternAliasDeclaration.cs
  11. 4
      ICSharpCode.Decompiler/CSharp/Syntax/TextLocation.cs
  12. 7
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  13. 2
      ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs
  14. 1
      ICSharpCode.Decompiler/IL/ControlFlow/LoopDetection.cs
  15. 2
      ICSharpCode.Decompiler/IL/ControlFlow/SwitchDetection.cs
  16. 2
      ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs
  17. 14
      ICSharpCode.Decompiler/IL/Instructions.cs
  18. 12
      ICSharpCode.Decompiler/IL/Instructions.tt
  19. 2
      ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
  20. 10
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  21. 10
      ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
  22. 2
      ICSharpCode.Decompiler/IL/Transforms/Stepper.cs
  23. 84
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
  24. 10
      ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs
  25. 4
      ICSharpCode.Decompiler/TypeSystem/IParameter.cs
  26. 4
      ICSharpCode.Decompiler/TypeSystem/ITypeParameter.cs
  27. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/ThreeState.cs
  28. 7
      ICSharpCode.Decompiler/TypeSystem/TypeKind.cs
  29. 8
      ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

2
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<NoWarn>1701;1702;1705,67,169,1058,728,1720,649,168,251</NoWarn>
<NoWarn>1701;1702;1705,67,169,1058,728,1720,649,168,251,660,661,675</NoWarn>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>

28
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.cs

@ -4577,12 +4577,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -4577,12 +4577,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
new CustomClass().StringProp += 1;
}
#if false
public uint PreIncrementIndexer(string name)
{
return ++M()[name];
}
#endif
public int PreIncrementByRef(ref int i)
{
return ++i;
@ -4593,6 +4592,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -4593,6 +4592,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return ++(*GetPointer());
}
public unsafe int PreIncrementOfPointer(int* ptr)
{
return *(++ptr);
}
public int PreIncrement2DArray()
{
return ++Array()[1, 2];
@ -4627,12 +4631,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -4627,12 +4631,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
return array[Environment.TickCount] *= 10;
}
#if false
public uint CompoundAssignIndexer(string name)
{
return M()[name] -= 2;
return M()[name] -= 2u;
}
#endif
public uint CompoundAssignIndexerComplexIndex(string name)
{
return M()[ToString()] -= 2u;
}
public int CompoundAssignIncrement2DArray()
{
return Array()[1, 2] %= 10;
@ -4643,6 +4652,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -4643,6 +4652,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return i <<= 2;
}
public unsafe int* CompoundAssignOfPointer(int* ptr)
{
return ptr += 10;
}
public unsafe double CompoundAssignByPointer(double* ptr)
{
return *ptr /= 1.5;
@ -4669,17 +4683,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -4669,17 +4683,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
return array[pos]--;
}
#if false
public uint PostIncrementIndexer(string name)
{
return M()[name]++;
}
#if false
public unsafe int PostIncrementOfPointer(int* ptr)
{
return *(ptr++);
}
#endif
public int PostDecrementInstanceField()
{
return M().Field--;

2
ICSharpCode.Decompiler/CSharp/OutputVisitor/FormattingOptionsFactory.cs

@ -209,7 +209,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -209,7 +209,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
}
/// <summary>
/// The K&R style, so named because it was used in Kernighan and Ritchie's book The C Programming Language,
/// The K&amp;R style, so named because it was used in Kernighan and Ritchie's book The C Programming Language,
/// is commonly used in C. It is less common for C++, C#, and others.
/// </summary>
public static CSharpFormattingOptions CreateKRStyle()

2
ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs

@ -647,7 +647,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -647,7 +647,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
{
TypeKind kind = type.Kind;
return kind == TypeKind.Class && type.GetDefinition().IsSealed
|| kind == TypeKind.Delegate || kind == TypeKind.Anonymous;
|| kind == TypeKind.Delegate;
}
#endregion

4
ICSharpCode.Decompiler/CSharp/Resolver/MethodGroupResolveResult.cs

@ -174,12 +174,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -174,12 +174,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
return extensionMethods ?? Enumerable.Empty<IEnumerable<IMethod>>();
}
/// <summary>
/// Gets the eligible extension methods.
/// </summary>
/// <param name="substituteInferredTypes">
/// Specifies whether to produce a <see cref="SpecializedMethod"/>
/// Specifies whether to produce a <c>SpecializedMethod</c>
/// when type arguments could be inferred from <see cref="TargetType"/>.
/// This setting is only used for inferred types and has no effect if the type parameters are
/// specified explicitly.

1
ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs

@ -940,6 +940,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -940,6 +940,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// <param name="initializerStatements">
/// Statements for Objects/Collections initializer.
/// <see cref="InvocationResolveResult.InitializerStatements"/>
/// </param>
/// <param name="returnTypeOverride">
/// If not null, use this instead of the ReturnType of the member as the type of the created resolve result.
/// </param>

42
ICSharpCode.Decompiler/CSharp/Resolver/RenameCallbackArguments.cs

@ -1,42 +0,0 @@ @@ -1,42 +0,0 @@
// Copyright (c) 2010-2014 AlphaSierraPapa for the SharpDevelop Team
//
// 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 ICSharpCode.Decompiler.CSharp.Syntax;
namespace ICSharpCode.Decompiler.CSharp.Resolver
{
/// <summary>
/// Arguments for the callback of <see cref="FindReferences.RenameReferencesInFile"/>.
/// </summary>
public class RenameCallbackArguments
{
public AstNode NodeToReplace { get; private set; }
public AstNode NewNode { get; private set; }
public RenameCallbackArguments(AstNode nodeToReplace, AstNode newNode)
{
if (nodeToReplace == null)
throw new ArgumentNullException("nodeToReplace");
if (newNode == null)
throw new ArgumentNullException("newNode");
this.NodeToReplace = nodeToReplace;
this.NewNode = newNode;
}
}
}

6
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AssignmentExpression.cs

@ -250,13 +250,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -250,13 +250,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
Divide,
/// <summary>left %= right</summary>
Modulus,
/// <summary>left <<= right</summary>
/// <summary>left &lt;&lt;= right</summary>
ShiftLeft,
/// <summary>left >>= right</summary>
ShiftRight,
/// <summary>left &= right</summary>
/// <summary>left &amp;= right</summary>
BitwiseAnd,
/// <summary>left |= right</summary>
BitwiseOr,

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/UnaryOperatorExpression.cs

@ -182,7 +182,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -182,7 +182,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
PostDecrement,
/// <summary>Dereferencing (*a)</summary>
Dereference,
/// <summary>Get address (&a)</summary>
/// <summary>Get address (&amp;a)</summary>
AddressOf,
/// <summary>C# 5.0 await</summary>
Await,

2
ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/ExternAliasDeclaration.cs

@ -28,7 +28,7 @@ @@ -28,7 +28,7 @@
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
/// extern alias <Identifier>;
/// extern alias IDENTIFIER;
/// </summary>
public class ExternAliasDeclaration : AstNode
{

4
ICSharpCode.Decompiler/CSharp/Syntax/TextLocation.cs

@ -26,10 +26,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -26,10 +26,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// A line/column position.
/// Text editor lines/columns are counted started from one.
/// </summary>
/// <remarks>
/// The document provides the methods <see cref="IDocument.GetLocation"/> and
/// <see cref="IDocument.GetOffset(ICSharpCode.Decompiler.CSharp.Syntax.TextLocation)"/> to convert between offsets and TextLocations.
/// </remarks>
[Serializable]
[TypeConverter(typeof(TextLocationConverter))]
public struct TextLocation : IComparable<TextLocation>, IEquatable<TextLocation>

7
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
<EnableDefaultItems>false</EnableDefaultItems>
<LangVersion>7.2</LangVersion>
<DocumentationFile>$(TargetDir)ICSharpCode.Decompiler.xml</DocumentationFile>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>ICSharpCode.Decompiler.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
@ -48,6 +48,10 @@ @@ -48,6 +48,10 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;1591;1573</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.2.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
@ -224,7 +228,6 @@ @@ -224,7 +228,6 @@
<Compile Include="CSharp\Resolver\OverloadResolution.cs" />
<Compile Include="CSharp\Resolver\OverloadResolutionErrors.cs" />
<Compile Include="TypeSystem\Implementation\LocalFunctionMethod.cs" />
<Compile Include="CSharp\Resolver\RenameCallbackArguments.cs" />
<Compile Include="CSharp\Resolver\TypeInference.cs" />
<Compile Include="CSharp\Transforms\CombineQueryExpressions.cs" />
<Compile Include="CSharp\Transforms\FlattenSwitchBlocks.cs" />

2
ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs

@ -403,7 +403,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -403,7 +403,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
/// <summary>
/// if (cond) { if (nestedCond) { nestedThen... } }
/// ->
/// if (cond && nestedCond) { nestedThen... }
/// if (cond &amp;&amp; nestedCond) { nestedThen... }
/// </summary>
private void IntroduceShortCircuit(IfInstruction ifInst)
{

1
ICSharpCode.Decompiler/IL/ControlFlow/LoopDetection.cs

@ -458,7 +458,6 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -458,7 +458,6 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
/// or that leave the block Container.
/// </summary>
/// <param name="loopHead">Entry point of the loop.</param>
/// <param name="isSwitch">Whether to ignore branches that map to C# 'continue' statements.</param>
/// <param name="exitNodeArity">out: The number of different CFG nodes.
/// Possible values:
/// 0 = no CFG nodes used as exit nodes (although edges leaving the block container might still be exits);

2
ICSharpCode.Decompiler/IL/ControlFlow/SwitchDetection.cs

@ -441,7 +441,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -441,7 +441,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
/// s c
///
/// where:
/// p|n: if (a && b) goto c; goto s;
/// p|n: if (a &amp;&amp; b) goto c; goto s;
///
/// Note that if n has only 1 successor, but is still a flow node, then a short circuit expression
/// has a target (c) with no corresponding block (leave)

2
ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs

@ -70,7 +70,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -70,7 +70,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
/// <remarks>Set in AnalyzeCurrentProperty()</remarks>
IField currentField;
/// <summary>The disposing field of the compiler-generated enumerator class./summary>
/// <summary>The disposing field of the compiler-generated enumerator class.</summary>
/// <remarks>Set in ConstructExceptionTable() for assembly compiled with Mono</remarks>
IField disposingField;

14
ICSharpCode.Decompiler/IL/Instructions.cs

@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler.IL @@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler.IL
/// In case 3 (managed reference), the dereferenced value is the input being tested, and the nullable.unwrap instruction returns the managed reference unmodified (if the value is non-null).</summary>
NullableUnwrap,
/// <summary>Serves as jump target for the nullable.unwrap instruction.
/// If the input evaluates normally, evaluates to the input value (wrapped in Nullable<T> if the input is a non-nullable value type).If a nullable.unwrap instruction encounters a null input and jumps to the (endpoint of the) nullable.rewrap instruction,the nullable.rewrap instruction evaluates to null.</summary>
/// If the input evaluates normally, evaluates to the input value (wrapped in Nullable&lt;T&gt; if the input is a non-nullable value type).If a nullable.unwrap instruction encounters a null input and jumps to the (endpoint of the) nullable.rewrap instruction,the nullable.rewrap instruction evaluates to null.</summary>
NullableRewrap,
/// <summary>Loads a constant string.</summary>
LdStr,
@ -189,7 +189,7 @@ namespace ICSharpCode.Decompiler.IL @@ -189,7 +189,7 @@ namespace ICSharpCode.Decompiler.IL
StringToInt,
/// <summary>ILAst representation of Expression.Convert.</summary>
ExpressionTreeCast,
/// <summary>Use of user-defined && or || operator.</summary>
/// <summary>Use of user-defined &amp;&amp; or || operator.</summary>
UserDefinedLogicOperator,
/// <summary>ILAst representation of a short-circuiting binary operator inside a dynamic expression.</summary>
DynamicLogicOperatorInstruction,
@ -1063,7 +1063,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1063,7 +1063,7 @@ namespace ICSharpCode.Decompiler.IL
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as NumericCompoundAssign;
return o != null && type.Equals(o.type) && CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator && Target.PerformMatch(o.Target, ref match) && Value.PerformMatch(o.Value, ref match);
return o != null && type.Equals(o.type) && CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator && this.EvalMode == o.EvalMode && this.TargetKind == o.TargetKind && Target.PerformMatch(o.Target, ref match) && Value.PerformMatch(o.Value, ref match);
}
}
}
@ -1097,7 +1097,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1097,7 +1097,7 @@ namespace ICSharpCode.Decompiler.IL
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as UserDefinedCompoundAssign;
return o != null && this.Method.Equals(o.Method) && this.EvalMode == o.EvalMode && Target.PerformMatch(o.Target, ref match) && Value.PerformMatch(o.Value, ref match);
return o != null && this.Method.Equals(o.Method) && this.EvalMode == o.EvalMode && this.TargetKind == o.TargetKind && Target.PerformMatch(o.Target, ref match) && Value.PerformMatch(o.Value, ref match);
}
}
}
@ -1131,7 +1131,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1131,7 +1131,7 @@ namespace ICSharpCode.Decompiler.IL
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as DynamicCompoundAssign;
return o != null && this.EvalMode == o.EvalMode && Target.PerformMatch(o.Target, ref match) && Value.PerformMatch(o.Value, ref match);
return o != null && this.EvalMode == o.EvalMode && this.TargetKind == o.TargetKind && Target.PerformMatch(o.Target, ref match) && Value.PerformMatch(o.Value, ref match);
}
}
}
@ -2714,7 +2714,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2714,7 +2714,7 @@ namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Serves as jump target for the nullable.unwrap instruction.
/// If the input evaluates normally, evaluates to the input value (wrapped in Nullable<T> if the input is a non-nullable value type).If a nullable.unwrap instruction encounters a null input and jumps to the (endpoint of the) nullable.rewrap instruction,the nullable.rewrap instruction evaluates to null.</summary>
/// If the input evaluates normally, evaluates to the input value (wrapped in Nullable&lt;T&gt; if the input is a non-nullable value type).If a nullable.unwrap instruction encounters a null input and jumps to the (endpoint of the) nullable.rewrap instruction,the nullable.rewrap instruction evaluates to null.</summary>
public sealed partial class NullableRewrap : UnaryInstruction
{
public NullableRewrap(ILInstruction argument) : base(OpCode.NullableRewrap, argument)
@ -4910,7 +4910,7 @@ namespace ICSharpCode.Decompiler.IL @@ -4910,7 +4910,7 @@ namespace ICSharpCode.Decompiler.IL
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Use of user-defined && or || operator.</summary>
/// <summary>Use of user-defined &amp;&amp; or || operator.</summary>
public sealed partial class UserDefinedLogicOperator : ILInstruction, IInstructionWithMethodOperand
{
public UserDefinedLogicOperator(IMethod method, ILInstruction left, ILInstruction right) : base(OpCode.UserDefinedLogicOperator)

12
ICSharpCode.Decompiler/IL/Instructions.tt

@ -75,19 +75,23 @@ @@ -75,19 +75,23 @@
CustomClassName("NumericCompoundAssign"), BaseClass("CompoundAssignmentInstruction"), CustomConstructor, CustomComputeFlags,
MayThrow, HasTypeOperand, ResultType("type.GetStackType()"), CustomWriteTo,
MatchCondition("CheckForOverflow == o.CheckForOverflow && Sign == o.Sign && Operator == o.Operator"),
MatchCondition("this.EvalMode == o.EvalMode"),
MatchCondition("this.TargetKind == o.TargetKind"),
MatchCondition("Target.PerformMatch(o.Target, ref match)"),
MatchCondition("Value.PerformMatch(o.Value, ref match)")),
new OpCode("user.compound", "Common instruction for user-defined compound assignments.",
CustomClassName("UserDefinedCompoundAssign"), BaseClass("CompoundAssignmentInstruction"), CustomConstructor,
MayThrow, SideEffect, CustomWriteTo,
MatchCondition("this.Method.Equals(o.Method)"),
MatchCondition("this.CompoundAssignmentType == o.CompoundAssignmentType"),
MatchCondition("this.EvalMode == o.EvalMode"),
MatchCondition("this.TargetKind == o.TargetKind"),
MatchCondition("Target.PerformMatch(o.Target, ref match)"),
MatchCondition("Value.PerformMatch(o.Value, ref match)")),
new OpCode("dynamic.compound", "Common instruction for dynamic compound assignments.",
CustomClassName("DynamicCompoundAssign"), BaseClass("CompoundAssignmentInstruction"),
MayThrow, SideEffect, CustomWriteTo, CustomConstructor, ResultType("O"),
MatchCondition("this.CompoundAssignmentType == o.CompoundAssignmentType"),
MatchCondition("this.EvalMode == o.EvalMode"),
MatchCondition("this.TargetKind == o.TargetKind"),
MatchCondition("Target.PerformMatch(o.Target, ref match)"),
MatchCondition("Value.PerformMatch(o.Value, ref match)")),
new OpCode("bit.not", "Bitwise NOT", Unary, CustomConstructor, MatchCondition("IsLifted == o.IsLifted && UnderlyingResultType == o.UnderlyingResultType")),
@ -190,7 +194,7 @@ @@ -190,7 +194,7 @@
+ "returns the managed reference unmodified (if the value is non-null).",
Unary, CustomConstructor, CustomWriteTo, HasFlag("InstructionFlags.MayUnwrapNull")),
new OpCode("nullable.rewrap", "Serves as jump target for the nullable.unwrap instruction." + Environment.NewLine
+ "If the input evaluates normally, evaluates to the input value (wrapped in Nullable<T> if the input is a non-nullable value type)."
+ "If the input evaluates normally, evaluates to the input value (wrapped in Nullable&lt;T&gt; if the input is a non-nullable value type)."
+ "If a nullable.unwrap instruction encounters a null input and jumps to the (endpoint of the) nullable.rewrap instruction,"
+ "the nullable.rewrap instruction evaluates to null.",
Unary, CustomComputeFlags),
@ -282,7 +286,7 @@ @@ -282,7 +286,7 @@
CustomClassName("ExpressionTreeCast"), Unary, HasTypeOperand, MayThrow, CustomConstructor, CustomWriteTo, ResultType("type.GetStackType()"),
MatchCondition("this.IsChecked == o.IsChecked")),
new OpCode("user.logic.operator", "Use of user-defined && or || operator.",
new OpCode("user.logic.operator", "Use of user-defined &amp;&amp; or || operator.",
CustomClassName("UserDefinedLogicOperator"),
HasMethodOperand, ResultType("O"),
CustomChildren(new []{

2
ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs

@ -30,7 +30,7 @@ namespace ICSharpCode.Decompiler.IL @@ -30,7 +30,7 @@ namespace ICSharpCode.Decompiler.IL
///
/// IfInstruction is also used to represent logical operators:
/// "a || b" ==> if (a) (ldc.i4 1) else (b)
/// "a && b" ==> if (a) (b) else (ldc.i4 0)
/// "a &amp;&amp; b" ==> if (a) (b) else (ldc.i4 0)
/// "a ? b : c" ==> if (a) (b) else (c)
/// </remarks>
partial class IfInstruction : ILInstruction

10
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -373,7 +373,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -373,7 +373,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Determines whether a variable should be inlined in non-aggressive mode, even though it is not a generated variable.
/// </summary>
/// <param name="next">The next top-level expression</param>
/// <param name="loadInst">The load within 'next'</param>
/// <param name="v">The variable being eliminated by inlining.</param>
/// <param name="inlinedExpression">The expression being inlined</param>
static bool NonAggressiveInlineInto(ILInstruction next, FindResult findResult, ILInstruction inlinedExpression, ILVariable v)
{
@ -432,6 +432,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -432,6 +432,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
case OpCode.ArrayToPointer:
case OpCode.LocAllocSpan:
return true; // inline size-expressions into localloc.span
case OpCode.Call:
case OpCode.CallVirt:
// Aggressive inline into property/indexer getter calls for compound assignment calls
// (The compiler generates locals for these because it doesn't want to evalute the args twice for getter+setter)
if (parent.SlotInfo == CompoundAssignmentInstruction.TargetSlot) {
return true;
}
break;
}
// decide based on the top-level target instruction into which we are inlining:
switch (next.OpCode) {

10
ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs

@ -66,10 +66,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -66,10 +66,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// <summary>
/// VS2017.8 / Roslyn 2.9 started optimizing some cases of
/// "a.GetValueOrDefault() == b.GetValueOrDefault() && (a.HasValue & b.HasValue)"
/// "a.GetValueOrDefault() == b.GetValueOrDefault() &amp;&amp; (a.HasValue &amp; b.HasValue)"
/// to
/// "(a.GetValueOrDefault() == b.GetValueOrDefault()) & (a.HasValue & b.HasValue)"
/// so this secondary entry point analyses logic.and as-if it was a short-circuting &&.
/// "(a.GetValueOrDefault() == b.GetValueOrDefault()) &amp; (a.HasValue &amp; b.HasValue)"
/// so this secondary entry point analyses logic.and as-if it was a short-circuting &amp;&amp;.
/// </summary>
public bool Run(BinaryNumericInstruction bni)
{
@ -85,7 +85,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -85,7 +85,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
public bool RunStatements(Block block, int pos)
{
/// e.g.:
// e.g.:
// if (!condition) Block {
// leave IL_0000 (default.value System.Nullable`1[[System.Int64]])
// }
@ -541,7 +541,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -541,7 +541,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Performs nullable lifting.
///
/// Produces a lifted instruction with semantics equivalent to:
/// (v1 != null && ... && vn != null) ? trueInst : falseInst,
/// (v1 != null &amp;&amp; ... &amp;&amp; vn != null) ? trueInst : falseInst,
/// where the v1,...,vn are the <c>this.nullableVars</c>.
/// If lifting fails, returns <c>null</c>.
/// </summary>

2
ICSharpCode.Decompiler/IL/Transforms/Stepper.cs

@ -25,7 +25,7 @@ using ICSharpCode.Decompiler.Util; @@ -25,7 +25,7 @@ using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL.Transforms
{
/// <summary>
/// Exception thrown when an IL transform runs into the <see cref="Stepper.MaxStepCount"/> limit.
/// Exception thrown when an IL transform runs into the <see cref="Stepper.StepLimit"/>.
/// </summary>
public class StepLimitReachedException : Exception
{

84
ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

@ -174,10 +174,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -174,10 +174,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// because the ExpressionTransforms don't look into inline blocks, manually trigger HandleCallCompoundAssign
if (HandleCompoundAssign(call, context)) {
// if we did construct a compound assignment, it should have made our inline block redundant:
if (inlineBlock.Instructions.Single().MatchStLoc(newVar, out var compoundAssign)) {
Debug.Assert(newVar.IsSingleDefinition && newVar.LoadCount == 1);
inlineBlock.ReplaceWith(compoundAssign);
}
Debug.Assert(!inlineBlock.IsConnected);
}
return true;
} else {
@ -205,8 +202,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -205,8 +202,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
}
static bool MatchingGetterAndSetterCalls(CallInstruction getterCall, CallInstruction setterCall)
static bool MatchingGetterAndSetterCalls(CallInstruction getterCall, CallInstruction setterCall, out Action<ILTransformContext> finalizeMatch)
{
finalizeMatch = null;
if (getterCall == null || setterCall == null || !IsSameMember(getterCall.Method.AccessorOwner, setterCall.Method.AccessorOwner))
return false;
if (setterCall.OpCode != getterCall.OpCode)
@ -218,12 +216,33 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -218,12 +216,33 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
// Ensure that same arguments are passed to getterCall and setterCall:
for (int j = 0; j < getterCall.Arguments.Count; j++) {
if (setterCall.Arguments[j].MatchStLoc(out var v) && v.IsSingleDefinition && v.LoadCount == 1) {
if (getterCall.Arguments[j].MatchLdLoc(v)) {
// OK, setter call argument is saved in temporary that is re-used for getter call
if (finalizeMatch == null) {
finalizeMatch = AdjustArguments;
}
continue;
}
}
if (!SemanticHelper.IsPure(getterCall.Arguments[j].Flags))
return false;
if (!getterCall.Arguments[j].Match(setterCall.Arguments[j]).Success)
return false;
}
return true;
void AdjustArguments(ILTransformContext context)
{
Debug.Assert(setterCall.Arguments.Count == getterCall.Arguments.Count + 1);
for (int j = 0; j < getterCall.Arguments.Count; j++) {
if (setterCall.Arguments[j].MatchStLoc(out var v, out var value)) {
Debug.Assert(v.IsSingleDefinition && v.LoadCount == 1);
Debug.Assert(getterCall.Arguments[j].MatchLdLoc(v));
getterCall.Arguments[j] = value;
}
}
}
}
/// <summary>
@ -275,18 +294,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -275,18 +294,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
ILInstruction newInst;
if (UnwrapSmallIntegerConv(setterValue, out var smallIntConv) is BinaryNumericInstruction binary) {
if (!IsMatchingCompoundLoad(binary.Left, compoundStore, out var target, out var targetKind, forbiddenVariable: storeInSetter?.Variable))
if (!IsMatchingCompoundLoad(binary.Left, compoundStore, out var target, out var targetKind, out var finalizeMatch, forbiddenVariable: storeInSetter?.Variable))
return false;
if (!ValidateCompoundAssign(binary, smallIntConv, targetType))
return false;
context.Step($"Compound assignment (binary.numeric)", compoundStore);
finalizeMatch?.Invoke(context);
newInst = new NumericCompoundAssign(
binary, target, targetKind, binary.Right,
targetType, CompoundEvalMode.EvaluatesToNewValue);
} else if (setterValue is Call operatorCall && operatorCall.Method.IsOperator) {
if (operatorCall.Arguments.Count == 0)
return false;
if (!IsMatchingCompoundLoad(operatorCall.Arguments[0], compoundStore, out var target, out var targetKind, forbiddenVariable: storeInSetter?.Variable))
if (!IsMatchingCompoundLoad(operatorCall.Arguments[0], compoundStore, out var target, out var targetKind, out var finalizeMatch, forbiddenVariable: storeInSetter?.Variable))
return false;
ILInstruction rhs;
if (operatorCall.Arguments.Count == 2) {
@ -304,12 +324,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -304,12 +324,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (operatorCall.IsLifted)
return false; // TODO: add tests and think about whether nullables need special considerations
context.Step($"Compound assignment (user-defined binary)", compoundStore);
finalizeMatch?.Invoke(context);
newInst = new UserDefinedCompoundAssign(operatorCall.Method, CompoundEvalMode.EvaluatesToNewValue,
target, targetKind, rhs);
} else if (setterValue is DynamicBinaryOperatorInstruction dynamicBinaryOp) {
if (!IsMatchingCompoundLoad(dynamicBinaryOp.Left, compoundStore, out var target, out var targetKind, forbiddenVariable: storeInSetter?.Variable))
if (!IsMatchingCompoundLoad(dynamicBinaryOp.Left, compoundStore, out var target, out var targetKind, out var finalizeMatch, forbiddenVariable: storeInSetter?.Variable))
return false;
context.Step($"Compound assignment (dynamic binary)", compoundStore);
finalizeMatch?.Invoke(context);
newInst = new DynamicCompoundAssign(dynamicBinaryOp.Operation, dynamicBinaryOp.BinderFlags, target, dynamicBinaryOp.LeftArgumentInfo, dynamicBinaryOp.Right, dynamicBinaryOp.RightArgumentInfo, targetKind);
} else if (setterValue is Call concatCall && UserDefinedCompoundAssign.IsStringConcat(concatCall.Method)) {
// setterValue is a string.Concat() invocation
@ -317,9 +339,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -317,9 +339,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; // for now we only support binary compound assignments
if (!targetType.IsKnownType(KnownTypeCode.String))
return false;
if (!IsMatchingCompoundLoad(concatCall.Arguments[0], compoundStore, out var target, out var targetKind, forbiddenVariable: storeInSetter?.Variable))
if (!IsMatchingCompoundLoad(concatCall.Arguments[0], compoundStore, out var target, out var targetKind, out var finalizeMatch, forbiddenVariable: storeInSetter?.Variable))
return false;
context.Step($"Compound assignment (string concatenation)", compoundStore);
finalizeMatch?.Invoke(context);
newInst = new UserDefinedCompoundAssign(concatCall.Method, CompoundEvalMode.EvaluatesToNewValue,
target, targetKind, concatCall.Arguments[1]);
} else {
@ -332,6 +355,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -332,6 +355,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.RequestRerun(); // moving stloc to top-level might trigger inlining
}
compoundStore.ReplaceWith(newInst);
if (newInst.Parent is Block inlineAssignBlock && inlineAssignBlock.Kind == BlockKind.CallInlineAssign) {
// It's possible that we first replaced the instruction in an inline-assign helper block.
// In such a situation, we know from the block invariant that we're have a storeInSetter.
Debug.Assert(storeInSetter != null);
Debug.Assert(storeInSetter.Variable.IsSingleDefinition && storeInSetter.Variable.LoadCount == 1);
Debug.Assert(inlineAssignBlock.Instructions.Single() == storeInSetter);
Debug.Assert(inlineAssignBlock.FinalInstruction.MatchLdLoc(storeInSetter.Variable));
// Block CallInlineAssign { stloc I_0(compound.op(...)); final: ldloc I_0 }
// --> compound.op(...)
inlineAssignBlock.ReplaceWith(storeInSetter.Value);
}
return true;
}
@ -468,6 +502,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -468,6 +502,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
}
foreach (var arg in call.Arguments.SkipLast(1)) {
if (arg.MatchStLoc(out var v) && v.IsSingleDefinition && v.LoadCount == 1) {
continue; // OK, IsMatchingCompoundLoad can perform an adjustment in this special case
}
if (!SemanticHelper.IsPure(arg.Flags)) {
return false;
}
@ -484,13 +521,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -484,13 +521,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
/// <summary>
/// Checks whether 'load' and 'store' both access the same store, and can be combined to a compound assignment.
/// </summary>
/// <param name="load">The load instruction to test.</param>
/// <param name="store">The compound store to test against. Must have previously been tested via IsCompoundStore()</param>
/// <param name="target">The target to use for the compound assignment instruction.</param>
/// <param name="targetKind">The target kind to use for the compound assignment instruction.</param>
/// <param name="finalizeMatch">If set to a non-null value, call this delegate to fix up minor mismatches between getter and setter.</param>
/// <param name="forbiddenVariable">
/// If given a non-null value, this function returns false if the forbiddenVariable is used in the load/store instructions.
/// Some transforms effectively move a store around,
/// which is only valid if the variable stored to does not occur in the compound load/store.
/// </param>
static bool IsMatchingCompoundLoad(ILInstruction load, ILInstruction store,
out ILInstruction target, out CompoundTargetKind targetKind,
ILFunction contextFunction = null,
out Action<ILTransformContext> finalizeMatch,
ILVariable forbiddenVariable = null)
{
target = null;
targetKind = 0;
finalizeMatch = null;
if (load is LdObj ldobj && store is StObj stobj) {
Debug.Assert(SemanticHelper.IsPure(stobj.Target.Flags));
if (!SemanticHelper.IsPure(ldobj.Target.Flags))
@ -500,7 +551,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -500,7 +551,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
target = ldobj.Target;
targetKind = CompoundTargetKind.Address;
return ldobj.Target.Match(stobj.Target).Success;
} else if (MatchingGetterAndSetterCalls(load as CallInstruction, store as CallInstruction)) {
} else if (MatchingGetterAndSetterCalls(load as CallInstruction, store as CallInstruction, out finalizeMatch)) {
if (forbiddenVariable != null && forbiddenVariable.IsUsedWithin(load))
return false;
target = load;
@ -509,11 +560,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -509,11 +560,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} else if (load is LdLoc ldloc && store is StLoc stloc && ILVariableEqualityComparer.Instance.Equals(ldloc.Variable, stloc.Variable)) {
if (ILVariableEqualityComparer.Instance.Equals(ldloc.Variable, forbiddenVariable))
return false;
if (contextFunction == null)
return false; // locals only supported for the callers that specify the context
target = new LdLoca(ldloc.Variable).WithILRange(ldloc);
targetKind = CompoundTargetKind.Address;
contextFunction.RecombineVariables(ldloc.Variable, stloc.Variable);
finalizeMatch = context => context.Function.RecombineVariables(ldloc.Variable, stloc.Variable);
return true;
} else {
return false;
@ -566,11 +615,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -566,11 +615,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!(stloc.Variable.Kind == VariableKind.Local || stloc.Variable.Kind == VariableKind.StackSlot))
return false;
if (!IsMatchingCompoundLoad(stloc.Value, store, out var target, out var targetKind, forbiddenVariable: stloc.Variable))
if (!IsMatchingCompoundLoad(stloc.Value, store, out var target, out var targetKind, out var finalizeMatch, forbiddenVariable: stloc.Variable))
return false;
if (IsImplicitTruncation(stloc.Value, stloc.Variable.Type, context.TypeSystem))
return false;
context.Step("TransformPostIncDecOperatorWithInlineStore", store);
finalizeMatch?.Invoke(context);
if (binary != null) {
block.Instructions[pos] = new StLoc(stloc.Variable, new NumericCompoundAssign(
binary, target, targetKind, binary.Right, targetType, CompoundEvalMode.EvaluatesToOldValue));
@ -614,7 +664,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -614,7 +664,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// 'stloc tmp' is implicitly truncating the value
return false;
}
if (!IsMatchingCompoundLoad(inst.Value, store, out var target, out var targetKind, context.Function, forbiddenVariable: inst.Variable))
if (!IsMatchingCompoundLoad(inst.Value, store, out var target, out var targetKind, out var finalizeMatch, forbiddenVariable: inst.Variable))
return false;
if (UnwrapSmallIntegerConv(value, out var conv) is BinaryNumericInstruction binary) {
if (!binary.Left.MatchLdLoc(tmpVar) || !binary.Right.MatchLdcI(1))
@ -624,6 +674,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -624,6 +674,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!ValidateCompoundAssign(binary, conv, targetType))
return false;
context.Step("TransformPostIncDecOperator (builtin)", inst);
finalizeMatch?.Invoke(context);
inst.Value = new NumericCompoundAssign(binary, target, targetKind, binary.Right,
targetType, CompoundEvalMode.EvaluatesToOldValue);
} else if (value is Call operatorCall && operatorCall.Method.IsOperator && operatorCall.Arguments.Count == 1) {
@ -634,6 +685,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -634,6 +685,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (operatorCall.IsLifted)
return false; // TODO: add tests and think about whether nullables need special considerations
context.Step("TransformPostIncDecOperator (user-defined)", inst);
finalizeMatch?.Invoke(context);
inst.Value = new UserDefinedCompoundAssign(operatorCall.Method,
CompoundEvalMode.EvaluatesToOldValue, target, targetKind, new LdcI4(1));
} else {

10
ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs

@ -78,10 +78,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -78,10 +78,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
VisitILFunction(f);
}
}
context.Step($"Remove instructions", function);
foreach (var store in instructionsToRemove) {
if (store.Parent is Block containingBlock)
containingBlock.Instructions.Remove(store);
if (instructionsToRemove.Count > 0) {
context.Step($"Remove instructions", function);
foreach (var store in instructionsToRemove) {
if (store.Parent is Block containingBlock)
containingBlock.Instructions.Remove(store);
}
}
} finally {
instructionsToRemove.Clear();

4
ICSharpCode.Decompiler/TypeSystem/IParameter.cs

@ -47,10 +47,10 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -47,10 +47,10 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// Gets whether this parameter is a C# 'params' parameter.
/// </summary>
bool IsParams { get; }
/// <summary>
/// Gets whether this parameter is optional.
/// The default value is given by the <see cref="IVariable.ConstantValue"/> property.
/// The default value is given by the <see cref="IVariable.GetConstantValue"/> function.
/// </summary>
bool IsOptional { get; }

4
ICSharpCode.Decompiler/TypeSystem/ITypeParameter.cs

@ -30,10 +30,10 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -30,10 +30,10 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary>
/// <returns>SymbolKind.TypeDefinition or SymbolKind.Method</returns>
SymbolKind OwnerType { get; }
/// <summary>
/// Gets the owning method/class.
/// This property may return null (for example for the dummy type parameters used by <see cref="ParameterListComparer.NormalizeMethodTypeParameters"/>).
/// This property may return null (for example for the dummy type parameters used by <see cref="NormalizeTypeVisitor.ReplaceMethodTypeParametersWithDummy"/>).
/// </summary>
/// <remarks>
/// For "class Outer&lt;T&gt; { class Inner {} }",

2
ICSharpCode.Decompiler/TypeSystem/Implementation/ThreeState.cs

@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
namespace ICSharpCode.Decompiler.TypeSystem.Implementation
{
/// <summary>
/// Constants used instead of <see cref="bool?"/>
/// Constants used instead of <c>bool?</c>
/// in multithreaded code, as <c>bool?</c> might produce torn reads.
/// </summary>
static class ThreeState

7
ICSharpCode.Decompiler/TypeSystem/TypeKind.cs

@ -41,7 +41,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -41,7 +41,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
Enum,
/// <summary>The <c>System.Void</c> type.</summary>
/// <see cref="KnownTypeReference.Void"/>
/// <see cref="KnownTypeCode.Void"/>
Void,
/// <summary>Type used for invalid expressions and for types whose definition could not be found.</summary>
@ -58,7 +58,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -58,7 +58,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
Dynamic,
/// <summary>Represents missing type arguments in partially parameterized types.</summary>
/// <see cref="SpecialType.UnboundTypeArgument"/>
/// <see cref="IType.GetNestedTypes(Predicate{ITypeDefinition}, GetMemberOptions)"/>
/// <see cref="IType">IType.GetNestedTypes(Predicate{ITypeDefinition}, GetMemberOptions)</see>
UnboundTypeArgument,
/// <summary>The type is a type parameter.</summary>
@ -74,9 +74,6 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -74,9 +74,6 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// <summary>A managed reference type</summary>
/// <see cref="ByReferenceType"/>
ByReference,
/// <summary>An anonymous type</summary>
/// <see cref="AnonymousType"/>
Anonymous,
/// <summary>Intersection of several types</summary>
/// <see cref="IntersectionType"/>

8
ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

@ -384,9 +384,9 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -384,9 +384,9 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// (if the given <paramref name="entity"/> in an <c>override</c>)
/// should be returned.
/// </param>
public static bool HasAttribute(this IEntity entity, KnownAttribute attrType, bool inherit=false)
public static bool HasAttribute(this IEntity entity, KnownAttribute attributeType, bool inherit=false)
{
return GetAttribute(entity, attrType, inherit) != null;
return GetAttribute(entity, attributeType, inherit) != null;
}
/// <summary>
@ -445,9 +445,9 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -445,9 +445,9 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary>
/// <param name="parameter">The parameter on which the attributes are declared.</param>
/// <param name="attributeType">The attribute type to look for.</param>
public static bool HasAttribute(this IParameter parameter, KnownAttribute attrType)
public static bool HasAttribute(this IParameter parameter, KnownAttribute attributeType)
{
return GetAttribute(parameter, attrType) != null;
return GetAttribute(parameter, attributeType) != null;
}
/// <summary>

Loading…
Cancel
Save