diff --git a/Debugger/ILSpy.Debugger/Commands/DebuggerCommands.cs b/Debugger/ILSpy.Debugger/Commands/DebuggerCommands.cs
index f00c24542..3a122360b 100644
--- a/Debugger/ILSpy.Debugger/Commands/DebuggerCommands.cs
+++ b/Debugger/ILSpy.Debugger/Commands/DebuggerCommands.cs
@@ -10,7 +10,6 @@ using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Xml.Linq;
-
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.ILSpy.Bookmarks;
using ICSharpCode.ILSpy.Debugger;
@@ -20,6 +19,7 @@ using ICSharpCode.ILSpy.Debugger.UI;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.TreeView;
using Microsoft.Win32;
+using Mono.Cecil;
namespace ICSharpCode.ILSpy.Debugger.Commands
{
@@ -182,7 +182,14 @@ namespace ICSharpCode.ILSpy.Debugger.Commands
{
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)
diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
index dfeff794e..cab334432 100644
--- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
+++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
@@ -782,9 +782,15 @@ namespace ICSharpCode.Decompiler.Ast
}
}
ObjectCreateExpression oce = arg1 as ObjectCreateExpression;
+ DefaultValueExpression dve = arg1 as DefaultValueExpression;
if (oce != null) {
oce.Initializer = initializer;
return oce;
+ } else if (dve != null) {
+ oce = new ObjectCreateExpression(dve.Type.Detach());
+ oce.CopyAnnotationsFrom(dve);
+ oce.Initializer = initializer;
+ return oce;
} else {
return new AssignmentExpression(arg1, initializer);
}
diff --git a/ICSharpCode.Decompiler/Ast/CecilTypeResolveContext.cs b/ICSharpCode.Decompiler/Ast/CecilTypeResolveContext.cs
index 2bdedd06b..2e10dfda1 100644
--- a/ICSharpCode.Decompiler/Ast/CecilTypeResolveContext.cs
+++ b/ICSharpCode.Decompiler/Ast/CecilTypeResolveContext.cs
@@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.TypeSystem;
using Mono.Cecil;
@@ -27,7 +28,7 @@ namespace ICSharpCode.Decompiler.Ast
///
/// ITypeResolveContext implementation that lazily loads types from Cecil.
///
- public class CecilTypeResolveContext : ISynchronizedTypeResolveContext, IProjectContent
+ public class CecilTypeResolveContext : AbstractAnnotatable, ISynchronizedTypeResolveContext, IProjectContent
{
readonly ModuleDefinition module;
readonly string[] namespaces;
@@ -91,7 +92,7 @@ namespace ICSharpCode.Decompiler.Ast
public IList 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)
name = name + "`" + typeParameterCount.ToString();
@@ -113,14 +114,14 @@ namespace ICSharpCode.Decompiler.Ast
return null;
}
- public IEnumerable GetClasses()
+ public IEnumerable GetTypes()
{
foreach (TypeDefinition cecilType in module.Types) {
yield return GetClass(cecilType);
}
}
- public IEnumerable GetClasses(string nameSpace, StringComparer nameComparer)
+ public IEnumerable GetTypes(string nameSpace, StringComparer nameComparer)
{
foreach (TypeDefinition cecilType in module.Types) {
if (nameComparer.Equals(nameSpace, cecilType.Namespace))
@@ -159,5 +160,14 @@ namespace ICSharpCode.Decompiler.Ast
{
// exit from Synchronize() block
}
+
+ IEnumerable IProjectContent.Files {
+ get { return new IParsedFile[0]; }
+ }
+
+ IParsedFile IProjectContent.GetFile(string fileName)
+ {
+ return null;
+ }
}
}
diff --git a/ICSharpCode.Decompiler/Ast/NameVariables.cs b/ICSharpCode.Decompiler/Ast/NameVariables.cs
index 9b3632119..f0a862f44 100644
--- a/ICSharpCode.Decompiler/Ast/NameVariables.cs
+++ b/ICSharpCode.Decompiler/Ast/NameVariables.cs
@@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.Ast
nv.AddExistingName(v.Name);
} else if (v.OriginalVariable != null && context.Settings.UseDebugSymbols) {
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
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;
List fieldNamesInCurrentType;
Dictionary typeNames = new Dictionary();
@@ -139,7 +152,7 @@ namespace ICSharpCode.Decompiler.Ast
typeNames.Add(nameWithoutDigits, number - 1);
}
int count = ++typeNames[nameWithoutDigits];
- if (count > 1) {
+ if (count != 1) {
return nameWithoutDigits + count.ToString();
} else {
return nameWithoutDigits;
diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
index 42c2893e5..aebda33e8 100644
--- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
+++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
@@ -42,6 +42,7 @@ namespace ICSharpCode.Decompiler.ILAst
SimplifyTernaryOperator,
SimplifyNullCoalescing,
JoinBasicBlocks,
+ SimplifyShiftOperators,
TransformDecimalCtorToConstant,
SimplifyLdObjAndStObj,
SimplifyCustomShortCircuit,
@@ -54,6 +55,7 @@ namespace ICSharpCode.Decompiler.ILAst
FindLoops,
FindConditions,
FlattenNestedMovableBlocks,
+ RemoveEndFinally,
RemoveRedundantCode2,
GotoRemoval,
DuplicateReturns,
@@ -131,7 +133,10 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks) return;
modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks);
-
+
+ if (abortBeforeStep == ILAstOptimizationStep.SimplifyShiftOperators) return;
+ modified |= block.RunOptimization(SimplifyShiftOperators);
+
if (abortBeforeStep == ILAstOptimizationStep.TransformDecimalCtorToConstant) return;
modified |= block.RunOptimization(TransformDecimalCtorToConstant);
modified |= block.RunOptimization(SimplifyLdcI4ConvI8);
@@ -178,6 +183,9 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) return;
FlattenBasicBlocks(method);
+ if (abortBeforeStep == ILAstOptimizationStep.RemoveEndFinally) return;
+ RemoveEndFinally(method);
+
if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode2) return;
RemoveRedundantCode(method);
@@ -534,6 +542,25 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
+ ///
+ /// Replace endfinally with jump to the end of the finally block
+ ///
+ void RemoveEndFinally(ILBlock method)
+ {
+ // Go thought the list in reverse so that we do the nested blocks first
+ foreach(var tryCatch in method.GetSelfAndChildrenRecursive(tc => tc.FinallyBlock != null).Reverse()) {
+ ILLabel label = new ILLabel() { Name = "EndFinally_" + nextLabelIndex++ };
+ tryCatch.FinallyBlock.Body.Add(label);
+ foreach(var block in tryCatch.FinallyBlock.GetSelfAndChildrenRecursive()) {
+ 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);
+ }
+ }
+ }
+ }
+ }
+
///
/// Reduce the nesting of conditions.
/// 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 ilranges)
+ {
+ expr.ILRanges.AddRange(ilranges);
+ return expr;
+ }
+
public static void RemoveTail(this List body, params ILCode[] codes)
{
for (int i = 0; i < codes.Length; i++) {
diff --git a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
index f86225fb8..4f3930fcd 100644
--- a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
+++ b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
@@ -43,6 +43,7 @@ namespace ICSharpCode.Decompiler.ILAst
void AccumulateSelfAndChildrenRecursive(List list, Func predicate) where T:ILNode
{
+ // Note: RemoveEndFinally depends on self coming before children
T thisAsT = this as T;
if (thisAsT != null && (predicate == null || predicate(thisAsT)))
list.Add(thisAsT);
diff --git a/ICSharpCode.Decompiler/ILAst/ILCodes.cs b/ICSharpCode.Decompiler/ILAst/ILCodes.cs
index 36bc56d52..e7322a770 100644
--- a/ICSharpCode.Decompiler/ILAst/ILCodes.cs
+++ b/ICSharpCode.Decompiler/ILAst/ILCodes.cs
@@ -261,8 +261,8 @@ namespace ICSharpCode.Decompiler.ILAst
// InitCollection(CallGetter(Collection, InitializedObject))),
// Call(Add, InitializedObject, 2, 3),
// Call(Add, InitializedObject, 4, 5)))
- InitObject, // Object initializer: first arg is newobj, remaining args are the initializing statements
- InitCollection, // Collection 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/defaultvalue, remaining args are the initializing statements
InitializedObject, // Refers the the object being initialized (refers to first arg in parent InitObject or InitCollection instruction)
TernaryOp, // ?:
diff --git a/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs b/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs
index 1a9ad78cf..5b194b738 100644
--- a/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs
+++ b/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs
@@ -93,9 +93,9 @@ namespace ICSharpCode.Decompiler.ILAst
List ctorArgs;
ArrayType arrayType;
if (expr.Match(ILCode.Stloc, out v, out newarrExpr) &&
- newarrExpr.Match(ILCode.Newobj, out ctor, out ctorArgs) &&
- (arrayType = (ctor.DeclaringType as ArrayType)) != null &&
- arrayType.Rank == ctorArgs.Count) {
+ newarrExpr.Match(ILCode.Newobj, out ctor, out ctorArgs) &&
+ (arrayType = (ctor.DeclaringType as ArrayType)) != null &&
+ arrayType.Rank == ctorArgs.Count) {
// Clone the type, so we can muck about with the Dimensions
arrayType = new ArrayType(arrayType.ElementType, arrayType.Rank);
var arrayLengths = new int[arrayType.Rank];
@@ -124,19 +124,24 @@ namespace ICSharpCode.Decompiler.ILAst
MethodReference methodRef;
ILExpression methodArg1;
ILExpression methodArg2;
- FieldDefinition field;
+ FieldReference fieldRef;
if (body.ElementAtOrDefault(pos).Match(ILCode.Call, out methodRef, out methodArg1, out methodArg2) &&
- methodRef.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers" &&
- methodRef.Name == "InitializeArray" &&
- methodArg1.Match(ILCode.Ldloc, out v2) &&
- array == v2 &&
- methodArg2.Match(ILCode.Ldtoken, out field) &&
- field != null && field.InitialValue != null) {
- ILExpression[] newArr = new ILExpression[arrayLength];
- if (DecodeArrayInitializer(TypeAnalysis.GetTypeCode(arrayType.GetElementType()), field.InitialValue, newArr)) {
- values = newArr;
- foundPos = pos;
- return true;
+ methodRef.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers" &&
+ methodRef.Name == "InitializeArray" &&
+ methodArg1.Match(ILCode.Ldloc, out v2) &&
+ array == v2 &&
+ methodArg2.Match(ILCode.Ldtoken, out fieldRef))
+ {
+ FieldDefinition fieldDef = fieldRef.ResolveWithinSameModule();
+ if (fieldDef != null && fieldDef.InitialValue != null) {
+ ILExpression[] newArr = new ILExpression[arrayLength];
+ if (DecodeArrayInitializer(TypeAnalysis.GetTypeCode(arrayType.GetElementType()),
+ fieldDef.InitialValue, newArr))
+ {
+ values = newArr;
+ foundPos = pos;
+ return true;
+ }
}
}
values = null;
@@ -148,7 +153,6 @@ namespace ICSharpCode.Decompiler.ILAst
{
switch (elementType) {
case TypeCode.Boolean:
- case TypeCode.SByte:
case TypeCode.Byte:
if (initialValue.Length == output.Length) {
for (int j = 0; j < output.Length; j++) {
@@ -157,9 +161,15 @@ namespace ICSharpCode.Decompiler.ILAst
return true;
}
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.UInt16:
if (initialValue.Length == output.Length * 2) {
for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_I4, (int)BitConverter.ToInt16(initialValue, j * 2));
@@ -167,6 +177,15 @@ namespace ICSharpCode.Decompiler.ILAst
return true;
}
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.UInt32:
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
ILVariable v;
ILExpression newObjExpr;
+ TypeReference newObjType;
+ bool isValueType;
MethodReference ctor;
List ctorArgs;
- // v = newObj(ctor, ctorArgs)
- if (!(expr.Match(ILCode.Stloc, out v, out newObjExpr) && newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs)))
+ if (expr.Match(ILCode.Stloc, out v, out newObjExpr)) {
+ 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(ctorArgs);
+ ctorArgs.RemoveAt(0);
+ newObjExpr = new ILExpression(ILCode.Newobj, ctor, ctorArgs);
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ if (newObjType.IsValueType != isValueType)
return false;
+
int originalPos = pos;
// 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;
- 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
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
ILInlining inlining = new ILInlining(method);
- // 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;
+ if (isValueType) {
+ // one ldloc for the use of the initialized object
+ if (inlining.numLdloc.GetOrDefault(v) != 1)
+ 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;
if (!inlining.CanInlineInto(nextExpr, v, initializer))
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
body.RemoveRange(originalPos + 1, pos - originalPos - 1);
@@ -288,7 +354,7 @@ namespace ICSharpCode.Decompiler.ILAst
{
if (expr == null)
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 false;
@@ -320,9 +386,8 @@ namespace ICSharpCode.Decompiler.ILAst
/// The variable that holds the object being initialized
/// The newobj instruction
/// InitObject instruction
- ILExpression ParseObjectInitializer(List body, ref int pos, ILVariable v, ILExpression newObjExpr, bool isCollection)
+ ILExpression ParseObjectInitializer(List 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.
// We just construct new ones around the old ones, any modifications must wait until the whole
// object/collection initializer was analyzed.
@@ -332,13 +397,13 @@ namespace ICSharpCode.Decompiler.ILAst
while (++pos < body.Count) {
ILExpression nextExpr = body[pos] as ILExpression;
if (IsSetterInObjectInitializer(nextExpr)) {
- if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, false)) {
+ if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, false, isValueType)) {
CleanupInitializerStackAfterFailedAdjustment(initializerStack);
break;
}
initializerStack[initializerStack.Count - 1].Arguments.Add(nextExpr);
} else if (IsAddMethodCall(nextExpr)) {
- if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, true)) {
+ if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, true, isValueType)) {
CleanupInitializerStackAfterFailedAdjustment(initializerStack);
break;
}
@@ -351,20 +416,26 @@ namespace ICSharpCode.Decompiler.ILAst
return objectInitializer;
}
- static bool AdjustInitializerStack(List initializerStack, ILExpression argument, ILVariable v, bool isCollection)
+ static bool AdjustInitializerStack(List initializerStack, ILExpression argument, ILVariable v, bool isCollection, bool isValueType)
{
// Argument is of the form 'getter(getter(...(v)))'
// Unpack it into a list of getters:
List getters = new List();
- 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);
if (argument.Arguments.Count != 1)
return false;
argument = argument.Arguments[0];
}
// Ensure that the final argument is 'v'
- if (!argument.MatchLdloc(v))
- return false;
+ if (isValueType) {
+ 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:
int i;
for (i = 1; i <= Math.Min(getters.Count, initializerStack.Count - 1); i++) {
diff --git a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
index 88900a73b..b8110651b 100644
--- a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
+++ b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
@@ -868,5 +868,40 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
#endregion
+
+ #region SimplifyShiftOperators
+ static bool SimplifyShiftOperators(List 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
}
}
diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
index 4755ea4c7..0891f82f1 100644
--- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
+++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
@@ -323,13 +323,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (forceInferChildren) {
for (int i = 0; i < expr.Arguments.Count; i++) {
if (i == 0 && method.HasThis) {
- ILExpressionPrefix constraint = 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);
+ InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(method.DeclaringType, expr.GetPrefix(ILCode.Constrained)));
} else {
InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(method.Parameters[method.HasThis ? i - 1 : i].ParameterType, method));
}
@@ -361,17 +355,22 @@ namespace ICSharpCode.Decompiler.ILAst
#endregion
#region Load/Store Fields
case ILCode.Ldfld:
- if (forceInferChildren)
- InferTypeForExpression(expr.Arguments[0], ((FieldReference)expr.Operand).DeclaringType);
+ if (forceInferChildren) {
+ InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained)));
+ }
return GetFieldType((FieldReference)expr.Operand);
case ILCode.Ldsfld:
return GetFieldType((FieldReference)expr.Operand);
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:
return new ByReferenceType(GetFieldType((FieldReference)expr.Operand));
case ILCode.Stfld:
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));
}
return GetFieldType((FieldReference)expr.Operand);
@@ -515,14 +514,47 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Rem_Un:
return InferArgumentsInBinaryOperator(expr, false, expectedType);
case ILCode.Shl:
- case ILCode.Shr:
if (forceInferChildren)
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:
- if (forceInferChildren)
- InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
- return InferTypeForExpression(expr.Arguments[0], typeSystem.UInt32);
+ {
+ if (forceInferChildren)
+ 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:
{
TypeReference varType = InferTypeForExpression(expr.Arguments[0].Arguments[0], null);
@@ -543,9 +575,19 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldc_I4:
if (IsBoolean(expectedType) && ((int)expr.Operand == 0 || (int)expr.Operand == 1))
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:
- 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:
return typeSystem.Single;
case ILCode.Ldc_R8:
@@ -753,6 +795,41 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
+ ///
+ /// 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.
+ ///
+ 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;
+ }
+
+ ///
+ /// Promotes primitive types smaller than int32 to int32.
+ ///
+ ///
+ /// Always promotes to signed int32.
+ ///
+ 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)
{
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)
{
TypeSpecification typeSpec = type as TypeSpecification;
diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
index 13af1018c..a3bcddf9e 100644
--- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
+++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -63,6 +63,7 @@
+
diff --git a/ICSharpCode.Decompiler/Tests/InitializerTests.cs b/ICSharpCode.Decompiler/Tests/InitializerTests.cs
index 80fbe7478..a4ab57fbf 100644
--- a/ICSharpCode.Decompiler/Tests/InitializerTests.cs
+++ b/ICSharpCode.Decompiler/Tests/InitializerTests.cs
@@ -52,8 +52,37 @@ public class InitializerTests
get;
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
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()
{
int[,] expr_09 = new int[, ]
diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs
index cdfde87af..f6d21fde1 100644
--- a/ICSharpCode.Decompiler/Tests/TestRunner.cs
+++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs
@@ -142,6 +142,12 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\YieldReturn.cs");
}
+ [Test]
+ public void TypeAnalysis()
+ {
+ TestFile(@"..\..\Tests\TypeAnalysisTests.cs");
+ }
+
static void TestFile(string fileName)
{
string code = File.ReadAllText(fileName);
diff --git a/ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs b/ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs
new file mode 100644
index 000000000..3224debdd
--- /dev/null
+++ b/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);
+ }
+}
diff --git a/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs b/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
index a1b77fb6b..21ea662a6 100644
--- a/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
+++ b/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs
@@ -18,10 +18,10 @@ namespace ILSpy.BamlDecompiler
return null;
}
- public ILSpyTreeNode CreateNode(string key, Stream data)
+ public ILSpyTreeNode CreateNode(string key, object data)
{
- if (key.EndsWith(".baml", StringComparison.OrdinalIgnoreCase))
- return new BamlResourceEntryNode(key, data);
+ if (key.EndsWith(".baml", StringComparison.OrdinalIgnoreCase) && data is Stream)
+ return new BamlResourceEntryNode(key, (Stream)data);
else
return null;
}
diff --git a/ILSpy.BamlDecompiler/CecilDependencyPropertyDescriptor.cs b/ILSpy.BamlDecompiler/CecilDependencyPropertyDescriptor.cs
index 9a0e1e559..21806b21f 100644
--- a/ILSpy.BamlDecompiler/CecilDependencyPropertyDescriptor.cs
+++ b/ILSpy.BamlDecompiler/CecilDependencyPropertyDescriptor.cs
@@ -2,6 +2,7 @@
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
+using System.Diagnostics;
using System.Linq;
using ICSharpCode.ILSpy;
using Mono.Cecil;
@@ -16,6 +17,8 @@ namespace ILSpy.BamlDecompiler
public CecilDependencyPropertyDescriptor(string member, TypeDefinition type)
{
+ if (type == null)
+ throw new ArgumentNullException("type");
this.member = member;
this.type = type;
}
diff --git a/ILSpy.BamlDecompiler/CecilType.cs b/ILSpy.BamlDecompiler/CecilType.cs
index e84f95938..d41cac4c9 100644
--- a/ILSpy.BamlDecompiler/CecilType.cs
+++ b/ILSpy.BamlDecompiler/CecilType.cs
@@ -15,6 +15,8 @@ namespace ILSpy.BamlDecompiler
public CecilType(TypeDefinition type)
{
+ if (type == null)
+ throw new ArgumentNullException("type");
this.type = type;
}
diff --git a/ILSpy.BamlDecompiler/CecilTypeResolver.cs b/ILSpy.BamlDecompiler/CecilTypeResolver.cs
index bc42696ea..1bc79ab11 100644
--- a/ILSpy.BamlDecompiler/CecilTypeResolver.cs
+++ b/ILSpy.BamlDecompiler/CecilTypeResolver.cs
@@ -52,7 +52,7 @@ namespace ILSpy.BamlDecompiler
var otherAssembly = resolver.Resolve(assemblyName);
if (otherAssembly == null)
throw new Exception("could not resolve '" + assemblyName + "'!");
- type = otherAssembly.MainModule.GetType(fullName);
+ type = otherAssembly.MainModule.GetType(fullName.Replace('+', '/'));
}
return new CecilType(type);
diff --git a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj
index 3274b3c08..4c4e5075e 100644
--- a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj
+++ b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj
@@ -80,23 +80,17 @@
-
-
-
- Component
-
-
+
-
diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/AppDomainTypeResolver.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/AppDomainTypeResolver.cs
deleted file mode 100644
index b33379323..000000000
--- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/AppDomainTypeResolver.cs
+++ /dev/null
@@ -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; }
- }
- }
-}
diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlAssembly.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlAssembly.cs
deleted file mode 100644
index d9d71860f..000000000
--- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlAssembly.cs
+++ /dev/null
@@ -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
- {}
-
-}
diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlFile.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlFile.cs
deleted file mode 100644
index d4af6bb81..000000000
--- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/BamlFile.cs
+++ /dev/null
@@ -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
-{
- ///
- /// Rappresenta un singole file Baml all'interno di un assembly
- ///
- 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;
- }
-
- ///
- /// Carica il Baml attraverso il motore di WPF con Application.LoadComponent
- ///
- ///
- 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;
- }
-
- ///
- /// Restituisce lo stream originale contenente il Baml
- ///
- public Stream Stream
- {
- get { return _stream; }
- }
-
- ///
- /// Restituisce l'indirizzo secondo lo schema pack://
- ///
- public Uri Uri
- {
- get { return _uri; }
- }
-
- }
-}
diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/DotNetType.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/DotNetType.cs
deleted file mode 100644
index 313863bd0..000000000
--- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/DotNetType.cs
+++ /dev/null
@@ -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;
- }
- }
-}
diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KeyMapping.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KeyMapping.cs
index 0b20620fc..abda8e317 100644
--- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KeyMapping.cs
+++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/KeyMapping.cs
@@ -36,5 +36,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
this.staticResources = new List
public IEnumerable DescendantsAndSelf {
get {
- return Utils.TreeTraversal.PreOrder(this, n => n.Children);
+ return Utils.TreeTraversal.PreOrder (this, n => n.Children);
}
}
@@ -205,10 +204,10 @@ namespace ICSharpCode.NRefactory.CSharp
/// Gets the first child with the specified role.
/// Returns the role's null object if the child is not found.
///
- public T GetChildByRole(Role role) where T : AstNode
+ public T GetChildByRole (Role role) where T : AstNode
{
if (role == null)
- throw new ArgumentNullException("role");
+ throw new ArgumentNullException ("role");
for (var cur = firstChild; cur != null; cur = cur.nextSibling) {
if (cur.role == role)
return (T)cur;
@@ -216,37 +215,37 @@ namespace ICSharpCode.NRefactory.CSharp
return role.NullObject;
}
- public AstNodeCollection GetChildrenByRole(Role role) where T : AstNode
+ public AstNodeCollection GetChildrenByRole (Role role) where T : AstNode
{
- return new AstNodeCollection(this, role);
+ return new AstNodeCollection (this, role);
}
- protected void SetChildByRole(Role role, T newChild) where T : AstNode
+ protected void SetChildByRole (Role role, T newChild) where T : AstNode
{
- AstNode oldChild = GetChildByRole(role);
+ AstNode oldChild = GetChildByRole (role);
if (oldChild.IsNull)
- AddChild(newChild, role);
+ AddChild (newChild, role);
else
- oldChild.ReplaceWith(newChild);
+ oldChild.ReplaceWith (newChild);
}
- public void AddChild(T child, Role role) where T : AstNode
+ public void AddChild (T child, Role role) where T : AstNode
{
if (role == null)
- throw new ArgumentNullException("role");
+ throw new ArgumentNullException ("role");
if (child == null || child.IsNull)
return;
if (this.IsNull)
- throw new InvalidOperationException("Cannot add children to null nodes");
+ throw new InvalidOperationException ("Cannot add children to null nodes");
if (child.parent != null)
throw new ArgumentException ("Node is already used in another tree.", "child");
- AddChildUnsafe(child, role);
+ AddChildUnsafe (child, role);
}
///
/// Adds a child without performing any safety checks.
///
- void AddChildUnsafe(AstNode child, Role role)
+ void AddChildUnsafe (AstNode child, Role role)
{
child.parent = this;
child.role = role;
@@ -259,12 +258,12 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
- public void InsertChildBefore(AstNode nextSibling, T child, Role role) where T : AstNode
+ public void InsertChildBefore (AstNode nextSibling, T child, Role role) where T : AstNode
{
if (role == null)
- throw new ArgumentNullException("role");
+ throw new ArgumentNullException ("role");
if (nextSibling == null || nextSibling.IsNull) {
- AddChild(child, role);
+ AddChild (child, role);
return;
}
@@ -276,11 +275,10 @@ namespace ICSharpCode.NRefactory.CSharp
throw new ArgumentException ("NextSibling is not a child of this node.", "nextSibling");
// No need to test for "Cannot add children to null nodes",
// as there isn't any valid nextSibling in null nodes.
- InsertChildBeforeUnsafe(nextSibling, child, role);
+ InsertChildBeforeUnsafe (nextSibling, child, role);
}
-
- void InsertChildBeforeUnsafe(AstNode nextSibling, AstNode child, Role role)
+ void InsertChildBeforeUnsafe (AstNode nextSibling, AstNode child, Role role)
{
child.parent = this;
child.role = role;
@@ -288,38 +286,38 @@ namespace ICSharpCode.NRefactory.CSharp
child.prevSibling = nextSibling.prevSibling;
if (nextSibling.prevSibling != null) {
- Debug.Assert(nextSibling.prevSibling.nextSibling == nextSibling);
+ Debug.Assert (nextSibling.prevSibling.nextSibling == nextSibling);
nextSibling.prevSibling.nextSibling = child;
} else {
- Debug.Assert(firstChild == nextSibling);
+ Debug.Assert (firstChild == nextSibling);
firstChild = child;
}
nextSibling.prevSibling = child;
}
- public void InsertChildAfter(AstNode prevSibling, T child, Role role) where T : AstNode
+ public void InsertChildAfter (AstNode prevSibling, T child, Role role) where T : AstNode
{
- InsertChildBefore((prevSibling == null || prevSibling.IsNull) ? firstChild : prevSibling.nextSibling, child, role);
+ InsertChildBefore ((prevSibling == null || prevSibling.IsNull) ? firstChild : prevSibling.nextSibling, child, role);
}
///
/// Removes this node from its parent.
///
- public void Remove()
+ public void Remove ()
{
if (parent != null) {
if (prevSibling != null) {
- Debug.Assert(prevSibling.nextSibling == this);
+ Debug.Assert (prevSibling.nextSibling == this);
prevSibling.nextSibling = nextSibling;
} else {
- Debug.Assert(parent.firstChild == this);
+ Debug.Assert (parent.firstChild == this);
parent.firstChild = nextSibling;
}
if (nextSibling != null) {
- Debug.Assert(nextSibling.prevSibling == this);
+ Debug.Assert (nextSibling.prevSibling == this);
nextSibling.prevSibling = prevSibling;
} else {
- Debug.Assert(parent.lastChild == this);
+ Debug.Assert (parent.lastChild == this);
parent.lastChild = prevSibling;
}
parent = null;
@@ -332,28 +330,28 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// Replaces this node with the new node.
///
- public void ReplaceWith(AstNode newNode)
+ public void ReplaceWith (AstNode newNode)
{
if (newNode == null || newNode.IsNull) {
- Remove();
+ Remove ();
return;
}
if (newNode == this)
return; // nothing to do...
if (parent == null) {
- throw new InvalidOperationException(this.IsNull ? "Cannot replace the null nodes" : "Cannot replace the root node");
+ throw new InvalidOperationException (this.IsNull ? "Cannot replace the null nodes" : "Cannot replace the root node");
}
// Because this method doesn't statically check the new node's type with the role,
// we perform a runtime test:
- if (!role.IsValid(newNode)) {
- throw new ArgumentException (string.Format("The new node '{0}' is not valid in the role {1}", newNode.GetType().Name, role.ToString()), "newNode");
+ if (!role.IsValid (newNode)) {
+ throw new ArgumentException (string.Format ("The new node '{0}' is not valid in the role {1}", newNode.GetType ().Name, role.ToString ()), "newNode");
}
if (newNode.parent != null) {
// newNode is used within this tree?
- if (newNode.Ancestors.Contains(this)) {
+ if (newNode.Ancestors.Contains (this)) {
// e.g. "parenthesizedExpr.ReplaceWith(parenthesizedExpr.Expression);"
// enable automatic removal
- newNode.Remove();
+ newNode.Remove ();
} else {
throw new ArgumentException ("Node is already used in another tree.", "newNode");
}
@@ -365,17 +363,17 @@ namespace ICSharpCode.NRefactory.CSharp
newNode.nextSibling = nextSibling;
if (parent != null) {
if (prevSibling != null) {
- Debug.Assert(prevSibling.nextSibling == this);
+ Debug.Assert (prevSibling.nextSibling == this);
prevSibling.nextSibling = newNode;
} else {
- Debug.Assert(parent.firstChild == this);
+ Debug.Assert (parent.firstChild == this);
parent.firstChild = newNode;
}
if (nextSibling != null) {
- Debug.Assert(nextSibling.prevSibling == this);
+ Debug.Assert (nextSibling.prevSibling == this);
nextSibling.prevSibling = newNode;
} else {
- Debug.Assert(parent.lastChild == this);
+ Debug.Assert (parent.lastChild == this);
parent.lastChild = newNode;
}
parent = null;
@@ -385,31 +383,31 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
- public AstNode ReplaceWith(Func replaceFunction)
+ public AstNode ReplaceWith (Func replaceFunction)
{
if (replaceFunction == null)
- throw new ArgumentNullException("replaceFunction");
+ throw new ArgumentNullException ("replaceFunction");
if (parent == null) {
- throw new InvalidOperationException(this.IsNull ? "Cannot replace the null nodes" : "Cannot replace the root node");
+ throw new InvalidOperationException (this.IsNull ? "Cannot replace the null nodes" : "Cannot replace the root node");
}
AstNode oldParent = parent;
AstNode oldSuccessor = nextSibling;
Role oldRole = role;
- Remove();
- AstNode replacement = replaceFunction(this);
+ Remove ();
+ AstNode replacement = replaceFunction (this);
if (oldSuccessor != null && oldSuccessor.parent != oldParent)
- throw new InvalidOperationException("replace function changed nextSibling of node being replaced?");
+ throw new InvalidOperationException ("replace function changed nextSibling of node being replaced?");
if (!(replacement == null || replacement.IsNull)) {
if (replacement.parent != null)
- throw new InvalidOperationException("replace function must return the root of a tree");
- if (!oldRole.IsValid(replacement)) {
- throw new InvalidOperationException (string.Format("The new node '{0}' is not valid in the role {1}", replacement.GetType().Name, oldRole.ToString()));
+ throw new InvalidOperationException ("replace function must return the root of a tree");
+ if (!oldRole.IsValid (replacement)) {
+ throw new InvalidOperationException (string.Format ("The new node '{0}' is not valid in the role {1}", replacement.GetType ().Name, oldRole.ToString ()));
}
if (oldSuccessor != null)
- oldParent.InsertChildBeforeUnsafe(oldSuccessor, replacement, oldRole);
+ oldParent.InsertChildBeforeUnsafe (oldSuccessor, replacement, oldRole);
else
- oldParent.AddChildUnsafe(replacement, oldRole);
+ oldParent.AddChildUnsafe (replacement, oldRole);
}
return replacement;
}
@@ -418,9 +416,9 @@ namespace ICSharpCode.NRefactory.CSharp
/// Clones the whole subtree starting at this AST node.
///
/// Annotations are copied over to the new nodes; and any annotations implementing ICloneable will be cloned.
- public AstNode Clone()
+ public AstNode Clone ()
{
- AstNode copy = (AstNode)MemberwiseClone();
+ AstNode copy = (AstNode)MemberwiseClone ();
// First, reset the shallow pointer copies
copy.parent = null;
copy.role = Roles.Root;
@@ -431,7 +429,7 @@ namespace ICSharpCode.NRefactory.CSharp
// Then perform a deep copy:
for (AstNode cur = firstChild; cur != null; cur = cur.nextSibling) {
- copy.AddChildUnsafe(cur.Clone(), cur.role);
+ copy.AddChildUnsafe (cur.Clone (), cur.role);
}
// Finally, clone the annotation, if necessary
@@ -442,175 +440,24 @@ namespace ICSharpCode.NRefactory.CSharp
return copy;
}
- #region Annotation support
- // 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, ICloneable
- {
- // There are two uses for this custom list type:
- // 1) it's private, and thus (unlike List) 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)
- throw new InvalidOperationException("Cannot add annotations to the null node");
- retry: // Retry until successful
- 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() 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() 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;
- }
-
- ///
- /// Gets all annotations stored on this AstNode.
- ///
- public IEnumerable 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();
- }
- }
- }
- #endregion
-
public abstract S AcceptVisitor (IAstVisitor visitor, T data);
#region Pattern Matching
- protected static bool MatchString(string name1, string name2)
+ protected static bool MatchString (string name1, string name2)
{
- return string.IsNullOrEmpty(name1) || name1 == name2;
+ return string.IsNullOrEmpty (name1) || name1 == name2;
}
- protected internal abstract bool DoMatch(AstNode other, PatternMatching.Match match);
+ protected internal abstract bool DoMatch (AstNode other, PatternMatching.Match match);
- bool PatternMatching.INode.DoMatch(PatternMatching.INode other, PatternMatching.Match match)
+ bool PatternMatching.INode.DoMatch (PatternMatching.INode other, PatternMatching.Match match)
{
AstNode o = other as AstNode;
// try matching if other is null, or if other is an AstNode
- return (other == null || o != null) && DoMatch(o, match);
+ return (other == null || o != null) && DoMatch (o, match);
}
- bool PatternMatching.INode.DoMatchCollection(Role role, PatternMatching.INode pos, PatternMatching.Match match, PatternMatching.BacktrackingInfo backtrackingInfo)
+ bool PatternMatching.INode.DoMatchCollection (Role role, PatternMatching.INode pos, PatternMatching.Match match, PatternMatching.BacktrackingInfo backtrackingInfo)
{
AstNode o = pos as AstNode;
return (pos == null || o != null) && DoMatch (o, match);
@@ -623,6 +470,7 @@ namespace ICSharpCode.NRefactory.CSharp
PatternMatching.INode PatternMatching.INode.FirstChild {
get { return firstChild; }
}
+
#endregion
public AstNode GetNextNode ()
@@ -655,8 +503,168 @@ namespace ICSharpCode.NRefactory.CSharp
return null;
}
+ public AstNode GetNodeAt (int line, int column)
+ {
+ return GetNodeAt (new AstLocation (line, column));
+ }
+
+ public AstNode GetNodeAt (AstLocation location, Predicate pred = null)
+ {
+ AstNode result = null;
+ AstNode node = this;
+ while (node.FirstChild != null) {
+ var child = node.FirstChild;
+ while (child != null) {
+ if (child.StartLocation <= location && location < child.EndLocation) {
+ if (pred == null || pred (child))
+ result = child;
+ node = child;
+ break;
+ }
+ child = child.NextSibling;
+ }
+ // found no better child node - therefore the parent is the right one.
+ if (child == null)
+ break;
+ }
+ return result;
+ }
+
+ public T GetNodeAt (int line, int column) where T : AstNode
+ {
+ return GetNodeAt (new AstLocation (line, column));
+ }
+
+ ///
+ /// Gets the node specified by T at location. This is useful for getting a specific node from the tree. For example searching
+ /// the current method declaration.
+ ///
+ public T GetNodeAt (AstLocation location) where T : AstNode
+ {
+ T result = null;
+ AstNode node = this;
+ while (node.FirstChild != null) {
+ var child = node.FirstChild;
+ while (child != null) {
+ if (child.StartLocation <= location && location < child.EndLocation) {
+ if (child is T)
+ result = (T)child;
+ node = child;
+ break;
+ }
+ child = child.NextSibling;
+ }
+ // found no better child node - therefore the parent is the right one.
+ if (child == null)
+ break;
+ }
+ return result;
+ }
+
+ public AstNode GetResolveableNodeAt (int line, int column)
+ {
+ return GetResolveableNodeAt (new AstLocation (line, column));
+ }
+
+ ///
+ /// Gets a node that can be resolved at location.
+ ///
+ public AstNode GetResolveableNodeAt (AstLocation location)
+ {
+ return GetNodeAt (location, delegate (AstNode n) {
+
+ if (n is TypeDeclaration) {
+ var decl = (TypeDeclaration)n;
+ return decl.NameToken.StartLocation <= location && location <= decl.NameToken.EndLocation;
+ }
+
+ if (n is DelegateDeclaration) {
+ var decl = (DelegateDeclaration)n;
+ return decl.NameToken.StartLocation <= location && location <= decl.NameToken.EndLocation;
+ }
+
+ if (n is MemberDeclaration) {
+ var decl = (MemberDeclaration)n;
+ return decl.NameToken.StartLocation <= location && location <= decl.NameToken.EndLocation;
+ }
+
+ if (n is ConstructorDeclaration) {
+ var decl = (ConstructorDeclaration)n;
+ return decl.IdentifierToken.StartLocation <= location && location <= decl.IdentifierToken.EndLocation;
+ }
+
+ if (n is DestructorDeclaration) {
+ var decl = (DestructorDeclaration)n;
+ return decl.IdentifierToken.StartLocation <= location && location <= decl.IdentifierToken.EndLocation;
+ }
+
+ if (n is VariableInitializer) {
+ var decl = (VariableInitializer)n;
+ return decl.NameToken.StartLocation <= location && location <= decl.NameToken.EndLocation;
+ }
+
+ if (n is ParameterDeclaration) {
+ var decl = (ParameterDeclaration)n;
+ return decl.NameToken.StartLocation <= location && location <= decl.NameToken.EndLocation;
+ }
+
+ if (n is MemberReferenceExpression) {
+ var decl = (MemberReferenceExpression)n;
+ return decl.MemberNameToken.StartLocation <= location && location <= decl.MemberNameToken.EndLocation;
+ }
+
+ return n is IdentifierExpression || n is AstType;
+ });
+ }
+
+ public IEnumerable GetNodesBetween (int startLine, int startColumn, int endLine, int endColumn)
+ {
+ return GetNodesBetween (new AstLocation (startLine, startColumn), new AstLocation (endLine, endColumn));
+ }
+
+ public IEnumerable GetNodesBetween (AstLocation start, AstLocation end)
+ {
+ AstNode node = this;
+ while (node != null) {
+ AstNode next;
+ if (start <= node.StartLocation && node.EndLocation <= end) {
+ // Remember next before yielding node.
+ // This allows iteration to continue when the caller removes/replaces the node.
+ next = node.NextSibling;
+ yield return node;
+ } else {
+ if (node.EndLocation <= start) {
+ next = node.NextSibling;
+ } else {
+ next = node.FirstChild;
+ }
+ }
+
+ if (next != null && next.StartLocation > end)
+ yield break;
+ node = next;
+ }
+ }
+
+ public bool Contains (int line, int column)
+ {
+ return Contains (new AstLocation (line, column));
+ }
+
+ public bool Contains (AstLocation location)
+ {
+ return this.StartLocation <= location && location < this.EndLocation;
+ }
+
+ public override void AddAnnotation (object annotation)
+ {
+ if (this.IsNull)
+ throw new InvalidOperationException ("Cannot add annotations to the null node");
+ base.AddAnnotation (annotation);
+ }
+
// the Root role must be available when creating the null nodes, so we can't put it in the Roles class
- static readonly Role RootRole = new Role("Root");
+ static readonly Role RootRole = new Role ("Root");
public static class Roles
{
@@ -666,41 +674,38 @@ namespace ICSharpCode.NRefactory.CSharp
public static readonly Role Root = RootRole;
// some pre defined constants for common roles
- public static readonly Role Identifier = new Role("Identifier", CSharp.Identifier.Null);
-
- public static readonly Role Body = new Role("Body", CSharp.BlockStatement.Null);
- public static readonly Role Parameter = new Role("Parameter");
- public static readonly Role Argument = new Role("Argument", CSharp.Expression.Null);
- public static readonly Role Type = new Role("Type", CSharp.AstType.Null);
- public static readonly Role Expression = new Role("Expression", CSharp.Expression.Null);
- public static readonly Role TargetExpression = new Role("Target", CSharp.Expression.Null);
- public readonly static Role Condition = new Role("Condition", CSharp.Expression.Null);
-
- public static readonly Role TypeParameter = new Role("TypeParameter");
- public static readonly Role TypeArgument = new Role("TypeArgument", CSharp.AstType.Null);
- public readonly static Role Constraint = new Role("Constraint");
- public static readonly Role Variable = new Role("Variable");
- public static readonly Role EmbeddedStatement = new Role("EmbeddedStatement", CSharp.Statement.Null);
-
- public static readonly Role Keyword = new Role("Keyword", CSharpTokenNode.Null);
- public static readonly Role InKeyword = new Role("InKeyword", CSharpTokenNode.Null);
+ public static readonly Role Identifier = new Role ("Identifier", CSharp.Identifier.Null);
+ public static readonly Role Body = new Role ("Body", CSharp.BlockStatement.Null);
+ public static readonly Role Parameter = new Role ("Parameter");
+ public static readonly Role Argument = new Role ("Argument", CSharp.Expression.Null);
+ public static readonly Role Type = new Role ("Type", CSharp.AstType.Null);
+ public static readonly Role Expression = new Role ("Expression", CSharp.Expression.Null);
+ public static readonly Role TargetExpression = new Role ("Target", CSharp.Expression.Null);
+ public readonly static Role Condition = new Role ("Condition", CSharp.Expression.Null);
+ public static readonly Role TypeParameter = new Role ("TypeParameter");
+ public static readonly Role TypeArgument = new Role ("TypeArgument", CSharp.AstType.Null);
+ public readonly static Role Constraint = new Role ("Constraint");
+ public static readonly Role Variable = new Role ("Variable");
+ public static readonly Role EmbeddedStatement = new Role ("EmbeddedStatement", CSharp.Statement.Null);
+ public static readonly Role Keyword = new Role ("Keyword", CSharpTokenNode.Null);
+ public static readonly Role InKeyword = new Role ("InKeyword", CSharpTokenNode.Null);
// some pre defined constants for most used punctuation
- public static readonly Role LPar = new Role("LPar", CSharpTokenNode.Null);
- public static readonly Role RPar = new Role("RPar", CSharpTokenNode.Null);
- public static readonly Role LBracket = new Role("LBracket", CSharpTokenNode.Null);
- public static readonly Role RBracket = new Role("RBracket", CSharpTokenNode.Null);
- public static readonly Role LBrace = new Role("LBrace", CSharpTokenNode.Null);
- public static readonly Role RBrace = new Role("RBrace", CSharpTokenNode.Null);
- public static readonly Role LChevron = new Role("LChevron", CSharpTokenNode.Null);
- public static readonly Role RChevron = new Role("RChevron", CSharpTokenNode.Null);
- public static readonly Role Comma = new Role("Comma", CSharpTokenNode.Null);
- public static readonly Role Dot = new Role("Dot", CSharpTokenNode.Null);
- public static readonly Role Semicolon = new Role("Semicolon", CSharpTokenNode.Null);
- public static readonly Role Assign = new Role("Assign", CSharpTokenNode.Null);
- public static readonly Role Colon = new Role("Colon", CSharpTokenNode.Null);
-
- public static readonly Role Comment = new Role("Comment");
+ public static readonly Role LPar = new Role ("LPar", CSharpTokenNode.Null);
+ public static readonly Role RPar = new Role ("RPar", CSharpTokenNode.Null);
+ public static readonly Role LBracket = new Role ("LBracket", CSharpTokenNode.Null);
+ public static readonly Role RBracket = new Role ("RBracket", CSharpTokenNode.Null);
+ public static readonly Role LBrace = new Role ("LBrace", CSharpTokenNode.Null);
+ public static readonly Role RBrace = new Role ("RBrace", CSharpTokenNode.Null);
+ public static readonly Role LChevron = new Role ("LChevron", CSharpTokenNode.Null);
+ public static readonly Role RChevron = new Role ("RChevron", CSharpTokenNode.Null);
+ public static readonly Role Comma = new Role ("Comma", CSharpTokenNode.Null);
+ public static readonly Role Dot = new Role ("Dot", CSharpTokenNode.Null);
+ public static readonly Role Semicolon = new Role ("Semicolon", CSharpTokenNode.Null);
+ public static readonly Role Assign = new Role ("Assign", CSharpTokenNode.Null);
+ public static readonly Role Colon = new Role ("Colon", CSharpTokenNode.Null);
+ public static readonly Role Comment = new Role ("Comment");
+ public static readonly Role Error = new Role ("Error");
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs
index a776f259f..b125413d0 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs
@@ -1,4 +1,4 @@
-//
+//
// TokenNode.cs
//
// Author:
@@ -27,7 +27,7 @@ using System;
namespace ICSharpCode.NRefactory.CSharp
{
- public class CSharpTokenNode : AstNode
+ public class CSharpTokenNode : AstNode, IRelocatable
{
public static new readonly CSharpTokenNode Null = new NullCSharpTokenNode ();
class NullCSharpTokenNode : CSharpTokenNode
@@ -80,6 +80,13 @@ namespace ICSharpCode.NRefactory.CSharp
this.tokenLength = tokenLength;
}
+ #region IRelocationable implementation
+ void IRelocatable.SetStartLocation (AstLocation startLocation)
+ {
+ this.startLocation = startLocation;
+ }
+ #endregion
+
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
return visitor.VisitCSharpTokenNode (this, data);
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpUtil.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpUtil.cs
new file mode 100644
index 000000000..46f528d46
--- /dev/null
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpUtil.cs
@@ -0,0 +1,95 @@
+//
+// CSharpUtil.cs
+//
+// Author:
+// Mike Krüger
+//
+// Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using ICSharpCode.NRefactory.CSharp;
+
+namespace ICSharpCode.NRefactory.CSharp
+{
+ public static class CSharpUtil
+ {
+ public static Expression InvertCondition (Expression condition)
+ {
+ return InvertConditionInternal (condition.Clone ());
+ }
+
+ static Expression InvertConditionInternal (Expression condition)
+ {
+ if (condition is ParenthesizedExpression) {
+ ((ParenthesizedExpression)condition).Expression = InvertCondition (((ParenthesizedExpression)condition).Expression);
+ return condition;
+ }
+
+ if (condition is UnaryOperatorExpression) {
+ var uOp = (UnaryOperatorExpression)condition;
+ if (uOp.Operator == UnaryOperatorType.Not)
+ return uOp.Expression;
+ return new UnaryOperatorExpression (UnaryOperatorType.Not, uOp);
+ }
+
+ if (condition is BinaryOperatorExpression) {
+ var bOp = (BinaryOperatorExpression)condition;
+ switch (bOp.Operator) {
+ case BinaryOperatorType.GreaterThan:
+ bOp.Operator = BinaryOperatorType.LessThanOrEqual;
+ return bOp;
+ case BinaryOperatorType.GreaterThanOrEqual:
+ bOp.Operator = BinaryOperatorType.LessThan;
+ return bOp;
+ case BinaryOperatorType.Equality:
+ bOp.Operator = BinaryOperatorType.InEquality;
+ return bOp;
+ case BinaryOperatorType.InEquality:
+ bOp.Operator = BinaryOperatorType.Equality;
+ return bOp;
+ case BinaryOperatorType.LessThan:
+ bOp.Operator = BinaryOperatorType.GreaterThanOrEqual;
+ return bOp;
+ case BinaryOperatorType.LessThanOrEqual:
+ bOp.Operator = BinaryOperatorType.GreaterThan;
+ return bOp;
+ default:
+ return new UnaryOperatorExpression (UnaryOperatorType.Not, new ParenthesizedExpression (condition));
+ }
+ }
+
+ if (condition is ConditionalExpression) {
+ var cEx = condition as ConditionalExpression;
+ cEx.Condition = InvertCondition (cEx.Condition);
+ return cEx;
+ }
+ if (condition is PrimitiveExpression) {
+ var pex = condition as PrimitiveExpression;
+ if (pex.Value is bool) {
+ pex.Value = !((bool)pex.Value);
+ return pex;
+ }
+ }
+
+ return new UnaryOperatorExpression (UnaryOperatorType.Not, condition);
+ }
+ }
+}
+
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs
index 6053d6848..889e8d048 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs
@@ -25,9 +25,7 @@
// THE SOFTWARE.
using System;
using System.Collections.Generic;
-using System.Linq;
-
-using ICSharpCode.NRefactory.Utils;
+using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp
{
@@ -41,67 +39,48 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
- public CompilationUnit ()
- {
+ List errors = new List ();
+
+ public List Errors {
+ get { return errors; }
}
- protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
- {
- CompilationUnit o = other as CompilationUnit;
- return o != null && GetChildrenByRole(MemberRole).DoMatch(o.GetChildrenByRole(MemberRole), match);
+ ///
+ /// Gets the expression that was on top of the parse stack.
+ /// This is the only way to get an expression that isn't part of a statment.
+ /// (eg. when an error follows an expression).
+ ///
+ /// This is used for code completion to 'get the expression before a token - like ., <, ('.
+ ///
+ public AstNode TopExpression {
+ get;
+ internal set;
}
- public AstNode GetNodeAt (int line, int column)
+ public CompilationUnit ()
{
- return GetNodeAt (new AstLocation (line, column));
}
- public AstNode GetNodeAt (AstLocation location)
+ public IEnumerable GetTypes (bool includeInnerTypes = false)
{
- AstNode node = this;
- while (node.FirstChild != null) {
- var child = node.FirstChild;
- while (child != null) {
- if (child.StartLocation <= location && location < child.EndLocation) {
- node = child;
- break;
- }
- child = child.NextSibling;
+ Stack nodeStack = new Stack ();
+ nodeStack.Push (this);
+ while (nodeStack.Count > 0) {
+ var curNode = nodeStack.Pop ();
+ if (curNode is TypeDeclaration)
+ yield return (TypeDeclaration)curNode;
+ foreach (var child in curNode.Children) {
+ if (!(child is Statement || child is Expression) &&
+ (child.Role != TypeDeclaration.MemberRole || (child is TypeDeclaration && includeInnerTypes)))
+ nodeStack.Push (child);
}
- // found no better child node - therefore the parent is the right one.
- if (child == null)
- break;
}
- return node;
}
- public IEnumerable GetNodesBetween (int startLine, int startColumn, int endLine, int endColumn)
- {
- return GetNodesBetween (new AstLocation (startLine, startColumn), new AstLocation (endLine, endColumn));
- }
-
- public IEnumerable GetNodesBetween (AstLocation start, AstLocation end)
+ protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
- AstNode node = this;
- while (node != null) {
- AstNode next;
- if (start <= node.StartLocation && node.EndLocation <= end) {
- // Remember next before yielding node.
- // This allows iteration to continue when the caller removes/replaces the node.
- next = node.NextSibling;
- yield return node;
- } else {
- if (node.EndLocation < start) {
- next = node.NextSibling;
- } else {
- next = node.FirstChild;
- }
- }
-
- if (next != null && next.StartLocation > end)
- yield break;
- node = next;
- }
+ CompilationUnit o = other as CompilationUnit;
+ return o != null && GetChildrenByRole(MemberRole).DoMatch(o.GetChildrenByRole(MemberRole), match);
}
public override S AcceptVisitor (IAstVisitor visitor, T data)
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ErrorNode.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ErrorNode.cs
new file mode 100644
index 000000000..af2fed750
--- /dev/null
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ErrorNode.cs
@@ -0,0 +1,79 @@
+//
+// ErrorNode.cs
+//
+// Author:
+// Mike Krüger
+//
+// Copyright (c) 2011 Xamarin (http://www.xamarin.com);
+//
+// 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;
+
+namespace ICSharpCode.NRefactory.CSharp
+{
+ ///
+ /// Represents a parsing error in the ast. At the moment it only represents missing closing bracket.
+ /// This closing bracket is replaced by a node at the highest possible position.
+ /// (To make GetAstNodeAt (line, col) working).
+ ///
+ public class ErrorNode : AstNode
+ {
+ static AstLocation maxLoc = new AstLocation (int.MaxValue, int.MaxValue);
+
+ public override NodeType NodeType {
+ get {
+ return NodeType.Unknown;
+ }
+ }
+
+ public override AstLocation StartLocation {
+ get {
+ return maxLoc;
+ }
+ }
+
+ public override AstLocation EndLocation {
+ get {
+ return maxLoc;
+ }
+ }
+
+ public ErrorNode ()
+ {
+ }
+
+ public override S AcceptVisitor (IAstVisitor visitor, T data)
+ {
+ // nothing
+ return default (S);
+ }
+
+ protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
+ {
+ var o = other as ErrorNode;
+ return o != null;
+ }
+
+ public override string ToString ()
+ {
+ return "[ErrorNode]";
+ }
+ }
+}
+
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/EmptyExpression.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/EmptyExpression.cs
index b057acbdf..3c23f54f8 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/EmptyExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/EmptyExpression.cs
@@ -30,7 +30,7 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// Type<[EMPTY]>
///
- public class EmptyExpression : Expression
+ public class EmptyExpression : Expression, IRelocatable
{
AstLocation location;
@@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp
return location;
}
}
-
+
public override AstLocation EndLocation {
get {
return location;
@@ -54,7 +54,14 @@ namespace ICSharpCode.NRefactory.CSharp
{
this.location = location;
}
-
+
+ #region IRelocationable implementation
+ void IRelocatable.SetStartLocation (AstLocation startLocation)
+ {
+ this.location = startLocation;
+ }
+ #endregion
+
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
return visitor.VisitEmptyExpression (this, data);
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IdentifierExpression.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IdentifierExpression.cs
index bbc6898c1..e982f1320 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IdentifierExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IdentifierExpression.cs
@@ -40,7 +40,7 @@ namespace ICSharpCode.NRefactory.CSharp
public IdentifierExpression(string identifier, AstLocation location)
{
- SetChildByRole(Roles.Identifier, new Identifier(identifier, location));
+ SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (identifier, location));
}
// public Identifier IdentifierToken {
@@ -52,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
set {
- SetChildByRole(Roles.Identifier, new Identifier(value, AstLocation.Empty));
+ SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, AstLocation.Empty));
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/MemberReferenceExpression.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/MemberReferenceExpression.cs
index 60d7a17ed..4a7decbe0 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/MemberReferenceExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/MemberReferenceExpression.cs
@@ -1,4 +1,4 @@
-//
+//
// MemberReferenceExpression.cs
//
// Author:
@@ -43,7 +43,16 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
set {
- SetChildByRole(Roles.Identifier, new Identifier(value, AstLocation.Empty));
+ SetChildByRole (Roles.Identifier, Identifier.Create (value, AstLocation.Empty));
+ }
+ }
+
+ public Identifier MemberNameToken {
+ get {
+ return GetChildByRole (Roles.Identifier);
+ }
+ set {
+ SetChildByRole (Roles.Identifier, value);
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/NamedArgumentExpression.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/NamedArgumentExpression.cs
index df51dcf93..73bcb2e27 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/NamedArgumentExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/NamedArgumentExpression.cs
@@ -15,7 +15,16 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
set {
- SetChildByRole(Roles.Identifier, new Identifier(value, AstLocation.Empty));
+ SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, AstLocation.Empty));
+ }
+ }
+
+ public Identifier IdentifierToken {
+ get {
+ return GetChildByRole (Roles.Identifier);
+ }
+ set {
+ SetChildByRole(Roles.Identifier, value);
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PointerReferenceExpression.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PointerReferenceExpression.cs
index 3ac10d387..21e805b67 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PointerReferenceExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PointerReferenceExpression.cs
@@ -1,4 +1,4 @@
-//
+//
// PointerReferenceExpression.cs
//
// Author:
@@ -45,7 +45,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
set {
- SetChildByRole(Roles.Identifier, new Identifier(value, AstLocation.Empty));
+ SetChildByRole(Roles.Identifier, Identifier.Create (value, AstLocation.Empty));
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs
index cc4fbe1c0..22e16e29b 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs
@@ -29,7 +29,7 @@ namespace ICSharpCode.NRefactory.CSharp
///
/// Represents a literal value.
///
- public class PrimitiveExpression : Expression
+ public class PrimitiveExpression : Expression, IRelocatable
{
public static readonly object AnyValue = new object();
@@ -40,16 +40,22 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
- int length;
+ string literalValue;
public override AstLocation EndLocation {
get {
- return new AstLocation (StartLocation.Line, StartLocation.Column + length);
+ return new AstLocation (StartLocation.Line, StartLocation.Column + literalValue.Length);
}
}
public object Value {
get;
- private set;
+ set;
+ }
+
+ public string LiteralValue {
+ get {
+ return literalValue;
+ }
}
public PrimitiveExpression (object value)
@@ -57,12 +63,25 @@ namespace ICSharpCode.NRefactory.CSharp
this.Value = value;
}
- public PrimitiveExpression (object value, AstLocation startLocation, int length)
+ public PrimitiveExpression (object value, string literalValue)
+ {
+ this.Value = value;
+ this.literalValue = literalValue ?? "";
+ }
+
+ public PrimitiveExpression (object value, AstLocation startLocation, string literalValue)
{
this.Value = value;
this.startLocation = startLocation;
- this.length = length;
+ this.literalValue = literalValue ?? "";
+ }
+
+ #region IRelocationable implementation
+ void IRelocatable.SetStartLocation (AstLocation startLocation)
+ {
+ this.startLocation = startLocation;
}
+ #endregion
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs
index 9841a7468..5cf887703 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs
@@ -89,7 +89,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
set {
- SetChildByRole(Roles.Identifier, new Identifier(value, AstLocation.Empty));
+ SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, AstLocation.Empty));
}
}
@@ -120,7 +120,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
set {
- SetChildByRole(Roles.Identifier, new Identifier(value, AstLocation.Empty));
+ SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, AstLocation.Empty));
}
}
@@ -153,7 +153,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole(Roles.Identifier).Name;
}
set {
- SetChildByRole(Roles.Identifier, new Identifier(value, AstLocation.Empty));
+ SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, AstLocation.Empty));
}
}
@@ -237,7 +237,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole(JoinIdentifierRole).Name;
}
set {
- SetChildByRole(JoinIdentifierRole, new Identifier(value, AstLocation.Empty));
+ SetChildByRole(JoinIdentifierRole, Identifier.Create (value, AstLocation.Empty));
}
}
@@ -277,7 +277,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (IntoIdentifierRole).Name;
}
set {
- SetChildByRole(IntoIdentifierRole, new Identifier(value, AstLocation.Empty));
+ SetChildByRole(IntoIdentifierRole, Identifier.Create (value, AstLocation.Empty));
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Attribute.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Attribute.cs
index 877771736..95235527f 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Attribute.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Attribute.cs
@@ -47,16 +47,31 @@ namespace ICSharpCode.NRefactory.CSharp
public AstNodeCollection Arguments {
get { return base.GetChildrenByRole (Roles.Argument); }
}
-
+
+ // HasArgumentList == false: [Empty]
+ public bool HasArgumentList {
+ get;
+ set;
+ }
+
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
return visitor.VisitAttribute (this, data);
}
- protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
+ protected internal override bool DoMatch (AstNode other, PatternMatching.Match match)
{
Attribute o = other as Attribute;
- return o != null && this.Type.DoMatch(o.Type, match) && this.Arguments.DoMatch(o.Arguments, match);
+ return o != null && this.Type.DoMatch (o.Type, match) && this.Arguments.DoMatch (o.Arguments, match);
+ }
+
+ public override string ToString ()
+ {
+ if (IsNull)
+ return "Null";
+ var w = new System.IO.StringWriter ();
+ AcceptVisitor (new OutputVisitor (w, new CSharpFormattingOptions ()), null);
+ return w.ToString ();
}
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Comment.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Comment.cs
index 4f757b264..61b424f49 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Comment.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Comment.cs
@@ -1,4 +1,4 @@
-//
+//
// Comment.cs
//
// Author:
@@ -32,7 +32,7 @@ namespace ICSharpCode.NRefactory.CSharp
Documentation
}
- public class Comment : AstNode
+ public class Comment : AstNode, IRelocatable
{
public override NodeType NodeType {
get {
@@ -81,6 +81,15 @@ namespace ICSharpCode.NRefactory.CSharp
this.startLocation = startLocation;
this.endLocation = endLocation;
}
+
+ #region IRelocationable implementation
+ void IRelocatable.SetStartLocation (AstLocation startLocation)
+ {
+ int lineDelta = startLocation.Line - this.startLocation.Line;
+ endLocation = new AstLocation (endLocation.Line + lineDelta, lineDelta != 0 ? endLocation.Column : endLocation.Column + startLocation.Column - this.startLocation.Column);
+ this.startLocation = startLocation;
+ }
+ #endregion
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs
index 8bac245c7..48c4e0ecb 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs
@@ -1,4 +1,4 @@
-//
+//
// Constraint.cs
//
// Author:
@@ -50,7 +50,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
set {
- SetChildByRole(Roles.Identifier, new Identifier(value, AstLocation.Empty));
+ SetChildByRole(Roles.Identifier, Identifier.Create (value, AstLocation.Empty));
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs
index e014a4b3f..c33c0bf24 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs
@@ -1,4 +1,4 @@
-//
+//
// DelegateDeclaration.cs
//
// Author:
@@ -50,7 +50,16 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
set {
- SetChildByRole (Roles.Identifier, new Identifier(value, AstLocation.Empty));
+ SetChildByRole (Roles.Identifier, Identifier.Create (value, AstLocation.Empty));
+ }
+ }
+
+ public Identifier NameToken {
+ get {
+ return GetChildByRole (Roles.Identifier);
+ }
+ set {
+ SetChildByRole (Roles.Identifier, value);
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/ExternAliasDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/ExternAliasDeclaration.cs
index bdd8c0f04..7d9a33df4 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/ExternAliasDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/ExternAliasDeclaration.cs
@@ -52,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
set {
- SetChildByRole (Roles.Identifier, new Identifier (value, AstLocation.Empty));
+ SetChildByRole (Roles.Identifier, Identifier.Create (value, AstLocation.Empty));
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/NamespaceDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/NamespaceDeclaration.cs
index 07dee45b7..c580f3790 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/NamespaceDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/NamespaceDeclaration.cs
@@ -1,4 +1,4 @@
-//
+//
// NamespaceDeclaration.cs
//
// Author:
@@ -54,7 +54,7 @@ namespace ICSharpCode.NRefactory.CSharp
return builder.ToString ();
}
set {
- GetChildrenByRole(Roles.Identifier).ReplaceWith(value.Split('.').Select(ident => new Identifier(ident, AstLocation.Empty)));
+ GetChildrenByRole(Roles.Identifier).ReplaceWith(value.Split('.').Select(ident => Identifier.Create (ident, AstLocation.Empty)));
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs
index df7ac2138..945c936cd 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs
@@ -1,4 +1,4 @@
-//
+//
// TypeDeclaration.cs
//
// Author:
@@ -55,7 +55,16 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
set {
- SetChildByRole (Roles.Identifier, new Identifier(value, AstLocation.Empty));
+ SetChildByRole (Roles.Identifier, Identifier.Create (value, AstLocation.Empty));
+ }
+ }
+
+ public Identifier NameToken {
+ get {
+ return GetChildByRole (Roles.Identifier);
+ }
+ set {
+ SetChildByRole (Roles.Identifier, value);
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs
index 84c9b2f50..ee2d58eb3 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs
@@ -35,7 +35,16 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
set {
- SetChildByRole(Roles.Identifier, new Identifier(value, AstLocation.Empty));
+ SetChildByRole(Roles.Identifier, Identifier.Create (value, AstLocation.Empty));
+ }
+ }
+
+ public Identifier NameToken {
+ get {
+ return GetChildByRole (Roles.Identifier);
+ }
+ set {
+ SetChildByRole (Roles.Identifier, value);
}
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/UsingAliasDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/UsingAliasDeclaration.cs
index a157ce62f..7fd3dfa09 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/UsingAliasDeclaration.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/UsingAliasDeclaration.cs
@@ -1,4 +1,4 @@
-//
+//
// UsingAliasDeclaration.cs
//
// Author:
@@ -49,7 +49,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (AliasRole).Name;
}
set {
- SetChildByRole(AliasRole, new Identifier(value, AstLocation.Empty));
+ SetChildByRole(AliasRole, Identifier.Create (value, AstLocation.Empty));
}
}
@@ -72,13 +72,13 @@ namespace ICSharpCode.NRefactory.CSharp
public UsingAliasDeclaration (string alias, string nameSpace)
{
- AddChild (new Identifier (alias, AstLocation.Empty), AliasRole);
+ AddChild (Identifier.Create (alias, AstLocation.Empty), AliasRole);
AddChild (new SimpleType (nameSpace), ImportRole);
}
public UsingAliasDeclaration (string alias, AstType import)
{
- AddChild (new Identifier (alias, AstLocation.Empty), AliasRole);
+ AddChild (Identifier.Create (alias, AstLocation.Empty), AliasRole);
AddChild (import, ImportRole);
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Formatter/Change.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/IRelocatable.cs
similarity index 56%
rename from NRefactory/ICSharpCode.NRefactory/CSharp/Formatter/Change.cs
rename to NRefactory/ICSharpCode.NRefactory/CSharp/Ast/IRelocatable.cs
index f2a241c1d..48205191f 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Formatter/Change.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/IRelocatable.cs
@@ -1,5 +1,5 @@
//
-// Change.cs
+// IRelocationable.cs
//
// Author:
// Mike Krüger
@@ -25,48 +25,11 @@
// THE SOFTWARE.
using System;
-namespace ICSharpCode.NRefactory
+namespace ICSharpCode.NRefactory.CSharp
{
- public class Change
+ public interface IRelocatable
{
- public int Offset {
- get;
- set;
- }
-
- int removedChars;
- public int RemovedChars {
- get {
- return removedChars;
- }
- set {
- if (value < 0)
- throw new ArgumentOutOfRangeException ("RemovedChars", "needs to be >= 0");
- removedChars = value;
- }
- }
-
- public string InsertedText {
- get;
- set;
- }
-
- public Change (int offset, int removedChars, string insertedText)
- {
- if (removedChars < 0)
- throw new ArgumentOutOfRangeException ("removedChars", "removedChars needs to be >= 0");
- if (offset < 0)
- throw new ArgumentOutOfRangeException ("offset", "offset needs to be >= 0");
- this.removedChars = removedChars;
- this.Offset = offset;
- this.InsertedText = insertedText;
- }
-
- public override string ToString ()
- {
- return string.Format ("[Change: Offset={0}, RemovedChars={1}, InsertedText={2}]", Offset, RemovedChars, InsertedText);
- }
+ void SetStartLocation (AstLocation startLocation);
}
-
}
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs
index 6db26e523..12bd64475 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs
@@ -1,4 +1,4 @@
-//
+//
// Identifier.cs
//
// Author:
@@ -28,9 +28,9 @@ using System;
namespace ICSharpCode.NRefactory.CSharp
{
- public class Identifier : AstNode
+ public class Identifier : AstNode, IRelocatable
{
- public static readonly new Identifier Null = new NullIdentifier ();
+ public static readonly Identifier Null = new NullIdentifier ();
class NullIdentifier : Identifier
{
public override bool IsNull {
@@ -66,40 +66,69 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
- ///
- /// True if this is a verbatim identifier (starting with '@')
- ///
- public bool IsVerbatim {
- get;
- set;
- }
-
AstLocation startLocation;
public override AstLocation StartLocation {
get {
return startLocation;
}
+
+ }
+
+ public virtual bool IsVerbatim {
+ get {
+ return false;
+ }
+ }
+
+ #region IRelocationable implementation
+ void IRelocatable.SetStartLocation (AstLocation startLocation)
+ {
+ this.startLocation = startLocation;
}
+ #endregion
public override AstLocation EndLocation {
get {
- return new AstLocation (StartLocation.Line, StartLocation.Column + (Name ?? "").Length + (IsVerbatim ? 1 : 0));
+ return new AstLocation (StartLocation.Line, StartLocation.Column + (Name ?? "").Length);
}
}
- private Identifier ()
+ Identifier ()
{
this.name = string.Empty;
}
- public Identifier (string name, AstLocation location)
+ protected Identifier (string name, AstLocation location)
{
if (name == null)
throw new ArgumentNullException("name");
- IsVerbatim = name.Length > 0 && name[0] == '@';
- this.Name = IsVerbatim ? name.Substring (1) : name;
+ this.Name = name;
this.startLocation = location;
}
+
+ public static Identifier Create (string name)
+ {
+ return Create (name, AstLocation.Empty);
+ }
+
+ public static Identifier Create (string name, AstLocation location)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+ if (name.Length > 0 && name[0] == '@')
+ return new VerbatimIdentifier(name.Substring (1), location);
+ return new Identifier (name, location);
+ }
+
+ public static Identifier Create (string name, AstLocation location, bool isVerbatim)
+ {
+ if (name == null)
+ throw new ArgumentNullException("name");
+
+ if (isVerbatim)
+ return new VerbatimIdentifier(name, location);
+ return new Identifier (name, location);
+ }
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
@@ -111,5 +140,24 @@ namespace ICSharpCode.NRefactory.CSharp
Identifier o = other as Identifier;
return o != null && !o.IsNull && MatchString(this.Name, o.Name);
}
+
+ class VerbatimIdentifier : Identifier
+ {
+ public override AstLocation EndLocation {
+ get {
+ return new AstLocation (StartLocation.Line, StartLocation.Column + (Name ?? "").Length + 1); // @"..."
+ }
+ }
+
+ public override bool IsVerbatim {
+ get {
+ return true;
+ }
+ }
+
+ public VerbatimIdentifier(string name, AstLocation location) : base (name, location)
+ {
+ }
+ }
}
-}
+}
\ No newline at end of file
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs
index b91048a5c..771623eac 100644
--- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs
@@ -1,4 +1,4 @@
-//
+//
// FullTypeName.cs
//
// Author:
@@ -47,7 +47,16 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
set {
- SetChildByRole (Roles.Identifier, new Identifier(value, AstLocation.Empty));
+ SetChildByRole (Roles.Identifier, Identifier.Create (value, AstLocation.Empty));
+ }
+ }
+
+ public Identifier MemberNameToken {
+ get {
+ return GetChildByRole (Roles.Identifier);
+ }
+ set {
+ SetChildByRole (Roles.Identifier, value);
}
}
@@ -55,6 +64,29 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildrenByRole (Roles.TypeArgument); }
}
+ public MemberType ()
+ {
+ }
+
+ public MemberType (AstType target, string memberName)
+ {
+ this.Target = target;
+ this.MemberName = memberName;
+ }
+
+ public MemberType (AstType target, string memberName, IEnumerable typeArguments)
+ {
+ this.Target = target;
+ this.MemberName = memberName;
+ foreach (var arg in typeArguments) {
+ AddChild (arg, Roles.TypeArgument);
+ }
+ }
+
+ public MemberType (AstType target, string memberName, params AstType[] typeArguments) : this (target, memberName, (IEnumerable)typeArguments)
+ {
+ }
+
public override S AcceptVisitor (IAstVisitor visitor, T data)
{
return visitor.VisitMemberType (this, data);
diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ObservableAstVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ObservableAstVisitor.cs
new file mode 100644
index 000000000..253f6ef3c
--- /dev/null
+++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/ObservableAstVisitor.cs
@@ -0,0 +1,1141 @@
+//
+// ObservableAstVisitor.cs
+//
+// Author:
+// Mike Krüger
+//
+// Copyright (c) 2011 Novell, Inc (http://www.novell.com)
+//
+// 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;
+
+namespace ICSharpCode.NRefactory.CSharp
+{
+ public class ObservableAstVisitor: IAstVisitor
+ {
+ S VisitChildren (AstNode node, T data)
+ {
+ AstNode next;
+ for (var child = node.FirstChild; child != null; child = next) {
+ // Store next to allow the loop to continue
+ // if the visitor removes/replaces child.
+ next = child.NextSibling;
+ child.AcceptVisitor (this, data);
+ }
+ return default (S);
+ }
+
+ public event Action CompilationUnitVisited;
+
+ S IAstVisitor.VisitCompilationUnit (CompilationUnit unit, T data)
+ {
+ var handler = CompilationUnitVisited;
+ if (handler != null)
+ handler (unit, data);
+ return VisitChildren (unit, data);
+ }
+
+ public event Action CommentVisited;
+
+ S IAstVisitor.VisitComment (Comment comment, T data)
+ {
+ var handler = CommentVisited;
+ if (handler != null)
+ handler (comment, data);
+ return VisitChildren (comment, data);
+ }
+
+ public event Action IdentifierVisited;
+
+ S IAstVisitor.VisitIdentifier (Identifier identifier, T data)
+ {
+ var handler = IdentifierVisited;
+ if (handler != null)
+ handler (identifier, data);
+ return VisitChildren (identifier, data);
+ }
+
+ public event Action CSharpTokenNodeVisited;
+
+ S IAstVisitor.VisitCSharpTokenNode (CSharpTokenNode token, T data)
+ {
+ var handler = CSharpTokenNodeVisited;
+ if (handler != null)
+ handler (token, data);
+ return VisitChildren (token, data);
+ }
+
+ public event Action PrimitiveTypeVisited;
+
+ S IAstVisitor.VisitPrimitiveType (PrimitiveType primitiveType, T data)
+ {
+ var handler = PrimitiveTypeVisited;
+ if (handler != null)
+ handler (primitiveType, data);
+ return VisitChildren (primitiveType, data);
+ }
+
+ public event Action ComposedTypeVisited;
+
+ S IAstVisitor.VisitComposedType (ComposedType composedType, T data)
+ {
+ var handler = ComposedTypeVisited;
+ if (handler != null)
+ handler (composedType, data);
+ return VisitChildren (composedType, data);
+ }
+
+ public event Action SimpleTypeVisited;
+
+ S IAstVisitor.VisitSimpleType (SimpleType simpleType, T data)
+ {
+ var handler = SimpleTypeVisited;
+ if (handler != null)
+ handler (simpleType, data);
+ return VisitChildren (simpleType, data);
+ }
+
+ public event Action MemberTypeVisited;
+
+ S IAstVisitor.VisitMemberType (MemberType memberType, T data)
+ {
+ var handler = MemberTypeVisited;
+ if (handler != null)
+ handler (memberType, data);
+ return VisitChildren (memberType, data);
+ }
+
+ public event Action AttributeVisited;
+
+ S IAstVisitor.VisitAttribute (Attribute attribute, T data)
+ {
+ var handler = AttributeVisited;
+ if (handler != null)
+ handler (attribute, data);
+ return VisitChildren (attribute, data);
+ }
+
+ public event Action AttributeSectionVisited;
+
+ S IAstVisitor.VisitAttributeSection (AttributeSection attributeSection, T data)
+ {
+ var handler = AttributeSectionVisited;
+ if (handler != null)
+ handler (attributeSection, data);
+ return VisitChildren (attributeSection, data);
+ }
+
+ public event Action DelegateDeclarationVisited;
+
+ S IAstVisitor.VisitDelegateDeclaration (DelegateDeclaration delegateDeclaration, T data)
+ {
+ var handler = DelegateDeclarationVisited;
+ if (handler != null)
+ handler (delegateDeclaration, data);
+ return VisitChildren (delegateDeclaration, data);
+ }
+
+ public event Action NamespaceDeclarationVisited;
+
+ S IAstVisitor.VisitNamespaceDeclaration (NamespaceDeclaration namespaceDeclaration, T data)
+ {
+ var handler = NamespaceDeclarationVisited;
+ if (handler != null)
+ handler (namespaceDeclaration, data);
+ return VisitChildren (namespaceDeclaration, data);
+ }
+
+ public event Action TypeDeclarationVisited;
+
+ S IAstVisitor.VisitTypeDeclaration (TypeDeclaration typeDeclaration, T data)
+ {
+ var handler = TypeDeclarationVisited;
+ if (handler != null)
+ handler (typeDeclaration, data);
+ return VisitChildren (typeDeclaration, data);
+ }
+
+ public event Action TypeParameterDeclarationVisited;
+
+ S IAstVisitor.VisitTypeParameterDeclaration (TypeParameterDeclaration typeParameterDeclaration, T data)
+ {
+ var handler = TypeParameterDeclarationVisited;
+ if (handler != null)
+ handler (typeParameterDeclaration, data);
+ return VisitChildren (typeParameterDeclaration, data);
+ }
+
+ public event Action EnumMemberDeclarationVisited;
+
+ S IAstVisitor.VisitEnumMemberDeclaration (EnumMemberDeclaration enumMemberDeclaration, T data)
+ {
+ var handler = EnumMemberDeclarationVisited;
+ if (handler != null)
+ handler (enumMemberDeclaration, data);
+ return VisitChildren (enumMemberDeclaration, data);
+ }
+
+ public event Action UsingDeclarationVisited;
+
+ S IAstVisitor.VisitUsingDeclaration (UsingDeclaration usingDeclaration, T data)
+ {
+ var handler = UsingDeclarationVisited;
+ if (handler != null)
+ handler (usingDeclaration, data);
+ return VisitChildren (usingDeclaration, data);
+ }
+
+ public event Action UsingAliasDeclarationVisited;
+
+ S IAstVisitor.VisitUsingAliasDeclaration (UsingAliasDeclaration usingDeclaration, T data)
+ {
+ var handler = UsingAliasDeclarationVisited;
+ if (handler != null)
+ handler (usingDeclaration, data);
+ return VisitChildren (usingDeclaration, data);
+ }
+
+ public event Action ExternAliasDeclarationVisited;
+
+ S IAstVisitor.VisitExternAliasDeclaration (ExternAliasDeclaration externAliasDeclaration, T data)
+ {
+ var handler = ExternAliasDeclarationVisited;
+ if (handler != null)
+ handler (externAliasDeclaration, data);
+ return VisitChildren (externAliasDeclaration, data);
+ }
+
+ public event Action ConstructorDeclarationVisited;
+
+ S IAstVisitor.VisitConstructorDeclaration (ConstructorDeclaration constructorDeclaration, T data)
+ {
+ var handler = ConstructorDeclarationVisited;
+ if (handler != null)
+ handler (constructorDeclaration, data);
+ return VisitChildren (constructorDeclaration, data);
+ }
+
+ public event Action ConstructorInitializerVisited;
+
+ S IAstVisitor.VisitConstructorInitializer (ConstructorInitializer constructorInitializer, T data)
+ {
+ var handler = ConstructorInitializerVisited;
+ if (handler != null)
+ handler (constructorInitializer, data);
+ return VisitChildren (constructorInitializer, data);
+ }
+
+ public event Action