Browse Source

Merge branch 'master' into bookmarks

pull/263/head
Ronny Klier 15 years ago
parent
commit
26f6dcd6de
  1. 11
      Debugger/ILSpy.Debugger/Commands/DebuggerCommands.cs
  2. 6
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 18
      ICSharpCode.Decompiler/Ast/CecilTypeResolveContext.cs
  4. 17
      ICSharpCode.Decompiler/Ast/NameVariables.cs
  5. 35
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  6. 1
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  7. 4
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  8. 145
      ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs
  9. 35
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  10. 133
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  11. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  12. 79
      ICSharpCode.Decompiler/Tests/InitializerTests.cs
  13. 6
      ICSharpCode.Decompiler/Tests/TestRunner.cs
  14. 109
      ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs
  15. 6
      ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
  16. 3
      ILSpy.BamlDecompiler/CecilDependencyPropertyDescriptor.cs
  17. 2
      ILSpy.BamlDecompiler/CecilType.cs
  18. 2
      ILSpy.BamlDecompiler/CecilTypeResolver.cs
  19. 8
      ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj
  20. 183
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/AppDomainTypeResolver.cs
  21. 112
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlAssembly.cs
  22. 80
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlFile.cs
  23. 64
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/DotNetType.cs
  24. 6
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KeyMapping.cs
  25. 4
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KnownInfo.cs
  26. 68
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/NodesCollection.cs
  27. 80
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs
  28. 35
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/WpfDependencyPropertyDescriptor.cs
  29. 19
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlElement.cs
  30. 2
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlPropertyElement.cs
  31. 210
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs
  32. 23
      ILSpy.BamlDecompiler/Tests/Cases/Dictionary1.xaml
  33. 1
      ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj
  34. 17
      ILSpy.BamlDecompiler/Tests/TestRunner.cs
  35. 4
      ILSpy/AssemblyList.cs
  36. 26
      ILSpy/Controls/ResourceStringTable.xaml
  37. 51
      ILSpy/Controls/ResourceStringTable.xaml.cs
  38. 6
      ILSpy/ILSpy.csproj
  39. 9
      ILSpy/LoadedAssembly.cs
  40. 15
      ILSpy/MainWindow.xaml.cs
  41. 15
      ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs
  42. 2
      ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs
  43. 18
      ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs
  44. 4
      ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs
  45. 31
      ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs
  46. 6
      ILSpy/TreeNodes/ResourceNodes/XamlResourceNode.cs
  47. 10
      ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs
  48. 2
      ILSpy/XmlDoc/XmlDocKeyProvider.cs
  49. 72
      NRefactory/ICSharpCode.Editor/ICSharpCode.Editor.csproj
  50. 141
      NRefactory/ICSharpCode.Editor/IDocument.cs
  51. 30
      NRefactory/ICSharpCode.Editor/IDocumentLine.cs
  52. 55
      NRefactory/ICSharpCode.Editor/ISegment.cs
  53. 102
      NRefactory/ICSharpCode.Editor/ITextAnchor.cs
  54. 100
      NRefactory/ICSharpCode.Editor/ITextEditor.cs
  55. 147
      NRefactory/ICSharpCode.Editor/ITextSource.cs
  56. 68
      NRefactory/ICSharpCode.Editor/LinkedElement.cs
  57. 31
      NRefactory/ICSharpCode.Editor/Properties/AssemblyInfo.cs
  58. 321
      NRefactory/ICSharpCode.Editor/ReadOnlyDocument.cs
  59. 91
      NRefactory/ICSharpCode.Editor/StringTextSource.cs
  60. 64
      NRefactory/ICSharpCode.Editor/TextChangeEventArgs.cs
  61. 173
      NRefactory/ICSharpCode.Editor/TextLocation.cs
  62. 2
      NRefactory/ICSharpCode.NRefactory.Demo/CSDemo.cs
  63. 26
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/InsertParenthesesVisitorTests.cs
  64. 17
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/TypeOfExpressionTests.cs
  65. 69
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/AttributeSectionTests.cs
  66. 8
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs
  67. 4
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs
  68. 8
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/AttributeTests.cs
  69. 57
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/BinaryOperatorTests.cs
  70. 115
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
  71. 2
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExtensionMethodTests.cs
  72. 12
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs
  73. 2
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs
  74. 88
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs
  75. 2
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ObjectCreationTests.cs
  76. 2
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ResolverTestBase.cs
  77. 47
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/TypeInferenceTests.cs
  78. 2
      NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnsafeCodeTests.cs
  79. 1
      NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TestBlankLineFormatting.cs
  80. 3
      NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TestBraceStlye.cs
  81. 1
      NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TestFormattingBugs.cs
  82. 19
      NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TestSpacingVisitor.cs
  83. 3
      NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TestStatementIndentation.cs
  84. 7
      NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TestTypeLevelIndentation.cs
  85. 70
      NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TextEditorTestAdapter.cs
  86. 40
      NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs
  87. 30
      NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs
  88. 6
      NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/ReflectionHelperTests.cs
  89. 4
      NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TestInterningProvider.cs
  90. 2
      NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs
  91. 82
      NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs
  92. 2
      NRefactory/ICSharpCode.NRefactory.VB.Tests/Parser/GlobalScope/ImportsStatementTests.cs
  93. 150
      NRefactory/ICSharpCode.NRefactory.VB/Ast/AstNode.cs
  94. 2
      NRefactory/ICSharpCode.NRefactory.VB/Ast/General/TypeParameterDeclaration.cs
  95. 2
      NRefactory/ICSharpCode.NRefactory.VB/Ast/GlobalScope/NamespaceDeclaration.cs
  96. 10
      NRefactory/ICSharpCode.NRefactory.VB/Ast/GlobalScope/TypeDeclaration.cs
  97. 2
      NRefactory/ICSharpCode.NRefactory.VB/Ast/TypeName/QualifiedType.cs
  98. 4
      NRefactory/ICSharpCode.NRefactory.VB/Ast/TypeName/SimpleType.cs
  99. 6
      NRefactory/ICSharpCode.NRefactory.VB/Parser/Parser.cs
  100. 7
      NRefactory/ICSharpCode.NRefactory/CSharp/Analysis/ControlFlow.cs
  101. Some files were not shown because too many files have changed in this diff Show More

11
Debugger/ILSpy.Debugger/Commands/DebuggerCommands.cs

@ -10,7 +10,6 @@ using System.Windows.Input;
using System.Windows.Interop; using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Xml.Linq; using System.Xml.Linq;
using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.ILSpy.Bookmarks; using ICSharpCode.ILSpy.Bookmarks;
using ICSharpCode.ILSpy.Debugger; using ICSharpCode.ILSpy.Debugger;
@ -20,6 +19,7 @@ using ICSharpCode.ILSpy.Debugger.UI;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
using Microsoft.Win32; using Microsoft.Win32;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.Debugger.Commands namespace ICSharpCode.ILSpy.Debugger.Commands
{ {
@ -182,7 +182,14 @@ namespace ICSharpCode.ILSpy.Debugger.Commands
{ {
public bool IsVisible(SharpTreeNode[] selectedNodes) public bool IsVisible(SharpTreeNode[] selectedNodes)
{ {
return selectedNodes.All(n => n is AssemblyTreeNode && null != (n as AssemblyTreeNode).LoadedAssembly.AssemblyDefinition.EntryPoint); return selectedNodes.All(
delegate (SharpTreeNode n) {
AssemblyTreeNode a = n as AssemblyTreeNode;
if (a == null)
return false;
AssemblyDefinition asm = a.LoadedAssembly.AssemblyDefinition;
return asm != null && asm.EntryPoint != null;
});
} }
public bool IsEnabled(SharpTreeNode[] selectedNodes) public bool IsEnabled(SharpTreeNode[] selectedNodes)

6
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -782,9 +782,15 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
ObjectCreateExpression oce = arg1 as ObjectCreateExpression; ObjectCreateExpression oce = arg1 as ObjectCreateExpression;
DefaultValueExpression dve = arg1 as DefaultValueExpression;
if (oce != null) { if (oce != null) {
oce.Initializer = initializer; oce.Initializer = initializer;
return oce; return oce;
} else if (dve != null) {
oce = new ObjectCreateExpression(dve.Type.Detach());
oce.CopyAnnotationsFrom(dve);
oce.Initializer = initializer;
return oce;
} else { } else {
return new AssignmentExpression(arg1, initializer); return new AssignmentExpression(arg1, initializer);
} }

18
ICSharpCode.Decompiler/Ast/CecilTypeResolveContext.cs

@ -19,6 +19,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using Mono.Cecil; using Mono.Cecil;
@ -27,7 +28,7 @@ namespace ICSharpCode.Decompiler.Ast
/// <summary> /// <summary>
/// ITypeResolveContext implementation that lazily loads types from Cecil. /// ITypeResolveContext implementation that lazily loads types from Cecil.
/// </summary> /// </summary>
public class CecilTypeResolveContext : ISynchronizedTypeResolveContext, IProjectContent public class CecilTypeResolveContext : AbstractAnnotatable, ISynchronizedTypeResolveContext, IProjectContent
{ {
readonly ModuleDefinition module; readonly ModuleDefinition module;
readonly string[] namespaces; readonly string[] namespaces;
@ -91,7 +92,7 @@ namespace ICSharpCode.Decompiler.Ast
public IList<IAttribute> AssemblyAttributes { get; private set; } public IList<IAttribute> AssemblyAttributes { get; private set; }
public ITypeDefinition GetClass(string nameSpace, string name, int typeParameterCount, StringComparer nameComparer) public ITypeDefinition GetTypeDefinition(string nameSpace, string name, int typeParameterCount, StringComparer nameComparer)
{ {
if (typeParameterCount > 0) if (typeParameterCount > 0)
name = name + "`" + typeParameterCount.ToString(); name = name + "`" + typeParameterCount.ToString();
@ -113,14 +114,14 @@ namespace ICSharpCode.Decompiler.Ast
return null; return null;
} }
public IEnumerable<ITypeDefinition> GetClasses() public IEnumerable<ITypeDefinition> GetTypes()
{ {
foreach (TypeDefinition cecilType in module.Types) { foreach (TypeDefinition cecilType in module.Types) {
yield return GetClass(cecilType); yield return GetClass(cecilType);
} }
} }
public IEnumerable<ITypeDefinition> GetClasses(string nameSpace, StringComparer nameComparer) public IEnumerable<ITypeDefinition> GetTypes(string nameSpace, StringComparer nameComparer)
{ {
foreach (TypeDefinition cecilType in module.Types) { foreach (TypeDefinition cecilType in module.Types) {
if (nameComparer.Equals(nameSpace, cecilType.Namespace)) if (nameComparer.Equals(nameSpace, cecilType.Namespace))
@ -159,5 +160,14 @@ namespace ICSharpCode.Decompiler.Ast
{ {
// exit from Synchronize() block // exit from Synchronize() block
} }
IEnumerable<IParsedFile> IProjectContent.Files {
get { return new IParsedFile[0]; }
}
IParsedFile IProjectContent.GetFile(string fileName)
{
return null;
}
} }
} }

17
ICSharpCode.Decompiler/Ast/NameVariables.cs

@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.Ast
nv.AddExistingName(v.Name); nv.AddExistingName(v.Name);
} else if (v.OriginalVariable != null && context.Settings.UseDebugSymbols) { } else if (v.OriginalVariable != null && context.Settings.UseDebugSymbols) {
string varName = v.OriginalVariable.Name; string varName = v.OriginalVariable.Name;
if (string.IsNullOrEmpty(varName) || varName.StartsWith("V_", StringComparison.Ordinal) || varName.StartsWith("CS$", StringComparison.Ordinal)) if (string.IsNullOrEmpty(varName) || varName.StartsWith("V_", StringComparison.Ordinal) || !IsValidName(varName))
{ {
// don't use the name from the debug symbols if it looks like a generated name // don't use the name from the debug symbols if it looks like a generated name
v.Name = null; v.Name = null;
@ -86,6 +86,19 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
static bool IsValidName(string varName)
{
if (string.IsNullOrEmpty(varName))
return false;
if (!(char.IsLetter(varName[0]) || varName[0] == '_'))
return false;
for (int i = 1; i < varName.Length; i++) {
if (!(char.IsLetterOrDigit(varName[i]) || varName[i] == '_'))
return false;
}
return true;
}
DecompilerContext context; DecompilerContext context;
List<string> fieldNamesInCurrentType; List<string> fieldNamesInCurrentType;
Dictionary<string, int> typeNames = new Dictionary<string, int>(); Dictionary<string, int> typeNames = new Dictionary<string, int>();
@ -139,7 +152,7 @@ namespace ICSharpCode.Decompiler.Ast
typeNames.Add(nameWithoutDigits, number - 1); typeNames.Add(nameWithoutDigits, number - 1);
} }
int count = ++typeNames[nameWithoutDigits]; int count = ++typeNames[nameWithoutDigits];
if (count > 1) { if (count != 1) {
return nameWithoutDigits + count.ToString(); return nameWithoutDigits + count.ToString();
} else { } else {
return nameWithoutDigits; return nameWithoutDigits;

35
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -42,6 +42,7 @@ namespace ICSharpCode.Decompiler.ILAst
SimplifyTernaryOperator, SimplifyTernaryOperator,
SimplifyNullCoalescing, SimplifyNullCoalescing,
JoinBasicBlocks, JoinBasicBlocks,
SimplifyShiftOperators,
TransformDecimalCtorToConstant, TransformDecimalCtorToConstant,
SimplifyLdObjAndStObj, SimplifyLdObjAndStObj,
SimplifyCustomShortCircuit, SimplifyCustomShortCircuit,
@ -54,6 +55,7 @@ namespace ICSharpCode.Decompiler.ILAst
FindLoops, FindLoops,
FindConditions, FindConditions,
FlattenNestedMovableBlocks, FlattenNestedMovableBlocks,
RemoveEndFinally,
RemoveRedundantCode2, RemoveRedundantCode2,
GotoRemoval, GotoRemoval,
DuplicateReturns, DuplicateReturns,
@ -131,7 +133,10 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks) return; if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks) return;
modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks); modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks);
if (abortBeforeStep == ILAstOptimizationStep.SimplifyShiftOperators) return;
modified |= block.RunOptimization(SimplifyShiftOperators);
if (abortBeforeStep == ILAstOptimizationStep.TransformDecimalCtorToConstant) return; if (abortBeforeStep == ILAstOptimizationStep.TransformDecimalCtorToConstant) return;
modified |= block.RunOptimization(TransformDecimalCtorToConstant); modified |= block.RunOptimization(TransformDecimalCtorToConstant);
modified |= block.RunOptimization(SimplifyLdcI4ConvI8); modified |= block.RunOptimization(SimplifyLdcI4ConvI8);
@ -178,6 +183,9 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) return; if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) return;
FlattenBasicBlocks(method); FlattenBasicBlocks(method);
if (abortBeforeStep == ILAstOptimizationStep.RemoveEndFinally) return;
RemoveEndFinally(method);
if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode2) return; if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode2) return;
RemoveRedundantCode(method); RemoveRedundantCode(method);
@ -534,6 +542,25 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
/// <summary>
/// Replace endfinally with jump to the end of the finally block
/// </summary>
void RemoveEndFinally(ILBlock method)
{
// Go thought the list in reverse so that we do the nested blocks first
foreach(var tryCatch in method.GetSelfAndChildrenRecursive<ILTryCatchBlock>(tc => tc.FinallyBlock != null).Reverse()) {
ILLabel label = new ILLabel() { Name = "EndFinally_" + nextLabelIndex++ };
tryCatch.FinallyBlock.Body.Add(label);
foreach(var block in tryCatch.FinallyBlock.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int i = 0; i < block.Body.Count; i++) {
if (block.Body[i].Match(ILCode.Endfinally)) {
block.Body[i] = new ILExpression(ILCode.Br, label).WithILRanges(((ILExpression)block.Body[i]).ILRanges);
}
}
}
}
}
/// <summary> /// <summary>
/// Reduce the nesting of conditions. /// Reduce the nesting of conditions.
/// It should be done on flat data that already had most gotos removed /// It should be done on flat data that already had most gotos removed
@ -766,6 +793,12 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
public static ILExpression WithILRanges(this ILExpression expr, IEnumerable<ILRange> ilranges)
{
expr.ILRanges.AddRange(ilranges);
return expr;
}
public static void RemoveTail(this List<ILNode> body, params ILCode[] codes) public static void RemoveTail(this List<ILNode> body, params ILCode[] codes)
{ {
for (int i = 0; i < codes.Length; i++) { for (int i = 0; i < codes.Length; i++) {

1
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -43,6 +43,7 @@ namespace ICSharpCode.Decompiler.ILAst
void AccumulateSelfAndChildrenRecursive<T>(List<T> list, Func<T, bool> predicate) where T:ILNode void AccumulateSelfAndChildrenRecursive<T>(List<T> list, Func<T, bool> predicate) where T:ILNode
{ {
// Note: RemoveEndFinally depends on self coming before children
T thisAsT = this as T; T thisAsT = this as T;
if (thisAsT != null && (predicate == null || predicate(thisAsT))) if (thisAsT != null && (predicate == null || predicate(thisAsT)))
list.Add(thisAsT); list.Add(thisAsT);

4
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -261,8 +261,8 @@ namespace ICSharpCode.Decompiler.ILAst
// InitCollection(CallGetter(Collection, InitializedObject))), // InitCollection(CallGetter(Collection, InitializedObject))),
// Call(Add, InitializedObject, 2, 3), // Call(Add, InitializedObject, 2, 3),
// Call(Add, InitializedObject, 4, 5))) // Call(Add, InitializedObject, 4, 5)))
InitObject, // Object initializer: first arg is newobj, remaining args are the initializing statements InitObject, // Object initializer: first arg is newobj/defaultvalue, remaining args are the initializing statements
InitCollection, // Collection initializer: first arg is newobj, remaining args are the initializing statements InitCollection, // Collection initializer: first arg is newobj/defaultvalue, remaining args are the initializing statements
InitializedObject, // Refers the the object being initialized (refers to first arg in parent InitObject or InitCollection instruction) InitializedObject, // Refers the the object being initialized (refers to first arg in parent InitObject or InitCollection instruction)
TernaryOp, // ?: TernaryOp, // ?:

145
ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs

@ -93,9 +93,9 @@ namespace ICSharpCode.Decompiler.ILAst
List<ILExpression> ctorArgs; List<ILExpression> ctorArgs;
ArrayType arrayType; ArrayType arrayType;
if (expr.Match(ILCode.Stloc, out v, out newarrExpr) && if (expr.Match(ILCode.Stloc, out v, out newarrExpr) &&
newarrExpr.Match(ILCode.Newobj, out ctor, out ctorArgs) && newarrExpr.Match(ILCode.Newobj, out ctor, out ctorArgs) &&
(arrayType = (ctor.DeclaringType as ArrayType)) != null && (arrayType = (ctor.DeclaringType as ArrayType)) != null &&
arrayType.Rank == ctorArgs.Count) { arrayType.Rank == ctorArgs.Count) {
// Clone the type, so we can muck about with the Dimensions // Clone the type, so we can muck about with the Dimensions
arrayType = new ArrayType(arrayType.ElementType, arrayType.Rank); arrayType = new ArrayType(arrayType.ElementType, arrayType.Rank);
var arrayLengths = new int[arrayType.Rank]; var arrayLengths = new int[arrayType.Rank];
@ -124,19 +124,24 @@ namespace ICSharpCode.Decompiler.ILAst
MethodReference methodRef; MethodReference methodRef;
ILExpression methodArg1; ILExpression methodArg1;
ILExpression methodArg2; ILExpression methodArg2;
FieldDefinition field; FieldReference fieldRef;
if (body.ElementAtOrDefault(pos).Match(ILCode.Call, out methodRef, out methodArg1, out methodArg2) && if (body.ElementAtOrDefault(pos).Match(ILCode.Call, out methodRef, out methodArg1, out methodArg2) &&
methodRef.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers" && methodRef.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers" &&
methodRef.Name == "InitializeArray" && methodRef.Name == "InitializeArray" &&
methodArg1.Match(ILCode.Ldloc, out v2) && methodArg1.Match(ILCode.Ldloc, out v2) &&
array == v2 && array == v2 &&
methodArg2.Match(ILCode.Ldtoken, out field) && methodArg2.Match(ILCode.Ldtoken, out fieldRef))
field != null && field.InitialValue != null) { {
ILExpression[] newArr = new ILExpression[arrayLength]; FieldDefinition fieldDef = fieldRef.ResolveWithinSameModule();
if (DecodeArrayInitializer(TypeAnalysis.GetTypeCode(arrayType.GetElementType()), field.InitialValue, newArr)) { if (fieldDef != null && fieldDef.InitialValue != null) {
values = newArr; ILExpression[] newArr = new ILExpression[arrayLength];
foundPos = pos; if (DecodeArrayInitializer(TypeAnalysis.GetTypeCode(arrayType.GetElementType()),
return true; fieldDef.InitialValue, newArr))
{
values = newArr;
foundPos = pos;
return true;
}
} }
} }
values = null; values = null;
@ -148,7 +153,6 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
switch (elementType) { switch (elementType) {
case TypeCode.Boolean: case TypeCode.Boolean:
case TypeCode.SByte:
case TypeCode.Byte: case TypeCode.Byte:
if (initialValue.Length == output.Length) { if (initialValue.Length == output.Length) {
for (int j = 0; j < output.Length; j++) { for (int j = 0; j < output.Length; j++) {
@ -157,9 +161,15 @@ namespace ICSharpCode.Decompiler.ILAst
return true; return true;
} }
return false; return false;
case TypeCode.Char: case TypeCode.SByte:
if (initialValue.Length == output.Length) {
for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_I4, (int)unchecked((sbyte)initialValue[j]));
}
return true;
}
return false;
case TypeCode.Int16: case TypeCode.Int16:
case TypeCode.UInt16:
if (initialValue.Length == output.Length * 2) { if (initialValue.Length == output.Length * 2) {
for (int j = 0; j < output.Length; j++) { for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_I4, (int)BitConverter.ToInt16(initialValue, j * 2)); output[j] = new ILExpression(ILCode.Ldc_I4, (int)BitConverter.ToInt16(initialValue, j * 2));
@ -167,6 +177,15 @@ namespace ICSharpCode.Decompiler.ILAst
return true; return true;
} }
return false; return false;
case TypeCode.Char:
case TypeCode.UInt16:
if (initialValue.Length == output.Length * 2) {
for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_I4, (int)BitConverter.ToUInt16(initialValue, j * 2));
}
return true;
}
return false;
case TypeCode.Int32: case TypeCode.Int32:
case TypeCode.UInt32: case TypeCode.UInt32:
if (initialValue.Length == output.Length * 4) { if (initialValue.Length == output.Length * 4) {
@ -218,18 +237,45 @@ namespace ICSharpCode.Decompiler.ILAst
Debug.Assert(body[pos] == expr); // should be called for top-level expressions only Debug.Assert(body[pos] == expr); // should be called for top-level expressions only
ILVariable v; ILVariable v;
ILExpression newObjExpr; ILExpression newObjExpr;
TypeReference newObjType;
bool isValueType;
MethodReference ctor; MethodReference ctor;
List<ILExpression> ctorArgs; List<ILExpression> ctorArgs;
// v = newObj(ctor, ctorArgs) if (expr.Match(ILCode.Stloc, out v, out newObjExpr)) {
if (!(expr.Match(ILCode.Stloc, out v, out newObjExpr) && newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs))) if (newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs)) {
// v = newObj(ctor, ctorArgs)
newObjType = ctor.DeclaringType;
isValueType = false;
} else if (newObjExpr.Match(ILCode.DefaultValue, out newObjType)) {
// v = defaultvalue(type)
isValueType = true;
} else {
return false;
}
} else if (expr.Match(ILCode.Call, out ctor, out ctorArgs)) {
// call(SomeStruct::.ctor, ldloca(v), remainingArgs)
if (ctorArgs.Count > 0 && ctorArgs[0].Match(ILCode.Ldloca, out v)) {
isValueType = true;
newObjType = ctor.DeclaringType;
ctorArgs = new List<ILExpression>(ctorArgs);
ctorArgs.RemoveAt(0);
newObjExpr = new ILExpression(ILCode.Newobj, ctor, ctorArgs);
} else {
return false;
}
} else {
return false;
}
if (newObjType.IsValueType != isValueType)
return false; return false;
int originalPos = pos; int originalPos = pos;
// don't use object initializer syntax for closures // don't use object initializer syntax for closures
if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, ctor.DeclaringType.ResolveWithinSameModule())) if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, newObjType.ResolveWithinSameModule()))
return false; return false;
ILExpression initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr, IsCollectionType(ctor.DeclaringType)); ILExpression initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr, IsCollectionType(newObjType), isValueType);
if (initializer.Arguments.Count == 1) // only newobj argument, no initializer elements if (initializer.Arguments.Count == 1) // only newobj argument, no initializer elements
return false; return false;
@ -242,16 +288,36 @@ namespace ICSharpCode.Decompiler.ILAst
return false; // reached end of block, but there should be another instruction which consumes the initialized object return false; // reached end of block, but there should be another instruction which consumes the initialized object
ILInlining inlining = new ILInlining(method); ILInlining inlining = new ILInlining(method);
// one ldloc for each initializer argument, and another ldloc for the use of the initialized object if (isValueType) {
if (inlining.numLdloc.GetOrDefault(v) != totalElementCount + 1) // one ldloc for the use of the initialized object
return false; if (inlining.numLdloc.GetOrDefault(v) != 1)
if (!(inlining.numStloc.GetOrDefault(v) == 1 && inlining.numLdloca.GetOrDefault(v) == 0)) return false;
return false; // one ldloca for each initializer argument, and also for the ctor call (if it exists)
if (inlining.numLdloca.GetOrDefault(v) != totalElementCount + (expr.Code == ILCode.Call ? 1 : 0))
return false;
// one stloc for the initial store (if no ctor call was used)
if (inlining.numStloc.GetOrDefault(v) != (expr.Code == ILCode.Call ? 0 : 1))
return false;
} else {
// one ldloc for each initializer argument, and another ldloc for the use of the initialized object
if (inlining.numLdloc.GetOrDefault(v) != totalElementCount + 1)
return false;
if (!(inlining.numStloc.GetOrDefault(v) == 1 && inlining.numLdloca.GetOrDefault(v) == 0))
return false;
}
ILExpression nextExpr = body[pos] as ILExpression; ILExpression nextExpr = body[pos] as ILExpression;
if (!inlining.CanInlineInto(nextExpr, v, initializer)) if (!inlining.CanInlineInto(nextExpr, v, initializer))
return false; return false;
expr.Arguments[0] = initializer; if (expr.Code == ILCode.Stloc) {
expr.Arguments[0] = initializer;
} else {
Debug.Assert(expr.Code == ILCode.Call);
expr.Code = ILCode.Stloc;
expr.Operand = v;
expr.Arguments.Clear();
expr.Arguments.Add(initializer);
}
// remove all the instructions that were pulled into the initializer // remove all the instructions that were pulled into the initializer
body.RemoveRange(originalPos + 1, pos - originalPos - 1); body.RemoveRange(originalPos + 1, pos - originalPos - 1);
@ -288,7 +354,7 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
if (expr == null) if (expr == null)
return false; return false;
if (expr.Code == ILCode.CallvirtSetter || expr.Code == ILCode.Stfld) { if (expr.Code == ILCode.CallvirtSetter || expr.Code == ILCode.CallSetter || expr.Code == ILCode.Stfld) {
return expr.Arguments.Count == 2; return expr.Arguments.Count == 2;
} }
return false; return false;
@ -320,9 +386,8 @@ namespace ICSharpCode.Decompiler.ILAst
/// <param name="v">The variable that holds the object being initialized</param> /// <param name="v">The variable that holds the object being initialized</param>
/// <param name="newObjExpr">The newobj instruction</param> /// <param name="newObjExpr">The newobj instruction</param>
/// <returns>InitObject instruction</returns> /// <returns>InitObject instruction</returns>
ILExpression ParseObjectInitializer(List<ILNode> body, ref int pos, ILVariable v, ILExpression newObjExpr, bool isCollection) ILExpression ParseObjectInitializer(List<ILNode> body, ref int pos, ILVariable v, ILExpression newObjExpr, bool isCollection, bool isValueType)
{ {
Debug.Assert(((ILExpression)body[pos]).Code == ILCode.Stloc);
// Take care not to modify any existing ILExpressions in here. // Take care not to modify any existing ILExpressions in here.
// We just construct new ones around the old ones, any modifications must wait until the whole // We just construct new ones around the old ones, any modifications must wait until the whole
// object/collection initializer was analyzed. // object/collection initializer was analyzed.
@ -332,13 +397,13 @@ namespace ICSharpCode.Decompiler.ILAst
while (++pos < body.Count) { while (++pos < body.Count) {
ILExpression nextExpr = body[pos] as ILExpression; ILExpression nextExpr = body[pos] as ILExpression;
if (IsSetterInObjectInitializer(nextExpr)) { if (IsSetterInObjectInitializer(nextExpr)) {
if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, false)) { if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, false, isValueType)) {
CleanupInitializerStackAfterFailedAdjustment(initializerStack); CleanupInitializerStackAfterFailedAdjustment(initializerStack);
break; break;
} }
initializerStack[initializerStack.Count - 1].Arguments.Add(nextExpr); initializerStack[initializerStack.Count - 1].Arguments.Add(nextExpr);
} else if (IsAddMethodCall(nextExpr)) { } else if (IsAddMethodCall(nextExpr)) {
if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, true)) { if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, true, isValueType)) {
CleanupInitializerStackAfterFailedAdjustment(initializerStack); CleanupInitializerStackAfterFailedAdjustment(initializerStack);
break; break;
} }
@ -351,20 +416,26 @@ namespace ICSharpCode.Decompiler.ILAst
return objectInitializer; return objectInitializer;
} }
static bool AdjustInitializerStack(List<ILExpression> initializerStack, ILExpression argument, ILVariable v, bool isCollection) static bool AdjustInitializerStack(List<ILExpression> initializerStack, ILExpression argument, ILVariable v, bool isCollection, bool isValueType)
{ {
// Argument is of the form 'getter(getter(...(v)))' // Argument is of the form 'getter(getter(...(v)))'
// Unpack it into a list of getters: // Unpack it into a list of getters:
List<ILExpression> getters = new List<ILExpression>(); List<ILExpression> getters = new List<ILExpression>();
while (argument.Code == ILCode.CallvirtGetter || argument.Code == ILCode.Ldfld) { while (argument.Code == ILCode.CallvirtGetter || argument.Code == ILCode.CallGetter || argument.Code == ILCode.Ldfld) {
getters.Add(argument); getters.Add(argument);
if (argument.Arguments.Count != 1) if (argument.Arguments.Count != 1)
return false; return false;
argument = argument.Arguments[0]; argument = argument.Arguments[0];
} }
// Ensure that the final argument is 'v' // Ensure that the final argument is 'v'
if (!argument.MatchLdloc(v)) if (isValueType) {
return false; ILVariable loadedVar;
if (!(argument.Match(ILCode.Ldloca, out loadedVar) && loadedVar == v))
return false;
} else {
if (!argument.MatchLdloc(v))
return false;
}
// Now compare the getters with those that are currently active on the initializer stack: // Now compare the getters with those that are currently active on the initializer stack:
int i; int i;
for (i = 1; i <= Math.Min(getters.Count, initializerStack.Count - 1); i++) { for (i = 1; i <= Math.Min(getters.Count, initializerStack.Count - 1); i++) {

35
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -868,5 +868,40 @@ namespace ICSharpCode.Decompiler.ILAst
return false; return false;
} }
#endregion #endregion
#region SimplifyShiftOperators
static bool SimplifyShiftOperators(List<ILNode> body, ILExpression expr, int pos)
{
// C# compiles "a << b" to "a << (b & 31)", so we will remove the "& 31" if possible.
bool modified = false;
SimplifyShiftOperators(expr, ref modified);
return modified;
}
static void SimplifyShiftOperators(ILExpression expr, ref bool modified)
{
for (int i = 0; i < expr.Arguments.Count; i++)
SimplifyShiftOperators(expr.Arguments[i], ref modified);
if (expr.Code != ILCode.Shl && expr.Code != ILCode.Shr && expr.Code != ILCode.Shr_Un)
return;
var a = expr.Arguments[1];
if (a.Code != ILCode.And || a.Arguments[1].Code != ILCode.Ldc_I4 || expr.InferredType == null)
return;
int mask;
switch (expr.InferredType.MetadataType) {
case MetadataType.Int32:
case MetadataType.UInt32: mask = 31; break;
case MetadataType.Int64:
case MetadataType.UInt64: mask = 63; break;
default: return;
}
if ((int)a.Arguments[1].Operand != mask) return;
var res = a.Arguments[0];
res.ILRanges.AddRange(a.ILRanges);
res.ILRanges.AddRange(a.Arguments[1].ILRanges);
expr.Arguments[1] = res;
modified = true;
}
#endregion
} }
} }

133
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -323,13 +323,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (forceInferChildren) { if (forceInferChildren) {
for (int i = 0; i < expr.Arguments.Count; i++) { for (int i = 0; i < expr.Arguments.Count; i++) {
if (i == 0 && method.HasThis) { if (i == 0 && method.HasThis) {
ILExpressionPrefix constraint = expr.GetPrefix(ILCode.Constrained); InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(method.DeclaringType, expr.GetPrefix(ILCode.Constrained)));
if (constraint != null)
InferTypeForExpression(expr.Arguments[i], new ByReferenceType((TypeReference)constraint.Operand));
else if (method.DeclaringType.IsValueType)
InferTypeForExpression(expr.Arguments[i], new ByReferenceType(method.DeclaringType));
else
InferTypeForExpression(expr.Arguments[i], method.DeclaringType);
} else { } else {
InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(method.Parameters[method.HasThis ? i - 1 : i].ParameterType, method)); InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(method.Parameters[method.HasThis ? i - 1 : i].ParameterType, method));
} }
@ -361,17 +355,22 @@ namespace ICSharpCode.Decompiler.ILAst
#endregion #endregion
#region Load/Store Fields #region Load/Store Fields
case ILCode.Ldfld: case ILCode.Ldfld:
if (forceInferChildren) if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], ((FieldReference)expr.Operand).DeclaringType); InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained)));
}
return GetFieldType((FieldReference)expr.Operand); return GetFieldType((FieldReference)expr.Operand);
case ILCode.Ldsfld: case ILCode.Ldsfld:
return GetFieldType((FieldReference)expr.Operand); return GetFieldType((FieldReference)expr.Operand);
case ILCode.Ldflda: case ILCode.Ldflda:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained)));
}
return new ByReferenceType(GetFieldType((FieldReference)expr.Operand));
case ILCode.Ldsflda: case ILCode.Ldsflda:
return new ByReferenceType(GetFieldType((FieldReference)expr.Operand)); return new ByReferenceType(GetFieldType((FieldReference)expr.Operand));
case ILCode.Stfld: case ILCode.Stfld:
if (forceInferChildren) { if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], ((FieldReference)expr.Operand).DeclaringType); InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained)));
InferTypeForExpression(expr.Arguments[1], GetFieldType((FieldReference)expr.Operand)); InferTypeForExpression(expr.Arguments[1], GetFieldType((FieldReference)expr.Operand));
} }
return GetFieldType((FieldReference)expr.Operand); return GetFieldType((FieldReference)expr.Operand);
@ -515,14 +514,47 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Rem_Un: case ILCode.Rem_Un:
return InferArgumentsInBinaryOperator(expr, false, expectedType); return InferArgumentsInBinaryOperator(expr, false, expectedType);
case ILCode.Shl: case ILCode.Shl:
case ILCode.Shr:
if (forceInferChildren) if (forceInferChildren)
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
return InferTypeForExpression(expr.Arguments[0], typeSystem.Int32); if (expectedType != null && (
expectedType.MetadataType == MetadataType.Int32 || expectedType.MetadataType == MetadataType.UInt32 ||
expectedType.MetadataType == MetadataType.Int64 || expectedType.MetadataType == MetadataType.UInt64)
)
return NumericPromotion(InferTypeForExpression(expr.Arguments[0], expectedType));
else
return NumericPromotion(InferTypeForExpression(expr.Arguments[0], null));
case ILCode.Shr:
case ILCode.Shr_Un: case ILCode.Shr_Un:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); if (forceInferChildren)
return InferTypeForExpression(expr.Arguments[0], typeSystem.UInt32); InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
TypeReference type = NumericPromotion(InferTypeForExpression(expr.Arguments[0], null));
TypeReference expectedInputType = null;
switch (type.MetadataType) {
case MetadataType.Int32:
if (expr.Code == ILCode.Shr_Un)
expectedInputType = typeSystem.UInt32;
break;
case MetadataType.UInt32:
if (expr.Code == ILCode.Shr)
expectedInputType = typeSystem.Int32;
break;
case MetadataType.Int64:
if (expr.Code == ILCode.Shr_Un)
expectedInputType = typeSystem.UInt64;
break;
case MetadataType.UInt64:
if (expr.Code == ILCode.Shr)
expectedInputType = typeSystem.UInt64;
break;
}
if (expectedInputType != null) {
InferTypeForExpression(expr.Arguments[0], expectedInputType);
return expectedInputType;
} else {
return type;
}
}
case ILCode.CompoundAssignment: case ILCode.CompoundAssignment:
{ {
TypeReference varType = InferTypeForExpression(expr.Arguments[0].Arguments[0], null); TypeReference varType = InferTypeForExpression(expr.Arguments[0].Arguments[0], null);
@ -543,9 +575,19 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldc_I4: case ILCode.Ldc_I4:
if (IsBoolean(expectedType) && ((int)expr.Operand == 0 || (int)expr.Operand == 1)) if (IsBoolean(expectedType) && ((int)expr.Operand == 0 || (int)expr.Operand == 1))
return typeSystem.Boolean; return typeSystem.Boolean;
return (IsIntegerOrEnum(expectedType) || expectedType is PointerType) ? expectedType : typeSystem.Int32; if (expectedType is PointerType && (int)expr.Operand == 0)
return expectedType;
if (IsIntegerOrEnum(expectedType) && OperandFitsInType(expectedType, (int)expr.Operand))
return expectedType;
else
return typeSystem.Int32;
case ILCode.Ldc_I8: case ILCode.Ldc_I8:
return (IsIntegerOrEnum(expectedType) || expectedType is PointerType) ? expectedType : typeSystem.Int64; if (expectedType is PointerType && (long)expr.Operand == 0)
return expectedType;
if (IsIntegerOrEnum(expectedType) && GetInformationAmount(expectedType) >= NativeInt)
return expectedType;
else
return typeSystem.Int64;
case ILCode.Ldc_R4: case ILCode.Ldc_R4:
return typeSystem.Single; return typeSystem.Single;
case ILCode.Ldc_R8: case ILCode.Ldc_R8:
@ -753,6 +795,41 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
/// <summary>
/// Wraps 'type' in a ByReferenceType if it is a value type. If a constrained prefix is specified,
/// returns the constrained type wrapped in a ByReferenceType.
/// </summary>
TypeReference MakeRefIfValueType(TypeReference type, ILExpressionPrefix constrainedPrefix)
{
if (constrainedPrefix != null)
return new ByReferenceType((TypeReference)constrainedPrefix.Operand);
if (type.IsValueType)
return new ByReferenceType(type);
else
return type;
}
/// <summary>
/// Promotes primitive types smaller than int32 to int32.
/// </summary>
/// <remarks>
/// Always promotes to signed int32.
/// </remarks>
TypeReference NumericPromotion(TypeReference type)
{
if (type == null)
return null;
switch (type.MetadataType) {
case MetadataType.SByte:
case MetadataType.Int16:
case MetadataType.Byte:
case MetadataType.UInt16:
return typeSystem.Int32;
default:
return type;
}
}
TypeReference HandleConversion(int targetBitSize, bool targetSigned, ILExpression arg, TypeReference expectedType, TypeReference targetType) TypeReference HandleConversion(int targetBitSize, bool targetSigned, ILExpression arg, TypeReference expectedType, TypeReference targetType)
{ {
if (targetBitSize >= NativeInt && expectedType is PointerType) { if (targetBitSize >= NativeInt && expectedType is PointerType) {
@ -1043,6 +1120,28 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
static bool OperandFitsInType(TypeReference type, int num)
{
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
if (typeDef != null && typeDef.IsEnum) {
type = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType;
}
switch (type.MetadataType) {
case MetadataType.SByte:
return sbyte.MinValue <= num && num <= sbyte.MaxValue;
case MetadataType.Int16:
return short.MinValue <= num && num <= short.MaxValue;
case MetadataType.Byte:
return byte.MinValue <= num && num <= byte.MaxValue;
case MetadataType.Char:
return char.MinValue <= num && num <= char.MaxValue;
case MetadataType.UInt16:
return ushort.MinValue <= num && num <= ushort.MaxValue;
default:
return true;
}
}
static bool IsArrayPointerOrReference(TypeReference type) static bool IsArrayPointerOrReference(TypeReference type)
{ {
TypeSpecification typeSpec = type as TypeSpecification; TypeSpecification typeSpec = type as TypeSpecification;

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -63,6 +63,7 @@
<Compile Include="PInvoke.cs" /> <Compile Include="PInvoke.cs" />
<Compile Include="QueryExpressions.cs" /> <Compile Include="QueryExpressions.cs" />
<Compile Include="Switch.cs" /> <Compile Include="Switch.cs" />
<Compile Include="TypeAnalysisTests.cs" />
<Compile Include="UndocumentedExpressions.cs" /> <Compile Include="UndocumentedExpressions.cs" />
<Compile Include="UnsafeCode.cs" /> <Compile Include="UnsafeCode.cs" />
<Compile Include="Types\S_TypeDeclarations.cs" /> <Compile Include="Types\S_TypeDeclarations.cs" />

79
ICSharpCode.Decompiler/Tests/InitializerTests.cs

@ -52,8 +52,37 @@ public class InitializerTests
get; get;
set; set;
} }
public InitializerTests.StructData NestedStruct
{
get;
set;
}
} }
private struct StructData
{
public int Field;
public int Property
{
get;
set;
}
public InitializerTests.Data MoreData
{
get;
set;
}
public StructData(int initialValue)
{
this = default(InitializerTests.StructData);
this.Field = initialValue;
this.Property = initialValue;
}
}
// Helper methods used to ensure initializers used within expressions work correctly // Helper methods used to ensure initializers used within expressions work correctly
private static void X(object a, object b) private static void X(object a, object b)
{ {
@ -456,7 +485,53 @@ public class InitializerTests
} }
}); });
} }
public static void StructInitializer_DefaultConstructor()
{
InitializerTests.X(InitializerTests.Y(), new InitializerTests.StructData
{
Field = 1,
Property = 2
});
}
public static void StructInitializer_ExplicitConstructor()
{
InitializerTests.X(InitializerTests.Y(), new InitializerTests.StructData(0)
{
Field = 1,
Property = 2
});
}
public static void StructInitializerWithInitializationOfNestedObjects()
{
InitializerTests.X(InitializerTests.Y(), new InitializerTests.StructData
{
MoreData =
{
a = InitializerTests.MyEnum.a,
FieldList =
{
InitializerTests.MyEnum2.c,
InitializerTests.MyEnum2.d
}
}
});
}
public static void StructInitializerWithinObjectInitializer()
{
InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data
{
NestedStruct = new InitializerTests.StructData(2)
{
Field = 1,
Property = 2
}
});
}
public void MultidimensionalInit() public void MultidimensionalInit()
{ {
int[,] expr_09 = new int[, ] int[,] expr_09 = new int[, ]

6
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -142,6 +142,12 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\YieldReturn.cs"); TestFile(@"..\..\Tests\YieldReturn.cs");
} }
[Test]
public void TypeAnalysis()
{
TestFile(@"..\..\Tests\TypeAnalysisTests.cs");
}
static void TestFile(string fileName) static void TestFile(string fileName)
{ {
string code = File.ReadAllText(fileName); string code = File.ReadAllText(fileName);

109
ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs

@ -0,0 +1,109 @@
// Copyright (c) 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;
public class TypeAnalysisTests
{
public byte SubtractFrom256(byte b)
{
return (byte)(256 - (int)b);
}
#region Shift
public int LShiftInteger(int num1, int num2)
{
return num1 << num2;
}
public uint LShiftUnsignedInteger(uint num1, uint num2)
{
return num1 << (int)num2;
}
public long LShiftLong(long num1, long num2)
{
return num1 << (int)num2;
}
public ulong LShiftUnsignedLong(ulong num1, ulong num2)
{
return num1 << (int)num2;
}
public int RShiftInteger(int num1, int num2)
{
return num1 >> num2;
}
public uint RShiftUnsignedInteger(uint num1, int num2)
{
return num1 >> num2;
}
public long RShiftLong(long num1, long num2)
{
return num1 >> (int)num2;
}
public ulong RShiftUnsignedLong(ulong num1, ulong num2)
{
return num1 >> (int)num2;
}
public int ShiftByte(byte num)
{
return (int)num << 8;
}
public int RShiftByte(byte num)
{
return num >> 8;
}
public uint RShiftByteWithZeroExtension(byte num)
{
return (uint)num >> 8;
}
public int RShiftByteAsSByte(byte num)
{
return (sbyte)num >> 8;
}
public int RShiftSByte(sbyte num)
{
return num >> 8;
}
public uint RShiftSByteWithZeroExtension(sbyte num)
{
return (uint)num >> 8;
}
public int RShiftSByteAsByte(sbyte num)
{
return (byte)num >> 8;
}
#endregion
public int GetHashCode(long num)
{
return (int)num ^ (int)(num >> 32);
}
}

6
ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs

@ -18,10 +18,10 @@ namespace ILSpy.BamlDecompiler
return null; return null;
} }
public ILSpyTreeNode CreateNode(string key, Stream data) public ILSpyTreeNode CreateNode(string key, object data)
{ {
if (key.EndsWith(".baml", StringComparison.OrdinalIgnoreCase)) if (key.EndsWith(".baml", StringComparison.OrdinalIgnoreCase) && data is Stream)
return new BamlResourceEntryNode(key, data); return new BamlResourceEntryNode(key, (Stream)data);
else else
return null; return null;
} }

3
ILSpy.BamlDecompiler/CecilDependencyPropertyDescriptor.cs

@ -2,6 +2,7 @@
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt) // This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System; using System;
using System.Diagnostics;
using System.Linq; using System.Linq;
using ICSharpCode.ILSpy; using ICSharpCode.ILSpy;
using Mono.Cecil; using Mono.Cecil;
@ -16,6 +17,8 @@ namespace ILSpy.BamlDecompiler
public CecilDependencyPropertyDescriptor(string member, TypeDefinition type) public CecilDependencyPropertyDescriptor(string member, TypeDefinition type)
{ {
if (type == null)
throw new ArgumentNullException("type");
this.member = member; this.member = member;
this.type = type; this.type = type;
} }

2
ILSpy.BamlDecompiler/CecilType.cs

@ -15,6 +15,8 @@ namespace ILSpy.BamlDecompiler
public CecilType(TypeDefinition type) public CecilType(TypeDefinition type)
{ {
if (type == null)
throw new ArgumentNullException("type");
this.type = type; this.type = type;
} }

2
ILSpy.BamlDecompiler/CecilTypeResolver.cs

@ -52,7 +52,7 @@ namespace ILSpy.BamlDecompiler
var otherAssembly = resolver.Resolve(assemblyName); var otherAssembly = resolver.Resolve(assemblyName);
if (otherAssembly == null) if (otherAssembly == null)
throw new Exception("could not resolve '" + assemblyName + "'!"); throw new Exception("could not resolve '" + assemblyName + "'!");
type = otherAssembly.MainModule.GetType(fullName); type = otherAssembly.MainModule.GetType(fullName.Replace('+', '/'));
} }
return new CecilType(type); return new CecilType(type);

8
ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj

@ -80,23 +80,17 @@
<Compile Include="ConnectMethodDecompiler.cs" /> <Compile Include="ConnectMethodDecompiler.cs" />
<Compile Include="Extensions.cs" /> <Compile Include="Extensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\AppDomainTypeResolver.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlAssembly.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlBinaryReader.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlBinaryReader.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlFile.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlRecordType.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\BamlRecordType.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\DotNetType.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\IDependencyPropertyDescriptor.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\IDependencyPropertyDescriptor.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\IType.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\IType.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\ITypeResolver.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\ITypeResolver.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\KeyMapping.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\KeyMapping.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\KnownInfo.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\KnownInfo.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\NodesCollection.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\PropertyDeclaration.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\PropertyDeclaration.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\ResourceName.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\ResourceName.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\TypeDeclaration.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\TypeDeclaration.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\WpfDependencyPropertyDescriptor.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlElement.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlElement.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlNode.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlNode.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlProperty.cs" /> <Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlProperty.cs" />

183
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/AppDomainTypeResolver.cs

@ -1,183 +0,0 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Text;
using System.IO;
using System.Linq;
using Microsoft.Win32;
using System.Threading;
using System.Security.Permissions;
using System.Security;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public delegate void AssemblyResolveEventHandler(object s, AssemblyResolveEventArgs e);
public class AppDomainTypeResolver : MarshalByRefObject, ITypeResolver
{
private readonly AppDomain _domain;
private string baseDir;
public event AssemblyResolveEventHandler AssemblyResolve;
public static AppDomainTypeResolver GetIntoNewAppDomain(string baseDir)
{
AppDomainSetup info = new AppDomainSetup();
info.ApplicationBase = Environment.CurrentDirectory;
AppDomain domain = AppDomain.CreateDomain("AppDomainTypeResolver", null, info, new PermissionSet(PermissionState.Unrestricted));
AppDomainTypeResolver resolver = (AppDomainTypeResolver)domain.CreateInstanceAndUnwrap(typeof(AppDomainTypeResolver).Assembly.FullName,
typeof(AppDomainTypeResolver).FullName, false, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, new object[] { domain, baseDir }, null, null, null);
return resolver;
}
Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// Cerco di risolvere automaticamente
AssemblyName name = new AssemblyName(args.Name);
string fileName = Path.Combine(this.baseDir, name.Name + ".exe");
if (!File.Exists(fileName))
fileName = Path.Combine(this.baseDir, name.Name + ".dll");
// Carico il percorso autocalcolato
if (File.Exists(fileName))
return Assembly.LoadFile(fileName);
if (AssemblyResolve != null)
{
AssemblyResolveEventArgs e = new AssemblyResolveEventArgs(args.Name, this.baseDir);
AssemblyResolve(this, e);
if (!String.IsNullOrEmpty(e.Location) && File.Exists(e.Location))
return Assembly.LoadFile(e.Location);
}
return null;
}
public static void DestroyResolver(AppDomainTypeResolver resolver)
{
if (resolver == null) throw new ArgumentNullException("resolver");
ThreadPool.QueueUserWorkItem(delegate
{
AppDomain.Unload(resolver.Domain);
});
}
protected AppDomainTypeResolver(AppDomain domain, string baseDir)
{
_domain = domain;
this.baseDir = baseDir;
domain.AssemblyResolve += new ResolveEventHandler(domain_AssemblyResolve);
}
public BamlAssembly LoadAssembly(AssemblyName asm)
{
//return new BamlAssembly(Assembly.Load(asm));
return new BamlAssembly(_domain.Load(asm));
}
public BamlAssembly LoadAssembly(string location)
{
Assembly asm = Assembly.LoadFile(location);
return new BamlAssembly(asm);
//return _domain.Load(System.IO.File.ReadAllBytes(location));
//return Assembly.LoadFrom(location);
}
public BamlAssembly[] GetReferencedAssemblies(BamlAssembly asm)
{
AssemblyName[] list = asm.Assembly.GetReferencedAssemblies();
return (from an in list
select this.LoadAssembly(an)).ToArray();
}
public AppDomain Domain
{
get { return _domain; }
}
#region ITypeResolver Members
public IType GetTypeByAssemblyQualifiedName(string name)
{
return new DotNetType(name);
}
public IDependencyPropertyDescriptor GetDependencyPropertyDescriptor(string name, IType ownerType, IType targetType)
{
if (name == null) throw new ArgumentNullException("name");
if (ownerType == null) throw new ArgumentNullException("ownerType");
if (targetType == null) throw new ArgumentNullException("targetType");
Type dOwnerType = ((DotNetType)ownerType).Type;
Type dTargetType = ((DotNetType)targetType).Type;
try
{
DependencyPropertyDescriptor propertyDescriptor = DependencyPropertyDescriptor.FromName(name, dOwnerType, dTargetType);
if (propertyDescriptor != null)
return new WpfDependencyPropertyDescriptor(propertyDescriptor);
return null;
}
catch (Exception)
{
return null;
}
}
public bool IsLocalAssembly(string name)
{
return false;
}
public string RuntimeVersion {
get {
throw new NotImplementedException();
}
}
#endregion
public override object InitializeLifetimeService()
{
return null;
}
}
public class AssemblyResolveEventArgs : MarshalByRefObject
{
private string _location;
private string _name;
private string _baseDir;
public AssemblyResolveEventArgs(string name, string baseDir)
{
_name = name;
_baseDir = baseDir;
}
public string Location
{
get { return _location; }
set { _location = value; }
}
public string Name
{
get { return _name; }
}
public string BaseDir
{
get { return _baseDir; }
}
}
}

112
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlAssembly.cs

@ -1,112 +0,0 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public class BamlAssembly : MarshalByRefObject
{
private readonly string _filePath;
private Assembly _assembly;
private BamlFileList _bamlFile;
public BamlAssembly(Assembly assembly)
{
_assembly = assembly;
_filePath = assembly.CodeBase;
ReadBaml();
}
public BamlAssembly(string filePath)
{
this._filePath = Path.GetFullPath(filePath);
this._assembly = Assembly.LoadFile(this.FilePath);
if (String.Compare(this.Assembly.CodeBase, this.FilePath, true) != 0)
throw new ArgumentException("Cannot load filePath because Assembly is already loaded", "filePath");
ReadBaml();
}
private void ReadBaml()
{
// Get available names
string[] resources = this.Assembly.GetManifestResourceNames();
foreach (string res in resources)
{
// Solo le risorse
if (String.Compare(Path.GetExtension(res), ".resources", true) != 0) continue;
// Get stream
using (Stream stream = this.Assembly.GetManifestResourceStream(res))
{
try
{
ResourceReader reader = new ResourceReader(stream);
foreach (DictionaryEntry entry in reader)
{
if (String.Compare(Path.GetExtension(entry.Key.ToString()), ".baml", true) == 0 && entry.Value is Stream)
{
BamlFile bm = new BamlFile(GetAssemblyResourceUri(entry.Key.ToString()), (Stream)entry.Value);
this.BamlFiles.Add(bm);
}
}
}
catch (ArgumentException)
{}
}
}
}
private Uri GetAssemblyResourceUri(string resourceName)
{
AssemblyName asm = this.Assembly.GetName();
byte[] data = asm.GetPublicKeyToken();
StringBuilder token = new StringBuilder(data.Length * 2);
for (int x = 0; x < data.Length; x++)
{
token.Append(data[x].ToString("x", System.Globalization.CultureInfo.InvariantCulture));
}
return new Uri(String.Format(@"{0};V{1};{2};component\{3}", asm.Name, asm.Version, token, Path.ChangeExtension(resourceName, ".xaml")), UriKind.RelativeOrAbsolute);
}
public string FilePath
{
get { return _filePath; }
}
public Assembly Assembly
{
get { return _assembly; }
}
public BamlFileList BamlFiles
{
get
{
if (_bamlFile == null)
_bamlFile = new BamlFileList();
return _bamlFile;
}
}
public override object InitializeLifetimeService()
{
return null;
}
}
[Serializable()]
public class BamlFileList : Collection<BamlFile>
{}
}

80
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlFile.cs

@ -1,80 +0,0 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Resources;
using System.Text;
using System.Windows;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
/// <summary>
/// Rappresenta un singole file Baml all'interno di un assembly
/// </summary>
public class BamlFile : Component
{
private Uri _uri;
private readonly Stream _stream;
public BamlFile(Uri uri, Stream stream)
{
if (uri == null)
new ArgumentNullException("uri");
if (stream == null)
throw new ArgumentNullException("stream");
_uri = uri;
_stream = stream;
}
/// <summary>
/// Carica il Baml attraverso il motore di WPF con Application.LoadComponent
/// </summary>
/// <returns></returns>
public object LoadContent()
{
try
{
return Application.LoadComponent(this.Uri);
}
catch (Exception e)
{
throw new InvalidOperationException("Invalid baml file.", e);
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
this.Stream.Dispose();
}
public override object InitializeLifetimeService()
{
return null;
}
/// <summary>
/// Restituisce lo stream originale contenente il Baml
/// </summary>
public Stream Stream
{
get { return _stream; }
}
/// <summary>
/// Restituisce l'indirizzo secondo lo schema pack://
/// </summary>
public Uri Uri
{
get { return _uri; }
}
}
}

64
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/DotNetType.cs

@ -1,64 +0,0 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public class DotNetType : MarshalByRefObject, IType
{
private readonly string _assemblyQualifiedName;
private Type _type;
public DotNetType(string assemblyQualifiedName)
{
if (assemblyQualifiedName == null) throw new ArgumentNullException("assemblyQualifiedName");
_assemblyQualifiedName = assemblyQualifiedName;
_type = Type.GetType(assemblyQualifiedName, false, true);
}
#region IType Members
public string AssemblyQualifiedName
{
get { return _assemblyQualifiedName; }
}
public bool IsSubclassOf(IType type)
{
if (type == null) throw new ArgumentNullException("type");
if (!(type is DotNetType)) throw new ArgumentException("type");
if (_type == null) return false;
return this._type.IsSubclassOf(((DotNetType)type).Type);
}
public bool Equals(IType type)
{
if (type == null) throw new ArgumentNullException("type");
if (!(type is DotNetType)) throw new ArgumentException("type");
if (_type == null) return false;
return this._type.Equals(((DotNetType)type).Type);
}
public IType BaseType {
get {
return new DotNetType(this._type.BaseType.AssemblyQualifiedName);
}
}
#endregion
public Type Type
{
get { return _type; }
}
public override object InitializeLifetimeService()
{
return null;
}
}
}

6
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KeyMapping.cs

@ -36,5 +36,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
this.staticResources = new List<object>(); this.staticResources = new List<object>();
this.Position = -1; this.Position = -1;
} }
public override string ToString()
{
return '"' + KeyString + '"';
}
} }
} }

4
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KnownInfo.cs

@ -58,7 +58,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
KnownTypeTable[9] = new TypeDeclaration(resolver, "Animatable", "System.Windows.Media.Animaton", 1); KnownTypeTable[9] = new TypeDeclaration(resolver, "Animatable", "System.Windows.Media.Animaton", 1);
KnownTypeTable[10] = new TypeDeclaration(resolver, "AnimationClock", "System.Windows.Media.Animation", 1); KnownTypeTable[10] = new TypeDeclaration(resolver, "AnimationClock", "System.Windows.Media.Animation", 1);
KnownTypeTable[11] = new TypeDeclaration(resolver, "AnimationTimeline", "System.Windows.Media.Animation", 1); KnownTypeTable[11] = new TypeDeclaration(resolver, "AnimationTimeline", "System.Windows.Media.Animation", 1);
KnownTypeTable[12] = new TypeDeclaration(resolver, "Application", "System.Net.Mime", 3); KnownTypeTable[12] = new TypeDeclaration(resolver, "Application", "System.Windows", 0);
KnownTypeTable[13] = new TypeDeclaration(resolver, "ArcSegment", "System.Windows.Media", 1); KnownTypeTable[13] = new TypeDeclaration(resolver, "ArcSegment", "System.Windows.Media", 1);
KnownTypeTable[14] = new TypeDeclaration(resolver, "ArrayExtension", "System.Windows.Markup", 0); KnownTypeTable[14] = new TypeDeclaration(resolver, "ArrayExtension", "System.Windows.Markup", 0);
KnownTypeTable[15] = new TypeDeclaration(resolver, "AxisAngleRotation3D", "System.Windows.Media.Media3D", 1); KnownTypeTable[15] = new TypeDeclaration(resolver, "AxisAngleRotation3D", "System.Windows.Media.Media3D", 1);
@ -127,7 +127,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
KnownTypeTable[0x4e] = new TypeDeclaration(resolver, "CollectionContainer", "System.Windows.Data", 0); KnownTypeTable[0x4e] = new TypeDeclaration(resolver, "CollectionContainer", "System.Windows.Data", 0);
KnownTypeTable[0x4f] = new TypeDeclaration(resolver, "CollectionView", "System.Windows.Data", 0); KnownTypeTable[0x4f] = new TypeDeclaration(resolver, "CollectionView", "System.Windows.Data", 0);
KnownTypeTable[80] = new TypeDeclaration(resolver, "CollectionViewSource", "System.Windows.Data", 0); KnownTypeTable[80] = new TypeDeclaration(resolver, "CollectionViewSource", "System.Windows.Data", 0);
KnownTypeTable[0x51] = new TypeDeclaration(resolver, "Color", "Microsoft.Win32", 2); KnownTypeTable[0x51] = new TypeDeclaration(resolver, "Color", "Win32Native", "Microsoft.Win32", 2);
KnownTypeTable[0x52] = new TypeDeclaration(resolver, "ColorAnimation", "System.Windows.Media.Animation", 1); KnownTypeTable[0x52] = new TypeDeclaration(resolver, "ColorAnimation", "System.Windows.Media.Animation", 1);
KnownTypeTable[0x53] = new TypeDeclaration(resolver, "ColorAnimationBase", "System.Windows.Media.Animation", 1); KnownTypeTable[0x53] = new TypeDeclaration(resolver, "ColorAnimationBase", "System.Windows.Media.Animation", 1);
KnownTypeTable[0x54] = new TypeDeclaration(resolver, "ColorAnimationUsingKeyFrames", "System.Windows.Media.Animation", 1); KnownTypeTable[0x54] = new TypeDeclaration(resolver, "ColorAnimationUsingKeyFrames", "System.Windows.Media.Animation", 1);

68
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/NodesCollection.cs

@ -0,0 +1,68 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Windows.Media;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
class NodesCollection : List<XmlBamlNode>
{
public XmlBamlNode Last
{
get
{
if (this.Count > 0)
{
int i = this.Count - 1;
return this[i];
}
return null;
}
}
public void RemoveLast()
{
if (this.Count > 0)
this.Remove(this.Last);
}
public XmlBamlNode Dequeue()
{
return DequeueInternal(true);
}
public XmlBamlNode Peek()
{
return DequeueInternal(false);
}
XmlBamlNode DequeueInternal(bool remove)
{
if (this.Count > 0)
{
XmlBamlNode node = this[0];
if (remove)
this.RemoveAt(0);
return node;
}
else
return null;
}
public void Enqueue(XmlBamlNode node)
{
this.Add(node);
}
}
}

80
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs

@ -8,11 +8,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
internal class TypeDeclaration internal class TypeDeclaration
{ {
private readonly XmlBamlReader reader; private readonly XmlBamlReader reader;
private readonly short _assemblyId;
private readonly bool _isKnown;
private readonly string _name;
private readonly string _namespaceName;
private readonly bool _isExtension; private readonly bool _isExtension;
private IType _type; private IType _type;
private bool _typeLoaded; private bool _typeLoaded;
@ -21,7 +16,12 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
public TypeDeclaration(ITypeResolver resolver, string name, string namespaceName, short assemblyId) public TypeDeclaration(ITypeResolver resolver, string name, string namespaceName, short assemblyId)
: this(null, resolver, name, namespaceName, assemblyId, true) : this(null, resolver, name, namespaceName, assemblyId, true)
{ {
}
public TypeDeclaration(ITypeResolver resolver, string name, string enclosingTypeName, string namespaceName, short assemblyId)
: this(null, resolver, name, namespaceName, assemblyId, true)
{
this.EnclosingTypeName = enclosingTypeName;
} }
public TypeDeclaration(ITypeResolver resolver, string name, string namespaceName, short assemblyId, bool isExtension) public TypeDeclaration(ITypeResolver resolver, string name, string namespaceName, short assemblyId, bool isExtension)
@ -39,10 +39,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
{ {
this.reader = reader; this.reader = reader;
this.resolver = resolver; this.resolver = resolver;
this._name = name; this.Name = name;
this._namespaceName = namespaceName; this.Namespace = namespaceName;
this._assemblyId = assemblyId; this.AssemblyId = assemblyId;
this._isKnown = isKnown; this.IsKnown = isKnown;
if (!_isExtension) if (!_isExtension)
_isExtension = name.EndsWith("Extension"); _isExtension = name.EndsWith("Extension");
@ -50,8 +50,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
public override string ToString() public override string ToString()
{ {
return this._name; return this.Name;
} }
public string EnclosingTypeName { get; private set; }
public bool IsExtension public bool IsExtension
{ {
@ -60,8 +62,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
public string Assembly public string Assembly
{ {
get get {
{
if (reader != null) if (reader != null)
return this.reader.GetAssembly(this.AssemblyId); return this.reader.GetAssembly(this.AssemblyId);
else else
@ -69,46 +70,19 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
} }
} }
public short AssemblyId public short AssemblyId { get; private set; }
{
get { return _assemblyId; }
}
public string Name public string Name { get; private set; }
{
get
{
return this._name;
}
}
public bool IsKnown public bool IsKnown { get; private set; }
{
get { return _isKnown; }
}
//public Type DotNetType public IType Type {
//{
// get
// {
// if (!_typeLoaded)
// {
// _type = Type.GetType(String.Format("{0}.{1}, {2}", this.Namespace, this.Name, this.Assembly), false, true);
// _typeLoaded = true;
// }
// return _type;
// }
//}
public IType Type
{
get get
{ {
if (!_typeLoaded) if (!_typeLoaded)
{ {
if (this.Name.Length > 0) if (this.Name.Length > 0)
_type = resolver.GetTypeByAssemblyQualifiedName(String.Format("{0}.{1}, {2}", this.Namespace, this.Name, this.Assembly)); _type = resolver.GetTypeByAssemblyQualifiedName(AssemblyQualifiedName);
_typeLoaded = true; _typeLoaded = true;
} }
@ -116,26 +90,28 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
} }
} }
public string Namespace public string Namespace { get; private set; }
{
get public string FullyQualifiedName {
{ get { return EnclosingTypeName == null ? string.Format("{0}.{1}", Namespace, Name) : string.Format("{0}.{1}+{2}", Namespace, EnclosingTypeName, Name); }
return this._namespaceName; }
}
public string AssemblyQualifiedName {
get { return string.Format("{0}, {1}", FullyQualifiedName, Assembly); }
} }
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
TypeDeclaration td = obj as TypeDeclaration; TypeDeclaration td = obj as TypeDeclaration;
if (td != null) if (td != null)
return (this.Name == td.Name && this.Namespace == td.Namespace && this.AssemblyId == td.AssemblyId); return (this.Name == td.Name && this.EnclosingTypeName == td.EnclosingTypeName && this.Namespace == td.Namespace && this.AssemblyId == td.AssemblyId);
else else
return false; return false;
} }
public override int GetHashCode() public override int GetHashCode()
{ {
return this.AssemblyId ^ this.Name.GetHashCode() ^ this.Namespace.GetHashCode(); return this.AssemblyId ^ this.Name.GetHashCode() ^ this.EnclosingTypeName.GetHashCode() ^ this.Namespace.GetHashCode();
} }
} }

35
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/WpfDependencyPropertyDescriptor.cs

@ -1,35 +0,0 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
public class WpfDependencyPropertyDescriptor : MarshalByRefObject, IDependencyPropertyDescriptor
{
private readonly DependencyPropertyDescriptor _propertyDescriptor;
public WpfDependencyPropertyDescriptor(DependencyPropertyDescriptor propertyDescriptor)
{
if (propertyDescriptor == null) throw new ArgumentNullException("propertyDescriptor");
_propertyDescriptor = propertyDescriptor;
}
#region IDependencyPropertyDescriptor Members
public bool IsAttached
{
get { return _propertyDescriptor.IsAttached; }
}
#endregion
public override object InitializeLifetimeService()
{
return null;
}
}
}

19
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlElement.cs

@ -23,8 +23,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
this.Namespaces.AddRange(parent.Namespaces); this.Namespaces.AddRange(parent.Namespaces);
} }
public XmlNamespaceCollection Namespaces public XmlNamespaceCollection Namespaces {
{
get { return _namespaces; } get { return _namespaces; }
} }
@ -42,11 +41,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
public override string ToString() public override string ToString()
{ {
return String.Format("Element: {0}", TypeDeclaration.Name); return string.Format("Element: {0}", TypeDeclaration.Name);
} }
} }
internal class XmlBamlEndElement : XmlBamlElement class XmlBamlEndElement : XmlBamlElement
{ {
public XmlBamlEndElement(XmlBamlElement start) public XmlBamlEndElement(XmlBamlElement start)
{ {
@ -54,19 +53,13 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
this.Namespaces.AddRange(start.Namespaces); this.Namespaces.AddRange(start.Namespaces);
} }
public override XmlNodeType NodeType public override XmlNodeType NodeType {
{ get { return XmlNodeType.EndElement; }
get
{
return XmlNodeType.EndElement;
}
} }
public override string ToString() public override string ToString()
{ {
return String.Format("EndElement: {0}", TypeDeclaration.Name); return string.Format("EndElement: {0}", TypeDeclaration.Name);
} }
} }
} }

2
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlPropertyElement.cs

@ -41,7 +41,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
public override string ToString() public override string ToString()
{ {
return String.Format("PropertyElement: {0}.{1}", TypeDeclaration.Name, PropertyDeclaration.Name); return String.Format("PropertyElement: {0}.{1}", TypeDeclaration.Name.Replace('+', '.'), PropertyDeclaration.Name);
} }
} }
} }

210
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs

@ -41,9 +41,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
bool intoAttribute = false; bool intoAttribute = false;
bool initialized; bool initialized;
bool _eof; bool _eof;
bool isPartialDefKeysClosed = true;
bool isDefKeysClosed = true;
#region Context #region Context
Stack<ReaderContext> layer = new Stack<ReaderContext>(); Stack<ReaderContext> layer = new Stack<ReaderContext>();
@ -79,13 +76,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
List<KeyMapping> keys = new List<KeyMapping>(); List<KeyMapping> keys = new List<KeyMapping>();
KeyMapping LastKey { KeyMapping LastKey {
get { get { return keys.LastOrDefault(); }
KeyMapping last = keys.LastOrDefault();
if (last == null)
keys.Add(last = new KeyMapping());
return last;
}
} }
void LayerPop() void LayerPop()
@ -112,11 +103,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
public const string XWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml"; public const string XWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml";
public const string DefaultWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; public const string DefaultWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
public XmlBamlReader(Stream stream) : this (stream, AppDomainTypeResolver.GetIntoNewAppDomain(Environment.CurrentDirectory))
{
}
public XmlBamlReader(Stream stream, ITypeResolver resolver) public XmlBamlReader(Stream stream, ITypeResolver resolver)
{ {
if (stream == null) if (stream == null)
@ -339,7 +325,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
else else
currentType = (BamlRecordType)type; currentType = (BamlRecordType)type;
if (currentType.ToString().EndsWith("End"))
Debug.Unindent();
Debug.WriteLine(string.Format("{0} (0x{0:x})", currentType)); Debug.WriteLine(string.Format("{0} (0x{0:x})", currentType));
if (currentType.ToString().EndsWith("Start"))
Debug.Indent();
} }
bool SetNextNode() bool SetNextNode()
@ -402,6 +392,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
break; break;
case BamlRecordType.DeferableContentStart: case BamlRecordType.DeferableContentStart:
Current.IsDeferred = true; Current.IsDeferred = true;
keys = new List<KeyMapping>();
currentKey = 0;
reader.ReadInt32(); reader.ReadInt32();
break; break;
case BamlRecordType.DefAttribute: case BamlRecordType.DefAttribute:
@ -637,9 +629,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
{ {
get get
{ {
if (intoAttribute) return String.Empty; if (intoAttribute) return string.Empty;
String localName = String.Empty; String localName = string.Empty;
XmlBamlNode node = this.CurrentNode; XmlBamlNode node = this.CurrentNode;
if (node is XmlBamlSimpleProperty) { if (node is XmlBamlSimpleProperty) {
@ -689,13 +681,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
object GetResourceName(short identifier) object GetResourceName(short identifier)
{ {
if (identifier >= 0) if (identifier >= 0) {
{
PropertyDeclaration declaration = this.propertyTable[identifier]; PropertyDeclaration declaration = this.propertyTable[identifier];
return declaration; return declaration;
} } else {
else
{
identifier = (short)-identifier; identifier = (short)-identifier;
bool isNotKey = (identifier > 0xe8); bool isNotKey = (identifier > 0xe8);
if (isNotKey) if (isNotKey)
@ -998,6 +987,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
bool sharedSet = reader.ReadBoolean(); bool sharedSet = reader.ReadBoolean();
string text = this.stringTable[stringId]; string text = this.stringTable[stringId];
Debug.Print("KeyString: " + text);
if (text == null) if (text == null)
throw new NotSupportedException(); throw new NotSupportedException();
@ -1039,6 +1029,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
void ReadElementEnd() void ReadElementEnd()
{ {
CloseElement(); CloseElement();
if (Current.IsDeferred)
keys = null;
LayerPop(); LayerPop();
} }
@ -1095,12 +1087,12 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
// this property could be a markup extension // this property could be a markup extension
// try to convert it // try to convert it
int start = nodes.IndexOf(propertyElement) + 1; int start = nodes.IndexOf(propertyElement) + 1;
IEnumerator enumerator = nodes.GetEnumerator(); IEnumerator<XmlBamlNode> enumerator = nodes.GetEnumerator();
// move enumerator to the start of this property value // move enumerator to the start of this property value
for (int i = 0; i < start && enumerator.MoveNext(); i++) ; for (int i = 0; i < start && enumerator.MoveNext(); i++) ;
if (IsExtension(enumerator)) { if (IsExtension(enumerator) && start < nodes.Count - 1) {
start--; start--;
nodes.RemoveAt(start); nodes.RemoveAt(start);
nodes.RemoveLast(); nodes.RemoveLast();
@ -1173,11 +1165,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
} }
} }
bool IsExtension(IEnumerator enumerator) bool IsExtension(IEnumerator<XmlBamlNode> enumerator)
{ {
while (enumerator.MoveNext()) { while (enumerator.MoveNext()) {
object node = enumerator.Current; var node = enumerator.Current;
if (node is XmlBamlElement && !(node is XmlBamlEndElement) && !((XmlBamlElement)node).TypeDeclaration.IsExtension) if (node.NodeType == XmlNodeType.Element && !((XmlBamlElement)node).TypeDeclaration.IsExtension)
return false; return false;
} }
@ -1231,7 +1223,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
nodes.Enqueue(element); nodes.Enqueue(element);
if (oldDeclaration != null) { if (oldDeclaration != null) {
nodes.Enqueue(new XmlBamlSimpleProperty(XWPFNamespace, "Class", string.Format("{0}.{1}", oldDeclaration.Namespace, oldDeclaration.Name))); nodes.Enqueue(new XmlBamlSimpleProperty(XWPFNamespace, "Class", oldDeclaration.FullyQualifiedName.Replace('+', '.')));
} }
if (parentElement != null && complexPropertyOpened == 0 && !Current.IsInStaticResource && Current.Previous.IsDeferred) { if (parentElement != null && complexPropertyOpened == 0 && !Current.IsInStaticResource && Current.Previous.IsDeferred) {
@ -1342,9 +1334,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
CloseElement(); CloseElement();
complexPropertyOpened--; complexPropertyOpened--;
if (complexPropertyOpened == 0) if (complexPropertyOpened == 0) {
{
int start = nodes.IndexOf(propertyElement); int start = nodes.IndexOf(propertyElement);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -1409,27 +1399,26 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
void ReadOptimizedStaticResource() void ReadOptimizedStaticResource()
{ {
byte num = reader.ReadByte(); byte flags = reader.ReadByte();
short typeIdentifier = reader.ReadInt16(); short typeIdentifier = reader.ReadInt16();
bool isValueType = (num & 1) == 1; bool isValueType = (flags & 1) == 1;
bool isStaticType = (num & 2) == 2; bool isStaticType = (flags & 2) == 2;
object resource; object resource;
if (isValueType) if (isValueType)
resource = this.GetTypeExtension(typeIdentifier); resource = GetTypeExtension(typeIdentifier);
else if (isStaticType) else if (isStaticType) {
{ object name = GetResourceName(typeIdentifier);
ResourceName resourceName = (ResourceName)this.GetResourceName(typeIdentifier); if (name is ResourceName)
resource = GetStaticExtension(resourceName.Name); resource = GetStaticExtension(((ResourceName)name).Name);
} else if (name is PropertyDeclaration)
else resource = GetStaticExtension(FormatPropertyDeclaration(((PropertyDeclaration)name), true, false, false));
{ else
throw new InvalidOperationException("Invalid resource: " + name.GetType());
} else {
resource = this.stringTable[typeIdentifier]; resource = this.stringTable[typeIdentifier];
} }
//this.staticResourceTable.Add(resource);
isPartialDefKeysClosed = true;
// Aggiungo la risorsa nell'ultimo gruppo
LastKey.StaticResources.Add(resource); LastKey.StaticResources.Add(resource);
} }
@ -1474,8 +1463,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
return String.Format("{0}:{1}", prefix, name); return String.Format("{0}:{1}", prefix, name);
} }
string FormatPropertyDeclaration(PropertyDeclaration propertyDeclaration, bool withPrefix, bool useReading, bool checkType) string FormatPropertyDeclaration(PropertyDeclaration propertyDeclaration, bool withPrefix, bool useReading, bool checkType)
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -1511,11 +1498,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
void ReadPropertyWithStaticResourceIdentifier() void ReadPropertyWithStaticResourceIdentifier()
{ {
short identifier = reader.ReadInt16(); short propertyId = reader.ReadInt16();
short staticIdentifier = reader.ReadInt16(); short index = reader.ReadInt16();
PropertyDeclaration pd = this.GetPropertyDeclaration(identifier); PropertyDeclaration pd = this.GetPropertyDeclaration(propertyId);
object staticResource = GetStaticResource(staticIdentifier); object staticResource = GetStaticResource(index);
string prefix = this.LookupPrefix(XmlPIMapping.PresentationNamespace, false); string prefix = this.LookupPrefix(XmlPIMapping.PresentationNamespace, false);
string value = String.Format("{{{0}{1}StaticResource {2}}}", prefix, (String.IsNullOrEmpty(prefix)) ? String.Empty : ":", staticResource); string value = String.Format("{{{0}{1}StaticResource {2}}}", prefix, (String.IsNullOrEmpty(prefix)) ? String.Empty : ":", staticResource);
@ -1528,10 +1515,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
object GetStaticResource(short identifier) object GetStaticResource(short identifier)
{ {
if (identifier < LastKey.StaticResources.Count) if (identifier < keys[currentKey - 1].StaticResources.Count)
return LastKey.StaticResources[(int)identifier]; return keys[currentKey - 1].StaticResources[(int)identifier];
// return "???" + identifier +"???"; // return "???" + identifier + "???";
throw new ArgumentException("Cannot find StaticResource", "identifier"); throw new ArgumentException("Cannot find StaticResource", "identifier");
} }
@ -1595,11 +1582,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
TypeDeclaration GetKnownTypeDeclarationByName(string name) TypeDeclaration GetKnownTypeDeclarationByName(string name)
{ {
foreach (var type in KnownInfo.KnownTypeTable) { foreach (var type in KnownInfo.KnownTypeTable) {
if (name == string.Format("{0}.{1}, {2}", type.Namespace, type.Name, type.Assembly)) if (name == type.AssemblyQualifiedName)
return type; return type;
} }
throw new NotSupportedException(); throw new NotSupportedException("Type '" + name + "' not found!");
} }
internal string GetAssembly(short identifier) internal string GetAssembly(short identifier)
@ -1607,26 +1594,18 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
return this.assemblyTable[identifier]; return this.assemblyTable[identifier];
} }
XmlBamlNode CurrentNode XmlBamlNode CurrentNode {
{ get { return _currentNode; }
get
{
return _currentNode;
}
} }
///<summary> ///<summary>
///When overridden in a derived class, gets the namespace URI (as defined in the W3C Namespace specification) of the node on which the reader is positioned. ///When overridden in a derived class, gets the namespace URI (as defined in the W3C Namespace specification) of the node on which the reader is positioned.
///</summary> ///</summary>
///
///<returns> ///<returns>
///The namespace URI of the current node; otherwise an empty string. ///The namespace URI of the current node; otherwise an empty string.
///</returns> ///</returns>
/// public override string NamespaceURI {
public override string NamespaceURI get {
{
get
{
if (intoAttribute) return String.Empty; if (intoAttribute) return String.Empty;
TypeDeclaration declaration; TypeDeclaration declaration;
@ -1664,11 +1643,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
///<summary> ///<summary>
///When overridden in a derived class, gets the namespace prefix associated with the current node. ///When overridden in a derived class, gets the namespace prefix associated with the current node.
///</summary> ///</summary>
///
///<returns> ///<returns>
///The namespace prefix associated with the current node. ///The namespace prefix associated with the current node.
///</returns> ///</returns>
///
public override string Prefix public override string Prefix
{ {
get get
@ -1682,11 +1659,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
///<summary> ///<summary>
///When overridden in a derived class, gets a value indicating whether the current node can have a <see cref="P:System.Xml.XmlReader.Value"></see>. ///When overridden in a derived class, gets a value indicating whether the current node can have a <see cref="P:System.Xml.XmlReader.Value"></see>.
///</summary> ///</summary>
///
///<returns> ///<returns>
///true if the node on which the reader is currently positioned can have a Value; otherwise, false. If false, the node has a value of String.Empty. ///true if the node on which the reader is currently positioned can have a Value; otherwise, false. If false, the node has a value of String.Empty.
///</returns> ///</returns>
///
public override bool HasValue public override bool HasValue
{ {
get { return this.Value != null; } get { return this.Value != null; }
@ -1703,11 +1678,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
///<summary> ///<summary>
///When overridden in a derived class, gets the text value of the current node. ///When overridden in a derived class, gets the text value of the current node.
///</summary> ///</summary>
///
///<returns> ///<returns>
///The value returned depends on the <see cref="P:System.Xml.XmlReader.NodeType"></see> of the node. The following table lists node types that have a value to return. All other node types return String.Empty.Node type Value AttributeThe value of the attribute. CDATAThe content of the CDATA section. CommentThe content of the comment. DocumentTypeThe internal subset. ProcessingInstructionThe entire content, excluding the target. SignificantWhitespaceThe white space between markup in a mixed content model. TextThe content of the text node. WhitespaceThe white space between markup. XmlDeclarationThe content of the declaration. ///The value returned depends on the <see cref="P:System.Xml.XmlReader.NodeType"></see> of the node. The following table lists node types that have a value to return. All other node types return String.Empty.Node type Value AttributeThe value of the attribute. CDATAThe content of the CDATA section. CommentThe content of the comment. DocumentTypeThe internal subset. ProcessingInstructionThe entire content, excluding the target. SignificantWhitespaceThe white space between markup in a mixed content model. TextThe content of the text node. WhitespaceThe white space between markup. XmlDeclarationThe content of the declaration.
///</returns> ///</returns>
///
public override string Value public override string Value
{ {
get get
@ -1737,11 +1710,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
///<summary> ///<summary>
///When overridden in a derived class, gets the depth of the current node in the XML document. ///When overridden in a derived class, gets the depth of the current node in the XML document.
///</summary> ///</summary>
///
///<returns> ///<returns>
///The depth of the current node in the XML document. ///The depth of the current node in the XML document.
///</returns> ///</returns>
///
public override int Depth public override int Depth
{ {
get { return this.readingElements.Count; } get { return this.readingElements.Count; }
@ -1750,11 +1721,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
///<summary> ///<summary>
///When overridden in a derived class, gets the base URI of the current node. ///When overridden in a derived class, gets the base URI of the current node.
///</summary> ///</summary>
///
///<returns> ///<returns>
///The base URI of the current node. ///The base URI of the current node.
///</returns> ///</returns>
///
public override string BaseURI public override string BaseURI
{ {
get { return String.Empty; } get { return String.Empty; }
@ -1763,62 +1732,42 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
///<summary> ///<summary>
///When overridden in a derived class, gets a value indicating whether the current node is an empty element (for example, &lt;MyElement/&gt;). ///When overridden in a derived class, gets a value indicating whether the current node is an empty element (for example, &lt;MyElement/&gt;).
///</summary> ///</summary>
///
///<returns> ///<returns>
///true if the current node is an element (<see cref="P:System.Xml.XmlReader.NodeType"></see> equals XmlNodeType.Element) that ends with /&gt;; otherwise, false. ///true if the current node is an element (<see cref="P:System.Xml.XmlReader.NodeType"></see> equals XmlNodeType.Element) that ends with /&gt;; otherwise, false.
///</returns> ///</returns>
///
public override bool IsEmptyElement public override bool IsEmptyElement
{ {
get { return false; } get { return false; }
} }
//public override bool IsDefault
//{
// get
// {
// return this.NamespaceURI == null;
// }
//}
///<summary> ///<summary>
///When overridden in a derived class, gets the number of attributes on the current node. ///When overridden in a derived class, gets the number of attributes on the current node.
///</summary> ///</summary>
///
///<returns> ///<returns>
///The number of attributes on the current node. ///The number of attributes on the current node.
///</returns> ///</returns>
/// public override int AttributeCount {
public override int AttributeCount
{
get { throw new NotImplementedException(); } get { throw new NotImplementedException(); }
} }
///<summary> ///<summary>
///When overridden in a derived class, gets a value indicating whether the reader is positioned at the end of the stream. ///When overridden in a derived class, gets a value indicating whether the reader is positioned at the end of the stream.
///</summary> ///</summary>
///
///<returns> ///<returns>
///true if the reader is positioned at the end of the stream; otherwise, false. ///true if the reader is positioned at the end of the stream; otherwise, false.
///</returns> ///</returns>
/// public override bool EOF {
public override bool EOF
{
get { return _eof; } get { return _eof; }
} }
///<summary> ///<summary>
///When overridden in a derived class, gets the state of the reader. ///When overridden in a derived class, gets the state of the reader.
///</summary> ///</summary>
///
///<returns> ///<returns>
///One of the <see cref="T:System.Xml.ReadState"></see> values. ///One of the <see cref="T:System.Xml.ReadState"></see> values.
///</returns> ///</returns>
/// public override ReadState ReadState {
public override ReadState ReadState get {
{
get
{
if (!initialized) if (!initialized)
return ReadState.Initial; return ReadState.Initial;
else if (reader == null) else if (reader == null)
@ -1838,11 +1787,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
///<summary> ///<summary>
///When overridden in a derived class, gets the <see cref="T:System.Xml.XmlNameTable"></see> associated with this implementation. ///When overridden in a derived class, gets the <see cref="T:System.Xml.XmlNameTable"></see> associated with this implementation.
///</summary> ///</summary>
///
///<returns> ///<returns>
///The XmlNameTable enabling you to get the atomized version of a string within the node. ///The XmlNameTable enabling you to get the atomized version of a string within the node.
///</returns> ///</returns>
///
public override XmlNameTable NameTable public override XmlNameTable NameTable
{ {
get { return _nameTable; } get { return _nameTable; }
@ -1938,60 +1885,5 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
} }
#endregion #endregion
#region NodesCollection
internal class NodesCollection : List<XmlBamlNode>
{
public XmlBamlNode Last
{
get
{
if (this.Count > 0)
{
int i = this.Count - 1;
return this[i];
}
return null;
}
}
public void RemoveLast()
{
if (this.Count > 0)
this.Remove(this.Last);
}
public XmlBamlNode Dequeue()
{
return DequeueInternal(true);
}
public XmlBamlNode Peek()
{
return DequeueInternal(false);
}
XmlBamlNode DequeueInternal(bool remove)
{
if (this.Count > 0)
{
XmlBamlNode node = this[0];
if (remove)
this.RemoveAt(0);
return node;
}
else
return null;
}
public void Enqueue(XmlBamlNode node)
{
this.Add(node);
}
}
#endregion
} }
} }

23
ILSpy.BamlDecompiler/Tests/Cases/Dictionary1.xaml

@ -0,0 +1,23 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Color x:Key="VeryDark" A="255" R="70" G="70" B="70" />
<Color x:Key="Dark" A="255" R="102" G="102" B="102" />
<Color x:Key="Medium" A="255" R="140" G="140" B="140" />
<Color x:Key="Light" A="255" R="204" G="204" B="204" />
<Color x:Key="VeryLight" A="255" R="241" G="241" B="241" />
<Color x:Key="OffWhite" A="255" R="255" G="255" B="255" />
<Color x:Key="Highlight" A="255" R="220" G="107" B="47" />
<SolidColorBrush x:Key="VeryDarkBrush" Color="{StaticResource VeryDark}" />
<SolidColorBrush x:Key="DarkBrush" Color="{StaticResource Dark}" />
<SolidColorBrush x:Key="MediumBrush" Color="{StaticResource Medium}" />
<SolidColorBrush x:Key="LightBrush" Color="{StaticResource Light}" />
<SolidColorBrush x:Key="VeryLightBrush" Color="{StaticResource VeryLight}" />
<SolidColorBrush x:Key="OffWhiteBrush" Color="{StaticResource OffWhite}" />
<SolidColorBrush x:Key="HighlightBrush" Color="{StaticResource Highlight}" />
<LinearGradientBrush x:Key="EdgeBorder" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#0000" Offset="0" />
<GradientStop Color="#1000" Offset="0.65" />
<GradientStop Color="#3000" Offset="1" />
</LinearGradientBrush>
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#6FFF" />
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="{StaticResource Light}" />
</ResourceDictionary>

1
ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj

@ -128,6 +128,7 @@
</Page> </Page>
<Page Include="Cases\SimpleDictionary.xaml" /> <Page Include="Cases\SimpleDictionary.xaml" />
<Page Include="Cases\SimpleNames.xaml" /> <Page Include="Cases\SimpleNames.xaml" />
<Page Include="Cases\Dictionary1.xaml" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project> </Project>

17
ILSpy.BamlDecompiler/Tests/TestRunner.cs

@ -61,18 +61,27 @@ namespace ILSpy.BamlDecompiler.Tests
RunTest("cases/attachedevent"); RunTest("cases/attachedevent");
} }
[Test]
public void Dictionary1()
{
RunTest("cases/dictionary1");
}
#region RunTest #region RunTest
void RunTest(string name) void RunTest(string name)
{ {
string asmPath = typeof(TestRunner).Assembly.Location; RunTest(name, typeof(TestRunner).Assembly.Location, Path.Combine("..\\..\\Tests", name + ".xaml"));
}
void RunTest(string name, string asmPath, string sourcePath)
{
var assembly = AssemblyDefinition.ReadAssembly(asmPath); var assembly = AssemblyDefinition.ReadAssembly(asmPath);
Resource res = assembly.MainModule.Resources.First(); Resource res = assembly.MainModule.Resources.First();
Stream bamlStream = LoadBaml(res, name + ".baml"); Stream bamlStream = LoadBaml(res, name + ".baml");
Assert.IsNotNull(bamlStream); Assert.IsNotNull(bamlStream);
XDocument document = BamlResourceEntryNode.LoadIntoDocument(new DefaultAssemblyResolver(), assembly, bamlStream); XDocument document = BamlResourceEntryNode.LoadIntoDocument(new DefaultAssemblyResolver(), assembly, bamlStream);
string path = Path.Combine("..\\..\\Tests", name + ".xaml");
CodeAssert.AreEqual(File.ReadAllText(sourcePath), document.ToString());
CodeAssert.AreEqual(File.ReadAllText(path), document.ToString());
} }
Stream LoadBaml(Resource res, string name) Stream LoadBaml(Resource res, string name)

4
ILSpy/AssemblyList.cs

@ -41,6 +41,8 @@ namespace ICSharpCode.ILSpy
/// <summary>Dirty flag, used to mark modifications so that the list is saved later</summary> /// <summary>Dirty flag, used to mark modifications so that the list is saved later</summary>
bool dirty; bool dirty;
internal readonly ConcurrentDictionary<string, LoadedAssembly> assemblyLookupCache = new ConcurrentDictionary<string, LoadedAssembly>();
/// <summary> /// <summary>
/// The assemblies in this list. /// The assemblies in this list.
/// Needs locking for multi-threaded access! /// Needs locking for multi-threaded access!
@ -101,6 +103,7 @@ namespace ICSharpCode.ILSpy
void Assemblies_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) void Assemblies_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{ {
assemblyLookupCache.Clear();
// Whenever the assembly list is modified, mark it as dirty // Whenever the assembly list is modified, mark it as dirty
// and enqueue a task that saves it once the UI has finished modifying the assembly list. // and enqueue a task that saves it once the UI has finished modifying the assembly list.
if (!dirty) { if (!dirty) {
@ -111,6 +114,7 @@ namespace ICSharpCode.ILSpy
delegate { delegate {
dirty = false; dirty = false;
AssemblyListManager.SaveList(this); AssemblyListManager.SaveList(this);
assemblyLookupCache.Clear();
}) })
); );
} }

26
ILSpy/Controls/ResourceStringTable.xaml

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<UserControl
x:Class="ICSharpCode.ILSpy.Controls.ResourceStringTable" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.CommandBindings>
<CommandBinding Command="ApplicationCommands.Copy"
Executed="ExecuteCopy"
CanExecute="CanExecuteCopy"/>
</UserControl.CommandBindings>
<ListView
Name="resourceListView"
SelectionMode="Extended">
<ListView.View>
<GridView
AllowsColumnReorder="False">
<GridView.Columns>
<GridViewColumn
Header="Resource id"
DisplayMemberBinding="{Binding Key}" />
<GridViewColumn
Header="Resource value"
DisplayMemberBinding="{Binding Value}" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
</UserControl>

51
ILSpy/Controls/ResourceStringTable.xaml.cs

@ -0,0 +1,51 @@
/*
* Created by SharpDevelop.
* User: Ronny Klier
* Date: 31.05.2011
* Time: 00:13
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace ICSharpCode.ILSpy.Controls
{
/// <summary>
/// Interaction logic for ResourceStringTable.xaml
/// </summary>
public partial class ResourceStringTable : UserControl
{
public ResourceStringTable(IEnumerable strings)
{
InitializeComponent();
// set size to fit decompiler window
// TODO: there should be a more transparent way to do this
MaxWidth = MainWindow.Instance.mainPane.ActualWidth-20;
MaxHeight = MainWindow.Instance.mainPane.ActualHeight-100;
resourceListView.ItemsSource = strings;
}
void ExecuteCopy(object sender, ExecutedRoutedEventArgs args)
{
StringBuilder sb = new StringBuilder();
foreach (var item in resourceListView.SelectedItems)
{
sb.AppendLine(item.ToString());
}
Clipboard.SetText(sb.ToString());
}
void CanExecuteCopy(object sender, CanExecuteRoutedEventArgs args)
{
args.CanExecute = true;
}
}
}

6
ILSpy/ILSpy.csproj

@ -69,6 +69,7 @@
<Reference Include="System.Data.DataSetExtensions"> <Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework> <RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference> </Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Xaml"> <Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework> <RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference> </Reference>
@ -136,6 +137,10 @@
<DependentUpon>OpenFromGacDialog.xaml</DependentUpon> <DependentUpon>OpenFromGacDialog.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Controls\ResourceStringTable.xaml.cs">
<DependentUpon>ResourceStringTable.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Options\DecompilerSettingsPanel.xaml.cs"> <Compile Include="Options\DecompilerSettingsPanel.xaml.cs">
<DependentUpon>DecompilerSettingsPanel.xaml</DependentUpon> <DependentUpon>DecompilerSettingsPanel.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
@ -252,6 +257,7 @@
<EmbeddedResource Include="TextView\ILAsm-Mode.xshd" /> <EmbeddedResource Include="TextView\ILAsm-Mode.xshd" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Page Include="Controls\ResourceStringTable.xaml" />
<Page Include="Controls\SearchBoxStyle.xaml"> <Page Include="Controls\SearchBoxStyle.xaml">
<DependentUpon>SearchBox.cs</DependentUpon> <DependentUpon>SearchBox.cs</DependentUpon>
</Page> </Page>

9
ILSpy/LoadedAssembly.cs

@ -17,11 +17,11 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Concurrent;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Threading; using System.Windows.Threading;
using ICSharpCode.ILSpy.Options; using ICSharpCode.ILSpy.Options;
using Mono.Cecil; using Mono.Cecil;
@ -134,6 +134,8 @@ namespace ICSharpCode.ILSpy
if (!disposed) { if (!disposed) {
disposed = true; disposed = true;
assemblyLoadDisableCount--; assemblyLoadDisableCount--;
// clear the lookup cache since we might have stored the lookups failed due to DisableAssemblyLoad()
MainWindow.Instance.CurrentAssemblyList.assemblyLookupCache.Clear();
} }
} }
} }
@ -178,6 +180,11 @@ namespace ICSharpCode.ILSpy
} }
public LoadedAssembly LookupReferencedAssembly(string fullName) public LoadedAssembly LookupReferencedAssembly(string fullName)
{
return assemblyList.assemblyLookupCache.GetOrAdd(fullName, LookupReferencedAssemblyInternal);
}
LoadedAssembly LookupReferencedAssemblyInternal(string fullName)
{ {
foreach (LoadedAssembly asm in assemblyList.GetAssemblies()) { foreach (LoadedAssembly asm in assemblyList.GetAssemblies()) {
if (asm.AssemblyDefinition != null && fullName.Equals(asm.AssemblyDefinition.FullName, StringComparison.OrdinalIgnoreCase)) if (asm.AssemblyDefinition != null && fullName.Equals(asm.AssemblyDefinition.FullName, StringComparison.OrdinalIgnoreCase))

15
ILSpy/MainWindow.xaml.cs

@ -208,6 +208,8 @@ namespace ICSharpCode.ILSpy
} }
var args = new CommandLineArguments(lines); var args = new CommandLineArguments(lines);
if (HandleCommandLineArguments(args)) { if (HandleCommandLineArguments(args)) {
if (!args.NoActivate && WindowState == WindowState.Minimized)
WindowState = WindowState.Normal;
HandleCommandLineArgumentsAfterShowList(args); HandleCommandLineArgumentsAfterShowList(args);
handled = true; handled = true;
return (IntPtr)1; return (IntPtr)1;
@ -392,9 +394,16 @@ namespace ICSharpCode.ILSpy
internal void SelectNode(SharpTreeNode obj) internal void SelectNode(SharpTreeNode obj)
{ {
if (obj != null) { if (obj != null) {
// Set both the selection and focus to ensure that keyboard navigation works as expected. if (!obj.AncestorsAndSelf().Any(node => node.IsHidden)) {
treeView.FocusNode(obj); // Set both the selection and focus to ensure that keyboard navigation works as expected.
treeView.SelectedItem = obj; treeView.FocusNode(obj);
treeView.SelectedItem = obj;
} else {
MessageBox.Show("Navigation failed because the target is hidden or a compiler-generated class.\n" +
"Please disable all filters that might hide the item (i.e. activate " +
"\"View > Show internal types and members\") and try again.",
"ILSpy", MessageBoxButton.OK, MessageBoxImage.Exclamation);
}
} }
} }

15
ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs

@ -40,11 +40,13 @@ namespace ICSharpCode.ILSpy.TreeNodes
return null; return null;
} }
public ILSpyTreeNode CreateNode(string key, Stream data) public ILSpyTreeNode CreateNode(string key, object data)
{ {
if (!(data is Stream))
return null;
foreach (string fileExt in imageFileExtensions) { foreach (string fileExt in imageFileExtensions) {
if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase)) if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase))
return new CursorResourceEntryNode(key, data); return new CursorResourceEntryNode(key, (Stream)data);
} }
return null; return null;
} }
@ -71,7 +73,14 @@ namespace ICSharpCode.ILSpy.TreeNodes
//HACK: windows imaging does not understand that .cur files have the same layout as .ico //HACK: windows imaging does not understand that .cur files have the same layout as .ico
// so load to data, and modify the ResourceType in the header to make look like an icon... // so load to data, and modify the ResourceType in the header to make look like an icon...
byte[] curData = ((MemoryStream)Data).ToArray(); MemoryStream s = Data as MemoryStream;
if (null == s)
{
// data was stored in another stream type (e.g. PinnedBufferedMemoryStream)
s = new MemoryStream();
Data.CopyTo(s);
}
byte[] curData = s.ToArray();
curData[2] = 1; curData[2] = 1;
using (Stream stream = new MemoryStream(curData)) { using (Stream stream = new MemoryStream(curData)) {
image.BeginInit(); image.BeginInit();

2
ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs

@ -28,6 +28,6 @@ namespace ICSharpCode.ILSpy.TreeNodes
public interface IResourceNodeFactory public interface IResourceNodeFactory
{ {
ILSpyTreeNode CreateNode(Resource resource); ILSpyTreeNode CreateNode(Resource resource);
ILSpyTreeNode CreateNode(string key, Stream data); ILSpyTreeNode CreateNode(string key, object data);
} }
} }

18
ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs

@ -40,11 +40,25 @@ namespace ICSharpCode.ILSpy.TreeNodes
return null; return null;
} }
public ILSpyTreeNode CreateNode(string key, Stream data) public ILSpyTreeNode CreateNode(string key, object data)
{ {
if (data is System.Drawing.Icon)
{
MemoryStream s = new MemoryStream();
((System.Drawing.Icon)data).Save(s);
return new ImageResourceEntryNode(key, s);
}
else if (data is System.Drawing.Image)
{
MemoryStream s = new MemoryStream();
((System.Drawing.Image)data).Save(s, System.Drawing.Imaging.ImageFormat.Bmp);
return new ImageResourceEntryNode(key, s);
}
if (!(data is Stream))
return null;
foreach (string fileExt in imageFileExtensions) { foreach (string fileExt in imageFileExtensions) {
if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase)) if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase))
return new ImageResourceEntryNode(key, data); return new ImageResourceEntryNode(key, (Stream)data);
} }
return null; return null;
} }

4
ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs

@ -62,7 +62,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
this.data = data; this.data = data;
} }
public static ILSpyTreeNode Create(string key, Stream data) public static ILSpyTreeNode Create(string key, object data)
{ {
ILSpyTreeNode result = null; ILSpyTreeNode result = null;
foreach (var factory in App.CompositionContainer.GetExportedValues<IResourceNodeFactory>()) { foreach (var factory in App.CompositionContainer.GetExportedValues<IResourceNodeFactory>()) {
@ -70,7 +70,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (result != null) if (result != null)
break; break;
} }
return result ?? new ResourceEntryNode(key, data); return result ?? new ResourceEntryNode(key, data as Stream);
} }
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)

31
ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs

@ -18,10 +18,15 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Resources; using System.Resources;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.Controls;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes namespace ICSharpCode.ILSpy.TreeNodes
@ -38,7 +43,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
return null; return null;
} }
public ILSpyTreeNode CreateNode(string key, Stream data) public ILSpyTreeNode CreateNode(string key, object data)
{ {
return null; return null;
} }
@ -46,6 +51,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
sealed class ResourcesFileTreeNode : ResourceTreeNode sealed class ResourcesFileTreeNode : ResourceTreeNode
{ {
ICollection<KeyValuePair<string, string>> filteredEntries = new ObservableCollection<KeyValuePair<string, string>>();
public ResourcesFileTreeNode(EmbeddedResource er) public ResourcesFileTreeNode(EmbeddedResource er)
: base(er) : base(er)
{ {
@ -71,12 +78,30 @@ namespace ICSharpCode.ILSpy.TreeNodes
return; return;
} }
foreach (DictionaryEntry entry in reader.Cast<DictionaryEntry>().OrderBy(e => e.Key.ToString())) { foreach (DictionaryEntry entry in reader.Cast<DictionaryEntry>().OrderBy(e => e.Key.ToString())) {
if (entry.Value is Stream) if (entry.Value is String)
Children.Add(ResourceEntryNode.Create(entry.Key.ToString(), (Stream)entry.Value)); filteredEntries.Add(new KeyValuePair<string, string>(entry.Key.ToString(), (string)entry.Value));
else if (entry.Value is byte[]) else if (entry.Value is byte[])
Children.Add(ResourceEntryNode.Create(entry.Key.ToString(), new MemoryStream((byte[])entry.Value))); Children.Add(ResourceEntryNode.Create(entry.Key.ToString(), new MemoryStream((byte[])entry.Value)));
else
Children.Add(ResourceEntryNode.Create(entry.Key.ToString(), entry.Value));
} }
} }
} }
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
base.Decompile(language, output, options);
if (filteredEntries.Count == 0)
return;
ISmartTextOutput smartOutput = output as ISmartTextOutput;
if (null != smartOutput) {
smartOutput.AddUIElement(
delegate {
return new ResourceStringTable(filteredEntries);
}
);
}
output.WriteLine();
}
} }
} }

6
ILSpy/TreeNodes/ResourceNodes/XamlResourceNode.cs

@ -35,10 +35,10 @@ namespace ICSharpCode.ILSpy.Xaml
return null; return null;
} }
public ILSpyTreeNode CreateNode(string key, Stream data) public ILSpyTreeNode CreateNode(string key, object data)
{ {
if (key.EndsWith(".xaml", StringComparison.OrdinalIgnoreCase)) if (key.EndsWith(".xaml", StringComparison.OrdinalIgnoreCase) && data is Stream)
return new XamlResourceEntryNode(key, data); return new XamlResourceEntryNode(key, (Stream)data);
else else
return null; return null;
} }

10
ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs

@ -41,12 +41,16 @@ namespace ICSharpCode.ILSpy.Xaml
return null; return null;
} }
public ILSpyTreeNode CreateNode(string key, Stream data) public ILSpyTreeNode CreateNode(string key, object data)
{ {
if (!(data is Stream))
return null;
foreach (string fileExt in xmlFileExtensions) foreach (string fileExt in xmlFileExtensions)
{
if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase)) if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase))
return new XmlResourceEntryNode(key, data); return new XmlResourceEntryNode(key, (Stream)data);
return null; }
return null;
} }
} }

2
ILSpy/XmlDoc/XmlDocKeyProvider.cs

@ -169,6 +169,7 @@ namespace ICSharpCode.ILSpy.XmlDoc
} else { } else {
dotPos = key.LastIndexOf('.'); dotPos = key.LastIndexOf('.');
} }
if (dotPos < 0) return null;
TypeDefinition type = FindType(module, key.Substring(2, dotPos - 2)); TypeDefinition type = FindType(module, key.Substring(2, dotPos - 2));
if (type == null) if (type == null)
return null; return null;
@ -192,6 +193,7 @@ namespace ICSharpCode.ILSpy.XmlDoc
} else { } else {
ns = string.Empty; ns = string.Empty;
} }
if (string.IsNullOrEmpty(name)) return null;
TypeDefinition type = module.GetType(ns, name); TypeDefinition type = module.GetType(ns, name);
if (type == null && ns.Length > 0) { if (type == null && ns.Length > 0) {
// try if this is a nested type // try if this is a nested type

72
NRefactory/ICSharpCode.Editor/ICSharpCode.Editor.csproj

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<ProjectGuid>{F054A788-B591-4561-A8BA-AE745BBEB817}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<OutputType>Library</OutputType>
<RootNamespace>ICSharpCode.Editor</RootNamespace>
<AssemblyName>ICSharpCode.Editor</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<AppDesignerFolder>Properties</AppDesignerFolder>
<SignAssembly>False</SignAssembly>
<DelaySign>False</DelaySign>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<DocumentationFile>bin\Debug\ICSharpCode.Editor.xml</DocumentationFile>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<RunCodeAnalysis>False</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'x86' ">
<PlatformTarget>x86</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
<DebugSymbols>true</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<StartAction>Project</StartAction>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="IDocument.cs" />
<Compile Include="IDocumentLine.cs" />
<Compile Include="ISegment.cs" />
<Compile Include="ITextEditor.cs" />
<Compile Include="ITextSource.cs" />
<Compile Include="LinkedElement.cs" />
<Compile Include="ReadOnlyDocument.cs" />
<Compile Include="StringTextSource.cs" />
<Compile Include="TextLocation.cs" />
<Compile Include="ITextAnchor.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TextChangeEventArgs.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>

141
NRefactory/ICSharpCode.Editor/IDocument.cs

@ -0,0 +1,141 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT license (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.Editor
{
/// <summary>
/// A document representing a source code file for refactoring.
/// Line and column counting starts at 1.
/// Offset counting starts at 0.
/// </summary>
public interface IDocument : ITextSource, IServiceProvider
{
/// <summary>
/// Gets/Sets the text of the whole document..
/// </summary>
new string Text { get; set; } // hides TextBuffer.Text to add the setter
/// <summary>
/// Is raised when the Text property changes.
/// </summary>
event EventHandler TextChanged;
/// <summary>
/// Gets the total number of lines in the document.
/// </summary>
int TotalNumberOfLines { get; }
/// <summary>
/// Gets the document line with the specified number.
/// </summary>
/// <param name="lineNumber">The number of the line to retrieve. The first line has number 1.</param>
IDocumentLine GetLine(int lineNumber);
/// <summary>
/// Gets the document line that contains the specified offset.
/// </summary>
IDocumentLine GetLineByOffset(int offset);
/// <summary>
/// Gets the offset from a text location.
/// </summary>
/// <seealso cref="GetLocation"/>
int GetOffset(int line, int column);
/// <summary>
/// Gets the offset from a text location.
/// </summary>
/// <seealso cref="GetLocation"/>
int GetOffset(TextLocation location);
/// <summary>
/// Gets the location from an offset.
/// </summary>
/// <seealso cref="GetOffset(TextLocation)"/>
TextLocation GetLocation(int offset);
/// <summary>
/// Inserts text.
/// </summary>
/// <param name="offset">The offset at which the text is inserted.</param>
/// <param name="text">The new text.</param>
/// <remarks>
/// Anchors positioned exactly at the insertion offset will move according to their movement type.
/// For AnchorMovementType.Default, they will move behind the inserted text.
/// The caret will also move behind the inserted text.
/// </remarks>
void Insert(int offset, string text);
/// <summary>
/// Inserts text.
/// </summary>
/// <param name="offset">The offset at which the text is inserted.</param>
/// <param name="text">The new text.</param>
/// <param name="defaultAnchorMovementType">
/// Anchors positioned exactly at the insertion offset will move according to the anchor's movement type.
/// For AnchorMovementType.Default, they will move according to the movement type specified by this parameter.
/// The caret will also move according to the <paramref name="defaultAnchorMovementType"/> parameter.
/// </param>
void Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType);
/// <summary>
/// Removes text.
/// </summary>
/// <param name="offset">Starting offset of the text to be removed.</param>
/// <param name="length">Length of the text to be removed.</param>
void Remove(int offset, int length);
/// <summary>
/// Replaces text.
/// </summary>
/// <param name="offset">The starting offset of the text to be replaced.</param>
/// <param name="length">The length of the text to be replaced.</param>
/// <param name="newText">The new text.</param>
void Replace(int offset, int length, string newText);
/// <summary>
/// Make the document combine the following actions into a single
/// action for undo purposes.
/// </summary>
void StartUndoableAction();
/// <summary>
/// Ends the undoable action started with <see cref="StartUndoableAction"/>.
/// </summary>
void EndUndoableAction();
/// <summary>
/// Creates an undo group. Dispose the returned value to close the undo group.
/// </summary>
/// <returns>An object that closes the undo group when Dispose() is called.</returns>
IDisposable OpenUndoGroup();
/// <summary>
/// Creates a new <see cref="ITextAnchor"/> at the specified offset.
/// </summary>
/// <inheritdoc cref="ITextAnchor" select="remarks|example"/>
ITextAnchor CreateAnchor(int offset);
/// <summary>
/// This event is called directly before a change is applied to the document.
/// </summary>
/// <remarks>
/// It is invalid to modify the document within this event handler.
/// Aborting the change (by throwing an exception) is likely to cause corruption of data structures
/// that listen to the Changing and Changed events.
/// </remarks>
event EventHandler<TextChangeEventArgs> Changing;
/// <summary>
/// This event is called directly after a change is applied to the document.
/// </summary>
/// <remarks>
/// It is invalid to modify the document within this event handler.
/// Aborting the event handler (by throwing an exception) is likely to cause corruption of data structures
/// that listen to the Changing and Changed events.
/// </remarks>
event EventHandler<TextChangeEventArgs> Changed;
}
}

30
NRefactory/ICSharpCode.Editor/IDocumentLine.cs

@ -0,0 +1,30 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT license (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.Editor
{
/// <summary>
/// A line inside a <see cref="IDocument"/>.
/// </summary>
public interface IDocumentLine : ISegment
{
/// <summary>
/// Gets the length of this line, including the line delimiter.
/// </summary>
int TotalLength { get; }
/// <summary>
/// Gets the length of the line terminator.
/// Returns 1 or 2; or 0 at the end of the document.
/// </summary>
int DelimiterLength { get; }
/// <summary>
/// Gets the number of this line.
/// The first line has the number 1.
/// </summary>
int LineNumber { get; }
}
}

55
NRefactory/ICSharpCode.Editor/ISegment.cs

@ -0,0 +1,55 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT license (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.Editor
{
/// <summary>
/// An (Offset,Length)-pair.
/// </summary>
public interface ISegment
{
/// <summary>
/// Gets the start offset of the segment.
/// </summary>
int Offset { get; }
/// <summary>
/// Gets the length of the segment.
/// </summary>
/// <remarks>Must not be negative.</remarks>
int Length { get; }
/// <summary>
/// Gets the end offset of the segment.
/// </summary>
/// <remarks>EndOffset = Offset + Length;</remarks>
int EndOffset { get; }
}
/// <summary>
/// Extension methods for <see cref="ISegment"/>.
/// </summary>
public static class ISegmentExtensions
{
/// <summary>
/// Gets whether the segment contains the offset.
/// </summary>
/// <returns>
/// True, if offset is between segment.Start and segment.End (inclusive); otherwise, false.
/// </returns>
public static bool Contains (this ISegment segment, int offset)
{
return segment.Offset <= offset && offset <= segment.EndOffset;
}
/// <summary>
/// True, if the segment contains the specified segment, false otherwise.
/// </summary>
public static bool Contains (this ISegment thisSegment, ISegment segment)
{
return segment != null && thisSegment.Offset <= segment.Offset && segment.EndOffset <= thisSegment.EndOffset;
}
}
}

102
NRefactory/ICSharpCode.Editor/ITextAnchor.cs

@ -0,0 +1,102 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT license (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.Editor
{
/// <summary>
/// The TextAnchor class references an offset (a position between two characters).
/// It automatically updates the offset when text is inserted/removed in front of the anchor.
/// </summary>
/// <remarks>
/// <para>Use the <see cref="ITextAnchor.Offset"/> property to get the offset from a text anchor.
/// Use the <see cref="IDocument.CreateAnchor"/> method to create an anchor from an offset.
/// </para>
/// <para>
/// The document will automatically update all text anchors; and because it uses weak references to do so,
/// the garbage collector can simply collect the anchor object when you don't need it anymore.
/// </para>
/// <para>Moreover, the document is able to efficiently update a large number of anchors without having to look
/// at each anchor object individually. Updating the offsets of all anchors usually only takes time logarithmic
/// to the number of anchors. Retrieving the <see cref="ITextAnchor.Offset"/> property also runs in O(lg N).</para>
/// </remarks>
/// <example>
/// Usage:
/// <code>TextAnchor anchor = document.CreateAnchor(offset);
/// ChangeMyDocument();
/// int newOffset = anchor.Offset;
/// </code>
/// </example>
public interface ITextAnchor
{
/// <summary>
/// Gets the text location of this anchor.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown when trying to get the Offset from a deleted anchor.</exception>
TextLocation Location { get; }
/// <summary>
/// Gets the offset of the text anchor.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown when trying to get the Offset from a deleted anchor.</exception>
int Offset { get; }
/// <summary>
/// Controls how the anchor moves.
/// </summary>
AnchorMovementType MovementType { get; set; }
/// <summary>
/// Specifies whether the anchor survives deletion of the text containing it.
/// <c>false</c>: The anchor is deleted when the a selection that includes the anchor is deleted.
/// <c>true</c>: The anchor is not deleted.
/// </summary>
bool SurviveDeletion { get; set; }
/// <summary>
/// Gets whether the anchor was deleted.
/// </summary>
bool IsDeleted { get; }
/// <summary>
/// Occurs after the anchor was deleted.
/// </summary>
event EventHandler Deleted;
/// <summary>
/// Gets the line number of the anchor.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown when trying to get the Offset from a deleted anchor.</exception>
int Line { get; }
/// <summary>
/// Gets the column number of this anchor.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown when trying to get the Offset from a deleted anchor.</exception>
int Column { get; }
}
/// <summary>
/// Defines how a text anchor moves.
/// </summary>
public enum AnchorMovementType
{
/// <summary>
/// When text is inserted at the anchor position, the type of the insertion
/// determines where the caret moves to. For normal insertions, the anchor will stay
/// behind the inserted text.
/// </summary>
Default,
/// <summary>
/// Behaves like a start marker - when text is inserted at the anchor position, the anchor will stay
/// before the inserted text.
/// </summary>
BeforeInsertion,
/// <summary>
/// Behave like an end marker - when text is insered at the anchor position, the anchor will move
/// after the inserted text.
/// </summary>
AfterInsertion
}
}

100
NRefactory/ICSharpCode.Editor/ITextEditor.cs

@ -0,0 +1,100 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ICSharpCode.Editor
{
/// <summary>
/// Interface for text editors.
/// </summary>
public interface ITextEditor : IServiceProvider
{
/// <summary>
/// Gets the document that is being edited.
/// </summary>
IDocument Document { get; }
/// <summary>
/// Gets an object that represents the caret inside this text editor.
/// </summary>
ITextEditorCaret Caret { get; }
/// <summary>
/// Sets the caret to the specified line/column and brings the caret into view.
/// </summary>
void JumpTo(int line, int column);
/// <summary>
/// Gets the start offset of the selection.
/// </summary>
int SelectionStart { get; }
/// <summary>
/// Gets the length of the selection.
/// </summary>
int SelectionLength { get; }
/// <summary>
/// Gets/Sets the selected text.
/// </summary>
string SelectedText { get; set; }
/// <summary>
/// Sets the selection.
/// </summary>
/// <param name="selectionStart">Start offset of the selection</param>
/// <param name="selectionLength">Length of the selection</param>
void Select(int selectionStart, int selectionLength);
/// <summary>
/// Shows the specified linked elements, and allows the user to edit them.
/// </summary>
/// <returns>
/// Returns true when the user has finished editing the elements and pressed Return;
/// or false when editing is aborted for any reason.
/// </returns>
/// <remarks>
/// The user can also edit other parts of the document (or other documents) while in link mode.
/// In case of success (true return value), this method will update the offsets of the linked elements
/// to reflect the changes done by the user.
/// If the text editor does not support link mode, it will immediately return false.
/// </remarks>
// Task<bool> ShowLinkedElements(IEnumerable<LinkedElement> linkedElements);
}
/// <summary>
/// Represents the caret in a text editor.
/// </summary>
public interface ITextEditorCaret
{
/// <summary>
/// Gets/Sets the caret offset;
/// </summary>
int Offset { get; set; }
/// <summary>
/// Gets/Sets the caret line number.
/// Line numbers are counted starting from 1.
/// </summary>
int Line { get; set; }
/// <summary>
/// Gets/Sets the caret column number.
/// Column numbers are counted starting from 1.
/// </summary>
int Column { get; set; }
/// <summary>
/// Gets/sets the caret location.
/// </summary>
TextLocation Location { get; set; }
/// <summary>
/// Is raised whenever the location of the caret has changed.
/// </summary>
event EventHandler LocationChanged;
}
}

147
NRefactory/ICSharpCode.Editor/ITextSource.cs

@ -0,0 +1,147 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.IO;
namespace ICSharpCode.Editor
{
/// <summary>
/// A read-only view on a (potentially mutable) text source.
/// The IDocument interfaces derives from this interface.
/// </summary>
public interface ITextSource
{
/// <summary>
/// Gets a version identifier for this text source.
/// Returns null for unversioned text sources.
/// </summary>
ITextSourceVersion Version { get; }
/// <summary>
/// Creates an immutable snapshot of this text source.
/// Unlike all other methods in this interface, this method is thread-safe.
/// </summary>
ITextSource CreateSnapshot();
/// <summary>
/// Creates an immutable snapshot of a part of this text source.
/// Unlike all other methods in this interface, this method is thread-safe.
/// </summary>
ITextSource CreateSnapshot(int offset, int length);
/// <summary>
/// Creates a new TextReader to read from this text source.
/// </summary>
TextReader CreateReader();
/// <summary>
/// Creates a new TextReader to read from this text source.
/// </summary>
TextReader CreateReader(int offset, int length);
/// <summary>
/// Gets the total text length.
/// </summary>
/// <returns>The length of the text, in characters.</returns>
/// <remarks>This is the same as Text.Length, but is more efficient because
/// it doesn't require creating a String object.</remarks>
int TextLength { get; }
/// <summary>
/// Gets the whole text as string.
/// </summary>
string Text { get; }
/// <summary>
/// Gets a character at the specified position in the document.
/// </summary>
/// <paramref name="offset">The index of the character to get.</paramref>
/// <exception cref="ArgumentOutOfRangeException">Offset is outside the valid range (0 to TextLength-1).</exception>
/// <returns>The character at the specified position.</returns>
/// <remarks>This is the same as Text[offset], but is more efficient because
/// it doesn't require creating a String object.</remarks>
char GetCharAt(int offset);
/// <summary>
/// Retrieves the text for a portion of the document.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">offset or length is outside the valid range.</exception>
/// <remarks>This is the same as Text.Substring, but is more efficient because
/// it doesn't require creating a String object for the whole document.</remarks>
string GetText(int offset, int length);
/// <summary>
/// Retrieves the text for a portion of the document.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">offset or length is outside the valid range.</exception>
string GetText(ISegment segment);
/// <summary>
/// Gets the index of the first occurrence of any character in the specified array.
/// </summary>
/// <param name="anyOf">Characters to search for</param>
/// <param name="startIndex">Start index of the search.</param>
/// <param name="count">Length of the area to search.</param>
/// <returns>The first index where any character was found; or -1 if no occurrence was found.</returns>
int IndexOfAny(char[] anyOf, int startIndex, int count);
/* What about:
void Insert (int offset, string value);
void Remove (int offset, int count);
void Remove (ISegment segment);
void Replace (int offset, int count, string value);
Or more search operations:
IEnumerable<int> SearchForward (string pattern, int startIndex);
IEnumerable<int> SearchForwardIgnoreCase (string pattern, int startIndex);
IEnumerable<int> SearchBackward (string pattern, int startIndex);
IEnumerable<int> SearchBackwardIgnoreCase (string pattern, int startIndex);
*/
}
/// <summary>
/// Represents a version identifier for a text source.
/// </summary>
/// <remarks>
/// Verions can be used to efficiently detect whether a document has changed and needs reparsing;
/// or even to implement incremental parsers.
/// It is a separate class from ITextBuffer to allow the GC to collect the text buffer while
/// the version checkpoint is still in use.
/// </remarks>
public interface ITextSourceVersion
{
/// <summary>
/// Gets whether this checkpoint belongs to the same document as the other checkpoint.
/// </summary>
bool BelongsToSameDocumentAs(ITextSourceVersion other);
/// <summary>
/// Compares the age of this checkpoint to the other checkpoint.
/// </summary>
/// <remarks>This method is thread-safe.</remarks>
/// <exception cref="ArgumentException">Raised if 'other' belongs to a different document than this version.</exception>
/// <returns>-1 if this version is older than <paramref name="other"/>.
/// 0 if <c>this</c> version instance represents the same version as <paramref name="other"/>.
/// 1 if this version is newer than <paramref name="other"/>.</returns>
int CompareAge(ITextSourceVersion other);
/// <summary>
/// Gets the changes from this checkpoint to the other checkpoint.
/// If 'other' is older than this checkpoint, reverse changes are calculated.
/// </summary>
/// <remarks>This method is thread-safe.</remarks>
/// <exception cref="ArgumentException">Raised if 'other' belongs to a different document than this checkpoint.</exception>
IEnumerable<TextChangeEventArgs> GetChangesTo(ITextSourceVersion other);
/// <summary>
/// Calculates where the offset has moved in the other buffer version.
/// </summary>
/// <exception cref="ArgumentException">Raised if 'other' belongs to a different document than this checkpoint.</exception>
int MoveOffsetTo(ITextSourceVersion other, int oldOffset, AnchorMovementType movement);
}
}

68
NRefactory/ICSharpCode.Editor/LinkedElement.cs

@ -0,0 +1,68 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT license (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.Editor
{
// I'm not sure if we need this.
// How about a method in the context - this method could wrap the internal representation.
// public void StartTextLinkMode (int linkLength, IEnumerable<int> offsets)
// and maybe then variations taking more than one link element ?
// /// <summary>
// /// Represents an element in the text editor that is either editable, or bound to another editable element.
// /// Used with <see cref="ITextEditor.ShowLinkedElements"/>
// /// </summary>
// public class LinkedElement
// {
// LinkedElement boundTo;
//
// /// <summary>
// /// Gets/Sets the start offset of this linked element.
// /// </summary>
// public int StartOffset { get; set; }
//
// /// <summary>
// /// Gets/Sets the end offset of this linked element.
// /// </summary>
// public int EndOffset { get; set; }
//
// /// <summary>
// /// Gets the linked element to which this element is bound.
// /// </summary>
// public LinkedElement BoundTo {
// get { return boundTo; }
// }
//
// /// <summary>
// /// Gets whether this element is editable. Returns true if this element is not bound.
// /// </summary>
// public bool IsEditable {
// get { return boundTo == null; }
// }
//
// /// <summary>
// /// Creates a new editable element.
// /// </summary>
// public LinkedElement(int startOffset, int endOffset)
// {
// this.StartOffset = startOffset;
// this.EndOffset = endOffset;
// }
//
// /// <summary>
// /// Creates a new element that is bound to <paramref name="boundTo"/>.
// /// </summary>
// public LinkedElement(int startOffset, int endOffset, LinkedElement boundTo)
// {
// if (boundTo == null)
// throw new ArgumentNullException("boundTo");
// this.StartOffset = startOffset;
// this.EndOffset = endOffset;
// while (boundTo.boundTo != null)
// boundTo = boundTo.boundTo;
// this.boundTo = boundTo;
// }
// }
}

31
NRefactory/ICSharpCode.Editor/Properties/AssemblyInfo.cs

@ -0,0 +1,31 @@
#region Using directives
using System;
using System.Reflection;
using System.Runtime.InteropServices;
#endregion
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ICSharpCode.Editor")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ICSharpCode.Editor")]
[assembly: AssemblyCopyright("Copyright 2011")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// This sets the default COM visibility of types in the assembly to invisible.
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
[assembly: ComVisible(false)]
// The assembly version has following format :
//
// Major.Minor.Build.Revision
//
// You can specify all the values or you can use the default the Revision and
// Build Numbers by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]

321
NRefactory/ICSharpCode.Editor/ReadOnlyDocument.cs

@ -0,0 +1,321 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
namespace ICSharpCode.Editor
{
/// <summary>
/// Read-only implementation of <see cref="IDocument"/>.
/// </summary>
public sealed class ReadOnlyDocument : IDocument
{
readonly ITextSource textSource;
int[] lines;
static readonly char[] newline = { '\r', '\n' };
/// <summary>
/// Creates a new ReadOnlyDocument from the given text source.
/// </summary>
public ReadOnlyDocument(ITextSource textSource)
{
if (textSource == null)
throw new ArgumentNullException("textSource");
// ensure that underlying buffer is immutable
this.textSource = textSource.CreateSnapshot();
List<int> lines = new List<int>();
lines.Add(0);
int offset = 0;
int textLength = textSource.TextLength;
while ((offset = textSource.IndexOfAny(newline, offset, textLength - offset)) >= 0) {
offset++;
if (textSource.GetCharAt(offset - 1) == '\r' && offset < textLength && textSource.GetCharAt(offset) == '\n') {
offset++;
}
lines.Add(offset);
}
this.lines = lines.ToArray();
}
/// <summary>
/// Creates a new ReadOnlyDocument from the given string.
/// </summary>
public ReadOnlyDocument(string text)
: this(new StringTextSource(text))
{
}
/// <inheritdoc/>
public IDocumentLine GetLine(int lineNumber)
{
if (lineNumber < 1 || lineNumber > lines.Length)
throw new ArgumentOutOfRangeException("lineNumber", lineNumber, "Value must be between 1 and " + lines.Length);
return new ReadOnlyDocumentLine(this, lineNumber);
}
sealed class ReadOnlyDocumentLine : IDocumentLine
{
readonly ReadOnlyDocument doc;
readonly int lineNumber;
readonly int offset, endOffset;
public ReadOnlyDocumentLine(ReadOnlyDocument doc, int lineNumber)
{
this.doc = doc;
this.lineNumber = lineNumber;
this.offset = doc.GetStartOffset(lineNumber);
this.endOffset = doc.GetEndOffset(lineNumber);
}
public int Offset {
get { return offset; }
}
public int Length {
get { return endOffset - offset; }
}
public int EndOffset {
get { return endOffset; }
}
public int TotalLength {
get {
return doc.GetTotalEndOffset(lineNumber) - offset;
}
}
public int DelimiterLength {
get {
return doc.GetTotalEndOffset(lineNumber) - endOffset;
}
}
public int LineNumber {
get { return lineNumber; }
}
}
int GetStartOffset(int lineNumber)
{
return lines[lineNumber-1];
}
int GetTotalEndOffset(int lineNumber)
{
return lineNumber < lines.Length ? lines[lineNumber] : textSource.TextLength;
}
int GetEndOffset(int lineNumber)
{
if (lineNumber == lines.Length)
return textSource.TextLength;
int off = lines[lineNumber] - 1;
if (off > 0 && textSource.GetCharAt(off - 1) == '\r' && textSource.GetCharAt(off) == '\n')
off--;
return off;
}
/// <inheritdoc/>
public IDocumentLine GetLineByOffset(int offset)
{
return GetLine(GetLineNumberForOffset(offset));
}
int GetLineNumberForOffset(int offset)
{
int r = Array.BinarySearch(lines, offset);
return r < 0 ? ~r : r + 1;
}
/// <inheritdoc/>
public int GetOffset(int line, int column)
{
if (line < 1 || line > lines.Length)
throw new ArgumentOutOfRangeException("line", line, "Value must be between 1 and " + lines.Length);
int lineStart = GetStartOffset(line);
if (column <= 0)
return lineStart;
int lineEnd = GetEndOffset(line);
if (column >= lineEnd - lineStart)
return lineEnd;
return lineStart + column - 1;
}
/// <inheritdoc/>
public int GetOffset(TextLocation location)
{
return GetOffset(location.Line, location.Column);
}
/// <inheritdoc/>
public TextLocation GetLocation(int offset)
{
if (offset < 0 || offset > textSource.TextLength)
throw new ArgumentOutOfRangeException("offset", offset, "Value must be between 0 and " + textSource.TextLength);
int line = GetLineNumberForOffset(offset);
return new TextLocation(offset-GetStartOffset(line)+1, line);
}
/// <inheritdoc/>
public string Text {
get { return textSource.Text; }
set {
throw new NotSupportedException();
}
}
/// <inheritdoc/>
public int TotalNumberOfLines {
get { return lines.Length; }
}
ITextSourceVersion ITextSource.Version {
get { return null; }
}
/// <inheritdoc/>
public int TextLength {
get { return textSource.TextLength; }
}
event EventHandler<TextChangeEventArgs> IDocument.Changing { add {} remove {} }
event EventHandler<TextChangeEventArgs> IDocument.Changed { add {} remove {} }
event EventHandler IDocument.TextChanged { add {} remove {} }
void IDocument.Insert(int offset, string text)
{
throw new NotSupportedException();
}
void IDocument.Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType)
{
throw new NotSupportedException();
}
void IDocument.Remove(int offset, int length)
{
throw new NotSupportedException();
}
void IDocument.Replace(int offset, int length, string newText)
{
throw new NotSupportedException();
}
void IDocument.StartUndoableAction()
{
}
void IDocument.EndUndoableAction()
{
}
IDisposable IDocument.OpenUndoGroup()
{
return null;
}
/// <inheritdoc/>
public ITextAnchor CreateAnchor(int offset)
{
return new ReadOnlyDocumentTextAnchor(GetLocation(offset), offset);
}
sealed class ReadOnlyDocumentTextAnchor : ITextAnchor
{
readonly TextLocation location;
readonly int offset;
public ReadOnlyDocumentTextAnchor(TextLocation location, int offset)
{
this.location = location;
this.offset = offset;
}
public event EventHandler Deleted { add {} remove {} }
public TextLocation Location {
get { return location; }
}
public int Offset {
get { return offset; }
}
public AnchorMovementType MovementType { get; set; }
public bool SurviveDeletion { get; set; }
public bool IsDeleted {
get { return false; }
}
public int Line {
get { return location.Line; }
}
public int Column {
get { return location.Column; }
}
}
/// <inheritdoc/>
public ITextSource CreateSnapshot()
{
return textSource; // textBuffer is immutable
}
/// <inheritdoc/>
public ITextSource CreateSnapshot(int offset, int length)
{
return textSource.CreateSnapshot(offset, length);
}
/// <inheritdoc/>
public System.IO.TextReader CreateReader()
{
return textSource.CreateReader();
}
/// <inheritdoc/>
public System.IO.TextReader CreateReader(int offset, int length)
{
return textSource.CreateReader(offset, length);
}
/// <inheritdoc/>
public char GetCharAt(int offset)
{
return textSource.GetCharAt(offset);
}
/// <inheritdoc/>
public string GetText(int offset, int length)
{
return textSource.GetText(offset, length);
}
/// <inheritdoc/>
public string GetText(ISegment segment)
{
return textSource.GetText(segment);
}
/// <inheritdoc/>
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
return textSource.IndexOfAny(anyOf, startIndex, count);
}
/// <inheritdoc/>
public object GetService(Type serviceType)
{
return null;
}
}
}

91
NRefactory/ICSharpCode.Editor/StringTextSource.cs

@ -0,0 +1,91 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT license (for details please see \doc\license.txt)
using System;
using System.IO;
namespace ICSharpCode.Editor
{
/// <summary>
/// Implements the ITextSource interface using a string.
/// </summary>
[Serializable]
public class StringTextSource : ITextSource
{
readonly string text;
/// <summary>
/// Creates a new StringTextSource with the given text.
/// </summary>
public StringTextSource(string text)
{
if (text == null)
throw new ArgumentNullException("text");
this.text = text;
}
ITextSourceVersion ITextSource.Version {
get { return null; }
}
/// <inheritdoc/>
public int TextLength {
get { return text.Length; }
}
/// <inheritdoc/>
public string Text {
get { return text; }
}
/// <inheritdoc/>
public ITextSource CreateSnapshot()
{
return this; // StringTextBuffer is immutable
}
/// <inheritdoc/>
public ITextSource CreateSnapshot(int offset, int length)
{
return new StringTextSource(text.Substring(offset, length));
}
/// <inheritdoc/>
public TextReader CreateReader()
{
return new StringReader(text);
}
/// <inheritdoc/>
public TextReader CreateReader(int offset, int length)
{
return new StringReader(text.Substring(offset, length));
}
/// <inheritdoc/>
public char GetCharAt(int offset)
{
return text[offset];
}
/// <inheritdoc/>
public string GetText(int offset, int length)
{
return text.Substring(offset, length);
}
/// <inheritdoc/>
public string GetText(ISegment segment)
{
if (segment == null)
throw new ArgumentNullException("segment");
return text.Substring(segment.Offset, segment.Length);
}
/// <inheritdoc/>
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
return text.IndexOfAny(anyOf, startIndex, count);
}
}
}

64
NRefactory/ICSharpCode.Editor/TextChangeEventArgs.cs

@ -0,0 +1,64 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT license (for details please see \doc\license.txt)
using System;
namespace ICSharpCode.Editor
{
/// <summary>
/// Describes a change of the document text.
/// This class is thread-safe.
/// </summary>
[Serializable]
public class TextChangeEventArgs : EventArgs
{
readonly int offset;
readonly string removedText;
readonly string insertedText;
/// <summary>
/// The offset at which the change occurs.
/// </summary>
public int Offset {
get { return offset; }
}
/// <summary>
/// The text that was inserted.
/// </summary>
public string RemovedText {
get { return removedText; }
}
/// <summary>
/// The number of characters removed.
/// </summary>
public int RemovalLength {
get { return removedText.Length; }
}
/// <summary>
/// The text that was inserted.
/// </summary>
public string InsertedText {
get { return insertedText; }
}
/// <summary>
/// The number of characters inserted.
/// </summary>
public int InsertionLength {
get { return insertedText.Length; }
}
/// <summary>
/// Creates a new TextChangeEventArgs object.
/// </summary>
public TextChangeEventArgs(int offset, string removedText, string insertedText)
{
this.offset = offset;
this.removedText = removedText ?? string.Empty;
this.insertedText = insertedText ?? string.Empty;
}
}
}

173
NRefactory/ICSharpCode.Editor/TextLocation.cs

@ -0,0 +1,173 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT license (for details please see \doc\license.txt)
using System;
using System.Globalization;
namespace ICSharpCode.Editor
{
/// <summary>
/// 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(TextLocation)"/> to convert between offsets and TextLocations.
/// </remarks>
[Serializable]
public struct TextLocation : IComparable<TextLocation>, IEquatable<TextLocation>
{
/// <summary>
/// Represents no text location (0, 0).
/// </summary>
public static readonly TextLocation Empty = new TextLocation(0, 0);
/// <summary>
/// Constant of the minimum line.
/// </summary>
public const int MinLine = 1;
/// <summary>
/// Constant of the minimum column.
/// </summary>
public const int MinColumn = 1;
/// <summary>
/// Creates a TextLocation instance.
/// </summary>
public TextLocation(int line, int column)
{
this.line = line;
this.column = column;
}
int column, line;
/// <summary>
/// Gets the line number.
/// </summary>
public int Line {
get { return line; }
}
/// <summary>
/// Gets the column number.
/// </summary>
public int Column {
get { return column; }
}
/// <summary>
/// Gets whether the TextLocation instance is empty.
/// </summary>
public bool IsEmpty {
get {
return column < MinLine && line < MinColumn;
}
}
/// <summary>
/// Gets a string representation for debugging purposes.
/// </summary>
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "(Line {1}, Col {0})", this.column, this.line);
}
/// <summary>
/// Gets a hash code.
/// </summary>
public override int GetHashCode()
{
return unchecked (191 * column.GetHashCode() ^ line.GetHashCode());
}
/// <summary>
/// Equality test.
/// </summary>
public override bool Equals(object obj)
{
if (!(obj is TextLocation)) return false;
return (TextLocation)obj == this;
}
/// <summary>
/// Equality test.
/// </summary>
public bool Equals(TextLocation other)
{
return this == other;
}
/// <summary>
/// Equality test.
/// </summary>
public static bool operator ==(TextLocation left, TextLocation right)
{
return left.column == right.column && left.line == right.line;
}
/// <summary>
/// Inequality test.
/// </summary>
public static bool operator !=(TextLocation left, TextLocation right)
{
return left.column != right.column || left.line != right.line;
}
/// <summary>
/// Compares two text locations.
/// </summary>
public static bool operator <(TextLocation left, TextLocation right)
{
if (left.line < right.line)
return true;
else if (left.line == right.line)
return left.column < right.column;
else
return false;
}
/// <summary>
/// Compares two text locations.
/// </summary>
public static bool operator >(TextLocation left, TextLocation right)
{
if (left.line > right.line)
return true;
else if (left.line == right.line)
return left.column > right.column;
else
return false;
}
/// <summary>
/// Compares two text locations.
/// </summary>
public static bool operator <=(TextLocation left, TextLocation right)
{
return !(left > right);
}
/// <summary>
/// Compares two text locations.
/// </summary>
public static bool operator >=(TextLocation left, TextLocation right)
{
return !(left < right);
}
/// <summary>
/// Compares two text locations.
/// </summary>
public int CompareTo(TextLocation other)
{
if (this == other)
return 0;
if (this < other)
return -1;
else
return 1;
}
}
}

2
NRefactory/ICSharpCode.NRefactory.Demo/CSDemo.cs

@ -180,7 +180,7 @@ namespace ICSharpCode.NRefactory.Demo
SimpleProjectContent project = new SimpleProjectContent(); SimpleProjectContent project = new SimpleProjectContent();
TypeSystemConvertVisitor convertVisitor = new TypeSystemConvertVisitor(project, "dummy.cs"); TypeSystemConvertVisitor convertVisitor = new TypeSystemConvertVisitor(project, "dummy.cs");
compilationUnit.AcceptVisitor(convertVisitor, null); compilationUnit.AcceptVisitor(convertVisitor, null);
project.UpdateProjectContent(null, convertVisitor.ParsedFile.TopLevelTypeDefinitions, null, null); project.UpdateProjectContent(null, convertVisitor.ParsedFile);
List<ITypeResolveContext> projects = new List<ITypeResolveContext>(); List<ITypeResolveContext> projects = new List<ITypeResolveContext>();
projects.Add(project); projects.Add(project);

26
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/InsertParenthesesVisitorTests.cs

@ -23,7 +23,8 @@ namespace ICSharpCode.NRefactory.CSharp
expr = expr.Clone(); expr = expr.Clone();
expr.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }, null); expr.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }, null);
StringWriter w = new StringWriter(); StringWriter w = new StringWriter();
expr.AcceptVisitor(new OutputVisitor(w, policy), null); w.NewLine = " ";
expr.AcceptVisitor(new OutputVisitor(new TextWriterOutputFormatter(w) { IndentationString = "" }, policy), null);
return w.ToString(); return w.ToString();
} }
@ -32,7 +33,8 @@ namespace ICSharpCode.NRefactory.CSharp
expr = expr.Clone(); expr = expr.Clone();
expr.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = false }, null); expr.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = false }, null);
StringWriter w = new StringWriter(); StringWriter w = new StringWriter();
expr.AcceptVisitor(new OutputVisitor(w, policy), null); w.NewLine = " ";
expr.AcceptVisitor(new OutputVisitor(new TextWriterOutputFormatter(w) { IndentationString = "" }, policy), null);
return w.ToString(); return w.ToString();
} }
@ -197,8 +199,8 @@ namespace ICSharpCode.NRefactory.CSharp
} }
}.Invoke("ToArray"); }.Invoke("ToArray");
Assert.AreEqual("(from a in b" + Environment.NewLine + "select a.c ()).ToArray ()", InsertRequired(expr)); Assert.AreEqual("( from a in b select a.c ()).ToArray ()", InsertRequired(expr));
Assert.AreEqual("(from a in b" + Environment.NewLine + "select a.c ()).ToArray ()", InsertReadable(expr)); Assert.AreEqual("( from a in b select a.c ()).ToArray ()", InsertReadable(expr));
} }
[Test] [Test]
@ -221,12 +223,10 @@ namespace ICSharpCode.NRefactory.CSharp
query.Clone() query.Clone()
); );
Assert.AreEqual("(from a in b" + Environment.NewLine + Assert.AreEqual("( from a in b select a) + " +
"select a) + from a in b" + Environment.NewLine + " from a in b select a", InsertRequired(expr));
"select a", InsertRequired(expr)); Assert.AreEqual("( from a in b select a) + " +
Assert.AreEqual("(from a in b" + Environment.NewLine + "( from a in b select a)", InsertReadable(expr));
"select a) + (from a in b" + Environment.NewLine +
"select a)", InsertReadable(expr));
} }
[Test] [Test]
@ -244,10 +244,8 @@ namespace ICSharpCode.NRefactory.CSharp
} }
}.IsType(new PrimitiveType("int")); }.IsType(new PrimitiveType("int"));
Assert.AreEqual("(from a in b" + Environment.NewLine + Assert.AreEqual("( from a in b select a) is int", InsertRequired(expr));
"select a) is int", InsertRequired(expr)); Assert.AreEqual("( from a in b select a) is int", InsertReadable(expr));
Assert.AreEqual("(from a in b" + Environment.NewLine +
"select a) is int", InsertReadable(expr));
} }
[Test] [Test]

17
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/TypeOfExpressionTests.cs

@ -118,7 +118,22 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression
"typeof(MyType<,>)", "typeof(MyType<,>)",
new TypeOfExpression { new TypeOfExpression {
Type = type Type = type
}); });
}
[Test]
public void NestedArraysTest()
{
ParseUtilCSharp.AssertExpression(
"typeof(int[,][])",
new TypeOfExpression {
Type = new ComposedType {
BaseType = new PrimitiveType("int"),
ArraySpecifiers = {
new ArraySpecifier(2),
new ArraySpecifier(1)
}
}});
} }
} }
} }

69
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/AttributeSectionTests.cs

@ -4,7 +4,9 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.PatternMatching;
using ICSharpCode.NRefactory.TypeSystem;
using NUnit.Framework; using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope
@ -12,7 +14,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope
[TestFixture] [TestFixture]
public class AttributeSectionTests public class AttributeSectionTests
{ {
[Test, Ignore("Parser crash")] [Test]
public void GlobalAttributeCSharp() public void GlobalAttributeCSharp()
{ {
string program = @"[global::Microsoft.VisualBasic.CompilerServices.DesignerGenerated()] string program = @"[global::Microsoft.VisualBasic.CompilerServices.DesignerGenerated()]
@ -27,7 +29,7 @@ public class Form1 {
Assert.AreEqual("someprefix::DesignerGenerated", decl.Attributes.Last().Attributes.Single().Type.ToString()); Assert.AreEqual("someprefix::DesignerGenerated", decl.Attributes.Last().Attributes.Single().Type.ToString());
} }
[Test, Ignore("assembly/module attributes are broken")] [Test]
public void AssemblyAttributeCSharp() public void AssemblyAttributeCSharp()
{ {
string program = @"[assembly: System.Attribute()]"; string program = @"[assembly: System.Attribute()]";
@ -80,20 +82,59 @@ public class Form1 {
[Test, Ignore("Parser doesn't support attributes on type parameters")] [Test, Ignore("Parser doesn't support attributes on type parameters")]
public void AttributesOnTypeParameter() public void AttributesOnTypeParameter()
{ {
string program = @"class Test<[A,B]C> {}"; ParseUtilCSharp.AssertGlobal(
TypeDeclaration type = ParseUtilCSharp.ParseGlobal<TypeDeclaration>(program); "class Test<[A,B]C> {}",
Assert.IsTrue( new TypeDeclaration {
new TypeParameterDeclaration { ClassType = ClassType.Class,
Attributes = { Name = "Test",
new AttributeSection { TypeParameters = {
new TypeParameterDeclaration {
Attributes = { Attributes = {
new Attribute { Type = new SimpleType("A") }, new AttributeSection {
new Attribute { Type = new SimpleType("B") } Attributes = {
} new Attribute { Type = new SimpleType("A") },
new Attribute { Type = new SimpleType("B") }
}
}
},
Name = "C"
}
}});
}
[Test]
public void AttributeOnMethodParameter()
{
ParseUtilCSharp.AssertTypeMember(
"void M([In] int p);",
new MethodDeclaration {
ReturnType = new PrimitiveType("void"),
Name = "M",
Parameters = {
new ParameterDeclaration {
Attributes = { new AttributeSection(new Attribute { Type = new SimpleType("In") }) },
Type = new PrimitiveType("int"),
Name = "p"
} }
}, }});
Name = "C" }
}.IsMatch(type.TypeParameters.Single()));
[Test]
public void AttributeOnSetterValue()
{
ParseUtilCSharp.AssertTypeMember(
"int P { get; [param: In] set; }",
new PropertyDeclaration {
ReturnType = new PrimitiveType("int"),
Name = "P",
Getter = new Accessor(),
Setter = new Accessor {
Attributes = {
new AttributeSection {
AttributeTarget = "param",
Attributes = { new Attribute { Type = new SimpleType("In") } },
} },
}});
} }
// TODO: Tests for other contexts where attributes can appear // TODO: Tests for other contexts where attributes can appear

8
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs

@ -280,5 +280,13 @@ public abstract class MyClass : MyBase, Interface1, My.Test.Interface2
Assert.AreEqual("Val1", member.Name); Assert.AreEqual("Val1", member.Name);
Assert.AreEqual(10, ((PrimitiveExpression)member.Initializer).Value); Assert.AreEqual(10, ((PrimitiveExpression)member.Initializer).Value);
} }
[Test]
public void EnumWithBaseType()
{
TypeDeclaration td = ParseUtilCSharp.ParseGlobal<TypeDeclaration>("enum MyEnum : short { }");
Assert.AreEqual("MyEnum", td.Name);
Assert.AreEqual("short", ((PrimitiveType)td.BaseTypes.Single()).Keyword);
}
} }
} }

4
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs

@ -10,7 +10,7 @@ using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Parser namespace ICSharpCode.NRefactory.CSharp.Parser
{ {
[TestFixture, Ignore("TypeSystemConvertVisitor is not complete yet")] [TestFixture]
public class TypeSystemConvertVisitorTests : TypeSystemTests public class TypeSystemConvertVisitorTests : TypeSystemTests
{ {
ITypeResolveContext ctx = CecilLoaderTests.Mscorlib; ITypeResolveContext ctx = CecilLoaderTests.Mscorlib;
@ -30,7 +30,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser
TypeSystemConvertVisitor visitor = new TypeSystemConvertVisitor(testCasePC, fileName); TypeSystemConvertVisitor visitor = new TypeSystemConvertVisitor(testCasePC, fileName);
cu.AcceptVisitor(visitor, null); cu.AcceptVisitor(visitor, null);
ParsedFile parsedFile = visitor.ParsedFile; ParsedFile parsedFile = visitor.ParsedFile;
((SimpleProjectContent)testCasePC).UpdateProjectContent(null, parsedFile.TopLevelTypeDefinitions, null, null); ((SimpleProjectContent)testCasePC).UpdateProjectContent(null, parsedFile);
} }
} }
} }

8
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/AttributeTests.cs

@ -7,7 +7,7 @@ using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Resolver namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
[TestFixture, Ignore("DOM for attributes is incomplete")] [TestFixture]
public class AttributeTests : ResolverTestBase public class AttributeTests : ResolverTestBase
{ {
[Test] [Test]
@ -41,7 +41,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
string program = "using System; [$LoaderOptimization(3)$] class Test { }"; string program = "using System; [$LoaderOptimization(3)$] class Test { }";
var mrr = Resolve<MemberResolveResult>(program); var mrr = Resolve<MemberResolveResult>(program);
Assert.AreEqual("System.LoaderOptimization.#ctor", mrr.Member.FullName); Assert.AreEqual("System.LoaderOptimizationAttribute..ctor", mrr.Member.FullName);
Assert.AreEqual("System.Byte", (mrr.Member as IMethod).Parameters[0].Type.Resolve(context).FullName); Assert.AreEqual("System.Byte", (mrr.Member as IMethod).Parameters[0].Type.Resolve(context).FullName);
} }
@ -50,7 +50,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
string program = "using System; [$LoaderOptimization(LoaderOptimization.NotSpecified)$] class Test { }"; string program = "using System; [$LoaderOptimization(LoaderOptimization.NotSpecified)$] class Test { }";
var mrr = Resolve<MemberResolveResult>(program); var mrr = Resolve<MemberResolveResult>(program);
Assert.AreEqual("System.LoaderOptimization.#ctor", mrr.Member.FullName); Assert.AreEqual("System.LoaderOptimizationAttribute..ctor", mrr.Member.FullName);
Assert.AreEqual("System.LoaderOptimization", (mrr.Member as IMethod).Parameters[0].Type.Resolve(context).FullName); Assert.AreEqual("System.LoaderOptimization", (mrr.Member as IMethod).Parameters[0].Type.Resolve(context).FullName);
} }
@ -78,7 +78,7 @@ enum E { A, B }
Assert.AreEqual("MyNamespace.E.A", result.Member.FullName); Assert.AreEqual("MyNamespace.E.A", result.Member.FullName);
} }
[Test] [Test, Ignore("Not implemented in type system.")]
public void SD_1384() public void SD_1384()
{ {
string program = @"using System; string program = @"using System;

57
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/BinaryOperatorTests.cs

@ -388,5 +388,62 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
AssertType(typeof(dynamic), resolver.ResolveBinaryOperator( AssertType(typeof(dynamic), resolver.ResolveBinaryOperator(
BinaryOperatorType.NullCoalescing, MakeResult(typeof(string)), MakeResult(typeof(dynamic)))); BinaryOperatorType.NullCoalescing, MakeResult(typeof(string)), MakeResult(typeof(dynamic))));
} }
[Test, Ignore("user-defined operators not yet implemented")]
public void LiftedUserDefined()
{
AssertType(typeof(TimeSpan), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(DateTime)), MakeResult(typeof(DateTime))));
AssertType(typeof(TimeSpan?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(DateTime?)), MakeResult(typeof(DateTime))));
AssertType(typeof(TimeSpan?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(DateTime)), MakeResult(typeof(DateTime?))));
AssertType(typeof(TimeSpan?), resolver.ResolveBinaryOperator(
BinaryOperatorType.Subtract, MakeResult(typeof(DateTime?)), MakeResult(typeof(DateTime?))));
}
[Test, Ignore("user-defined operators not yet implemented")]
public void UserDefinedNeedsLiftingDueToImplicitConversion()
{
string program = @"struct S {}
struct A {
public static implicit operator S?(A a) { return null; }
public static S operator +(A a, S s) { return s; }
}
class Test {
void M(A a) {
var s = $a + a$;
}
}
";
MemberResolveResult trr = Resolve<MemberResolveResult>(program);
Assert.IsFalse(trr.IsError);
Assert.AreEqual("A.op_Addition", trr.Member.FullName);
// even though we're calling the lifted operator, trr.Member should be the original operator method
Assert.AreEqual("S", trr.Member.ReturnType.Resolve(context).ReflectionName);
Assert.AreEqual("System.Nullable`1[[S]]", trr.Type.ReflectionName);
}
[Test, Ignore("user-defined operators not yet implemented")]
public void ThereIsNoLiftedOperatorsForClasses()
{
string program = @"struct S {}
class A {
public static implicit operator S?(A a) { return null; }
public static S operator +(A a, S s) { return s; }
}
class Test {
void M(A a) {
var s = $a + a$;
}
}
";
MemberResolveResult trr = Resolve<MemberResolveResult>(program);
Assert.IsTrue(trr.IsError); // cannot convert from A to S
Assert.AreEqual("A.op_Addition", trr.Member.FullName);
Assert.AreEqual("S", trr.Type.ReflectionName);
}
} }
} }

115
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs

@ -5,6 +5,7 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using NUnit.Framework; using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Resolver namespace ICSharpCode.NRefactory.CSharp.Resolver
@ -16,13 +17,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
[TestFixture] [TestFixture]
public unsafe class ConversionsTest public unsafe class ConversionsTest
{ {
IProjectContent mscorlib = CecilLoaderTests.Mscorlib; ITypeResolveContext ctx = CecilLoaderTests.Mscorlib;
Conversions conversions = new Conversions(CecilLoaderTests.Mscorlib); Conversions conversions = new Conversions(CecilLoaderTests.Mscorlib);
bool ImplicitConversion(Type from, Type to) bool ImplicitConversion(Type from, Type to)
{ {
IType from2 = from.ToTypeReference().Resolve(mscorlib); IType from2 = from.ToTypeReference().Resolve(ctx);
IType to2 = to.ToTypeReference().Resolve(mscorlib); IType to2 = to.ToTypeReference().Resolve(ctx);
return conversions.ImplicitConversion(from2, to2); return conversions.ImplicitConversion(from2, to2);
} }
@ -194,18 +195,102 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.IsFalse(ImplicitConversion(typeof(int*), typeof(dynamic))); Assert.IsFalse(ImplicitConversion(typeof(int*), typeof(dynamic)));
} }
[Test, Ignore] [Test]
public void TypeParameterConversions() public void UnconstrainedTypeParameter()
{
DefaultTypeParameter t = new DefaultTypeParameter(EntityType.TypeDefinition, 0, "T");
DefaultTypeParameter t2 = new DefaultTypeParameter(EntityType.TypeDefinition, 1, "T2");
DefaultTypeParameter tm = new DefaultTypeParameter(EntityType.Method, 0, "TM");
Assert.IsFalse(conversions.ImplicitConversion(SharedTypes.Null, t));
Assert.IsTrue(conversions.ImplicitConversion(t, KnownTypeReference.Object.Resolve(ctx)));
Assert.IsTrue(conversions.ImplicitConversion(t, SharedTypes.Dynamic));
Assert.IsFalse(conversions.ImplicitConversion(t, ctx.GetTypeDefinition(typeof(ValueType))));
Assert.IsTrue(conversions.ImplicitConversion(t, t));
Assert.IsFalse(conversions.ImplicitConversion(t2, t));
Assert.IsFalse(conversions.ImplicitConversion(t, t2));
Assert.IsFalse(conversions.ImplicitConversion(t, tm));
Assert.IsFalse(conversions.ImplicitConversion(tm, t));
}
[Test]
public void TypeParameterWithReferenceTypeConstraint()
{
DefaultTypeParameter t = new DefaultTypeParameter(EntityType.TypeDefinition, 0, "T");
t.HasReferenceTypeConstraint = true;
Assert.IsTrue(conversions.ImplicitConversion(SharedTypes.Null, t));
Assert.IsTrue(conversions.ImplicitConversion(t, KnownTypeReference.Object.Resolve(ctx)));
Assert.IsTrue(conversions.ImplicitConversion(t, SharedTypes.Dynamic));
Assert.IsFalse(conversions.ImplicitConversion(t, ctx.GetTypeDefinition(typeof(ValueType))));
}
[Test]
public void TypeParameterWithValueTypeConstraint()
{
DefaultTypeParameter t = new DefaultTypeParameter(EntityType.TypeDefinition, 0, "T");
t.HasValueTypeConstraint = true;
Assert.IsFalse(conversions.ImplicitConversion(SharedTypes.Null, t));
Assert.IsTrue(conversions.ImplicitConversion(t, KnownTypeReference.Object.Resolve(ctx)));
Assert.IsTrue(conversions.ImplicitConversion(t, SharedTypes.Dynamic));
Assert.IsTrue(conversions.ImplicitConversion(t, ctx.GetTypeDefinition(typeof(ValueType))));
}
[Test]
public void TypeParameterWithClassConstraint()
{
DefaultTypeParameter t = new DefaultTypeParameter(EntityType.TypeDefinition, 0, "T");
t.Constraints.Add(ctx.GetTypeDefinition(typeof(StringComparer)));
Assert.IsTrue(conversions.ImplicitConversion(SharedTypes.Null, t));
Assert.IsTrue(conversions.ImplicitConversion(t, KnownTypeReference.Object.Resolve(ctx)));
Assert.IsTrue(conversions.ImplicitConversion(t, SharedTypes.Dynamic));
Assert.IsFalse(conversions.ImplicitConversion(t, ctx.GetTypeDefinition(typeof(ValueType))));
Assert.IsTrue(conversions.ImplicitConversion(t, ctx.GetTypeDefinition(typeof(StringComparer))));
Assert.IsTrue(conversions.ImplicitConversion(t, ctx.GetTypeDefinition(typeof(IComparer))));
Assert.IsFalse(conversions.ImplicitConversion(t, typeof(IComparer<int>).ToTypeReference().Resolve(ctx)));
Assert.IsTrue(conversions.ImplicitConversion(t, typeof(IComparer<string>).ToTypeReference().Resolve(ctx)));
}
[Test]
public void TypeParameterWithInterfaceConstraint()
{
DefaultTypeParameter t = new DefaultTypeParameter(EntityType.TypeDefinition, 0, "T");
t.Constraints.Add(ctx.GetTypeDefinition(typeof(IList)));
Assert.IsFalse(conversions.ImplicitConversion(SharedTypes.Null, t));
Assert.IsTrue(conversions.ImplicitConversion(t, KnownTypeReference.Object.Resolve(ctx)));
Assert.IsTrue(conversions.ImplicitConversion(t, SharedTypes.Dynamic));
Assert.IsFalse(conversions.ImplicitConversion(t, ctx.GetTypeDefinition(typeof(ValueType))));
Assert.IsTrue(conversions.ImplicitConversion(t, ctx.GetTypeDefinition(typeof(IList))));
Assert.IsTrue(conversions.ImplicitConversion(t, ctx.GetTypeDefinition(typeof(IEnumerable))));
}
[Test]
public void UserDefinedImplicitConversion()
{
Assert.IsTrue(ImplicitConversion(typeof(DateTime), typeof(DateTimeOffset)));
Assert.IsFalse(ImplicitConversion(typeof(DateTimeOffset), typeof(DateTime)));
}
[Test]
public void UserDefinedImplicitNullableConversion()
{ {
// TODO: write tests for conversions of type parameters // User-defined conversion followed by nullable conversion
throw new NotImplementedException(); Assert.IsTrue(ImplicitConversion(typeof(DateTime), typeof(DateTimeOffset?)));
// Lifted user-defined conversion
Assert.IsTrue(ImplicitConversion(typeof(DateTime?), typeof(DateTimeOffset?)));
// User-defined conversion doesn't drop the nullability
Assert.IsFalse(ImplicitConversion(typeof(DateTime?), typeof(DateTimeOffset)));
} }
bool IntegerLiteralConversion(object value, Type to) bool IntegerLiteralConversion(object value, Type to)
{ {
IType fromType = value.GetType().ToTypeReference().Resolve(mscorlib); IType fromType = value.GetType().ToTypeReference().Resolve(ctx);
ConstantResolveResult crr = new ConstantResolveResult(fromType, value); ConstantResolveResult crr = new ConstantResolveResult(fromType, value);
IType to2 = to.ToTypeReference().Resolve(mscorlib); IType to2 = to.ToTypeReference().Resolve(ctx);
return conversions.ImplicitConversion(crr, to2); return conversions.ImplicitConversion(crr, to2);
} }
@ -280,18 +365,18 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
int BetterConversion(Type s, Type t1, Type t2) int BetterConversion(Type s, Type t1, Type t2)
{ {
IType sType = s.ToTypeReference().Resolve(mscorlib); IType sType = s.ToTypeReference().Resolve(ctx);
IType t1Type = t1.ToTypeReference().Resolve(mscorlib); IType t1Type = t1.ToTypeReference().Resolve(ctx);
IType t2Type = t2.ToTypeReference().Resolve(mscorlib); IType t2Type = t2.ToTypeReference().Resolve(ctx);
return conversions.BetterConversion(sType, t1Type, t2Type); return conversions.BetterConversion(sType, t1Type, t2Type);
} }
int BetterConversion(object value, Type t1, Type t2) int BetterConversion(object value, Type t1, Type t2)
{ {
IType fromType = value.GetType().ToTypeReference().Resolve(mscorlib); IType fromType = value.GetType().ToTypeReference().Resolve(ctx);
ConstantResolveResult crr = new ConstantResolveResult(fromType, value); ConstantResolveResult crr = new ConstantResolveResult(fromType, value);
IType t1Type = t1.ToTypeReference().Resolve(mscorlib); IType t1Type = t1.ToTypeReference().Resolve(ctx);
IType t2Type = t2.ToTypeReference().Resolve(mscorlib); IType t2Type = t2.ToTypeReference().Resolve(ctx);
return conversions.BetterConversion(crr, t1Type, t2Type); return conversions.BetterConversion(crr, t1Type, t2Type);
} }

2
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExtensionMethodTests.cs

@ -57,7 +57,7 @@ namespace XN {
Assert.AreEqual("C.F", mrr.Member.FullName); Assert.AreEqual("C.F", mrr.Member.FullName);
} }
[Test, Ignore("Test fails due to parser returning incorrect position")] [Test, Ignore("Anonymous methods not yet implemented")]
public void ExtensionMethodsTest2() public void ExtensionMethodsTest2()
{ {
string program = @"using System; using System.Collections.Generic; string program = @"using System; using System.Collections.Generic;

12
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs

@ -49,7 +49,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.AreSame(SharedTypes.UnknownType, result.Type); Assert.AreSame(SharedTypes.UnknownType, result.Type);
} }
[Test, Ignore("Inheritance not supported in parser")] [Test, Ignore("Resolver returns the member from the base class, which is correct according to C# spec, but not what we want to show in tooltips")]
public void OverriddenMethodCall() public void OverriddenMethodCall()
{ {
string program = @"class A { string program = @"class A {
@ -70,7 +70,7 @@ class B : A {
Assert.AreEqual("B.GetRandomNumber", result.Member.FullName); Assert.AreEqual("B.GetRandomNumber", result.Member.FullName);
} }
[Test, Ignore("Inheritance not supported in parser")] [Test, Ignore("Resolver returns the member from the base class, which is correct according to C# spec, but not what we want to show in tooltips")]
public void OverriddenMethodCall2() public void OverriddenMethodCall2()
{ {
string program = @"class A { string program = @"class A {
@ -122,7 +122,7 @@ class A {
Assert.AreEqual("System.Void", Resolve(program).Type.ReflectionName); Assert.AreEqual("System.Void", Resolve(program).Type.ReflectionName);
} }
[Test, Ignore("parser is broken for events")] [Test]
public void EventCallTest() public void EventCallTest()
{ {
string program = @"using System; string program = @"using System;
@ -209,7 +209,7 @@ class Program {
Assert.IsTrue(((IMethod)mrr.Member).Parameters[0].IsRef); Assert.IsTrue(((IMethod)mrr.Member).Parameters[0].IsRef);
} }
[Test, Ignore("Inheritance not supported in parser")] [Test, Ignore("Grouping by declaring type not yet implemented")]
public void AddedOverload() public void AddedOverload()
{ {
string program = @"class BaseClass { string program = @"class BaseClass {
@ -225,7 +225,7 @@ class DerivedClass : BaseClass {
Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName); Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName);
} }
[Test, Ignore("Inheritance not supported in parser")] [Test]
public void AddedNonApplicableOverload() public void AddedNonApplicableOverload()
{ {
string program = @"class BaseClass { string program = @"class BaseClass {
@ -244,7 +244,7 @@ class DerivedClass : BaseClass {
Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName); Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName);
} }
[Test, Ignore("Inheritance not supported in parser")] [Test, Ignore("Grouping by declaring type not yet implemented")]
public void OverrideShadowed() public void OverrideShadowed()
{ {
string program = @"using System; string program = @"using System;

2
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs

@ -6,7 +6,7 @@ using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Resolver namespace ICSharpCode.NRefactory.CSharp.Resolver
{ {
[TestFixture, Ignore("Expression Lambdas not supported by parser")] [TestFixture, Ignore("Lambdas not supported by resolver")]
public class LambdaTests : ResolverTestBase public class LambdaTests : ResolverTestBase
{ {
[Test] [Test]

88
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs

@ -134,7 +134,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public void FindTypeParameters() public void FindTypeParameters()
{ {
resolver.UsingScope = MakeUsingScope("System.Collections.Generic"); resolver.UsingScope = MakeUsingScope("System.Collections.Generic");
resolver.CurrentTypeDefinition = context.GetClass(typeof(List<>)); resolver.CurrentTypeDefinition = context.GetTypeDefinition(typeof(List<>));
resolver.CurrentMember = resolver.CurrentTypeDefinition.Methods.Single(m => m.Name == "ConvertAll"); resolver.CurrentMember = resolver.CurrentTypeDefinition.Methods.Single(m => m.Name == "ConvertAll");
TypeResolveResult trr; TypeResolveResult trr;
@ -191,7 +191,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Assert.AreSame(SharedTypes.UnknownType, result.Type); Assert.AreSame(SharedTypes.UnknownType, result.Type);
} }
[Test, Ignore("not yet implemented (depends on distuishing types and expressions in the DOM)")] [Test]
public void PropertyNameAmbiguousWithTypeName() public void PropertyNameAmbiguousWithTypeName()
{ {
string program = @"class A { string program = @"class A {
@ -230,7 +230,7 @@ class Color { public static readonly Color Empty = null; }
Assert.AreEqual("value", result.Variable.Name); Assert.AreEqual("value", result.Variable.Name);
} }
[Test, Ignore("type references not supported")] [Test]
public void ValueInsideEventTest() public void ValueInsideEventTest()
{ {
string program = @"using System; class A { string program = @"using System; class A {
@ -263,7 +263,7 @@ class Color { public static readonly Color Empty = null; }
Assert.AreEqual("value", result.Variable.Name); Assert.AreEqual("value", result.Variable.Name);
} }
[Test, Ignore("Anonymous method parameters not supported by parser")] [Test, Ignore("Anonymous methods not supported in resolver")]
public void AnonymousMethodParameters() public void AnonymousMethodParameters()
{ {
string program = @"using System; string program = @"using System;
@ -350,7 +350,7 @@ namespace Root.Child {
Assert.AreEqual("Root.Alpha", result.Type.FullName); Assert.AreEqual("Root.Alpha", result.Type.FullName);
} }
[Test, Ignore("type references not implemented")] [Test]
public void ImportAliasTest() public void ImportAliasTest()
{ {
string program = @"using COL = System.Collections; string program = @"using COL = System.Collections;
@ -366,7 +366,7 @@ class TestClass {
Assert.AreEqual("System.Collections.ArrayList", member.Type.FullName, "the full type should be resolved"); Assert.AreEqual("System.Collections.ArrayList", member.Type.FullName, "the full type should be resolved");
} }
[Test, Ignore("Parser position bug")] [Test]
public void ImportAliasNamespaceResolveTest() public void ImportAliasNamespaceResolveTest()
{ {
NamespaceResolveResult ns; NamespaceResolveResult ns;
@ -377,7 +377,7 @@ class TestClass {
Assert.AreEqual("System.Collections.Generic", ns.NamespaceName, "COL.Generic"); Assert.AreEqual("System.Collections.Generic", ns.NamespaceName, "COL.Generic");
} }
[Test, Ignore("Cannot resolve type references")] [Test]
public void ImportAliasClassResolveTest() public void ImportAliasClassResolveTest()
{ {
string program = @"using COL = System.Collections.ArrayList; string program = @"using COL = System.Collections.ArrayList;
@ -394,7 +394,36 @@ class TestClass {
Assert.AreEqual("System.Collections.ArrayList", rr.Type.FullName, "a"); Assert.AreEqual("System.Collections.ArrayList", rr.Type.FullName, "a");
} }
[Test, Ignore("Parser position bug")] [Test]
public void ImportSubnamespaceWithAliasTest()
{
string program = @"namespace PC
{
// Define an alias for the nested namespace.
using Project = PC.MyCompany.Project;
class A
{
Project.MyClass M()
{
// Use the alias
$Project.MyClass$ mc = new Project.MyClass();
return mc;
}
}
namespace MyCompany
{
namespace Project
{
public class MyClass { }
}
}
}
";
var mrr = Resolve(program);
Assert.AreEqual("PC.MyCompany.Project.MyClass", mrr.Type.FullName);
}
[Test]
public void ResolveNamespaceSD_863() public void ResolveNamespaceSD_863()
{ {
string program = @"using System; string program = @"using System;
@ -414,7 +443,7 @@ namespace A.B {
Assert.AreEqual("A.B.C.D", trr.Type.FullName); Assert.AreEqual("A.B.C.D", trr.Type.FullName);
} }
[Test, Ignore("Broken due to parser returning incorrect positions")] [Test]
public void ResolveTypeSD_863() public void ResolveTypeSD_863()
{ {
string program = @"using System; string program = @"using System;
@ -432,6 +461,31 @@ namespace A.B {
Assert.AreEqual("A.B.C", trr.Type.FullName); Assert.AreEqual("A.B.C", trr.Type.FullName);
} }
[Test]
public void InnerTypeResolve ()
{
string program = @"public class C<T> { public class Inner { } }
class TestClass {
void Test() {
$C<string>.Inner$ a;
}
}
";
TypeResolveResult trr = Resolve<TypeResolveResult>(program);
Assert.AreEqual("C.Inner", trr.Type.FullName);
program = @"public class C<T> { public class D<S,U> { public class Inner { } }}
class TestClass {
void Test() {
$C<string>.D<int,TestClass>.Inner$ a;
}
}
";
trr = Resolve<TypeResolveResult>(program);
Assert.AreEqual("C.D.Inner", trr.Type.FullName);
}
[Test, Ignore("parser is broken and produces IdentifierExpression instead of PrimitiveType")] [Test, Ignore("parser is broken and produces IdentifierExpression instead of PrimitiveType")]
public void ShortMaxValueTest() public void ShortMaxValueTest()
{ {
@ -446,7 +500,7 @@ class TestClass {
Assert.AreEqual(short.MaxValue, rr.ConstantValue); Assert.AreEqual(short.MaxValue, rr.ConstantValue);
} }
[Test, Ignore("Parser produces incorrect positions for :: operator")] [Test]
public void ClassWithSameNameAsNamespace() public void ClassWithSameNameAsNamespace()
{ {
string program = @"using System; namespace XX { string program = @"using System; namespace XX {
@ -471,7 +525,7 @@ class TestClass {
Assert.AreEqual("XX.XX.Test", mrr.Member.FullName); Assert.AreEqual("XX.XX.Test", mrr.Member.FullName);
} }
[Test, Ignore("Parser position bug")] [Test]
public void ClassNameLookup1() public void ClassNameLookup1()
{ {
string program = @"namespace MainNamespace { string program = @"namespace MainNamespace {
@ -490,7 +544,7 @@ namespace Test.Subnamespace {
Assert.AreEqual("Test.Subnamespace.Test.TheClass", trr.Type.FullName); Assert.AreEqual("Test.Subnamespace.Test.TheClass", trr.Type.FullName);
} }
[Test, Ignore("Parser position bug")] [Test]
public void ClassNameLookup2() public void ClassNameLookup2()
{ {
string program = @"using Test.Subnamespace; string program = @"using Test.Subnamespace;
@ -566,7 +620,7 @@ namespace A {
Assert.AreEqual("MainNamespace.Test", nrr.NamespaceName); Assert.AreEqual("MainNamespace.Test", nrr.NamespaceName);
} }
[Test, Ignore("Fails because parser does not support base type references")] [Test]
public void InvocableRule() public void InvocableRule()
{ {
string program = @"using System; string program = @"using System;
@ -593,7 +647,7 @@ namespace A {
Assert.AreEqual("BaseClass.Test", mrr.Member.FullName); Assert.AreEqual("BaseClass.Test", mrr.Member.FullName);
} }
[Test, Ignore("Fails because parser does not support base type references")] [Test]
public void InvocableRule2() public void InvocableRule2()
{ {
string program = @"using System; string program = @"using System;
@ -621,7 +675,7 @@ namespace A {
Assert.AreEqual("BaseClass.Test", mrr.Member.FullName); Assert.AreEqual("BaseClass.Test", mrr.Member.FullName);
} }
[Test, Ignore("Fails because parser does not support base type references")] [Test]
public void AccessibleRule() public void AccessibleRule()
{ {
string program = @"using System; string program = @"using System;
@ -676,7 +730,7 @@ namespace A {
Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName); Assert.AreEqual("DerivedClass.Test", mrr.Member.FullName);
} }
[Test, Ignore("Parser doesn't support inheritance")] [Test, Ignore("Resolver Bug")]
public void SD_1487() public void SD_1487()
{ {
string program = @"using System; string program = @"using System;
@ -713,7 +767,7 @@ class Test {
Assert.AreEqual("System.Int32", rr.Member.ReturnType.Resolve(context).FullName); Assert.AreEqual("System.Int32", rr.Member.ReturnType.Resolve(context).FullName);
} }
[Test, Ignore("Parser doesn't support inheritance")] [Test, Ignore("Resolver bug")]
public void MethodHidesEvent() public void MethodHidesEvent()
{ {
// see SD-1542 // see SD-1542

2
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ObjectCreationTests.cs

@ -100,7 +100,7 @@ class A {
Assert.AreEqual(0, m.Parameters.Count); Assert.AreEqual(0, m.Parameters.Count);
} }
[Test, Ignore("parser doesn't produce any nodes for base constructor calls")] [Test, Ignore("Not implemented")]
public void ChainedConstructorCall() public void ChainedConstructorCall()
{ {
string program = @"using System; string program = @"using System;

2
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ResolverTestBase.cs

@ -151,7 +151,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ParsedFile parsedFile = new ParsedFile("test.cs", rootUsingScope); ParsedFile parsedFile = new ParsedFile("test.cs", rootUsingScope);
TypeSystemConvertVisitor convertVisitor = new TypeSystemConvertVisitor(parsedFile, resolver.UsingScope, null); TypeSystemConvertVisitor convertVisitor = new TypeSystemConvertVisitor(parsedFile, resolver.UsingScope, null);
cu.AcceptVisitor(convertVisitor, null); cu.AcceptVisitor(convertVisitor, null);
project.UpdateProjectContent(null, convertVisitor.ParsedFile.TopLevelTypeDefinitions, null, null); project.UpdateProjectContent(null, convertVisitor.ParsedFile);
FindNodeVisitor fnv = new FindNodeVisitor(dollars[0], dollars[1]); FindNodeVisitor fnv = new FindNodeVisitor(dollars[0], dollars[1]);
cu.AcceptVisitor(fnv, null); cu.AcceptVisitor(fnv, null);

47
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/TypeInferenceTests.cs

@ -6,8 +6,8 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using NUnit.Framework; using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Resolver namespace ICSharpCode.NRefactory.CSharp.Resolver
@ -15,14 +15,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
[TestFixture] [TestFixture]
public class TypeInferenceTests public class TypeInferenceTests
{ {
readonly ITypeResolveContext ctx = CecilLoaderTests.Mscorlib;
TypeInference ti; TypeInference ti;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
ti = new TypeInference(CecilLoaderTests.Mscorlib); ti = new TypeInference(ctx);
} }
#region Type Inference
IType[] Resolve(params Type[] types) IType[] Resolve(params Type[] types)
{ {
IType[] r = new IType[types.Length]; IType[] r = new IType[types.Length];
@ -34,6 +36,46 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return r; return r;
} }
[Test]
public void ArrayToEnumerable()
{
ITypeParameter tp = new DefaultTypeParameter(EntityType.Method, 0, "T");
IType stringType = KnownTypeReference.String.Resolve(ctx);
ITypeDefinition enumerableType = ctx.GetTypeDefinition(typeof(IEnumerable<>));
bool success;
Assert.AreEqual(
new [] { stringType },
ti.InferTypeArguments(new [] { tp },
new [] { new ResolveResult(new ArrayType(stringType)) },
new [] { new ParameterizedType(enumerableType, new [] { tp }) },
out success));
Assert.IsTrue(success);
}
[Test]
public void EnumerableToArrayInContravariantType()
{
ITypeParameter tp = new DefaultTypeParameter(EntityType.Method, 0, "T");
IType stringType = KnownTypeReference.String.Resolve(ctx);
ITypeDefinition enumerableType = ctx.GetTypeDefinition(typeof(IEnumerable<>));
ITypeDefinition comparerType = ctx.GetTypeDefinition(typeof(IComparer<>));
var comparerOfIEnumerableOfString = new ParameterizedType(comparerType, new [] { new ParameterizedType(enumerableType, new [] { stringType} ) });
var comparerOfTpArray = new ParameterizedType(comparerType, new [] { new ArrayType(tp) });
bool success;
Assert.AreEqual(
new [] { stringType },
ti.InferTypeArguments(new [] { tp },
new [] { new ResolveResult(comparerOfIEnumerableOfString) },
new [] { comparerOfTpArray },
out success));
Assert.IsTrue(success);
}
#endregion
#region FindTypeInBounds
IType[] FindAllTypesInBounds(IList<IType> lowerBounds, IList<IType> upperBounds = null) IType[] FindAllTypesInBounds(IList<IType> lowerBounds, IList<IType> upperBounds = null)
{ {
ti.Algorithm = TypeInferenceAlgorithm.ImprovedReturnAllResults; ti.Algorithm = TypeInferenceAlgorithm.ImprovedReturnAllResults;
@ -154,5 +196,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Resolve(typeof(List<string>), typeof(List<Version>), typeof(Collection<string>), typeof(Collection<Version>), typeof(ReadOnlyCollection<string>), typeof(ReadOnlyCollection<Version>)), Resolve(typeof(List<string>), typeof(List<Version>), typeof(Collection<string>), typeof(Collection<Version>), typeof(ReadOnlyCollection<string>), typeof(ReadOnlyCollection<Version>)),
FindAllTypesInBounds(Resolve(), Resolve(typeof(IEnumerable<ICloneable>), typeof(IEnumerable<IComparable>), typeof(IList)))); FindAllTypesInBounds(Resolve(), Resolve(typeof(IEnumerable<ICloneable>), typeof(IEnumerable<IComparable>), typeof(IList))));
} }
#endregion
} }
} }

2
NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnsafeCodeTests.cs

@ -9,7 +9,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
[TestFixture] [TestFixture]
public class UnsafeCodeTests : ResolverTestBase public class UnsafeCodeTests : ResolverTestBase
{ {
[Test, Ignore("fixed statement not implemented in parser")] [Test, Ignore("Parser returns incorrect positions")]
public void FixedStatement() public void FixedStatement()
{ {
string program = @"using System; string program = @"using System;

1
NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TestBlankLineFormatting.cs

@ -31,6 +31,7 @@ using ICSharpCode.NRefactory.CSharp;
namespace ICSharpCode.NRefactory.FormattingTests namespace ICSharpCode.NRefactory.FormattingTests
{ {
[Ignore ("TODO")]
[TestFixture()] [TestFixture()]
public class TestBlankLineFormatting : TestBase public class TestBlankLineFormatting : TestBase
{ {

3
NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TestBraceStlye.cs

@ -34,6 +34,7 @@ namespace ICSharpCode.NRefactory.FormattingTests
[TestFixture()] [TestFixture()]
public class TestBraceStyle : TestBase public class TestBraceStyle : TestBase
{ {
[Ignore ("TODO")]
[Test()] [Test()]
public void TestNamespaceBraceStyle () public void TestNamespaceBraceStyle ()
{ {
@ -221,6 +222,7 @@ namespace B {
}"); }");
} }
[Ignore ("TODO")]
[Test()] [Test()]
public void TestAllowPropertyGetBlockInline () public void TestAllowPropertyGetBlockInline ()
{ {
@ -262,6 +264,7 @@ namespace B {
}"); }");
} }
[Ignore ("TODO")]
[Test()] [Test()]
public void TestAllowPropertySetBlockInline () public void TestAllowPropertySetBlockInline ()
{ {

1
NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TestFormattingBugs.cs

@ -31,6 +31,7 @@ using ICSharpCode.NRefactory.CSharp;
namespace ICSharpCode.NRefactory.FormattingTests namespace ICSharpCode.NRefactory.FormattingTests
{ {
[Ignore()]
[TestFixture()] [TestFixture()]
public class TestFormattingBugs : TestBase public class TestFormattingBugs : TestBase
{ {

19
NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TestSpacingVisitor.cs

@ -1065,6 +1065,25 @@ return (Test)null;
i2 = result.Text.IndexOf (";") + ";".Length; i2 = result.Text.IndexOf (";") + ";".Length;
Assert.AreEqual (@"int a = 5,b = 6,c;", result.GetTextAt (i1, i2 - i1)); Assert.AreEqual (@"int a = 5,b = 6,c;", result.GetTextAt (i1, i2 - i1));
} }
[Test()]
public void TestLocalVariableWithGenerics ()
{
CSharpFormattingOptions policy = new CSharpFormattingOptions ();
policy.SpaceBeforeLocalVariableDeclarationComma = true;
policy.SpaceAfterLocalVariableDeclarationComma = true;
var result = GetResult (policy, @"class Test {
void TestMe ()
{
List<Test> a;
}
}");
int i1 = result.Text.IndexOf ("List");
int i2 = result.Text.IndexOf (";") + ";".Length;
Assert.AreEqual (@"List<Test> a;", result.GetTextAt (i1, i2 - i1));
}
#region Constructors #region Constructors

3
NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TestStatementIndentation.cs

@ -55,6 +55,7 @@ this.TestMethod ();
}"); }");
} }
[Ignore ("TODO")]
[Test()] [Test()]
public void TestIndentBlocks () public void TestIndentBlocks ()
{ {
@ -498,6 +499,7 @@ using (var o = new MyObj()) {
}"); }");
} }
[Ignore ("TODO")]
[Test()] [Test()]
public void TestUsingAlignment () public void TestUsingAlignment ()
{ {
@ -944,6 +946,7 @@ do {
}"); }");
} }
[Ignore ("TODO")]
[Test()] [Test()]
public void TestIfAlignment () public void TestIfAlignment ()
{ {

7
NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TestTypeLevelIndentation.cs

@ -249,6 +249,7 @@ A
}"); }");
} }
[Ignore ("TODO")]
[Test()] [Test()]
public void TestIndentMethodBodyOperatorCase () public void TestIndentMethodBodyOperatorCase ()
{ {
@ -283,6 +284,7 @@ A
}"); }");
} }
[Ignore ("TODO")]
[Test()] [Test()]
public void TestIndentPropertyBody () public void TestIndentPropertyBody ()
{ {
@ -354,6 +356,7 @@ set;
}"); }");
} }
[Ignore ("TODO")]
[Test()] [Test()]
public void TestIndentPropertyBodyIndexerCase () public void TestIndentPropertyBodyIndexerCase ()
{ {
@ -398,7 +401,7 @@ set {
}"); }");
} }
[Ignore ("TODO")]
[Test()] [Test()]
public void TestPropertyAlignment () public void TestPropertyAlignment ()
{ {
@ -432,6 +435,7 @@ set {
} }
[Ignore ("TODO")]
[Test()] [Test()]
public void TestIndentNamespaceBody () public void TestIndentNamespaceBody ()
{ {
@ -511,6 +515,7 @@ set;
} }
[Ignore ("TODO")]
[Test()] [Test()]
public void TestIndentEventBody () public void TestIndentEventBody ()
{ {

70
NRefactory/ICSharpCode.NRefactory.Tests/FormattingTests/TextEditorTestAdapter.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using System.IO; using System.IO;
using NUnit.Framework; using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.Refactoring;
namespace ICSharpCode.NRefactory.FormattingTests namespace ICSharpCode.NRefactory.FormattingTests
{ {
@ -41,7 +42,10 @@ namespace ICSharpCode.NRefactory.FormattingTests
return string.Format ("[Delimiter: Offset={0}, Length={1}]", Offset, Length); return string.Format ("[Delimiter: Offset={0}, Length={1}]", Offset, Length);
} }
} }
public void Replace (int offset, int count, string value)
{
this.text = this.text.Substring (0, offset) + value + this.text.Substring (offset + count);
}
static IEnumerable<Delimiter> FindDelimiter (string text) static IEnumerable<Delimiter> FindDelimiter (string text)
{ {
for (int i = 0; i < text.Length; i++) { for (int i = 0; i < text.Length; i++) {
@ -104,16 +108,6 @@ namespace ICSharpCode.NRefactory.FormattingTests
return new Segment (startOffset, endOffset - startOffset, delimiterLength); return new Segment (startOffset, endOffset - startOffset, delimiterLength);
} }
public void ApplyChanges (List<Change> changes)
{
changes.Sort ((x, y) => x.Offset.CompareTo (y.Offset));
changes.Reverse ();
foreach (var change in changes) {
text = text.Substring (0, change.Offset) + change.InsertedText + text.Substring (change.Offset + change.RemovedChars);
}
delimiters = new List<Delimiter> (FindDelimiter (text));
}
#region ITextEditorAdapter implementation #region ITextEditorAdapter implementation
public int LocationToOffset (int line, int col) public int LocationToOffset (int line, int col)
{ {
@ -221,14 +215,50 @@ namespace ICSharpCode.NRefactory.FormattingTests
public abstract class TestBase public abstract class TestBase
{ {
static IActionFactory factory = new TestFactory ();
class TestTextReplaceAction : TextReplaceAction
{
public TestTextReplaceAction (int offset, int removedChars, string insertedText) : base (offset, removedChars, insertedText)
{
}
public override void Perform (Script script)
{
}
}
class TestFactory : AbstractActionFactory
{
public override TextReplaceAction CreateTextReplaceAction (int offset, int removedChars, string insertedText)
{
return new TestTextReplaceAction (offset, removedChars, insertedText);
}
}
static void ApplyChanges (TextEditorTestAdapter adapter, List<TextReplaceAction> changes)
{
changes.Sort ((x, y) => y.Offset.CompareTo (x.Offset));
foreach (var change in changes) {
// Console.WriteLine ("---- apply:" + change);
// Console.WriteLine (adapter.Text);
if (change.Offset > adapter.Length)
continue;
adapter.Replace (change.Offset, change.RemovedChars, change.InsertedText);
}
// Console.WriteLine ("---result:");
// Console.WriteLine (adapter.Text);
}
protected static ITextEditorAdapter GetResult (CSharpFormattingOptions policy, string input) protected static ITextEditorAdapter GetResult (CSharpFormattingOptions policy, string input)
{ {
var adapter = new TextEditorTestAdapter (input); var adapter = new TextEditorTestAdapter (input);
var visitior = new AstFormattingVisitor (policy, adapter); var visitior = new AstFormattingVisitor (policy, adapter, factory);
var compilationUnit = new CSharpParser ().Parse (new StringReader (adapter.Text)); var compilationUnit = new CSharpParser ().Parse (new StringReader (adapter.Text));
compilationUnit.AcceptVisitor (visitior, null); compilationUnit.AcceptVisitor (visitior, null);
adapter.ApplyChanges (visitior.Changes);
ApplyChanges (adapter, visitior.Changes);
return adapter; return adapter;
} }
@ -236,22 +266,28 @@ namespace ICSharpCode.NRefactory.FormattingTests
protected static ITextEditorAdapter Test (CSharpFormattingOptions policy, string input, string expectedOutput) protected static ITextEditorAdapter Test (CSharpFormattingOptions policy, string input, string expectedOutput)
{ {
var adapter = new TextEditorTestAdapter (input); var adapter = new TextEditorTestAdapter (input);
var visitior = new AstFormattingVisitor (policy, adapter); var visitior = new AstFormattingVisitor (policy, adapter, factory);
var compilationUnit = new CSharpParser ().Parse (new StringReader (adapter.Text)); var compilationUnit = new CSharpParser ().Parse (new StringReader (adapter.Text));
compilationUnit.AcceptVisitor (visitior, null); compilationUnit.AcceptVisitor (visitior, null);
adapter.ApplyChanges (visitior.Changes); ApplyChanges (adapter, visitior.Changes);
if (expectedOutput != adapter.Text) {
Console.WriteLine (adapter.Text);
}
Assert.AreEqual (expectedOutput, adapter.Text); Assert.AreEqual (expectedOutput, adapter.Text);
return adapter; return adapter;
} }
protected static void Continue (CSharpFormattingOptions policy, ITextEditorAdapter adapter, string expectedOutput) protected static void Continue (CSharpFormattingOptions policy, ITextEditorAdapter adapter, string expectedOutput)
{ {
var visitior = new AstFormattingVisitor (policy, adapter); var visitior = new AstFormattingVisitor (policy, adapter, factory);
var compilationUnit = new CSharpParser ().Parse (new StringReader (adapter.Text)); var compilationUnit = new CSharpParser ().Parse (new StringReader (adapter.Text));
compilationUnit.AcceptVisitor (visitior, null); compilationUnit.AcceptVisitor (visitior, null);
((TextEditorTestAdapter)adapter).ApplyChanges (visitior.Changes); ApplyChanges (((TextEditorTestAdapter)adapter), visitior.Changes);
if (expectedOutput != adapter.Text) {
Console.WriteLine (adapter.Text);
}
Assert.AreEqual (expectedOutput, adapter.Text); Assert.AreEqual (expectedOutput, adapter.Text);
} }

40
NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/CecilLoaderTests.cs

@ -27,8 +27,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void InheritanceTest() public void InheritanceTest()
{ {
ITypeDefinition c = Mscorlib.GetClass(typeof(SystemException)); ITypeDefinition c = Mscorlib.GetTypeDefinition(typeof(SystemException));
ITypeDefinition c2 = Mscorlib.GetClass(typeof(Exception)); ITypeDefinition c2 = Mscorlib.GetTypeDefinition(typeof(Exception));
Assert.IsNotNull(c, "c is null"); Assert.IsNotNull(c, "c is null");
Assert.IsNotNull(c2, "c2 is null"); Assert.IsNotNull(c2, "c2 is null");
//Assert.AreEqual(3, c.BaseTypes.Count); // Inherited interfaces are not reported by Cecil //Assert.AreEqual(3, c.BaseTypes.Count); // Inherited interfaces are not reported by Cecil
@ -46,7 +46,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void GenericPropertyTest() public void GenericPropertyTest()
{ {
ITypeDefinition c = Mscorlib.GetClass(typeof(Comparer<>)); ITypeDefinition c = Mscorlib.GetTypeDefinition(typeof(Comparer<>));
IProperty def = c.Properties.Single(p => p.Name == "Default"); IProperty def = c.Properties.Single(p => p.Name == "Default");
ParameterizedType pt = (ParameterizedType)def.ReturnType.Resolve(ctx); ParameterizedType pt = (ParameterizedType)def.ReturnType.Resolve(ctx);
Assert.AreEqual("System.Collections.Generic.Comparer", pt.FullName); Assert.AreEqual("System.Collections.Generic.Comparer", pt.FullName);
@ -56,7 +56,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void PointerTypeTest() public void PointerTypeTest()
{ {
ITypeDefinition c = Mscorlib.GetClass(typeof(IntPtr)); ITypeDefinition c = Mscorlib.GetTypeDefinition(typeof(IntPtr));
IMethod toPointer = c.Methods.Single(p => p.Name == "ToPointer"); IMethod toPointer = c.Methods.Single(p => p.Name == "ToPointer");
Assert.AreEqual("System.Void*", toPointer.ReturnType.Resolve(ctx).ReflectionName); Assert.AreEqual("System.Void*", toPointer.ReturnType.Resolve(ctx).ReflectionName);
Assert.IsTrue (toPointer.ReturnType.Resolve(ctx) is PointerType); Assert.IsTrue (toPointer.ReturnType.Resolve(ctx) is PointerType);
@ -66,7 +66,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void DateTimeDefaultConstructor() public void DateTimeDefaultConstructor()
{ {
ITypeDefinition c = Mscorlib.GetClass(typeof(DateTime)); ITypeDefinition c = Mscorlib.GetTypeDefinition(typeof(DateTime));
Assert.IsFalse(c.Methods.Any(m => m.IsConstructor && m.Parameters.Count == 0)); // struct ctor isn't declared Assert.IsFalse(c.Methods.Any(m => m.IsConstructor && m.Parameters.Count == 0)); // struct ctor isn't declared
// but it is implicit: // but it is implicit:
Assert.IsTrue(c.GetConstructors(ctx).Any(m => m.Parameters.Count == 0)); Assert.IsTrue(c.GetConstructors(ctx).Any(m => m.Parameters.Count == 0));
@ -75,7 +75,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void NoEncodingInfoDefaultConstructor() public void NoEncodingInfoDefaultConstructor()
{ {
ITypeDefinition c = Mscorlib.GetClass(typeof(EncodingInfo)); ITypeDefinition c = Mscorlib.GetTypeDefinition(typeof(EncodingInfo));
// EncodingInfo only has an internal constructor // EncodingInfo only has an internal constructor
Assert.IsFalse(c.Methods.Any(m => m.IsConstructor)); Assert.IsFalse(c.Methods.Any(m => m.IsConstructor));
// and no implicit ctor should be added: // and no implicit ctor should be added:
@ -85,7 +85,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void StaticModifierTest() public void StaticModifierTest()
{ {
ITypeDefinition c = Mscorlib.GetClass(typeof(Environment)); ITypeDefinition c = Mscorlib.GetTypeDefinition(typeof(Environment));
Assert.IsNotNull(c, "System.Environment not found"); Assert.IsNotNull(c, "System.Environment not found");
Assert.IsTrue(c.IsAbstract, "class should be abstract"); Assert.IsTrue(c.IsAbstract, "class should be abstract");
Assert.IsTrue(c.IsSealed, "class should be sealed"); Assert.IsTrue(c.IsSealed, "class should be sealed");
@ -95,16 +95,16 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void InnerClassReferenceTest() public void InnerClassReferenceTest()
{ {
ITypeDefinition c = Mscorlib.GetClass(typeof(Environment)); ITypeDefinition c = Mscorlib.GetTypeDefinition(typeof(Environment));
Assert.IsNotNull(c, "System.Environment not found"); Assert.IsNotNull(c, "System.Environment not found");
ITypeReference rt = c.Methods.First(m => m.Name == "GetFolderPath").Parameters[0].Type; ITypeReference rt = c.Methods.First(m => m.Name == "GetFolderPath").Parameters[0].Type;
Assert.AreSame(c.InnerClasses.Single(ic => ic.Name == "SpecialFolder"), rt.Resolve(ctx)); Assert.AreSame(c.NestedTypes.Single(ic => ic.Name == "SpecialFolder"), rt.Resolve(ctx));
} }
[Test] [Test]
public void InnerClassesTest() public void NestedTypesTest()
{ {
ITypeDefinition c = Mscorlib.GetClass(typeof(Environment.SpecialFolder)); ITypeDefinition c = Mscorlib.GetTypeDefinition(typeof(Environment.SpecialFolder));
Assert.IsNotNull(c, "c is null"); Assert.IsNotNull(c, "c is null");
Assert.AreEqual("System.Environment.SpecialFolder", c.FullName); Assert.AreEqual("System.Environment.SpecialFolder", c.FullName);
Assert.AreEqual("System.Environment+SpecialFolder", c.ReflectionName); Assert.AreEqual("System.Environment+SpecialFolder", c.ReflectionName);
@ -113,7 +113,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void VoidTest() public void VoidTest()
{ {
ITypeDefinition c = Mscorlib.GetClass(typeof(void)); ITypeDefinition c = Mscorlib.GetTypeDefinition(typeof(void));
Assert.IsNotNull(c, "System.Void not found"); Assert.IsNotNull(c, "System.Void not found");
Assert.AreEqual(0, c.GetMethods(ctx).Count()); Assert.AreEqual(0, c.GetMethods(ctx).Count());
Assert.AreEqual(0, c.GetProperties(ctx).Count()); Assert.AreEqual(0, c.GetProperties(ctx).Count());
@ -131,11 +131,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void NestedClassInGenericClassTest() public void NestedClassInGenericClassTest()
{ {
ITypeDefinition dictionary = Mscorlib.GetClass(typeof(Dictionary<,>)); ITypeDefinition dictionary = Mscorlib.GetTypeDefinition(typeof(Dictionary<,>));
Assert.IsNotNull(dictionary); Assert.IsNotNull(dictionary);
ITypeDefinition valueCollection = Mscorlib.GetClass(typeof(Dictionary<,>.ValueCollection)); ITypeDefinition valueCollection = Mscorlib.GetTypeDefinition(typeof(Dictionary<,>.ValueCollection));
Assert.IsNotNull(valueCollection); Assert.IsNotNull(valueCollection);
var dictionaryRT = new ParameterizedType(dictionary, new[] { Mscorlib.GetClass(typeof(string)), Mscorlib.GetClass(typeof(int)) }); var dictionaryRT = new ParameterizedType(dictionary, new[] { Mscorlib.GetTypeDefinition(typeof(string)), Mscorlib.GetTypeDefinition(typeof(int)) });
IProperty valueProperty = dictionaryRT.GetProperties(ctx).Single(p => p.Name == "Values"); IProperty valueProperty = dictionaryRT.GetProperties(ctx).Single(p => p.Name == "Values");
IType parameterizedValueCollection = valueProperty.ReturnType.Resolve(ctx); IType parameterizedValueCollection = valueProperty.ReturnType.Resolve(ctx);
Assert.AreEqual("System.Collections.Generic.Dictionary`2+ValueCollection[[System.String],[System.Int32]]", parameterizedValueCollection.ReflectionName); Assert.AreEqual("System.Collections.Generic.Dictionary`2+ValueCollection[[System.String],[System.Int32]]", parameterizedValueCollection.ReflectionName);
@ -145,7 +145,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void ValueCollectionCountModifiers() public void ValueCollectionCountModifiers()
{ {
ITypeDefinition valueCollection = Mscorlib.GetClass(typeof(Dictionary<,>.ValueCollection)); ITypeDefinition valueCollection = Mscorlib.GetTypeDefinition(typeof(Dictionary<,>.ValueCollection));
Assert.AreEqual(Accessibility.Public, valueCollection.Accessibility); Assert.AreEqual(Accessibility.Public, valueCollection.Accessibility);
Assert.IsTrue(valueCollection.IsSealed); Assert.IsTrue(valueCollection.IsSealed);
Assert.IsFalse(valueCollection.IsAbstract); Assert.IsFalse(valueCollection.IsAbstract);
@ -162,7 +162,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void MathAcosModifiers() public void MathAcosModifiers()
{ {
ITypeDefinition math = Mscorlib.GetClass(typeof(Math)); ITypeDefinition math = Mscorlib.GetTypeDefinition(typeof(Math));
Assert.AreEqual(Accessibility.Public, math.Accessibility); Assert.AreEqual(Accessibility.Public, math.Accessibility);
Assert.IsTrue(math.IsSealed); Assert.IsTrue(math.IsSealed);
Assert.IsTrue(math.IsAbstract); Assert.IsTrue(math.IsAbstract);
@ -180,7 +180,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void EncodingModifiers() public void EncodingModifiers()
{ {
ITypeDefinition encoding = Mscorlib.GetClass(typeof(Encoding)); ITypeDefinition encoding = Mscorlib.GetTypeDefinition(typeof(Encoding));
Assert.AreEqual(Accessibility.Public, encoding.Accessibility); Assert.AreEqual(Accessibility.Public, encoding.Accessibility);
Assert.IsFalse(encoding.IsSealed); Assert.IsFalse(encoding.IsSealed);
Assert.IsTrue(encoding.IsAbstract); Assert.IsTrue(encoding.IsAbstract);
@ -213,7 +213,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void UnicodeEncodingModifiers() public void UnicodeEncodingModifiers()
{ {
ITypeDefinition encoding = Mscorlib.GetClass(typeof(UnicodeEncoding)); ITypeDefinition encoding = Mscorlib.GetTypeDefinition(typeof(UnicodeEncoding));
Assert.AreEqual(Accessibility.Public, encoding.Accessibility); Assert.AreEqual(Accessibility.Public, encoding.Accessibility);
Assert.IsFalse(encoding.IsSealed); Assert.IsFalse(encoding.IsSealed);
Assert.IsFalse(encoding.IsAbstract); Assert.IsFalse(encoding.IsAbstract);
@ -230,7 +230,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void UTF32EncodingModifiers() public void UTF32EncodingModifiers()
{ {
ITypeDefinition encoding = Mscorlib.GetClass(typeof(UTF32Encoding)); ITypeDefinition encoding = Mscorlib.GetTypeDefinition(typeof(UTF32Encoding));
Assert.AreEqual(Accessibility.Public, encoding.Accessibility); Assert.AreEqual(Accessibility.Public, encoding.Accessibility);
Assert.IsTrue(encoding.IsSealed); Assert.IsTrue(encoding.IsSealed);
Assert.IsFalse(encoding.IsAbstract); Assert.IsFalse(encoding.IsAbstract);

30
NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs

@ -100,8 +100,8 @@ namespace ICSharpCode.NRefactory.TypeSystem
c, c,
c.BaseTypes[0].Resolve(context), c.BaseTypes[0].Resolve(context),
c.BaseTypes[1].Resolve(context), c.BaseTypes[1].Resolve(context),
mscorlib.GetClass(typeof(IEnumerable)), mscorlib.GetTypeDefinition(typeof(IEnumerable)),
mscorlib.GetClass(typeof(object)) mscorlib.GetTypeDefinition(typeof(object))
}; };
Assert.AreEqual(expected, Assert.AreEqual(expected,
c.GetAllBaseTypes(context).OrderBy(t => t.ReflectionName).ToArray()); c.GetAllBaseTypes(context).OrderBy(t => t.ReflectionName).ToArray());
@ -114,15 +114,35 @@ namespace ICSharpCode.NRefactory.TypeSystem
// don't use a Cecil-loaded struct for this test; we're testing the implicit addition of System.ValueType // don't use a Cecil-loaded struct for this test; we're testing the implicit addition of System.ValueType
DefaultTypeDefinition s = new DefaultTypeDefinition(mscorlib, string.Empty, "S"); DefaultTypeDefinition s = new DefaultTypeDefinition(mscorlib, string.Empty, "S");
s.ClassType = ClassType.Struct; s.ClassType = ClassType.Struct;
s.BaseTypes.Add(new ParameterizedType(mscorlib.GetClass(typeof(IEquatable<>)), new[] { s })); s.BaseTypes.Add(new ParameterizedType(mscorlib.GetTypeDefinition(typeof(IEquatable<>)), new[] { s }));
IType[] expected = { IType[] expected = {
s, s,
s.BaseTypes[0].Resolve(context), s.BaseTypes[0].Resolve(context),
mscorlib.GetClass(typeof(object)), mscorlib.GetTypeDefinition(typeof(object)),
mscorlib.GetClass(typeof(ValueType)) mscorlib.GetTypeDefinition(typeof(ValueType))
}; };
Assert.AreEqual(expected, Assert.AreEqual(expected,
s.GetAllBaseTypes(context).OrderBy(t => t.ReflectionName).ToArray()); s.GetAllBaseTypes(context).OrderBy(t => t.ReflectionName).ToArray());
} }
[Test]
public void BaseTypesOfListOfString()
{
Assert.AreEqual(
GetTypes(typeof(List<string>), typeof(object),
typeof(IList), typeof(ICollection), typeof(IEnumerable),
typeof(IEnumerable<string>), typeof(ICollection<string>), typeof(IList<string>)),
GetAllBaseTypes(typeof(List<string>)));
}
[Test]
public void BaseTypeDefinitionsOfListOfString()
{
Assert.AreEqual(
GetTypes(typeof(List<>), typeof(object),
typeof(IList), typeof(ICollection), typeof(IEnumerable),
typeof(IEnumerable<>), typeof(ICollection<>), typeof(IList<>)),
typeof(List<string>).ToTypeReference().Resolve(context).GetAllBaseTypeDefinitions(context).OrderBy(t => t.ReflectionName).ToArray());
}
} }
} }

6
NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/ReflectionHelperTests.cs

@ -16,7 +16,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
void TestGetClass(Type type) void TestGetClass(Type type)
{ {
ITypeDefinition t = CecilLoaderTests.Mscorlib.GetClass(type); ITypeDefinition t = CecilLoaderTests.Mscorlib.GetTypeDefinition(type);
Assert.IsNotNull(t, type.FullName); Assert.IsNotNull(t, type.FullName);
Assert.AreEqual(type.FullName, t.ReflectionName); Assert.AreEqual(type.FullName, t.ReflectionName);
} }
@ -142,7 +142,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.AreEqual("System.Converter`2[[?],[?]]", Assert.AreEqual("System.Converter`2[[?],[?]]",
parameterType.ToTypeReference().Resolve(context).ReflectionName); parameterType.ToTypeReference().Resolve(context).ReflectionName);
// now try with parent entity: // now try with parent entity:
IMethod convertAll = context.GetClass(typeof(List<>)).Methods.Single(m => m.Name == "ConvertAll"); IMethod convertAll = context.GetTypeDefinition(typeof(List<>)).Methods.Single(m => m.Name == "ConvertAll");
Assert.AreEqual("System.Converter`2[[`0],[``0]]", Assert.AreEqual("System.Converter`2[[`0],[``0]]",
parameterType.ToTypeReference(entity: convertAll).Resolve(context).ReflectionName); parameterType.ToTypeReference(entity: convertAll).Resolve(context).ReflectionName);
} }
@ -163,7 +163,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void ParseOpenGenericReflectionName() public void ParseOpenGenericReflectionName()
{ {
IMethod convertAll = context.GetClass(typeof(List<>)).Methods.Single(m => m.Name == "ConvertAll"); IMethod convertAll = context.GetTypeDefinition(typeof(List<>)).Methods.Single(m => m.Name == "ConvertAll");
Assert.AreEqual("System.Converter`2[[?],[?]]", ReflectionHelper.ParseReflectionName("System.Converter`2[[`0],[``0]]").Resolve(context).ReflectionName); Assert.AreEqual("System.Converter`2[[?],[?]]", ReflectionHelper.ParseReflectionName("System.Converter`2[[`0],[``0]]").Resolve(context).ReflectionName);
Assert.AreEqual("System.Converter`2[[`0],[``0]]", ReflectionHelper.ParseReflectionName("System.Converter`2[[`0],[``0]]", convertAll).Resolve(context).ReflectionName); Assert.AreEqual("System.Converter`2[[`0],[``0]]", ReflectionHelper.ParseReflectionName("System.Converter`2[[`0],[``0]]", convertAll).Resolve(context).ReflectionName);
} }

4
NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TestInterningProvider.cs

@ -1,4 +1,4 @@
// Copyright (c) 2010 AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // Copyright (c) 2010 AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt) // This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System; using System;
@ -130,7 +130,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
public void InternProject(IProjectContent pc) public void InternProject(IProjectContent pc)
{ {
foreach (var c in TreeTraversal.PreOrder(pc.GetClasses(), c => c.InnerClasses)) { foreach (var c in TreeTraversal.PreOrder(pc.GetClasses(), c => c.NestedTypes)) {
Intern(c.Namespace); Intern(c.Namespace);
Intern(c.Name); Intern(c.Name);
foreach (IMember m in c.Members) { foreach (IMember m in c.Members) {

2
NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs

@ -10,6 +10,8 @@ using System.Runtime.InteropServices;
namespace ICSharpCode.NRefactory.TypeSystem.TestCase namespace ICSharpCode.NRefactory.TypeSystem.TestCase
{ {
public delegate S GenericDelegate<in T, out S>(T input) where T : S where S : class;
public class SimplePublicClass public class SimplePublicClass
{ {
public void Method() {} public void Method() {}

82
NRefactory/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs

@ -28,13 +28,13 @@ namespace ICSharpCode.NRefactory.TypeSystem
ITypeDefinition GetClass(Type type) ITypeDefinition GetClass(Type type)
{ {
return testCasePC.GetClass(type); return testCasePC.GetTypeDefinition(type);
} }
[Test] [Test]
public void SimplePublicClassTest() public void SimplePublicClassTest()
{ {
ITypeDefinition c = testCasePC.GetClass(typeof(SimplePublicClass)); ITypeDefinition c = testCasePC.GetTypeDefinition(typeof(SimplePublicClass));
Assert.AreEqual(typeof(SimplePublicClass).Name, c.Name); Assert.AreEqual(typeof(SimplePublicClass).Name, c.Name);
Assert.AreEqual(typeof(SimplePublicClass).FullName, c.FullName); Assert.AreEqual(typeof(SimplePublicClass).FullName, c.FullName);
Assert.AreEqual(typeof(SimplePublicClass).Namespace, c.Namespace); Assert.AreEqual(typeof(SimplePublicClass).Namespace, c.Namespace);
@ -50,8 +50,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void SimplePublicClassMethodTest() public void SimplePublicClassMethodTest()
{ {
ITypeDefinition c = testCasePC.GetClass(typeof(SimplePublicClass)); ITypeDefinition c = testCasePC.GetTypeDefinition(typeof(SimplePublicClass));
Assert.AreEqual(2, c.Methods.Count);
IMethod method = c.Methods.Single(m => m.Name == "Method"); IMethod method = c.Methods.Single(m => m.Name == "Method");
Assert.AreEqual(typeof(SimplePublicClass).FullName + ".Method", method.FullName); Assert.AreEqual(typeof(SimplePublicClass).FullName + ".Method", method.FullName);
@ -68,7 +67,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void DynamicType() public void DynamicType()
{ {
ITypeDefinition testClass = testCasePC.GetClass(typeof(DynamicTest)); ITypeDefinition testClass = testCasePC.GetTypeDefinition(typeof(DynamicTest));
Assert.AreSame(SharedTypes.Dynamic, testClass.Properties.Single().ReturnType.Resolve(ctx)); Assert.AreSame(SharedTypes.Dynamic, testClass.Properties.Single().ReturnType.Resolve(ctx));
Assert.AreEqual(0, testClass.Properties.Single().Attributes.Count); Assert.AreEqual(0, testClass.Properties.Single().Attributes.Count);
} }
@ -76,7 +75,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void DynamicTypeInGenerics() public void DynamicTypeInGenerics()
{ {
ITypeDefinition testClass = testCasePC.GetClass(typeof(DynamicTest)); ITypeDefinition testClass = testCasePC.GetTypeDefinition(typeof(DynamicTest));
IMethod m1 = testClass.Methods.Single(me => me.Name == "DynamicGenerics1"); IMethod m1 = testClass.Methods.Single(me => me.Name == "DynamicGenerics1");
Assert.AreEqual("System.Collections.Generic.List`1[[dynamic]]", m1.ReturnType.Resolve(ctx).ReflectionName); Assert.AreEqual("System.Collections.Generic.List`1[[dynamic]]", m1.ReturnType.Resolve(ctx).ReflectionName);
@ -104,7 +103,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void DynamicParameterHasNoAttributes() public void DynamicParameterHasNoAttributes()
{ {
ITypeDefinition testClass = testCasePC.GetClass(typeof(DynamicTest)); ITypeDefinition testClass = testCasePC.GetTypeDefinition(typeof(DynamicTest));
IMethod m1 = testClass.Methods.Single(me => me.Name == "DynamicGenerics1"); IMethod m1 = testClass.Methods.Single(me => me.Name == "DynamicGenerics1");
Assert.AreEqual(0, m1.Parameters[0].Attributes.Count); Assert.AreEqual(0, m1.Parameters[0].Attributes.Count);
} }
@ -134,7 +133,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void TestClassTypeParameters() public void TestClassTypeParameters()
{ {
var testClass = testCasePC.GetClass(typeof(GenericClass<,>)); var testClass = testCasePC.GetTypeDefinition(typeof(GenericClass<,>));
Assert.AreEqual(EntityType.TypeDefinition, testClass.TypeParameters[0].OwnerType); Assert.AreEqual(EntityType.TypeDefinition, testClass.TypeParameters[0].OwnerType);
Assert.AreEqual(EntityType.TypeDefinition, testClass.TypeParameters[1].OwnerType); Assert.AreEqual(EntityType.TypeDefinition, testClass.TypeParameters[1].OwnerType);
Assert.AreSame(testClass.TypeParameters[1], testClass.TypeParameters[0].Constraints[0].Resolve(ctx)); Assert.AreSame(testClass.TypeParameters[1], testClass.TypeParameters[0].Constraints[0].Resolve(ctx));
@ -143,7 +142,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void TestMethod() public void TestMethod()
{ {
var testClass = testCasePC.GetClass(typeof(GenericClass<,>)); var testClass = testCasePC.GetTypeDefinition(typeof(GenericClass<,>));
IMethod m = testClass.Methods.Single(me => me.Name == "TestMethod"); IMethod m = testClass.Methods.Single(me => me.Name == "TestMethod");
Assert.AreEqual("K", m.TypeParameters[0].Name); Assert.AreEqual("K", m.TypeParameters[0].Name);
@ -158,7 +157,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void GetIndex() public void GetIndex()
{ {
var testClass = testCasePC.GetClass(typeof(GenericClass<,>)); var testClass = testCasePC.GetTypeDefinition(typeof(GenericClass<,>));
IMethod m = testClass.Methods.Single(me => me.Name == "GetIndex"); IMethod m = testClass.Methods.Single(me => me.Name == "GetIndex");
Assert.AreEqual("T", m.TypeParameters[0].Name); Assert.AreEqual("T", m.TypeParameters[0].Name);
@ -174,7 +173,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void PropertyWithProtectedSetter() public void PropertyWithProtectedSetter()
{ {
var testClass = testCasePC.GetClass(typeof(PropertyTest)); var testClass = testCasePC.GetTypeDefinition(typeof(PropertyTest));
IProperty p = testClass.Properties.Single(pr => pr.Name == "PropertyWithProtectedSetter"); IProperty p = testClass.Properties.Single(pr => pr.Name == "PropertyWithProtectedSetter");
Assert.IsTrue(p.CanGet); Assert.IsTrue(p.CanGet);
Assert.IsTrue(p.CanSet); Assert.IsTrue(p.CanSet);
@ -186,7 +185,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void PropertyWithPrivateSetter() public void PropertyWithPrivateSetter()
{ {
var testClass = testCasePC.GetClass(typeof(PropertyTest)); var testClass = testCasePC.GetTypeDefinition(typeof(PropertyTest));
IProperty p = testClass.Properties.Single(pr => pr.Name == "PropertyWithPrivateSetter"); IProperty p = testClass.Properties.Single(pr => pr.Name == "PropertyWithPrivateSetter");
Assert.IsTrue(p.CanGet); Assert.IsTrue(p.CanGet);
Assert.IsTrue(p.CanSet); Assert.IsTrue(p.CanSet);
@ -198,7 +197,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void Indexer() public void Indexer()
{ {
var testClass = testCasePC.GetClass(typeof(PropertyTest)); var testClass = testCasePC.GetTypeDefinition(typeof(PropertyTest));
IProperty p = testClass.Properties.Single(pr => pr.IsIndexer); IProperty p = testClass.Properties.Single(pr => pr.IsIndexer);
Assert.IsTrue(p.CanGet); Assert.IsTrue(p.CanGet);
Assert.AreEqual(Accessibility.Public, p.Accessibility); Assert.AreEqual(Accessibility.Public, p.Accessibility);
@ -210,9 +209,9 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void EnumTest() public void EnumTest()
{ {
var e = testCasePC.GetClass(typeof(MyEnum)); var e = testCasePC.GetTypeDefinition(typeof(MyEnum));
Assert.AreEqual(ClassType.Enum, e.ClassType); Assert.AreEqual(ClassType.Enum, e.ClassType);
Assert.AreEqual(false, e.IsReferenceType); Assert.AreEqual(false, e.IsReferenceType(ctx));
Assert.AreEqual("System.Int16", e.BaseTypes[0].Resolve(ctx).ReflectionName); Assert.AreEqual("System.Int16", e.BaseTypes[0].Resolve(ctx).ReflectionName);
Assert.AreEqual(new[] { "System.Enum" }, e.GetBaseTypes(ctx).Select(t => t.ReflectionName).ToArray()); Assert.AreEqual(new[] { "System.Enum" }, e.GetBaseTypes(ctx).Select(t => t.ReflectionName).ToArray());
} }
@ -220,7 +219,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void EnumFieldsTest() public void EnumFieldsTest()
{ {
var e = testCasePC.GetClass(typeof(MyEnum)); var e = testCasePC.GetTypeDefinition(typeof(MyEnum));
Assert.AreEqual(5, e.Fields.Count); Assert.AreEqual(5, e.Fields.Count);
foreach (IField f in e.Fields) { foreach (IField f in e.Fields) {
@ -267,21 +266,21 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void SerializableAttribute() public void SerializableAttribute()
{ {
IAttribute attr = ctx.GetClass(typeof(NonCustomAttributes)).Attributes.Single(); IAttribute attr = ctx.GetTypeDefinition(typeof(NonCustomAttributes)).Attributes.Single();
Assert.AreEqual("System.SerializableAttribute", attr.AttributeType.Resolve(ctx).FullName); Assert.AreEqual("System.SerializableAttribute", attr.AttributeType.Resolve(ctx).FullName);
} }
[Test] [Test]
public void NonSerializedAttribute() public void NonSerializedAttribute()
{ {
IField field = ctx.GetClass(typeof(NonCustomAttributes)).Fields.Single(f => f.Name == "NonSerializedField"); IField field = ctx.GetTypeDefinition(typeof(NonCustomAttributes)).Fields.Single(f => f.Name == "NonSerializedField");
Assert.AreEqual("System.NonSerializedAttribute", field.Attributes.Single().AttributeType.Resolve(ctx).FullName); Assert.AreEqual("System.NonSerializedAttribute", field.Attributes.Single().AttributeType.Resolve(ctx).FullName);
} }
[Test] [Test]
public void ExplicitStructLayoutAttribute() public void ExplicitStructLayoutAttribute()
{ {
IAttribute attr = ctx.GetClass(typeof(ExplicitFieldLayoutStruct)).Attributes.Single(); IAttribute attr = ctx.GetTypeDefinition(typeof(ExplicitFieldLayoutStruct)).Attributes.Single();
Assert.AreEqual("System.Runtime.InteropServices.StructLayoutAttribute", attr.AttributeType.Resolve(ctx).FullName); Assert.AreEqual("System.Runtime.InteropServices.StructLayoutAttribute", attr.AttributeType.Resolve(ctx).FullName);
IConstantValue arg1 = attr.GetPositionalArguments(ctx).Single(); IConstantValue arg1 = attr.GetPositionalArguments(ctx).Single();
Assert.AreEqual("System.Runtime.InteropServices.LayoutKind", arg1.GetValueType(ctx).FullName); Assert.AreEqual("System.Runtime.InteropServices.LayoutKind", arg1.GetValueType(ctx).FullName);
@ -302,13 +301,13 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void FieldOffsetAttribute() public void FieldOffsetAttribute()
{ {
IField field = ctx.GetClass(typeof(ExplicitFieldLayoutStruct)).Fields.Single(f => f.Name == "Field0"); IField field = ctx.GetTypeDefinition(typeof(ExplicitFieldLayoutStruct)).Fields.Single(f => f.Name == "Field0");
Assert.AreEqual("System.Runtime.InteropServices.FieldOffsetAttribute", field.Attributes.Single().AttributeType.Resolve(ctx).FullName); Assert.AreEqual("System.Runtime.InteropServices.FieldOffsetAttribute", field.Attributes.Single().AttributeType.Resolve(ctx).FullName);
IConstantValue arg = field.Attributes.Single().GetPositionalArguments(ctx).Single(); IConstantValue arg = field.Attributes.Single().GetPositionalArguments(ctx).Single();
Assert.AreEqual("System.Int32", arg.GetValueType(ctx).FullName); Assert.AreEqual("System.Int32", arg.GetValueType(ctx).FullName);
Assert.AreEqual(0, arg.GetValue(ctx)); Assert.AreEqual(0, arg.GetValue(ctx));
field = ctx.GetClass(typeof(ExplicitFieldLayoutStruct)).Fields.Single(f => f.Name == "Field100"); field = ctx.GetTypeDefinition(typeof(ExplicitFieldLayoutStruct)).Fields.Single(f => f.Name == "Field100");
Assert.AreEqual("System.Runtime.InteropServices.FieldOffsetAttribute", field.Attributes.Single().AttributeType.Resolve(ctx).FullName); Assert.AreEqual("System.Runtime.InteropServices.FieldOffsetAttribute", field.Attributes.Single().AttributeType.Resolve(ctx).FullName);
arg = field.Attributes.Single().GetPositionalArguments(ctx).Single(); arg = field.Attributes.Single().GetPositionalArguments(ctx).Single();
Assert.AreEqual("System.Int32", arg.GetValueType(ctx).FullName); Assert.AreEqual("System.Int32", arg.GetValueType(ctx).FullName);
@ -318,7 +317,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void DllImportAttribute() public void DllImportAttribute()
{ {
IMethod method = ctx.GetClass(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod"); IMethod method = ctx.GetTypeDefinition(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod");
IAttribute dllImport = method.Attributes.Single(); IAttribute dllImport = method.Attributes.Single();
Assert.AreEqual("System.Runtime.InteropServices.DllImportAttribute", dllImport.AttributeType.Resolve(ctx).FullName); Assert.AreEqual("System.Runtime.InteropServices.DllImportAttribute", dllImport.AttributeType.Resolve(ctx).FullName);
Assert.AreEqual("unmanaged.dll", dllImport.GetPositionalArguments(ctx)[0].GetValue(ctx)); Assert.AreEqual("unmanaged.dll", dllImport.GetPositionalArguments(ctx)[0].GetValue(ctx));
@ -328,7 +327,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void InOutParametersOnRefMethod() public void InOutParametersOnRefMethod()
{ {
IParameter p = ctx.GetClass(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod").Parameters.Single(); IParameter p = ctx.GetTypeDefinition(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod").Parameters.Single();
Assert.IsTrue(p.IsRef); Assert.IsTrue(p.IsRef);
Assert.IsFalse(p.IsOut); Assert.IsFalse(p.IsOut);
Assert.AreEqual(2, p.Attributes.Count); Assert.AreEqual(2, p.Attributes.Count);
@ -339,7 +338,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void MarshalAsAttributeOnMethod() public void MarshalAsAttributeOnMethod()
{ {
IMethod method = ctx.GetClass(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod"); IMethod method = ctx.GetTypeDefinition(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod");
IAttribute marshalAs = method.ReturnTypeAttributes.Single(); IAttribute marshalAs = method.ReturnTypeAttributes.Single();
Assert.AreEqual((int)UnmanagedType.Bool, marshalAs.GetPositionalArguments(ctx).Single().GetValue(ctx)); Assert.AreEqual((int)UnmanagedType.Bool, marshalAs.GetPositionalArguments(ctx).Single().GetValue(ctx));
} }
@ -347,7 +346,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void MethodWithOutParameter() public void MethodWithOutParameter()
{ {
IParameter p = ctx.GetClass(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOutParameter").Parameters.Single(); IParameter p = ctx.GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOutParameter").Parameters.Single();
Assert.IsFalse(p.IsRef); Assert.IsFalse(p.IsRef);
Assert.IsTrue(p.IsOut); Assert.IsTrue(p.IsOut);
Assert.AreEqual(0, p.Attributes.Count); Assert.AreEqual(0, p.Attributes.Count);
@ -357,12 +356,43 @@ namespace ICSharpCode.NRefactory.TypeSystem
[Test] [Test]
public void MethodWithParamsArray() public void MethodWithParamsArray()
{ {
IParameter p = ctx.GetClass(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithParamsArray").Parameters.Single(); IParameter p = ctx.GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithParamsArray").Parameters.Single();
Assert.IsFalse(p.IsRef); Assert.IsFalse(p.IsRef);
Assert.IsFalse(p.IsOut); Assert.IsFalse(p.IsOut);
Assert.IsTrue(p.IsParams); Assert.IsTrue(p.IsParams);
Assert.AreEqual(0, p.Attributes.Count); Assert.AreEqual(0, p.Attributes.Count);
Assert.IsTrue(p.Type is ArrayTypeReference); Assert.IsTrue(p.Type is ArrayTypeReference);
} }
[Test, Ignore("C# Parser does not set the variance")]
public void GenericDelegate_Variance()
{
ITypeDefinition type = ctx.GetTypeDefinition(typeof(GenericDelegate<,>));
Assert.AreEqual(VarianceModifier.Contravariant, type.TypeParameters[0].Variance);
Assert.AreEqual(VarianceModifier.Covariant, type.TypeParameters[1].Variance);
Assert.AreSame(type.TypeParameters[1], type.TypeParameters[0].Constraints[0]);
}
[Test]
public void GenericDelegate_ReferenceTypeConstraints()
{
ITypeDefinition type = ctx.GetTypeDefinition(typeof(GenericDelegate<,>));
Assert.IsFalse(type.TypeParameters[0].HasReferenceTypeConstraint);
Assert.IsTrue(type.TypeParameters[1].HasReferenceTypeConstraint);
Assert.IsTrue(type.TypeParameters[0].IsReferenceType(ctx) == true);
Assert.IsTrue(type.TypeParameters[1].IsReferenceType(ctx) == true);
}
[Test]
public void GenericDelegate_GetInvokeMethod()
{
IType type = typeof(GenericDelegate<string, object>).ToTypeReference().Resolve(ctx);
IMethod m = type.GetDelegateInvokeMethod();
Assert.AreEqual("Invoke", m.Name);
Assert.AreEqual("System.Object", m.ReturnType.Resolve(ctx).FullName);
Assert.AreEqual("System.String", m.Parameters[0].Type.Resolve(ctx).FullName);
}
} }
} }

2
NRefactory/ICSharpCode.NRefactory.VB.Tests/Parser/GlobalScope/ImportsStatementTests.cs

@ -47,7 +47,7 @@ namespace ICSharpCode.NRefactory.VB.Tests.Ast
string program = "Imports My.Name.Space\n"; string program = "Imports My.Name.Space\n";
var clause2 = new MemberImportsClause { var clause2 = new MemberImportsClause {
Member = new QualifiedType(new QualifiedType(new SimpleType("My"), new Identifier("Name", AstLocation.Empty)), new Identifier("Space", AstLocation.Empty)) Member = new QualifiedType(new QualifiedType(new SimpleType("My"), new Identifier ("Name", AstLocation.Empty)), new Identifier ("Space", AstLocation.Empty))
}; };
var node = new ImportsStatement(); var node = new ImportsStatement();

150
NRefactory/ICSharpCode.NRefactory.VB/Ast/AstNode.cs

@ -35,7 +35,7 @@ using ICSharpCode.NRefactory.VB.Ast;
namespace ICSharpCode.NRefactory.VB namespace ICSharpCode.NRefactory.VB
{ {
public abstract class AstNode : PatternMatching.INode public abstract class AstNode : AbstractAnnotatable, PatternMatching.INode
{ {
#region Null #region Null
public static readonly AstNode Null = new NullAstNode (); public static readonly AstNode Null = new NullAstNode ();
@ -443,157 +443,13 @@ namespace ICSharpCode.NRefactory.VB
return copy; return copy;
} }
#region Annotation support public override void AddAnnotation (object annotation)
// Annotations: points either null (no annotations), to the single annotation,
// or to an AnnotationList.
// Once it is pointed at an AnnotationList, it will never change (this allows thread-safety support by locking the list)
object annotations;
sealed class AnnotationList : List<object>, ICloneable
{
// There are two uses for this custom list type:
// 1) it's private, and thus (unlike List<object>) cannot be confused with real annotations
// 2) It allows us to simplify the cloning logic by making the list behave the same as a clonable annotation.
public AnnotationList(int initialCapacity) : base(initialCapacity)
{
}
public object Clone()
{
lock (this) {
AnnotationList copy = new AnnotationList(this.Count);
for (int i = 0; i < this.Count; i++) {
object obj = this[i];
ICloneable c = obj as ICloneable;
copy.Add(c != null ? c.Clone() : obj);
}
return copy;
}
}
}
public void AddAnnotation(object annotation)
{ {
if (annotation == null)
throw new ArgumentNullException("annotation");
if (this.IsNull) if (this.IsNull)
throw new InvalidOperationException("Cannot add annotations to the null node"); throw new InvalidOperationException("Cannot add annotations to the null node");
retry: // Retry until successful base.AddAnnotation (annotation);
object oldAnnotation = Interlocked.CompareExchange(ref this.annotations, annotation, null);
if (oldAnnotation == null) {
return; // we successfully added a single annotation
}
AnnotationList list = oldAnnotation as AnnotationList;
if (list == null) {
// we need to transform the old annotation into a list
list = new AnnotationList(4);
list.Add(oldAnnotation);
list.Add(annotation);
if (Interlocked.CompareExchange(ref this.annotations, list, oldAnnotation) != oldAnnotation) {
// the transformation failed (some other thread wrote to this.annotations first)
goto retry;
}
} else {
// once there's a list, use simple locking
lock (list) {
list.Add(annotation);
}
}
}
public void RemoveAnnotations<T>() where T : class
{
retry: // Retry until successful
object oldAnnotations = this.annotations;
AnnotationList list = oldAnnotations as AnnotationList;
if (list != null) {
lock (list)
list.RemoveAll(obj => obj is T);
} else if (oldAnnotations is T) {
if (Interlocked.CompareExchange(ref this.annotations, null, oldAnnotations) != oldAnnotations) {
// Operation failed (some other thread wrote to this.annotations first)
goto retry;
}
}
} }
public void RemoveAnnotations(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
retry: // Retry until successful
object oldAnnotations = this.annotations;
AnnotationList list = oldAnnotations as AnnotationList;
if (list != null) {
lock (list)
list.RemoveAll(obj => type.IsInstanceOfType(obj));
} else if (type.IsInstanceOfType(oldAnnotations)) {
if (Interlocked.CompareExchange(ref this.annotations, null, oldAnnotations) != oldAnnotations) {
// Operation failed (some other thread wrote to this.annotations first)
goto retry;
}
}
}
public T Annotation<T>() where T: class
{
object annotations = this.annotations;
AnnotationList list = annotations as AnnotationList;
if (list != null) {
lock (list) {
foreach (object obj in list) {
T t = obj as T;
if (t != null)
return t;
}
return null;
}
} else {
return annotations as T;
}
}
public object Annotation(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
object annotations = this.annotations;
AnnotationList list = annotations as AnnotationList;
if (list != null) {
lock (list) {
foreach (object obj in list) {
if (type.IsInstanceOfType(obj))
return obj;
}
}
} else {
if (type.IsInstanceOfType(annotations))
return annotations;
}
return null;
}
/// <summary>
/// Gets all annotations stored on this AstNode.
/// </summary>
public IEnumerable<object> Annotations {
get {
object annotations = this.annotations;
AnnotationList list = annotations as AnnotationList;
if (list != null) {
lock (list) {
return list.ToArray();
}
} else {
if (annotations != null)
return new object[] { annotations };
else
return Enumerable.Empty<object>();
}
}
}
#endregion
public abstract S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data); public abstract S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data);
#region Pattern Matching #region Pattern Matching

2
NRefactory/ICSharpCode.NRefactory.VB/Ast/General/TypeParameterDeclaration.cs

@ -21,7 +21,7 @@ namespace ICSharpCode.NRefactory.VB.Ast
public string Name { public string Name {
get { return GetChildByRole (Roles.Identifier).Name; } get { return GetChildByRole (Roles.Identifier).Name; }
set { SetChildByRole(Roles.Identifier, new Identifier(value, AstLocation.Empty)); } set { SetChildByRole(Roles.Identifier, new Identifier (value, AstLocation.Empty)); }
} }
public AstNodeCollection<AstType> Constraints { public AstNodeCollection<AstType> Constraints {

2
NRefactory/ICSharpCode.NRefactory.VB/Ast/GlobalScope/NamespaceDeclaration.cs

@ -30,7 +30,7 @@ namespace ICSharpCode.NRefactory.VB.Ast
return builder.ToString (); return builder.ToString ();
} }
set { set {
GetChildrenByRole(Roles.Identifier).ReplaceWith(value.Split('.').Select(ident => new Identifier(ident, AstLocation.Empty))); GetChildrenByRole(Roles.Identifier).ReplaceWith(value.Split('.').Select(ident => new Identifier (ident, AstLocation.Empty)));
} }
} }

10
NRefactory/ICSharpCode.NRefactory.VB/Ast/GlobalScope/TypeDeclaration.cs

@ -20,9 +20,11 @@ namespace ICSharpCode.NRefactory.VB.Ast
public ClassType ClassType { get; set; } public ClassType ClassType { get; set; }
public Identifier Name { public string Name {
get { return GetChildByRole(Roles.Identifier); } get { return GetChildByRole(Roles.Identifier).Name; }
set { SetChildByRole(Roles.Identifier, value); } set {
SetChildByRole(Roles.Identifier, new Identifier (value, AstLocation.Empty));
}
} }
public AstNodeCollection<TypeParameterDeclaration> TypeParameters { public AstNodeCollection<TypeParameterDeclaration> TypeParameters {
@ -44,7 +46,7 @@ namespace ICSharpCode.NRefactory.VB.Ast
MatchAttributesAndModifiers(t, match) && MatchAttributesAndModifiers(t, match) &&
Members.DoMatch(t.Members, match) && Members.DoMatch(t.Members, match) &&
ClassType == t.ClassType && ClassType == t.ClassType &&
Name.DoMatch(t.Name, match) && MatchString(Name, t.Name) &&
TypeParameters.DoMatch(t.TypeParameters, match) && TypeParameters.DoMatch(t.TypeParameters, match) &&
InheritsType.DoMatch(t.InheritsType, match) && InheritsType.DoMatch(t.InheritsType, match) &&
ImplementsTypes.DoMatch(t.ImplementsTypes, match); ImplementsTypes.DoMatch(t.ImplementsTypes, match);

2
NRefactory/ICSharpCode.NRefactory.VB/Ast/TypeName/QualifiedType.cs

@ -24,7 +24,7 @@ namespace ICSharpCode.NRefactory.VB.Ast
return GetChildByRole (Roles.Identifier).Name; return GetChildByRole (Roles.Identifier).Name;
} }
set { set {
SetChildByRole (Roles.Identifier, new Identifier(value, AstLocation.Empty)); SetChildByRole (Roles.Identifier, new Identifier (value, AstLocation.Empty));
} }
} }

4
NRefactory/ICSharpCode.NRefactory.VB/Ast/TypeName/SimpleType.cs

@ -44,7 +44,7 @@ namespace ICSharpCode.NRefactory.VB.Ast
public SimpleType(string identifier, AstLocation location) public SimpleType(string identifier, AstLocation location)
{ {
SetChildByRole (Roles.Identifier, new Identifier(identifier, location)); SetChildByRole (Roles.Identifier, new Identifier (identifier, location));
} }
public string Identifier { public string Identifier {
@ -52,7 +52,7 @@ namespace ICSharpCode.NRefactory.VB.Ast
return GetChildByRole (Roles.Identifier).Name; return GetChildByRole (Roles.Identifier).Name;
} }
set { set {
SetChildByRole (Roles.Identifier, new Identifier(value, AstLocation.Empty)); SetChildByRole (Roles.Identifier, new Identifier (value, AstLocation.Empty));
} }
} }

6
NRefactory/ICSharpCode.NRefactory.VB/Parser/Parser.cs

@ -1,4 +1,4 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
@ -402,7 +402,7 @@ partial class VBParser
while (la.kind == 26) { while (la.kind == 26) {
Get(); Get();
Identifier(); Identifier();
type = new QualifiedType(type, new Identifier(t.val, t.Location)); type = new QualifiedType(type, new Identifier (t.val, t.Location));
} }
} }
@ -445,7 +445,7 @@ partial class VBParser
var result = new AliasImportsClause(); NodeStart(result); var result = new AliasImportsClause(); NodeStart(result);
AstType alias; AstType alias;
Identifier(); Identifier();
result.Name = new Identifier(t.val, t.Location); result.Name = new Identifier (t.val, t.Location);
Expect(20); Expect(20);
TypeName(out alias); TypeName(out alias);
result.Alias = alias; result.Alias = alias;

7
NRefactory/ICSharpCode.NRefactory/CSharp/Analysis/ControlFlow.cs

@ -143,7 +143,12 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
Dictionary<string, ControlFlowNode> labels; Dictionary<string, ControlFlowNode> labels;
List<ControlFlowNode> gotoStatements; List<ControlFlowNode> gotoStatements;
public IList<ControlFlowNode> BuildControlFlowGraph(Statement statement, ITypeResolveContext context, CancellationToken cancellationToken = default(CancellationToken)) public IList<ControlFlowNode> BuildControlFlowGraph(Statement statement, ITypeResolveContext context)
{
return BuildControlFlowGraph(statement, context, CancellationToken.None);
}
public IList<ControlFlowNode> BuildControlFlowGraph(Statement statement, ITypeResolveContext context, CancellationToken cancellationToken)
{ {
return BuildControlFlowGraph(statement, new ResolveVisitor( return BuildControlFlowGraph(statement, new ResolveVisitor(
new CSharpResolver(context, cancellationToken), new CSharpResolver(context, cancellationToken),

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save