diff --git a/.gitignore b/.gitignore index b96f1bdfd..a81b8dbf5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ bin/ obj/ /ICSharpCode.Decompiler/Properties/AssemblyInfo.cs -/ILSpy/Properties/AssemblyInfo.cs \ No newline at end of file +/ILSpy/Properties/AssemblyInfo.cs +*.suo \ No newline at end of file diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 7af14f7e8..9ef31e8f3 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -6,8 +6,10 @@ using System.Threading; using Decompiler.Transforms; using ICSharpCode.Decompiler; using ICSharpCode.NRefactory.CSharp; +using ICSharpCode.NRefactory.Utils; using Mono.Cecil; using Mono.Cecil.Cil; +using Ast = ICSharpCode.NRefactory.CSharp; using ClassType = ICSharpCode.NRefactory.TypeSystem.ClassType; using VarianceModifier = ICSharpCode.NRefactory.TypeSystem.VarianceModifier; @@ -62,20 +64,26 @@ namespace Decompiler astCompileUnit.AcceptVisitor(new OutputVisitor(outputFormatter, formattingPolicy), null); } - public void AddAssembly(AssemblyDefinition assemblyDefinition) + public void AddAssembly(AssemblyDefinition assemblyDefinition, bool onlyAssemblyLevel = false) { astCompileUnit.AddChild( new UsingDeclaration { Import = new SimpleType("System") }, CompilationUnit.MemberRole); - foreach(TypeDefinition typeDef in assemblyDefinition.MainModule.Types) { - // Skip nested types - they will be added by the parent type - if (typeDef.DeclaringType != null) continue; - // Skip the class - if (typeDef.Name == "") continue; - - AddType(typeDef); + ConvertCustomAttributes(astCompileUnit, assemblyDefinition, AttributeTarget.Assembly); + ConvertCustomAttributes(astCompileUnit, assemblyDefinition.MainModule, AttributeTarget.Module); + + if (!onlyAssemblyLevel) { + foreach (TypeDefinition typeDef in assemblyDefinition.MainModule.Types) + { + // Skip nested types - they will be added by the parent type + if (typeDef.DeclaringType != null) continue; + // Skip the class + if (typeDef.Name == "") continue; + + AddType(typeDef); + } } } @@ -167,13 +175,22 @@ namespace Decompiler if (typeDef.IsEnum) { + long expectedEnumMemberValue = 0; + bool forcePrintingInitializers = IsFlagsEnum(typeDef); foreach (FieldDefinition field in typeDef.Fields) { if (field.IsRuntimeSpecialName) { // the value__ field - astType.AddChild(ConvertType(field.FieldType), TypeDeclaration.BaseTypeRole); + if (field.FieldType != typeDef.Module.TypeSystem.Int32) { + astType.AddChild(ConvertType(field.FieldType), TypeDeclaration.BaseTypeRole); + } } else { EnumMemberDeclaration enumMember = new EnumMemberDeclaration(); enumMember.Name = CleanName(field.Name); + long memberValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false); + if (forcePrintingInitializers || memberValue != expectedEnumMemberValue) { + enumMember.AddChild(new PrimitiveExpression(field.Constant), EnumMemberDeclaration.InitializerRole); + } + expectedEnumMemberValue = memberValue + 1; astType.AddChild(enumMember, TypeDeclaration.MemberRole); } } @@ -188,9 +205,15 @@ namespace Decompiler AddTypeMembers(astType, typeDef); } - + + ConvertCustomAttributes(astType, typeDef); return astType; } + + public void Transform(IAstTransform transform) + { + transform.Run(astCompileUnit); + } string CleanName(string name) { @@ -482,22 +505,44 @@ namespace Decompiler astMethod.Modifiers = ConvertModifiers(methodDef); astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context); } + ConvertCustomAttributes(astMethod, methodDef); + ConvertCustomAttributes(astMethod, methodDef.MethodReturnType, AttributeTarget.Return); return astMethod; } IEnumerable MakeTypeParameters(IEnumerable genericParameters) { - return genericParameters.Select( - gp => new TypeParameterDeclaration { - Name = CleanName(gp.Name), - Variance = gp.IsContravariant ? VarianceModifier.Contravariant : gp.IsCovariant ? VarianceModifier.Covariant : VarianceModifier.Invariant - }); + foreach (var gp in genericParameters) { + TypeParameterDeclaration tp = new TypeParameterDeclaration(); + tp.Name = CleanName(gp.Name); + if (gp.IsContravariant) + tp.Variance = VarianceModifier.Contravariant; + else if (gp.IsCovariant) + tp.Variance = VarianceModifier.Covariant; + ConvertCustomAttributes(tp, gp); + yield return tp; + } } IEnumerable MakeConstraints(IEnumerable genericParameters) { - // TODO - return Enumerable.Empty(); + foreach (var gp in genericParameters) { + Constraint c = new Constraint(); + c.TypeParameter = CleanName(gp.Name); + // class/struct must be first + if (gp.HasReferenceTypeConstraint) + c.BaseTypes.Add(new PrimitiveType("class")); + if (gp.HasNotNullableValueTypeConstraint) + c.BaseTypes.Add(new PrimitiveType("struct")); + + foreach (var constraintType in gp.Constraints) + c.BaseTypes.Add(ConvertType(constraintType)); + + if (gp.HasDefaultConstructorConstraint) + c.BaseTypes.Add(new PrimitiveType("new")); // new() must be last + if (c.BaseTypes.Any()) + yield return c; + } } ConstructorDeclaration CreateConstructor(MethodDefinition methodDef) @@ -534,6 +579,8 @@ namespace Decompiler astProp.Getter = new Accessor { Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod, context) }.WithAnnotation(propDef.GetMethod); + ConvertCustomAttributes(astProp.Getter, propDef.GetMethod); + ConvertCustomAttributes(astProp.Getter, propDef.GetMethod.MethodReturnType, AttributeTarget.Return); if (methodMapping != null) astProp.Getter.AddAnnotation(methodMapping); @@ -545,10 +592,14 @@ namespace Decompiler astProp.Setter = new Accessor { Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, context) }.WithAnnotation(propDef.SetMethod); + ConvertCustomAttributes(astProp.Setter, propDef.SetMethod); + ConvertCustomAttributes(astProp.Setter, propDef.SetMethod.MethodReturnType, AttributeTarget.Return); + ConvertCustomAttributes(astProp.Setter, propDef.SetMethod.Parameters.Last(), AttributeTarget.Param); if (methodMapping != null) astProp.Setter.AddAnnotation(methodMapping); } + ConvertCustomAttributes(astProp, propDef); return astProp; } @@ -598,6 +649,7 @@ namespace Decompiler else initializer.Initializer = new PrimitiveExpression(fieldDef.Constant); } + ConvertCustomAttributes(astField, fieldDef); return astField; } @@ -613,8 +665,152 @@ namespace Decompiler } // TODO: params, this + ConvertCustomAttributes(astParam, paramDef); yield return astParam; } } + + static void ConvertCustomAttributes(AstNode attributedNode, ICustomAttributeProvider customAttributeProvider, AttributeTarget target = AttributeTarget.None) + { + if (customAttributeProvider.HasCustomAttributes) { + var attributes = new List(); + foreach (var customAttribute in customAttributeProvider.CustomAttributes) { + var attribute = new ICSharpCode.NRefactory.CSharp.Attribute(); + attribute.Type = ConvertType(customAttribute.AttributeType); + attributes.Add(attribute); + + SimpleType st = attribute.Type as SimpleType; + if (st != null && st.Identifier.EndsWith("Attribute", StringComparison.Ordinal)) { + st.Identifier = st.Identifier.Substring(0, st.Identifier.Length - "Attribute".Length); + } + + if(customAttribute.HasConstructorArguments) { + foreach (var parameter in customAttribute.ConstructorArguments) { + Expression parameterValue = ConvertArgumentValue(parameter); + attribute.Arguments.Add(parameterValue); + } + } + if (customAttribute.HasProperties) { + foreach (var propertyNamedArg in customAttribute.Properties) { + var propertyReference = customAttribute.AttributeType.Resolve().Properties.First(pr => pr.Name == propertyNamedArg.Name); + var propertyName = new IdentifierExpression(propertyNamedArg.Name).WithAnnotation(propertyReference); + var argumentValue = ConvertArgumentValue(propertyNamedArg.Argument); + attribute.Arguments.Add(new AssignmentExpression(propertyName, argumentValue)); + } + } + + if (customAttribute.HasFields) { + foreach (var fieldNamedArg in customAttribute.Fields) { + var fieldReference = customAttribute.AttributeType.Resolve().Fields.First(f => f.Name == fieldNamedArg.Name); + var fieldName = new IdentifierExpression(fieldNamedArg.Name).WithAnnotation(fieldReference); + var argumentValue = ConvertArgumentValue(fieldNamedArg.Argument); + attribute.Arguments.Add(new AssignmentExpression(fieldName, argumentValue)); + } + } + } + + if (target == AttributeTarget.Module || target == AttributeTarget.Assembly) { + // use separate section for each attribute + foreach (var attribute in attributes) { + var section = new AttributeSection(); + section.AttributeTarget = target; + section.Attributes.Add(attribute); + attributedNode.AddChild(section, AttributedNode.AttributeRole); + } + } else { + // use single section for all attributes + var section = new AttributeSection(); + section.AttributeTarget = target; + section.Attributes.AddRange(attributes); + attributedNode.AddChild(section, AttributedNode.AttributeRole); + } + } + } + + private static Expression ConvertArgumentValue(CustomAttributeArgument parameter) + { + var type = parameter.Type.Resolve(); + Expression parameterValue; + if (type.IsEnum) + { + parameterValue = MakePrimitive(Convert.ToInt64(parameter.Value), type); + } + else if (parameter.Value is TypeReference) + { + parameterValue = new TypeOfExpression() + { + Type = ConvertType((TypeReference)parameter.Value), + }; + } + else + { + parameterValue = new PrimitiveExpression(parameter.Value); + } + return parameterValue; + } + + + internal static Expression MakePrimitive(long val, TypeReference type) + { + if (TypeAnalysis.IsBoolean(type) && val == 0) + return new Ast.PrimitiveExpression(false); + else if (TypeAnalysis.IsBoolean(type) && val == 1) + return new Ast.PrimitiveExpression(true); + if (type != null) + { // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs) + TypeDefinition enumDefinition = type.Resolve(); + if (enumDefinition != null && enumDefinition.IsEnum) + { + foreach (FieldDefinition field in enumDefinition.Fields) + { + if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val)) + return ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + else if (!field.IsStatic && field.IsRuntimeSpecialName) + type = field.FieldType; // use primitive type of the enum + } + if (IsFlagsEnum(enumDefinition)) + { + long enumValue = val; + Expression expr = null; + foreach (FieldDefinition field in enumDefinition.Fields.Where(fld => fld.IsStatic)) + { + long fieldValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false); + if (fieldValue == 0) + continue; // skip None enum value + + if ((fieldValue & enumValue) == fieldValue) + { + var fieldExpression = ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + if (expr == null) + expr = fieldExpression; + else + expr = new BinaryOperatorExpression(expr, BinaryOperatorType.BitwiseOr, fieldExpression); + + enumValue &= ~fieldValue; + if (enumValue == 0) + break; + } + } + if(enumValue == 0 && expr != null) + return expr; + } + TypeCode enumBaseTypeCode = TypeAnalysis.GetTypeCode(type); + return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(enumDefinition)); + } + } + TypeCode code = TypeAnalysis.GetTypeCode(type); + if (code == TypeCode.Object) + return new Ast.PrimitiveExpression((int)val); + else + return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(code, val, false)); + } + + static bool IsFlagsEnum(TypeDefinition type) + { + if (!type.HasCustomAttributes) + return false; + + return type.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.FlagsAttribute"); + } } } diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index 05f163952..673e267a6 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -535,7 +535,7 @@ namespace Decompiler return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand)); } case Code.Ldc_I4: - return MakePrimitive((int)operand, byteCode.InferredType); + return AstBuilder.MakePrimitive((int)operand, byteCode.InferredType); case Code.Ldc_I8: case Code.Ldc_R4: case Code.Ldc_R8: @@ -794,7 +794,7 @@ namespace Decompiler if (TypeAnalysis.IsBoolean(actualType)) return expr; if (actualIsIntegerOrEnum) { - return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, MakePrimitive(0, actualType)); + return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, AstBuilder.MakePrimitive(0, actualType)); } else { return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, new NullReferenceExpression()); } @@ -802,39 +802,21 @@ namespace Decompiler if (TypeAnalysis.IsBoolean(actualType) && requiredIsIntegerOrEnum) { return new ConditionalExpression { Condition = expr, - TrueExpression = MakePrimitive(1, reqType), - FalseExpression = MakePrimitive(0, reqType) + TrueExpression = AstBuilder.MakePrimitive(1, reqType), + FalseExpression = AstBuilder.MakePrimitive(0, reqType) }; } + + if (expr is PrimitiveExpression && !requiredIsIntegerOrEnum && TypeAnalysis.IsEnum(actualType)) + { + return expr.CastTo(AstBuilder.ConvertType(actualType)); + } + if (actualIsIntegerOrEnum && requiredIsIntegerOrEnum) { return expr.CastTo(AstBuilder.ConvertType(reqType)); } return expr; } } - - Expression MakePrimitive(long val, TypeReference type) - { - if (TypeAnalysis.IsBoolean(type) && val == 0) - return new Ast.PrimitiveExpression(false); - else if (TypeAnalysis.IsBoolean(type) && val == 1) - return new Ast.PrimitiveExpression(true); - if (type != null) { // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs) - TypeDefinition enumDefinition = type.Resolve(); - if (enumDefinition != null && enumDefinition.IsEnum) { - foreach (FieldDefinition field in enumDefinition.Fields) { - if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val)) - return AstBuilder.ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); - else if (!field.IsStatic && field.IsRuntimeSpecialName) - type = field.FieldType; // use primitive type of the enum - } - } - } - TypeCode code = TypeAnalysis.GetTypeCode(type); - if (code == TypeCode.Object) - return new Ast.PrimitiveExpression((int)val); - else - return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(code, val, false)); - } } } diff --git a/ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs b/ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs index af82e224d..fe6a15d51 100644 --- a/ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs +++ b/ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs @@ -15,8 +15,8 @@ namespace Decompiler { static readonly ExpressionStatement assignmentPattern = new ExpressionStatement( new AssignmentExpression( - new NamedNode("ident", new IdentifierExpression()).ToExpression(), - new AnyNode("init").ToExpression() + new NamedNode("ident", new IdentifierExpression()), + new AnyNode("init") )); /// diff --git a/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs b/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs index 4ffa69c9c..ee2225073 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs @@ -48,6 +48,7 @@ namespace Decompiler.Transforms if (ctors.Length == 1 && ctors[0].Body.Children.Count() == 0 && ctors[0].Initializer.ConstructorInitializerType == ConstructorInitializerType.Base && ctors[0].Initializer.Arguments.Count() == 0 + && ctors[0].Parameters.Count == 0 && ctors[0].Modifiers == ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public)) { ctors[0].Remove(); diff --git a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs index d5bf7d8b2..87df7aca8 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs @@ -196,8 +196,8 @@ namespace Decompiler.Transforms // "variableName.MemberName = right;" ExpressionStatement closureFieldAssignmentPattern = new ExpressionStatement( new AssignmentExpression( - new NamedNode("left", new MemberReferenceExpression { Target = new IdentifierExpression(variable.Name) }).ToExpression(), - new AnyNode("right").ToExpression() + new NamedNode("left", new MemberReferenceExpression { Target = new IdentifierExpression(variable.Name) }), + new AnyNode("right") ) ); Match m = closureFieldAssignmentPattern.Match(cur); diff --git a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs index 78a9d3596..bdc4b1d37 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs @@ -26,14 +26,14 @@ namespace Decompiler.Transforms /// $type $variable = $initializer; /// static readonly AstNode variableDeclPattern = new VariableDeclarationStatement { - Type = new AnyNode("type").ToType(), + Type = new AnyNode("type"), Variables = { new NamedNode( "variable", new VariableInitializer { - Initializer = new AnyNode("initializer").ToExpression() + Initializer = new AnyNode("initializer") } - ).ToVariable() + ) } }; @@ -41,7 +41,7 @@ namespace Decompiler.Transforms /// Variable declaration without initializer. /// static readonly AstNode simpleVariableDefinition = new VariableDeclarationStatement { - Type = new AnyNode().ToType(), + Type = new AnyNode(), Variables = { new VariableInitializer() // any name but no initializer } @@ -49,7 +49,7 @@ namespace Decompiler.Transforms #region using static readonly AstNode usingTryCatchPattern = new TryCatchStatement { - TryBlock = new AnyNode("body").ToBlock(), + TryBlock = new AnyNode("body"), FinallyBlock = new BlockStatement { new Choice { { "valueType", @@ -58,7 +58,7 @@ namespace Decompiler.Transforms { "referenceType", new IfElseStatement { Condition = new BinaryOperatorExpression( - new NamedNode("ident", new IdentifierExpression()).ToExpression(), + new NamedNode("ident", new IdentifierExpression()), BinaryOperatorType.InEquality, new NullReferenceExpression() ), @@ -102,14 +102,14 @@ namespace Decompiler.Transforms #region foreach UsingStatement foreachPattern = new UsingStatement { ResourceAcquisition = new VariableDeclarationStatement { - Type = new AnyNode("enumeratorType").ToType(), + Type = new AnyNode("enumeratorType"), Variables = { new NamedNode( "enumeratorVariable", new VariableInitializer { Initializer = new AnyNode("collection").ToExpression().Invoke("GetEnumerator") } - ).ToVariable() + ) } }, EmbeddedStatement = new Choice { @@ -123,14 +123,14 @@ namespace Decompiler.Transforms Condition = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Invoke("MoveNext"), EmbeddedStatement = new BlockStatement { new VariableDeclarationStatement { - Type = new AnyNode("itemType").ToType(), + Type = new AnyNode("itemType"), Variables = { new NamedNode( "itemVariable", new VariableInitializer { Initializer = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Member("Current") } - ).ToVariable() + ) } }, new Repeat(new AnyNode("statement")).ToStatement() @@ -141,16 +141,16 @@ namespace Decompiler.Transforms { "itemVariableOutsideLoop", new BlockStatement { new VariableDeclarationStatement { - Type = new AnyNode("itemType").ToType(), + Type = new AnyNode("itemType"), Variables = { - new NamedNode("itemVariable", new VariableInitializer()).ToVariable() + new NamedNode("itemVariable", new VariableInitializer()) } }, new WhileStatement { Condition = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Invoke("MoveNext"), EmbeddedStatement = new BlockStatement { new AssignmentExpression { - Left = new IdentifierExpressionBackreference("itemVariable").ToExpression(), + Left = new IdentifierExpressionBackreference("itemVariable"), Operator = AssignmentOperatorType.Assign, Right = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Member("Current") }, @@ -191,20 +191,22 @@ namespace Decompiler.Transforms #region for WhileStatement forPattern = new WhileStatement { Condition = new BinaryOperatorExpression { - Left = new NamedNode("ident", new IdentifierExpression()).ToExpression(), + Left = new NamedNode("ident", new IdentifierExpression()), Operator = BinaryOperatorType.Any, - Right = new AnyNode("endExpr").ToExpression() + Right = new AnyNode("endExpr") }, EmbeddedStatement = new BlockStatement { - new Repeat(new AnyNode("statement")).ToStatement(), - new NamedNode( - "increment", - new ExpressionStatement( - new AssignmentExpression { - Left = new Backreference("ident").ToExpression(), - Operator = AssignmentOperatorType.Any, - Right = new AnyNode().ToExpression() - })).ToStatement() + Statements = { + new Repeat(new AnyNode("statement")), + new NamedNode( + "increment", + new ExpressionStatement( + new AssignmentExpression { + Left = new Backreference("ident"), + Operator = AssignmentOperatorType.Any, + Right = new AnyNode() + })) + } } }; diff --git a/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs b/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs index 0a9d943ee..1d04bd941 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs @@ -77,13 +77,13 @@ namespace Decompiler.Transforms } readonly static AstNode asCastIsNullPattern = new BinaryOperatorExpression( - new AnyNode("expr").ToExpression().CastAs(new AnyNode("type").ToType()), + new AnyNode("expr").ToExpression().CastAs(new AnyNode("type")), BinaryOperatorType.Equality, new NullReferenceExpression() ); readonly static AstNode asCastIsNotNullPattern = new BinaryOperatorExpression( - new AnyNode("expr").ToExpression().CastAs(new AnyNode("type").ToType()), + new AnyNode("expr").ToExpression().CastAs(new AnyNode("type")), BinaryOperatorType.InEquality, new NullReferenceExpression() ); diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs index 14a4c346e..31082f7f9 100644 --- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs +++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs @@ -647,6 +647,15 @@ namespace Decompiler { return IsSigned(type) != null; } + + public static bool IsEnum(TypeReference type) + { + if (type == null) + return false; + // unfortunately we cannot rely on type.IsValueType here - it's not set when the instruction operand is a typeref (as opposed to a typespec) + TypeDefinition typeDef = type.Resolve() as TypeDefinition; + return typeDef != null && typeDef.IsEnum; + } static bool? IsSigned(TypeReference type) { diff --git a/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs b/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs new file mode 100644 index 000000000..c481c25e8 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace ICSharpCode.Decompiler.Tests +{ + static class CodeSampleFileParser + { + public static IEnumerable ListSections(string s) + { + var query = from line in ToLines(s) + let sectionName = ReadSectionName(line) + where sectionName != null + select sectionName; + return query; + } + + public static string GetSection(string sectionName, string s) + { + var lines = ToLines(s); + + bool sectionFound = false; + var sectionText = new StringBuilder(); + + Action parser = null; + + Action commonSectionReader = line => + { + if (IsCommonSectionEnd(line)) + parser = null; + else + sectionText.AppendLine(line); + }; + + Action namedSectionReader = line => + { + string name = ReadSectionName(line); + if (name == null) + sectionText.AppendLine(line); + else if (name != sectionName) + parser = null; + }; + + Action defaultReader = line => + { + if (IsCommonSectionStart(line)) + parser = commonSectionReader; + else if (ReadSectionName(line) == sectionName) + { + parser = namedSectionReader; + sectionFound = true; + } + }; + + foreach(var line in lines) + { + (parser ?? defaultReader)(line); + } + + if (sectionFound) + return sectionText.ToString(); + else + return ""; + } + + public static bool IsCommentOrBlank(string s) + { + if(String.IsNullOrWhiteSpace(s)) + return true; + return s.Trim().StartsWith("//"); + } + + public static string ConcatLines(IEnumerable lines) + { + var buffer = new StringBuilder(); + foreach (var line in lines) + { + buffer.AppendLine(line); + } + return buffer.ToString(); + } + + static string ReadSectionName(string line) + { + line = line.TrimStart(); + if (line.StartsWith("//$$")) + return line.Substring(4).Trim(); + else + return null; + } + + static bool IsCommonSectionStart(string line) + { + return line.Trim() == "//$CS"; + } + + static bool IsCommonSectionEnd(string line) + { + return line.Trim() == "//$CE"; + } + + static IEnumerable ToLines(string s) + { + var reader = new StringReader(s); + string line; + while ((line = reader.ReadLine()) != null) + { + yield return line; + } + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes.code.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes.code.cs new file mode 100644 index 000000000..4130b0b0f --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes.code.cs @@ -0,0 +1,41 @@ +using System; +namespace aa +{ + public static class CustomAtributes + { + [Flags] + public enum EnumWithFlag + { + All = 15, + None = 0, + Item1 = 1, + Item2 = 2, + Item3 = 4, + Item4 = 8 + } + [AttributeUsage(AttributeTargets.All)] + public class MyAttribute : Attribute + { + public MyAttribute(CustomAtributes.EnumWithFlag en) + { + } + } + [CustomAtributes.MyAttribute(CustomAtributes.EnumWithFlag.Item1 | CustomAtributes.EnumWithFlag.Item2)] + private static int field; + [CustomAtributes.MyAttribute(CustomAtributes.EnumWithFlag.All)] + public static string Property + { + get + { + return "aa"; + } + } + [Obsolete("some message")] + public static void ObsoletedMethod() + { + Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, AttributeTargets.Property | AttributeTargets.Field); + AttributeTargets attributeTargets = AttributeTargets.Property | AttributeTargets.Field; + Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, attributeTargets); + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs new file mode 100644 index 000000000..892f33bf9 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; + +namespace ICSharpCode.Decompiler.Tests.CustomAttributes +{ + [TestFixture] + public class CustomAttributeTests : DecompilerTestBase + { + [Test] + public void CustomAttributeSamples() + { + ValidateFileRoundtrip(@"CustomAttributes\S_CustomAttributeSamples.cs"); + } + + [Test] + public void CustomAttributesMultiTest() + { + ValidateFileRoundtrip(@"CustomAttributes\S_CustomAttributes.cs"); + } + + [Test] + public void AssemblyCustomAttributesMultiTest() + { + ValidateFileRoundtrip(@"CustomAttributes\S_AssemblyCustomAttribute.cs"); + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_AssemblyCustomAttribute.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_AssemblyCustomAttribute.cs new file mode 100644 index 000000000..9d95a4861 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_AssemblyCustomAttribute.cs @@ -0,0 +1,6 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; + +[assembly: CLSCompliant(false)] diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs new file mode 100644 index 000000000..866d9aa06 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs @@ -0,0 +1,409 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +//$CS +using System; +//$CE + +//$$ TargetModule (ignored) +//[module: CLSCompliantAttribute(false)] +//$$ ParameterlessAttributeUsage +namespace ParameterLessAttributeUsage +{ + [Flags] + public enum EnumWithFlagsAttribute + { + None = 0 + } +} +//$$ AttributeWithEnumArgument +namespace AttributeWithEnumArgument +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } +} +//$$ AttributeWithEnumExpressionArgument +namespace AttributeWithEnumExpressionArgument +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Interface)] + public class MyAttributeAttribute : Attribute + { + } +} +//$$ AttributeWithStringExpressionArgument +namespace AttributeWithStringExpressionArgument +{ + [Obsolete("message")] + public class ObsoletedClass + { + } +} +//$$ AttributeWithTypeArgument +namespace AttributeWithTypeArgument +{ + [AttributeUsage(AttributeTargets.All)] + public class MyTypeAttribute : Attribute + { + public MyTypeAttribute(Type t) : base() + { + } + } + + [MyType(typeof(Attribute))] + public class SomeClass + { + } +} +//$$ AppliedToEvent +namespace AppliedToEvent +{ + [AttributeUsage(AttributeTargets.Event)] + public class MyAttributeAttribute : Attribute + { + } + public class TestClass + { + [MyAttribute] + public event EventHandler MyEvent; + } +} +//$$ AppliedToField +namespace AppliedToField +{ + [AttributeUsage(AttributeTargets.Field)] + public class MyAttributeAttribute : Attribute + { + } + public class TestClass + { + [MyAttribute] + public int Field; + } +} +//$$ AppliedToProperty +namespace AppliedToProperty +{ + public class TestClass + { + [Obsolete("reason")] + public int Property + { + get + { + return 0; + } + } + } +} +//$$ AppliedToPropertyGet +namespace AppliedToPropertyGet +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class TestClass + { + public int Property + { + [MyAttribute] + get + { + return 0; + } + } + } +} +//$$ AppliedToPropertySet +namespace AppliedToPropertySet +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class TestClass + { + public int Property + { + get + { + return 3; + } + [MyAttribute] + set + { + return; + } + } + } +} +//$$ AppliedToDelegate +[Obsolete("reason")] +public delegate int AppliedToDelegate(); +//$$ AppliedToMethod +namespace AppliedToMethod +{ + [AttributeUsage(AttributeTargets.Method)] + public class MyAttributeAttribute : Attribute + { + } + public class TestClass + { + [MyAttribute] + public void Method() + { + } + } +} +//$$ AppliedToInterface +[Obsolete("reason")] +public interface AppliedToInterface +{ +} +//$$ AppliedToStruct +[Obsolete("reason")] +public struct AppliedToStruct +{ + public int Field; +} +//$$ AppliedToParameter +namespace AppliedToParameter +{ + [AttributeUsage(AttributeTargets.Parameter)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + public void Method([MyAttribute]int val) + { + } + } +} +//$$ NamedInitializerProperty +namespace NamedInitializerProperty +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + public class MyAttributeAttribute : Attribute + { + } +} +//$$ NamedInitializerPropertyString +namespace NamedInitializerPropertyString +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + public string Prop + { + get + { + return ""; + } + set + { + return; + } + } + } + [MyAttribute(Prop = "value")] + public class MyClass + { + } +} +//$$ NamedInitializerPropertyType +namespace NamedInitializerPropertyType +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + public Type Prop + { + get + { + return null; + } + set + { + return; + } + } + } + [MyAttribute(Prop = typeof(Enum))] + public class MyClass + { + } +} +//$$ NamedInitializerPropertyEnum +namespace NamedInitializerPropertyEnum +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + public AttributeTargets Prop + { + get + { + return AttributeTargets.All; + } + set + { + return; + } + } + } + [MyAttribute(Prop = (AttributeTargets.Class | AttributeTargets.Method))] + public class MyClass + { + } +} +//$$ NamedInitializerFieldEnum +namespace NamedInitializerFieldEnum +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + public AttributeTargets Field; + } + [MyAttribute(Field = (AttributeTargets.Class | AttributeTargets.Method))] + public class MyClass + { + } +} +//$$ TargetReturn +namespace TargetReturn +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + [return: MyAttribute] + public int MyMethod() + { + return 5; + } + } +} +//$$ TargetPropertyGetReturn +namespace TargetPropertyGetReturn +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + public int Prop + { + [return: MyAttribute] + get + { + return 3; + } + } + } +} +//$$ TargetPropertySetParam +namespace TargetPropertySetParam +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + public int Prop + { + [param: MyAttribute] + set + { + return; + } + } + } +} +//$$ TargetPropertySetReturn +namespace TargetPropertySetReturn +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + public int Prop + { + get + { + return 3; + } + [return: MyAttribute] + set + { + return; + } + } + } +} +//$$ TargetPropertyIndexSetParam +namespace TargetPropertyIndexSetParam +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + public string this[int index] + { + get + { + return ""; + } + [param: MyAttribute] + set + { + return; + } + } + } +} +//$$ TargetPropertyIndexSetMultiParam +namespace TargetPropertyIndexSetMultiParam +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + public int Field; + } + public class MyClass + { + public string this[[MyAttribute(Field = 2)] int index1, [MyAttribute(Field = 3)] int index2] + { + get + { + return ""; + } + [param: MyAttribute] + set + { + return; + } + } + } +} +//$$ ClassAttributeOnTypeParameter +namespace ClassAttributeOnTypeParameter +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass<[MyAttribute] T> + { + } +} diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs new file mode 100644 index 000000000..dbd064eb4 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs @@ -0,0 +1,46 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; + +namespace aa +{ + public static class CustomAtributes + { + [Flags] + public enum EnumWithFlag + { + All = 15, + None = 0, + Item1 = 1, + Item2 = 2, + Item3 = 4, + Item4 = 8 + } + [AttributeUsage(AttributeTargets.All)] + public class MyAttribute : Attribute + { + public MyAttribute(CustomAtributes.EnumWithFlag en) : base() + { + } + } + [CustomAtributes.MyAttribute(CustomAtributes.EnumWithFlag.Item1 | CustomAtributes.EnumWithFlag.Item2)] + private static int field; + [CustomAtributes.MyAttribute(CustomAtributes.EnumWithFlag.All)] + public static string Property + { + get + { + return "aa"; + } + } + [Obsolete("some message")] + public static void ObsoletedMethod() + { + //Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, (AttributeTargets)(AttributeTargets.Property | AttributeTargets.Field)); + Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, AttributeTargets.Property | AttributeTargets.Field); + AttributeTargets attributeTargets = AttributeTargets.Property | AttributeTargets.Field; + Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, attributeTargets); + } + } +} \ No newline at end of file diff --git a/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs b/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs new file mode 100644 index 000000000..c1a13b925 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Mono.Cecil; +using System.IO; +using Decompiler; +using Microsoft.CSharp; +using System.CodeDom.Compiler; +using NUnit.Framework; + +namespace ICSharpCode.Decompiler.Tests +{ + public abstract class DecompilerTestBase + { + protected static void ValidateFileRoundtrip(string samplesFileName) + { + var lines = File.ReadAllLines(Path.Combine(@"..\..\Tests", samplesFileName)); + var testCode = RemoveIgnorableLines(lines); + var decompiledTestCode = RoundtripCode(testCode); + Assert.AreEqual(testCode, decompiledTestCode); + } + + static string RemoveIgnorableLines(IEnumerable lines) + { + return CodeSampleFileParser.ConcatLines(lines.Where(l => !CodeSampleFileParser.IsCommentOrBlank(l))); + } + + /// + /// Compiles and decompiles a source code. + /// + /// The source code to copile. + /// The decompilation result of compiled source code. + static string RoundtripCode(string code) + { + AssemblyDefinition assembly = Compile(code); + AstBuilder decompiler = new AstBuilder(new DecompilerContext()); + decompiler.AddAssembly(assembly); + decompiler.Transform(new Helpers.RemoveCompilerAttribute()); + StringWriter output = new StringWriter(); + decompiler.GenerateCode(new PlainTextOutput(output)); + return output.ToString(); + } + + static AssemblyDefinition Compile(string code) + { + CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary { { "CompilerVersion", "v4.0" } }); + CompilerParameters options = new CompilerParameters(); + options.ReferencedAssemblies.Add("System.Core.dll"); + CompilerResults results = provider.CompileAssemblyFromSource(options, code); + try + { + if (results.Errors.Count > 0) + { + StringBuilder b = new StringBuilder("Compiler error:"); + foreach (var error in results.Errors) + { + b.AppendLine(error.ToString()); + } + throw new Exception(b.ToString()); + } + return AssemblyDefinition.ReadAssembly(results.PathToAssembly); + } + finally + { + File.Delete(results.PathToAssembly); + results.TempFiles.Delete(); + } + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/Generics.cs b/ICSharpCode.Decompiler/Tests/Generics.cs index 636eb708c..d0b6cf240 100644 --- a/ICSharpCode.Decompiler/Tests/Generics.cs +++ b/ICSharpCode.Decompiler/Tests/Generics.cs @@ -27,4 +27,8 @@ public static class Generics } } } + + public static void MethodWithConstraint() where T : class, S where S : ICloneable, new() + { + } } diff --git a/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs b/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs new file mode 100644 index 000000000..00b5b4dba --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ICSharpCode.NRefactory.CSharp; +using Decompiler.Transforms; + +namespace ICSharpCode.Decompiler.Tests.Helpers +{ + class RemoveCompilerAttribute : DepthFirstAstVisitor, IAstTransform + { + public override object VisitAttribute(NRefactory.CSharp.Attribute attribute, object data) + { + var section = (AttributeSection)attribute.Parent; + SimpleType type = attribute.Type as SimpleType; + if (section.AttributeTarget == AttributeTarget.Assembly && + (type.Identifier == "CompilationRelaxations" || type.Identifier == "RuntimeCompatibility")) + { + attribute.Remove(); + if (section.Attributes.Count == 0) + section.Remove(); + } + return null; + } + + public void Run(AstNode node) + { + node.AcceptVisitor(this, null); + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index e210d308b..5b528d6d4 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -38,6 +38,10 @@ TRACE + + False + .\nunit.framework.dll + 3.5 @@ -48,13 +52,23 @@ - + + + + + + + + + + + + + - - @@ -63,14 +77,16 @@ {D68133BD-1E63-496E-9EDE-4FBDBF77B486} Mono.Cecil + + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371} + ICSharpCode.NRefactory + {984CC812-9470-4A13-AFF9-CC44068D666C} ICSharpCode.Decompiler - - - + diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs index d4fa06fdd..98e3daad7 100644 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs @@ -14,21 +14,23 @@ namespace ICSharpCode.Decompiler.Tests { public class TestRunner { - public static void Main() + public static void Main(string[] args) { - Test(@"..\..\Tests\DelegateConstruction.cs"); - + if (args.Length == 1) + TestFile(args[0]); + else + TestFile(@"..\..\Tests\DelegateConstruction.cs"); + Console.ReadKey(); } - - - - static void Test(string fileName) + + static void TestFile(string fileName) { string code = File.ReadAllText(fileName); AssemblyDefinition assembly = Compile(code); AstBuilder decompiler = new AstBuilder(new DecompilerContext()); decompiler.AddAssembly(assembly); + decompiler.Transform(new Helpers.RemoveCompilerAttribute()); StringWriter output = new StringWriter(); decompiler.GenerateCode(new PlainTextOutput(output)); StringWriter diff = new StringWriter(); @@ -79,7 +81,7 @@ namespace ICSharpCode.Decompiler.Tests static AssemblyDefinition Compile(string code) { - CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary {{ "CompilerVersion", "v4.0" }}); + CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary { { "CompilerVersion", "v4.0" } }); CompilerParameters options = new CompilerParameters(); options.ReferencedAssemblies.Add("System.Core.dll"); CompilerResults results = provider.CompileAssemblyFromSource(options, code); diff --git a/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs b/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs new file mode 100644 index 000000000..fb48d016e --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; + +namespace ICSharpCode.Decompiler.Tests.Types +{ + [TestFixture] + public class EnumTests : DecompilerTestBase + { + [Test] + public void EnumSamples() + { + ValidateFileRoundtrip(@"Types\S_EnumSamples.cs"); + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/Types/S_EnumSamples.cs b/ICSharpCode.Decompiler/Tests/Types/S_EnumSamples.cs new file mode 100644 index 000000000..67d81fa30 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/Types/S_EnumSamples.cs @@ -0,0 +1,114 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +//$CS +using System; +//$CE + +//$$ SingleValue +public class TS_SingleValue +{ + public AttributeTargets Method() + { + return AttributeTargets.Class; + } +} +//$$ TwoValuesOr +public class TS_TwoValuesOr +{ + public AttributeTargets Method() + { + return AttributeTargets.Class | AttributeTargets.Method; + } +} +//$$ ThreeValuesOr +public class TS_ThreeValuesOr +{ + public AttributeTargets Method() + { + return AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Parameter; + } +} +//$$ UnknownNumericValue +public class TS_UnknownNumericValue +{ + public AttributeTargets Method() + { + return (AttributeTargets)1000000; + } +} +//$$ AllValue +public class TS_AllValue +{ + public AttributeTargets Method() + { + return AttributeTargets.All; + } +} +//$$ ZeroValue +public class TS_ZeroValue +{ + public AttributeTargets Method() + { + return (AttributeTargets)0; + } +} +//$$ PreservingTypeWhenBoxed +public class TS_PreservingTypeWhenBoxed +{ + public object Method() + { + return AttributeTargets.Delegate; + } +} +//$$ PreservingTypeWhenBoxedTwoEnum +public class TS_PreservingTypeWhenBoxedTwoEnum +{ + public object Method() + { + return AttributeTargets.Class | AttributeTargets.Delegate; + } +} +//$$ DeclarationSimpleEnum +public enum TS_DeclarationSimpleEnum +{ + Item1, + Item2 +} +//$$ DeclarationLongBasedEnum +public enum TS_DeclarationLongBasedEnum : long +{ + Item1, + Item2 +} +//$$ DeclarationLongWithInitializers +public enum TS_DeclarationLongWithInitializers : long +{ + Item1, + Item2 = 20L, + Item3 +} +//$$ DeclarationShortWithInitializers +public enum TS_DeclarationShortWithInitializers : short +{ + Item1, + Item2 = 20, + Item3 +} +//$$ DeclarationByteWithInitializers +public enum TS_DeclarationByteWithInitializers : byte +{ + Item1, + Item2 = 20, + Item3 +} +//$$ DeclarationFlags +[Flags] +public enum TS_DeclarationFlags +{ + None = 0, + Item1 = 1, + Item2 = 2, + Item3 = 4, + All = 7 +} diff --git a/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs b/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs new file mode 100644 index 000000000..56d7db39f --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; + +namespace ICSharpCode.Decompiler.Tests.Types +{ + public class TypeTests : DecompilerTestBase + { + } +} diff --git a/ICSharpCode.Decompiler/Tests/nunit.framework.dll b/ICSharpCode.Decompiler/Tests/nunit.framework.dll new file mode 100644 index 000000000..875e09842 Binary files /dev/null and b/ICSharpCode.Decompiler/Tests/nunit.framework.dll differ diff --git a/ILSpy.sln b/ILSpy.sln index 3bb9f43f4..a9faa853c 100644 --- a/ILSpy.sln +++ b/ILSpy.sln @@ -26,68 +26,68 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler.Test EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Debug|x86.Build.0 = Debug|x86 - {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Debug|x86.ActiveCfg = Debug|x86 - {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Release|x86.Build.0 = Release|x86 - {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Release|x86.ActiveCfg = Release|x86 - {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Debug|Any CPU.Build.0 = Debug|Any CPU {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Release|Any CPU.Build.0 = Release|Any CPU + {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Debug|x86.ActiveCfg = Debug|x86 + {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Debug|x86.Build.0 = Debug|x86 {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Debug|x86.Build.0 = Debug|Any CPU - {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Debug|x86.ActiveCfg = Debug|Any CPU - {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|x86.Build.0 = Release|Any CPU - {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|x86.ActiveCfg = Release|Any CPU - {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Release|Any CPU.Build.0 = Release|Any CPU + {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Release|x86.ActiveCfg = Release|x86 + {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Release|x86.Build.0 = Release|x86 {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|Any CPU.Build.0 = Release|Any CPU + {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Debug|x86.ActiveCfg = Debug|Any CPU + {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Debug|x86.Build.0 = Debug|Any CPU {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|Any CPU.Build.0 = Release|Any CPU + {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|x86.ActiveCfg = Release|Any CPU + {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|x86.Build.0 = Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.ActiveCfg = net_3_5_Debug|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.Build.0 = net_2_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.ActiveCfg = net_4_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.Build.0 = net_4_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.ActiveCfg = net_3_5_Release|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.Build.0 = net_2_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.ActiveCfg = net_4_0_Release|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.Build.0 = net_2_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU - {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|x86.Build.0 = Debug|Any CPU - {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|x86.ActiveCfg = Debug|Any CPU - {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.Build.0 = Debug|Any CPU {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|x86.Build.0 = Release|Any CPU - {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|x86.ActiveCfg = Release|Any CPU - {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|Any CPU.Build.0 = Release|Any CPU + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|x86.ActiveCfg = Debug|Any CPU + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|x86.Build.0 = Debug|Any CPU {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|x86.Build.0 = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|x86.ActiveCfg = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|Any CPU.Build.0 = Release|Any CPU + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|x86.ActiveCfg = Release|Any CPU + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|x86.Build.0 = Release|Any CPU {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x86.Build.0 = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x86.ActiveCfg = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.Build.0 = Release|Any CPU + {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|x86.ActiveCfg = Debug|Any CPU + {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|x86.Build.0 = Debug|Any CPU {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|x86.Build.0 = Debug|Any CPU - {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|x86.ActiveCfg = Debug|Any CPU - {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Any CPU.Build.0 = Debug|Any CPU + {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.Build.0 = Release|Any CPU + {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x86.ActiveCfg = Release|Any CPU + {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x86.Build.0 = Release|Any CPU {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|x86.Build.0 = Release|Any CPU - {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|x86.ActiveCfg = Release|Any CPU - {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.Build.0 = Release|Any CPU + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|x86.ActiveCfg = Debug|Any CPU + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|x86.Build.0 = Debug|Any CPU {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|x86.Build.0 = Debug|x86 - {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|x86.ActiveCfg = Debug|x86 - {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|Any CPU.Build.0 = Debug|x86 + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.Build.0 = Release|Any CPU + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|x86.ActiveCfg = Release|Any CPU + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|x86.Build.0 = Release|Any CPU {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|Any CPU.ActiveCfg = Debug|x86 - {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.Build.0 = Release|x86 - {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.ActiveCfg = Release|x86 - {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|Any CPU.Build.0 = Release|x86 + {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|Any CPU.Build.0 = Debug|x86 + {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|x86.ActiveCfg = Debug|x86 + {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|x86.Build.0 = Debug|x86 {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|Any CPU.ActiveCfg = Release|x86 + {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|Any CPU.Build.0 = Release|x86 + {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.ActiveCfg = Release|x86 + {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.Build.0 = Release|x86 {1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|x86.Build.0 = Debug|Any CPU {1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|x86.ActiveCfg = Debug|Any CPU {1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -105,8 +105,7 @@ Global {6D3D0F0D-348D-456A-A6ED-E9BD5EFABB6A}.Release|Any CPU.Build.0 = Release|x86 {6D3D0F0D-348D-456A-A6ED-E9BD5EFABB6A}.Release|Any CPU.ActiveCfg = Release|x86 EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {6D3D0F0D-348D-456A-A6ED-E9BD5EFABB6A} = {1DEB3B4E-03AC-437C-821D-B09FBFCC3E5B} - {1D18D788-F7EE-4585-A23B-34DC8EC63CB8} = {1DEB3B4E-03AC-437C-821D-B09FBFCC3E5B} + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection EndGlobal diff --git a/ILSpy/CSharpLanguage.cs b/ILSpy/CSharpLanguage.cs index 7ff152475..4c6adbd2f 100644 --- a/ILSpy/CSharpLanguage.cs +++ b/ILSpy/CSharpLanguage.cs @@ -40,7 +40,7 @@ namespace ICSharpCode.ILSpy public class CSharpLanguage : Language { string name = "C#"; - bool showAllMembers; + bool showAllMembers = false; Predicate transformAbortCondition = null; public CSharpLanguage() @@ -132,6 +132,9 @@ namespace ICSharpCode.ILSpy } } else { base.DecompileAssembly(assembly, fileName, output, options); + AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: null); + codeDomBuilder.AddAssembly(assembly, onlyAssemblyLevel: true); + codeDomBuilder.GenerateCode(output, transformAbortCondition); } } @@ -375,7 +378,7 @@ namespace ICSharpCode.ILSpy CurrentType = currentType }); } - + public override string TypeToString(TypeReference type, bool includeNamespace, ICustomAttributeProvider typeAttributes) { AstType astType = AstBuilder.ConvertType(type, typeAttributes); diff --git a/ILSpy/ILAstLanguage.cs b/ILSpy/ILAstLanguage.cs index 39fcd50c6..8a7ae6f8e 100644 --- a/ILSpy/ILAstLanguage.cs +++ b/ILSpy/ILAstLanguage.cs @@ -30,10 +30,11 @@ using Mono.Cecil; namespace ICSharpCode.ILSpy { + #if DEBUG /// /// Represents the ILAst "language" used for debugging purposes. /// - public class ILAstLanguage : Language + sealed class ILAstLanguage : Language { string name; bool inlineVariables = true; @@ -78,7 +79,6 @@ namespace ICSharpCode.ILSpy } } - #if DEBUG internal static IEnumerable GetDebugLanguages() { yield return new ILAstLanguage { name = "ILAst (unoptimized)", inlineVariables = false }; @@ -89,7 +89,6 @@ namespace ICSharpCode.ILSpy } } - #endif public override string FileExtension { get { @@ -104,4 +103,5 @@ namespace ICSharpCode.ILSpy return output.ToString(); } } + #endif } diff --git a/Mono.Cecil/Mono.Cecil/SecurityDeclaration.cs b/Mono.Cecil/Mono.Cecil/SecurityDeclaration.cs index b09e4a6e8..8fcfcc458 100644 --- a/Mono.Cecil/Mono.Cecil/SecurityDeclaration.cs +++ b/Mono.Cecil/Mono.Cecil/SecurityDeclaration.cs @@ -177,7 +177,7 @@ namespace Mono.Cecil { { return module.HasImage () ? module.Read (ref variable, self, (provider, reader) => reader.ReadSecurityDeclarations (provider)) - : LazyInitializer.EnsureInitialized(ref variable); + : variable = new Collection(); } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Demo/ICSharpCode.NRefactory.Demo.csproj b/NRefactory/ICSharpCode.NRefactory.Demo/ICSharpCode.NRefactory.Demo.csproj index 36ea620c6..906a94773 100644 --- a/NRefactory/ICSharpCode.NRefactory.Demo/ICSharpCode.NRefactory.Demo.csproj +++ b/NRefactory/ICSharpCode.NRefactory.Demo/ICSharpCode.NRefactory.Demo.csproj @@ -40,21 +40,29 @@ - + + Form + VBEditDialog.cs - + + UserControl + VBDomView.cs - + + Form + MainForm.cs - + + UserControl + VBDemo.cs diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/AstStructureTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/AstStructureTests.cs index 16534dd1d..183efacdb 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/AstStructureTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/AstStructureTests.cs @@ -27,5 +27,20 @@ namespace ICSharpCode.NRefactory.CSharp } } } + + [Test] + public void AstNodesDoNotDeriveFromEachOther() + { + // Ast nodes should derive only from abstract classes; not from concrete types. + // For example, we want to avoid that an AST consumer doing "if (node is PropertyDeclaration)" + // unknowingly also handles IndexerDeclarations. + foreach (Type type in typeof(AstNode).Assembly.GetExportedTypes()) { + if (type == typeof(CSharpModifierToken)) // CSharpModifierToken is the exception (though I'm not too happy about that) + continue; + if (type.IsSubclassOf(typeof(AstNode))) { + Assert.IsTrue(type.BaseType.IsAbstract, type.FullName); + } + } + } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AliasReferenceExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AliasReferenceExpressionTests.cs index 8b0298e60..41ba8452c 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AliasReferenceExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AliasReferenceExpressionTests.cs @@ -8,27 +8,43 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture] + [TestFixture, Ignore("Aliases not yet implemented")] public class AliasReferenceExpressionTests { - [Test, Ignore] + [Test] public void GlobalReferenceExpressionTest() { CSharpParser parser = new CSharpParser(); - parser.ParseTypeReference(new StringReader("global::System")); - //Assert.IsTrue(tre.TypeReference.IsGlobal); - //Assert.AreEqual("System", tre.TypeReference.Type); - throw new NotImplementedException(); + AstType type = parser.ParseTypeReference(new StringReader("global::System")); + Assert.IsNotNull( + new MemberType { + Target = new SimpleType("global"), + IsDoubleColon = true, + MemberName = "System" + }.Match(type) + ); } - [Test, Ignore] + [Test] public void GlobalTypeDeclaration() { VariableDeclarationStatement lvd = ParseUtilCSharp.ParseStatement("global::System.String a;"); - //TypeReference typeRef = lvd.GetTypeForVariable(0); - //Assert.IsTrue(typeRef.IsGlobal); - //Assert.AreEqual("System.String", typeRef.Type); - throw new NotImplementedException(); + Assert.IsNotNull( + new VariableDeclarationStatement { + Type = new MemberType { + Target = new MemberType { + Target = new SimpleType("global"), + IsDoubleColon = true, + MemberName = "System" + }, + IsDoubleColon = false, + MemberName = "String", + }, + Variables = { + new VariableInitializer("a") + } + }.Match(lvd) + ); } // TODO: add tests for aliases other than 'global' diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AnonymousMethodTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AnonymousMethodTests.cs index 90e68d807..a1d4e1a45 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AnonymousMethodTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AnonymousMethodTests.cs @@ -47,6 +47,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression public void SimpleAnonymousMethod() { AnonymousMethodExpression ame = Parse("delegate(int a, int b) { return a + b; }"); + Assert.IsTrue(ame.HasParameterList); Assert.AreEqual(2, ame.Parameters.Count()); Assert.AreEqual(1, ame.Body.Statements.Count()); Assert.IsTrue(ame.Body.Children.First() is ReturnStatement); diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayObjectCreateExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayObjectCreateExpressionTests.cs index e3173c8cd..fbe1af58e 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayObjectCreateExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayObjectCreateExpressionTests.cs @@ -6,31 +6,51 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture, Ignore("Needs to be ported to new NRefactory")] + [TestFixture] public class ArrayObjectCreateExpressionTests { [Test] public void ArrayCreateExpressionTest1() { - /* - ArrayCreateExpression ace = ParseUtilCSharp.ParseExpression("new int[5]"); - Assert.AreEqual("System.Int32", ace.CreateType.Type); - Assert.IsTrue(ace.CreateType.IsKeyword); - Assert.AreEqual(1, ace.Arguments.Count); - Assert.AreEqual(new int[] {0}, ace.CreateType.RankSpecifier); - */ - throw new NotImplementedException(); + ParseUtilCSharp.AssertExpression( + "new int[5]", + new ArrayCreateExpression { + Type = new PrimitiveType("int"), + Arguments = { new PrimitiveExpression(5) } + }); } - [Test] + [Test, Ignore("AdditionalArraySpecifiers not yet implemented")] + public void MultidimensionalNestedArray() + { + ParseUtilCSharp.AssertExpression( + "new int[5,2][,,][]", + new ArrayCreateExpression { + Type = new PrimitiveType("int"), + Arguments = { new PrimitiveExpression(5), new PrimitiveExpression(2) }, + AdditionalArraySpecifiers = { + new ArraySpecifier(3), + new ArraySpecifier(1) + } + }); + } + + [Test, Ignore("Array initializers not yet implemented")] public void ImplicitlyTypedArrayCreateExpression() { - /* - ArrayCreateExpression ace = ParseUtilCSharp.ParseExpression("new[] { 1, 10, 100, 1000 }"); - Assert.AreEqual("", ace.CreateType.Type); - Assert.AreEqual(0, ace.Arguments.Count); - Assert.AreEqual(4, ace.ArrayInitializer.CreateExpressions.Count);*/ - throw new NotImplementedException(); + ParseUtilCSharp.AssertExpression( + "new[] { 1, 10, 100, 1000 }", + new ArrayCreateExpression { + Initializer = new ArrayInitializerExpression { + Elements = { + new PrimitiveExpression(1), + new PrimitiveExpression(10), + new PrimitiveExpression(100), + new PrimitiveExpression(1000) + } + } + }); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/CastExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/CastExpressionTests.cs index 57604d083..54d8d8c8b 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/CastExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/CastExpressionTests.cs @@ -9,132 +9,157 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression [TestFixture, Ignore("Port unit tests to new DOM")] public class CastExpressionTests { - /* [Test] public void SimpleCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(MyObject)o"); - Assert.AreEqual("MyObject", ce.CastTo.Type); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(MyObject)o", + new CastExpression { + Type = new SimpleType("MyObject"), + Expression = new IdentifierExpression("o") + }); } [Test] public void ArrayCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(MyType[])o"); - Assert.AreEqual("MyType", ce.CastTo.Type); - Assert.AreEqual(new int[] { 0 }, ce.CastTo.RankSpecifier); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(MyType[])o", + new CastExpression { + Type = new SimpleType("MyType").MakeArrayType(1), + Expression = new IdentifierExpression("o") + }); } [Test] public void NullablePrimitiveCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(int?)o"); - Assert.AreEqual("System.Nullable", ce.CastTo.Type); - Assert.AreEqual("System.Int32", ce.CastTo.GenericTypes[0].Type); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(int?)o", + new CastExpression { + Type = new ComposedType { BaseType = new PrimitiveType("int"), HasNullableSpecifier = true }, + Expression = new IdentifierExpression("o") + }); } [Test] public void NullableCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(MyType?)o"); - Assert.AreEqual("System.Nullable", ce.CastTo.Type); - Assert.AreEqual("MyType", ce.CastTo.GenericTypes[0].Type); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(MyType?)o", + new CastExpression { + Type = new ComposedType { BaseType = new SimpleType("MyType"), HasNullableSpecifier = true }, + Expression = new IdentifierExpression("o") + }); } [Test] public void NullableTryCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("o as int?"); - Assert.AreEqual("System.Nullable", ce.CastTo.Type); - Assert.IsTrue(ce.CastTo.IsKeyword); - Assert.AreEqual("System.Int32", ce.CastTo.GenericTypes[0].Type); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.TryCast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "o as int?", + new AsExpression { + Type = new ComposedType { BaseType = new PrimitiveType("int"), HasNullableSpecifier = true }, + Expression = new IdentifierExpression("o") + }); } [Test] public void GenericCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(List)o"); - Assert.AreEqual("List", ce.CastTo.Type); - Assert.AreEqual("System.String", ce.CastTo.GenericTypes[0].Type); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(List)o", + new CastExpression { + Type = new SimpleType("List") { TypeArguments = { new PrimitiveType("string") } }, + Expression = new IdentifierExpression("o") + }); } [Test] public void GenericArrayCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(List[])o"); - Assert.AreEqual("List", ce.CastTo.Type); - Assert.AreEqual("System.String", ce.CastTo.GenericTypes[0].Type); - Assert.AreEqual(new int[] { 0 }, ce.CastTo.RankSpecifier); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(List[])o", + new CastExpression { + Type = new ComposedType { + BaseType = new SimpleType("List") { TypeArguments = { new PrimitiveType("string") } }, + ArraySpecifiers = { new ArraySpecifier(1) } + }, + Expression = new IdentifierExpression("o") + }); } [Test] public void GenericArrayAsCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("o as List[]"); - Assert.AreEqual("List", ce.CastTo.Type); - Assert.AreEqual("System.String", ce.CastTo.GenericTypes[0].Type); - Assert.AreEqual(new int[] { 0 }, ce.CastTo.RankSpecifier); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.TryCast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "o as List[]", + new AsExpression { + Type = new ComposedType { + BaseType = new SimpleType("List") { TypeArguments = { new PrimitiveType("string") } }, + ArraySpecifiers = { new ArraySpecifier(1) } + }, + Expression = new IdentifierExpression("o") + }); } [Test] public void CastMemberReferenceOnParenthesizedExpression() { - // yes, we really wanted to evaluate .Member on expr and THEN cast the result to MyType - CastExpression ce = ParseUtilCSharp.ParseExpression("(MyType)(expr).Member"); - Assert.AreEqual("MyType", ce.CastTo.Type); - Assert.IsTrue(ce.Expression is MemberReferenceExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + // yes, we really want to evaluate .Member on expr and THEN cast the result to MyType + ParseUtilCSharp.AssertExpression( + "(MyType)(expr).Member", + new CastExpression { + Type = new SimpleType("MyType"), + Expression = new ParenthesizedExpression { Expression = new IdentifierExpression("expr") }.Member("Member") + }); } [Test] public void TryCastParenthesizedExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(o) as string"); - Assert.AreEqual("System.String", ce.CastTo.ToString()); - Assert.IsTrue(ce.Expression is ParenthesizedExpression); - Assert.AreEqual(CastType.TryCast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(o) as string", + new AsExpression { + Expression = new ParenthesizedExpression { Expression = new IdentifierExpression("o") }, + Type = new PrimitiveType("string") + }); } [Test] public void CastNegation() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(uint)-negativeValue"); - Assert.AreEqual("System.UInt32", ce.CastTo.ToString()); - Assert.IsTrue(ce.Expression is UnaryOperatorExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(uint)-negativeValue", + new CastExpression { + Type = new PrimitiveType("uint"), + Expression = new UnaryOperatorExpression( + UnaryOperatorType.Minus, + new IdentifierExpression("negativeValue") + )}); } - */ [Test] public void SubtractionIsNotCast() { - BinaryOperatorExpression boe = ParseUtilCSharp.ParseExpression("(BigInt)-negativeValue"); - Assert.IsTrue(boe.Left is ParenthesizedExpression); - Assert.IsTrue(boe.Right is IdentifierExpression); + ParseUtilCSharp.AssertExpression( + "(BigInt)-negativeValue", + new BinaryOperatorExpression { + Left = new ParenthesizedExpression { Expression = new IdentifierExpression("BigInt") }, + Operator = BinaryOperatorType.Subtract, + Right = new IdentifierExpression("negativeValue") + }); } [Test] public void IntMaxValueToBigInt() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(BigInt)int.MaxValue"); - Assert.AreEqual("BigInt", ce.Type.ToString()); - Assert.IsTrue(ce.Expression is MemberReferenceExpression); + ParseUtilCSharp.AssertExpression( + "(BigInt)int.MaxValue", + new CastExpression { + Type = new SimpleType("BigInt"), + Expression = new PrimitiveExpression("int").Member("MaxValue") + }); } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/DefaultValueExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/DefaultValueExpressionTests.cs index 7419740ff..9c5296920 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/DefaultValueExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/DefaultValueExpressionTests.cs @@ -6,48 +6,74 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture, Ignore("tests need to be ported")] + [TestFixture, Ignore("Aliases not yet implemented")] public class DefaultValueExpressionTests { [Test] public void SimpleDefaultValue() { DefaultValueExpression toe = ParseUtilCSharp.ParseExpression("default(T)"); - Assert.AreEqual("T", toe.Type); + Assert.AreEqual("T", ((SimpleType)toe.Type).Identifier); } - /* [Test] public void FullQualifiedDefaultValue() { - DefaultValueExpression toe = ParseUtilCSharp.ParseExpression("default(global::MyNamespace.N1.MyType)"); - Assert.IsTrue(toe.TypeReference.IsGlobal); - Assert.AreEqual("MyNamespace.N1.MyType", toe.TypeReference.Type); + ParseUtilCSharp.AssertExpression( + "default(global::MyNamespace.N1.MyType)", + new DefaultValueExpression { + Type = new MemberType { + Target = new MemberType { + Target = new MemberType { + Target = new SimpleType("global"), + IsDoubleColon = true, + MemberName = "MyNamespace" + }, + MemberName = "N1" + }, + MemberName = "MyType" + } + }); } [Test] public void GenericDefaultValue() { - DefaultValueExpression toe = ParseUtilCSharp.ParseExpression("default(MyNamespace.N1.MyType)"); - Assert.AreEqual("MyNamespace.N1.MyType", toe.TypeReference.Type); - Assert.AreEqual("System.String", toe.TypeReference.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "default(MyNamespace.N1.MyType)", + new DefaultValueExpression { + Type = new MemberType { + Target = new MemberType { + Target = new SimpleType("MyNamespace"), + MemberName = "N1" + }, + MemberName = "MyType", + TypeArguments = { new PrimitiveType("string") } + } + }); } [Test] public void DefaultValueAsIntializer() { - // This test is failing because we need a resolver for the "default:" / "default(" conflict. - LocalVariableDeclaration lvd = ParseUtilCSharp.ParseStatement("T a = default(T);"); - DefaultValueExpression dve = (DefaultValueExpression)lvd.Variables[0].Initializer; - Assert.AreEqual("T", dve.TypeReference.Type); + // This test was problematic (in old NRefactory) because we need a resolver for the "default:" / "default(" conflict. + ParseUtilCSharp.AssertStatement( + "T a = default(T);", + new VariableDeclarationStatement { + Type = new SimpleType("T"), + Variables = { + new VariableInitializer("a", new DefaultValueExpression { Type = new SimpleType("T") }) + }}); } [Test] public void DefaultValueInReturnStatement() { - ReturnStatement rs = ParseUtilCSharp.ParseStatement("return default(T);"); - DefaultValueExpression dve = (DefaultValueExpression)rs.Expression; - Assert.AreEqual("T", dve.TypeReference.Type); - }*/ + ParseUtilCSharp.AssertStatement( + "return default(T);", + new ReturnStatement { + Expression = new DefaultValueExpression { Type = new SimpleType("T") } + }); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IdentifierExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IdentifierExpressionTests.cs index 6cd54f521..d79658eff 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IdentifierExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IdentifierExpressionTests.cs @@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression CheckIdentifier(@"l\U00000065xer", "lexer"); } - [Test] + [Test, Ignore("The @ should not be part of IdentifierExpression.Identifier")] public void TestKeyWordAsIdentifier() { CheckIdentifier("@int", "int"); @@ -51,28 +51,36 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression CheckIdentifier(@"i\u006et", "int"); } - [Test] + [Test, Ignore("The @ should not be part of IdentifierExpression.Identifier")] public void TestKeyWordAsIdentifierStartingWithUnderscore() { CheckIdentifier("@_int", "_int"); } - [Test, Ignore] + [Test] public void GenericMethodReference() { IdentifierExpression ident = ParseUtilCSharp.ParseExpression("M"); - Assert.AreEqual("M", ident.Identifier); - //Assert.AreEqual(1, ident.TypeArguments.Count); - throw new NotImplementedException(); + Assert.IsNotNull( + new IdentifierExpression { + Identifier = "M" , + TypeArguments = { + new PrimitiveType("int") + } + }.Match(ident)); } - [Test, Ignore] + [Test] public void GenericMethodReference2() { IdentifierExpression ident = ParseUtilCSharp.ParseExpression("TargetMethod"); - Assert.AreEqual("TargetMethod", ident.Identifier); - //Assert.AreEqual(1, ident.TypeArguments.Count); - throw new NotImplementedException(); + Assert.IsNotNull( + new IdentifierExpression { + Identifier = "TargetMethod" , + TypeArguments = { + new PrimitiveType("string") + } + }.Match(ident)); } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/InvocationExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/InvocationExpressionTests.cs index f3a39b6fd..73ad17502 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/InvocationExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/InvocationExpressionTests.cs @@ -7,7 +7,7 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture, Ignore("Port unit tests to new DOM")] + [TestFixture] public class InvocationExpressionTests { [Test] @@ -19,55 +19,71 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression Assert.AreEqual("myMethod", ((IdentifierExpression)ie.Target).Identifier); } - /* TODO port unit tests to new DOM [Test] public void GenericInvocationExpressionTest() { - var expr = ParseUtilCSharp.ParseExpression("myMethod('a')"); - Assert.AreEqual(1, expr.Arguments.Count()); - Assert.IsTrue(expr.TargetObject is IdentifierExpression); - IdentifierExpression ident = (IdentifierExpression)expr.TargetObject; - Assert.AreEqual("myMethod", ident.Identifier); - Assert.AreEqual(1, ident.TypeArguments.Count); - Assert.AreEqual("System.Char", ident.TypeArguments[0].Type); + ParseUtilCSharp.AssertExpression( + "myMethod('a')", + new InvocationExpression { + Target = new IdentifierExpression { + Identifier = "myMethod", + TypeArguments = { new PrimitiveType("char") } + }, + Arguments = { new PrimitiveExpression('a') } + } + ); } [Test] public void GenericInvocation2ExpressionTest() { - var expr = ParseUtilCSharp.ParseExpression("myMethod()"); - Assert.AreEqual(0, expr.Arguments.Count); - Assert.IsTrue(expr.TargetObject is IdentifierExpression); - IdentifierExpression ident = (IdentifierExpression)expr.TargetObject; - Assert.AreEqual("myMethod", ident.Identifier); - Assert.AreEqual(2, ident.TypeArguments.Count); - Assert.AreEqual("T", ident.TypeArguments[0].Type); - Assert.IsFalse(ident.TypeArguments[0].IsKeyword); - Assert.AreEqual("System.Boolean", ident.TypeArguments[1].Type); - Assert.IsTrue(ident.TypeArguments[1].IsKeyword); + ParseUtilCSharp.AssertExpression( + "myMethod()", + new InvocationExpression { + Target = new IdentifierExpression { + Identifier = "myMethod", + TypeArguments = { + new SimpleType("T"), + new PrimitiveType("bool") + } + } + } + ); } [Test] public void AmbiguousGrammarGenericMethodCall() { - InvocationExpression ie = ParseUtilCSharp.ParseExpression("F(G(7))"); - Assert.IsTrue(ie.TargetObject is IdentifierExpression); - Assert.AreEqual(1, ie.Arguments.Count); - ie = (InvocationExpression)ie.Arguments[0]; - Assert.AreEqual(1, ie.Arguments.Count); - Assert.IsTrue(ie.Arguments[0] is PrimitiveExpression); - IdentifierExpression ident = (IdentifierExpression)ie.TargetObject; - Assert.AreEqual("G", ident.Identifier); - Assert.AreEqual(2, ident.TypeArguments.Count); + ParseUtilCSharp.AssertExpression( + "F(G(7))", + new InvocationExpression { + Target = new IdentifierExpression("F"), + Arguments = { + new InvocationExpression { + Target = new IdentifierExpression { + Identifier = "G", + TypeArguments = { new SimpleType("A"), new SimpleType("B") } + }, + Arguments = { new PrimitiveExpression(7) } + }}}); } - [Test] + [Test, Ignore("Mono Parser Bug???")] public void AmbiguousGrammarNotAGenericMethodCall() { - BinaryOperatorExpression boe = ParseUtilCSharp.ParseExpression("F+y"); - Assert.AreEqual(BinaryOperatorType.GreaterThan, boe.Op); - Assert.IsTrue(boe.Left is BinaryOperatorExpression); - Assert.IsTrue(boe.Right is UnaryOperatorExpression); + ParseUtilCSharp.AssertExpression( + "F+y", + new BinaryOperatorExpression { + Left = new BinaryOperatorExpression { + Left = new IdentifierExpression("F"), + Operator = BinaryOperatorType.LessThan, + Right = new IdentifierExpression("A") + }, + Operator = BinaryOperatorType.GreaterThan, + Right = new UnaryOperatorExpression { + Operator = UnaryOperatorType.Plus, + Expression = new IdentifierExpression("y") + }}); } [Test] @@ -76,80 +92,81 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression // this test was written because this bug caused the AbstractASTVisitor to crash InvocationExpression expr = ParseUtilCSharp.ParseExpression("WriteLine(myMethod(,))", true); - Assert.IsTrue(expr.TargetObject is IdentifierExpression); - Assert.AreEqual("WriteLine", ((IdentifierExpression)expr.TargetObject).Identifier); + Assert.IsTrue(expr.Target is IdentifierExpression); + Assert.AreEqual("WriteLine", ((IdentifierExpression)expr.Target).Identifier); Assert.AreEqual(1, expr.Arguments.Count); // here a second null parameter was added incorrectly - Assert.IsTrue(expr.Arguments[0] is InvocationExpression); - CheckSimpleInvoke((InvocationExpression)expr.Arguments[0]); + Assert.IsTrue(expr.Arguments.Single() is InvocationExpression); } - [Test] + [Test, Ignore("Positions not yet accurate when parsing expression only (because class/method is added around it)")] public void NestedInvocationPositions() { InvocationExpression expr = ParseUtilCSharp.ParseExpression("a.B().C(args)"); - Assert.AreEqual(new Location(8, 1), expr.StartLocation); - Assert.AreEqual(new Location(14, 1), expr.EndLocation); - MemberReferenceExpression mre = (MemberReferenceExpression)expr.TargetObject; - Assert.AreEqual(new Location(6, 1), mre.StartLocation); - Assert.AreEqual(new Location(8, 1), mre.EndLocation); + Assert.AreEqual(new AstLocation(1, 8), expr.StartLocation); + Assert.AreEqual(new AstLocation(1, 14), expr.EndLocation); + MemberReferenceExpression mre = (MemberReferenceExpression)expr.Target; + Assert.AreEqual(new AstLocation(1, 6), mre.StartLocation); + Assert.AreEqual(new AstLocation(1, 8), mre.EndLocation); - Assert.AreEqual(new Location(4, 1), mre.TargetObject.StartLocation); - Assert.AreEqual(new Location(6, 1), mre.TargetObject.EndLocation); + Assert.AreEqual(new AstLocation(1, 4), mre.Target.StartLocation); + Assert.AreEqual(new AstLocation(1, 6), mre.Target.EndLocation); } [Test] public void InvocationOnGenericType() { - InvocationExpression expr = ParseUtilCSharp.ParseExpression("A.Foo()"); - MemberReferenceExpression mre = (MemberReferenceExpression)expr.TargetObject; - Assert.AreEqual("Foo", mre.MemberName); - TypeReferenceExpression tre = (TypeReferenceExpression)mre.TargetObject; - Assert.AreEqual("A", tre.TypeReference.Type); - Assert.AreEqual("T", tre.TypeReference.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "A.Foo()", + new IdentifierExpression { + Identifier = "A", + TypeArguments = { new SimpleType("T") } + }.Invoke("Foo") + ); } [Test] public void InvocationOnInnerClassInGenericType() { - InvocationExpression expr = ParseUtilCSharp.ParseExpression("A.B.Foo()"); - MemberReferenceExpression mre = (MemberReferenceExpression)expr.TargetObject; - Assert.AreEqual("Foo", mre.MemberName); - MemberReferenceExpression mre2 = (MemberReferenceExpression)mre.TargetObject; - Assert.AreEqual("B", mre2.MemberName); - TypeReferenceExpression tre = (TypeReferenceExpression)mre2.TargetObject; - Assert.AreEqual("A", tre.TypeReference.Type); - Assert.AreEqual("T", tre.TypeReference.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "A.B.Foo()", + new IdentifierExpression { + Identifier = "A", + TypeArguments = { new SimpleType("T") } + }.Member("B").Invoke("Foo") + ); } [Test] public void InvocationOnGenericInnerClassInGenericType() { - InvocationExpression expr = ParseUtilCSharp.ParseExpression("A.B.C.Foo()"); - MemberReferenceExpression mre = (MemberReferenceExpression)expr.TargetObject; - Assert.AreEqual("Foo", mre.MemberName); - TypeReferenceExpression tre = (TypeReferenceExpression)mre.TargetObject; - InnerClassTypeReference ictr = (InnerClassTypeReference)tre.TypeReference; - Assert.AreEqual("B.C", ictr.Type); - Assert.AreEqual(1, ictr.GenericTypes.Count); - Assert.AreEqual("U", ictr.GenericTypes[0].Type); - - Assert.AreEqual("A", ictr.BaseType.Type); - Assert.AreEqual(1, ictr.BaseType.GenericTypes.Count); - Assert.AreEqual("T", ictr.BaseType.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "A.B.C.Foo()", + new MemberReferenceExpression { + Target = new IdentifierExpression { + Identifier = "A", + TypeArguments = { new SimpleType("T") } + }.Member("B"), + MemberName = "C", + TypeArguments = { new SimpleType("U") } + }.Invoke("Foo")); } - [Test] + [Test, Ignore("named arguments not yet supported")] public void InvocationWithNamedArgument() { - InvocationExpression expr = ParseUtilCSharp.ParseExpression("a(arg: ref v)"); - Assert.AreEqual(1, expr.Arguments.Count); - NamedArgumentExpression nae = (NamedArgumentExpression)expr.Arguments[0]; - Assert.AreEqual("arg", nae.Name); - DirectionExpression dir = (DirectionExpression)nae.Expression; - Assert.AreEqual(FieldDirection.Ref, dir.FieldDirection); - Assert.IsInstanceOf(dir.Expression); - }*/ + ParseUtilCSharp.AssertExpression( + "a(arg: ref v)", + new InvocationExpression { + Target = new IdentifierExpression("a"), + Arguments = { + new NamedArgumentExpression { + Identifier = "arg", + Expression = new DirectionExpression { + FieldDirection = FieldDirection.Ref, + Expression = new IdentifierExpression("v") + }}}}); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IsExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IsExpressionTests.cs index 4b5039565..bbab99a6f 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IsExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IsExpressionTests.cs @@ -9,15 +9,16 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression [TestFixture] public class IsExpressionTests { - [Test, Ignore] + [Test] public void GenericArrayIsExpression() { - /* TODO - TypeOfIsExpression ce = ParseUtilCSharp.ParseExpression("o is List[]"); - Assert.AreEqual("List", ce.TypeReference.Type); - Assert.AreEqual("System.String", ce.TypeReference.GenericTypes[0].Type); - Assert.AreEqual(new int[] { 0 }, ce.TypeReference.RankSpecifier); - Assert.IsTrue(ce.Expression is IdentifierExpression);*/ + ParseUtilCSharp.AssertExpression( + "o is List[]", + new IsExpression { + Expression = new IdentifierExpression("o"), + Type = new SimpleType("List") { TypeArguments = { new PrimitiveType("string") } }.MakeArrayType(1) + } + ); } [Test] diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/LambdaExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/LambdaExpressionTests.cs index 5f4addd3e..8350a6756 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/LambdaExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/LambdaExpressionTests.cs @@ -6,84 +6,103 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture, Ignore("Port unit tests")] + [TestFixture] public class LambdaExpressionTests { - static LambdaExpression ParseCSharp(string program) - { - return ParseUtilCSharp.ParseExpression(program); - } - - [Test] + [Test, Ignore("Lambdas with expression body not yet supported")] public void ImplicitlyTypedExpressionBody() { - /* - LambdaExpression e = ParseCSharp("(x) => x + 1"); - Assert.AreEqual("x", e.Parameters[0].ParameterName); - Assert.IsTrue(e.Parameters[0].TypeReference.IsNull); - Assert.IsTrue(e.ExpressionBody is BinaryOperatorExpression); - Assert.IsTrue(e.ReturnType.IsNull);*/ - throw new NotImplementedException(); + ParseUtilCSharp.AssertExpression( + "(x) => x + 1", + new LambdaExpression { + Parameters = { new ParameterDeclaration { Name = "x" } }, + Body = new BinaryOperatorExpression(new IdentifierExpression("x"), BinaryOperatorType.Add, new PrimitiveExpression(1)) + }); } - /* TODO Port unit tests - [Test] + [Test, Ignore("Lambdas with expression body not yet supported")] public void ImplicitlyTypedExpressionBodyWithoutParenthesis() { - LambdaExpression e = ParseCSharp("x => x + 1"); - Assert.AreEqual("x", e.Parameters[0].ParameterName); - Assert.IsTrue(e.Parameters[0].TypeReference.IsNull); - Assert.IsTrue(e.ExpressionBody is BinaryOperatorExpression); - Assert.IsTrue(e.ReturnType.IsNull); + ParseUtilCSharp.AssertExpression( + "x => x + 1", + new LambdaExpression { + Parameters = { new ParameterDeclaration { Name = "x" } }, + Body = new BinaryOperatorExpression(new IdentifierExpression("x"), BinaryOperatorType.Add, new PrimitiveExpression(1)) + }); } [Test] public void ImplicitlyTypedStatementBody() { - LambdaExpression e = ParseCSharp("(x) => { return x + 1; }"); - Assert.AreEqual("x", e.Parameters[0].ParameterName); - Assert.IsTrue(e.Parameters[0].TypeReference.IsNull); - Assert.IsTrue(e.StatementBody.Children[0] is ReturnStatement); - Assert.IsTrue(e.ReturnType.IsNull); + ParseUtilCSharp.AssertExpression( + "(x) => { return x + 1; }", + new LambdaExpression { + Parameters = { new ParameterDeclaration { Name = "x" } }, + Body = new BlockStatement { + new ReturnStatement { + Expression = new BinaryOperatorExpression( + new IdentifierExpression("x"), BinaryOperatorType.Add, new PrimitiveExpression(1)) + }}}); } [Test] public void ImplicitlyTypedStatementBodyWithoutParenthesis() { - LambdaExpression e = ParseCSharp("x => { return x + 1; }"); - Assert.AreEqual("x", e.Parameters[0].ParameterName); - Assert.IsTrue(e.Parameters[0].TypeReference.IsNull); - Assert.IsTrue(e.StatementBody.Children[0] is ReturnStatement); - Assert.IsTrue(e.ReturnType.IsNull); + ParseUtilCSharp.AssertExpression( + "x => { return x + 1; }", + new LambdaExpression { + Parameters = { new ParameterDeclaration { Name = "x" } }, + Body = new BlockStatement { + new ReturnStatement { + Expression = new BinaryOperatorExpression( + new IdentifierExpression("x"), BinaryOperatorType.Add, new PrimitiveExpression(1)) + }}}); } [Test] public void ExplicitlyTypedStatementBody() { - LambdaExpression e = ParseCSharp("(int x) => { return x + 1; }"); - Assert.AreEqual("x", e.Parameters[0].ParameterName); - Assert.AreEqual("System.Int32", e.Parameters[0].TypeReference.Type); - Assert.IsTrue(e.StatementBody.Children[0] is ReturnStatement); - Assert.IsTrue(e.ReturnType.IsNull); + ParseUtilCSharp.AssertExpression( + "(int x) => { return x + 1; }", + new LambdaExpression { + Parameters = { new ParameterDeclaration { Type = new PrimitiveType("int"), Name = "x" } }, + Body = new BlockStatement { + new ReturnStatement { + Expression = new BinaryOperatorExpression( + new IdentifierExpression("x"), BinaryOperatorType.Add, new PrimitiveExpression(1)) + }}}); } - [Test] - public void ExplicitlyTypedStatementBodyWithRefParameter() + [Test, Ignore("Lambdas with expression body not yet supported")] + public void ExplicitlyTypedWithRefParameter() { - LambdaExpression e = ParseCSharp("(ref int i) => i = 1"); - Assert.AreEqual("i", e.Parameters[0].ParameterName); - Assert.IsTrue((e.Parameters[0].ParamModifier & ParameterModifiers.Ref) == ParameterModifiers.Ref); - Assert.AreEqual("System.Int32", e.Parameters[0].TypeReference.Type); - Assert.IsTrue(e.ReturnType.IsNull); + ParseUtilCSharp.AssertExpression( + "(ref int i) => i = 1", + new LambdaExpression { + Parameters = { + new ParameterDeclaration { + ParameterModifier = ParameterModifier.Ref, + Type = new PrimitiveType("int"), + Name = "x" + } + }, + Body = new AssignmentExpression(new IdentifierExpression("i"), new PrimitiveExpression(1)) + }); } - [Test] + [Test, Ignore("Lambdas with expression body not yet supported")] public void LambdaExpressionContainingConditionalExpression() { - LambdaExpression e = ParseCSharp("rr => rr != null ? rr.ResolvedType : null"); - Assert.AreEqual("rr", e.Parameters[0].ParameterName); - Assert.IsTrue(e.ExpressionBody is ConditionalExpression); - Assert.IsTrue(e.ReturnType.IsNull); - }*/ + ParseUtilCSharp.AssertExpression( + "rr => rr != null ? rr.ResolvedType : null", + new LambdaExpression { + Parameters = { new ParameterDeclaration { Name = "rr" } }, + Body = new ConditionalExpression { + Condition = new BinaryOperatorExpression( + new IdentifierExpression("rr"), BinaryOperatorType.InEquality, new NullReferenceExpression()), + TrueExpression = new IdentifierExpression("rr").Member("ResolvedType"), + FalseExpression = new NullReferenceExpression() + }}); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/MemberReferenceExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/MemberReferenceExpressionTests.cs index 3f9ce69eb..960b53355 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/MemberReferenceExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/MemberReferenceExpressionTests.cs @@ -6,71 +6,84 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture, Ignore] + [TestFixture] public class MemberReferenceExpressionTests { [Test] public void SimpleFieldReferenceExpressionTest() { - MemberReferenceExpression fre = ParseUtilCSharp.ParseExpression("myTargetObject.myField"); - //Assert.AreEqual("myField", fre.MemberName); - //Assert.IsTrue(fre.TargetObject is IdentifierExpression); - //Assert.AreEqual("myTargetObject", ((IdentifierExpression)fre.TargetObject).Identifier); - throw new NotImplementedException(); + ParseUtilCSharp.AssertExpression( + "myTargetObject.myField", + new IdentifierExpression("myTargetObject").Member("myField") + ); + } + + [Test, Ignore("parser is broken and produces IdentifierExpression instead of PrimitiveType")] + public void ShortMaxValueTest() + { + ParseUtilCSharp.AssertExpression( + "short.MaxValue", + new PrimitiveType("short").Member("MaxValue") + ); + } + + [Test, Ignore("Parsing of @-identifiers is broken")] + public void IdentShortMaxValueTest() + { + ParseUtilCSharp.AssertExpression( + "@short.MaxValue", + new IdentifierExpression("short").Member("MaxValue") + ); } - /* TODO port unit tests [Test] public void GenericFieldReferenceExpressionTest() { - MemberReferenceExpression fre = ParseUtilCSharp.ParseExpression("SomeClass.myField"); - Assert.AreEqual("myField", fre.MemberName); - Assert.IsTrue(fre.TargetObject is TypeReferenceExpression); - TypeReference tr = ((TypeReferenceExpression)fre.TargetObject).TypeReference; - Assert.AreEqual("SomeClass", tr.Type); - Assert.AreEqual(1, tr.GenericTypes.Count); - Assert.AreEqual("System.String", tr.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "SomeClass.myField", + new IdentifierExpression("SomeClass") { TypeArguments = { new PrimitiveType("string") } }.Member("myField") + ); } [Test] public void FullNamespaceGenericFieldReferenceExpressionTest() { - MemberReferenceExpression fre = ParseUtilCSharp.ParseExpression("Namespace.Subnamespace.SomeClass.myField"); - Assert.AreEqual("myField", fre.MemberName); - Assert.IsTrue(fre.TargetObject is TypeReferenceExpression); - TypeReference tr = ((TypeReferenceExpression)fre.TargetObject).TypeReference; - Assert.AreEqual("Namespace.Subnamespace.SomeClass", tr.Type); - Assert.AreEqual(1, tr.GenericTypes.Count); - Assert.AreEqual("System.String", tr.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "Namespace.Subnamespace.SomeClass.myField", + new MemberReferenceExpression { + Target = new IdentifierExpression("Namespace").Member("Subnamespace"), + TypeArguments = { new PrimitiveType("string") } + }.Member("myField") + ); } - [Test] + [Test, Ignore("Aliases not yet implemented")] public void GlobalFullNamespaceGenericFieldReferenceExpressionTest() { - MemberReferenceExpression fre = ParseUtilCSharp.ParseExpression("global::Namespace.Subnamespace.SomeClass.myField"); - Assert.AreEqual("myField", fre.MemberName); - Assert.IsTrue(fre.TargetObject is TypeReferenceExpression); - TypeReference tr = ((TypeReferenceExpression)fre.TargetObject).TypeReference; - Assert.IsFalse(tr is InnerClassTypeReference); - Assert.AreEqual("Namespace.Subnamespace.SomeClass", tr.Type); - Assert.AreEqual(1, tr.GenericTypes.Count); - Assert.AreEqual("System.String", tr.GenericTypes[0].Type); - Assert.IsTrue(tr.IsGlobal); + ParseUtilCSharp.AssertExpression( + "global::Namespace.Subnamespace.SomeClass.myField", + new MemberReferenceExpression { + Target = new MemberType { + Target = new SimpleType("global"), + IsDoubleColon = true, + MemberName = "Namespace" + }.Member("Subnamespace"), + TypeArguments = { new PrimitiveType("string") } + }.Member("myField") + ); } [Test] public void NestedGenericFieldReferenceExpressionTest() { - MemberReferenceExpression fre = ParseUtilCSharp.ParseExpression("MyType.InnerClass.myField"); - Assert.AreEqual("myField", fre.MemberName); - Assert.IsTrue(fre.TargetObject is TypeReferenceExpression); - InnerClassTypeReference ic = (InnerClassTypeReference)((TypeReferenceExpression)fre.TargetObject).TypeReference; - Assert.AreEqual("InnerClass", ic.Type); - Assert.AreEqual(1, ic.GenericTypes.Count); - Assert.AreEqual("System.Int32", ic.GenericTypes[0].Type); - Assert.AreEqual("MyType", ic.BaseType.Type); - Assert.AreEqual(1, ic.BaseType.GenericTypes.Count); - Assert.AreEqual("System.String", ic.BaseType.GenericTypes[0].Type); - }*/ + ParseUtilCSharp.AssertExpression( + "MyType.InnerClass.myField", + new MemberReferenceExpression { + Target = new IdentifierExpression("MyType") { TypeArguments = { new PrimitiveType("string") } }, + MemberName = "InnerClass", + TypeArguments = { new PrimitiveType("int") } + }.Member("myField") + ); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PointerReferenceExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PointerReferenceExpressionTests.cs index f02c795e2..895ffff4c 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PointerReferenceExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PointerReferenceExpressionTests.cs @@ -9,13 +9,25 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression [TestFixture] public class PointerReferenceExpressionTests { - [Test, Ignore("where did PointerReferenceExpression.MemberName go?")] + [Test, Ignore("Parser bug!")] public void PointerReferenceExpressionTest() { PointerReferenceExpression pre = ParseUtilCSharp.ParseExpression("myObj.field->b"); Assert.IsTrue(pre.Target is MemberReferenceExpression); - //Assert.AreEqual("b", pre.MemberName); - throw new NotImplementedException(); + Assert.AreEqual("b", pre.MemberName); + } + + [Test, Ignore("Parser bug!")] + public void PointerReferenceGenericMethodTest() + { + ParseUtilCSharp.AssertExpression( + "ptr->M();", + new InvocationExpression { + Target = new PointerReferenceExpression { + Target = new IdentifierExpression("ptr"), + MemberName = "M", + TypeArguments = { new PrimitiveType("string") } + }}); } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/QueryExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/QueryExpressionTests.cs index 7b1d18e03..5601797c9 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/QueryExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/QueryExpressionTests.cs @@ -6,104 +6,220 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture, Ignore] + [TestFixture, Ignore("Query expressions not yet implemented")] public class QueryExpressionTests { [Test] public void SimpleExpression() { - /* - QueryExpression qe = ParseUtilCSharp.ParseExpression( - "from c in customers where c.City == \"London\" select c" - ); - Assert.AreEqual("c", qe.FromClause.Sources.First().Identifier); - Assert.AreEqual("customers", ((IdentifierExpression)qe.FromClause.Sources.First().Expression).Identifier); - Assert.AreEqual(1, qe.MiddleClauses.Count); - Assert.IsInstanceOf(typeof(QueryExpressionWhereClause), qe.MiddleClauses[0]); - QueryExpressionWhereClause wc = (QueryExpressionWhereClause)qe.MiddleClauses[0]; - Assert.IsInstanceOf(typeof(BinaryOperatorExpression), wc.Condition); - Assert.IsInstanceOf(typeof(QueryExpressionSelectClause), qe.SelectOrGroupClause);*/ - throw new NotImplementedException(); + ParseUtilCSharp.AssertExpression( + "from c in customers where c.City == \"London\" select c", + new QueryExpression { + Clauses = { + new QueryFromClause { + Identifier = "c", + Expression = new IdentifierExpression("customers") + }, + new QueryWhereClause { + Condition = new BinaryOperatorExpression { + Left = new IdentifierExpression("c").Member("City"), + Operator = BinaryOperatorType.Equality, + Right = new PrimitiveExpression("London") + } + }, + new QuerySelectClause { + Expression = new IdentifierExpression("c") + } + }}); } - /* TODO port unit tests [Test] public void ExpressionWithType1() { - QueryExpression qe = ParseUtilCSharp.ParseExpression( - "from Customer c in customers select c" - ); - Assert.AreEqual("c", qe.FromClause.Sources.First().Identifier); - Assert.AreEqual("Customer", qe.FromClause.Sources.First().Type.ToString()); - Assert.AreEqual("customers", ((IdentifierExpression)qe.FromClause.Sources.First().Expression).Identifier); - Assert.IsInstanceOf(typeof(QueryExpressionSelectClause), qe.SelectOrGroupClause); + ParseUtilCSharp.AssertExpression( + "from Customer c in customers select c", + new QueryExpression { + Clauses = { + new QueryFromClause { + Type = new SimpleType("Customer"), + Identifier = "c", + Expression = new IdentifierExpression("customers") + }, + new QuerySelectClause { + Expression = new IdentifierExpression("c") + } + }}); } [Test] public void ExpressionWithType2() { - QueryExpression qe = ParseUtilCSharp.ParseExpression( - "from int c in customers select c" - ); - Assert.AreEqual("c", qe.FromClause.Sources.First().Identifier); - Assert.AreEqual("System.Int32", qe.FromClause.Sources.First().Type.Type); - Assert.AreEqual("customers", ((IdentifierExpression)qe.FromClause.Sources.First().Expression).Identifier); - Assert.IsInstanceOf(typeof(QueryExpressionSelectClause), qe.SelectOrGroupClause); + ParseUtilCSharp.AssertExpression( + "from int c in customers select c", + new QueryExpression { + Clauses = { + new QueryFromClause { + Type = new PrimitiveType("int"), + Identifier = "c", + Expression = new IdentifierExpression("customers") + }, + new QuerySelectClause { + Expression = new IdentifierExpression("c") + } + }}); } [Test] public void ExpressionWithType3() { - QueryExpression qe = ParseUtilCSharp.ParseExpression( - "from S? c in customers select c" - ); - Assert.AreEqual("c", qe.FromClause.Sources.First().Identifier); - Assert.AreEqual("System.Nullable>", qe.FromClause.Sources.First().Type.ToString()); - Assert.AreEqual("customers", ((IdentifierExpression)qe.FromClause.Sources.First().Expression).Identifier); - Assert.IsInstanceOf(typeof(QueryExpressionSelectClause), qe.SelectOrGroupClause); + ParseUtilCSharp.AssertExpression( + "from S? c in customers select c", + new QueryExpression { + Clauses = { + new QueryFromClause { + Type = new ComposedType { + BaseType = new SimpleType { + Identifier = "S", + TypeArguments = { + new PrimitiveType("int").MakeArrayType() + } + }, + HasNullableSpecifier = true + }, + Identifier = "c", + Expression = new IdentifierExpression("customers") + }, + new QuerySelectClause { + Expression = new IdentifierExpression("c") + } + }}); } [Test] public void MultipleGenerators() { - QueryExpression qe = ParseUtilCSharp.ParseExpression(@" + ParseUtilCSharp.AssertExpression( + @" from c in customers where c.City == ""London"" from o in c.Orders where o.OrderDate.Year == 2005 -select new { c.Name, o.OrderID, o.Total }"); - Assert.AreEqual(3, qe.MiddleClauses.Count); - Assert.IsInstanceOf(typeof(QueryExpressionWhereClause), qe.MiddleClauses[0]); - Assert.IsInstanceOf(typeof(QueryExpressionFromClause), qe.MiddleClauses[1]); - Assert.IsInstanceOf(typeof(QueryExpressionWhereClause), qe.MiddleClauses[2]); - - Assert.IsInstanceOf(typeof(QueryExpressionSelectClause), qe.SelectOrGroupClause); +select new { c.Name, o.OrderID, o.Total }", + new QueryExpression { + Clauses = { + new QueryFromClause { + Identifier = "c", + Expression = new IdentifierExpression("customers") + }, + new QueryWhereClause { + Condition = new BinaryOperatorExpression { + Left = new IdentifierExpression("c").Member("City"), + Operator = BinaryOperatorType.Equality, + Right = new PrimitiveExpression("London") + } + }, + new QueryFromClause { + Identifier = "o", + Expression = new IdentifierExpression("c").Member("Orders") + }, + new QueryWhereClause { + Condition = new BinaryOperatorExpression { + Left = new IdentifierExpression("c").Member("OrderDate").Member("Year"), + Operator = BinaryOperatorType.Equality, + Right = new PrimitiveExpression(2005) + } + }, + new QuerySelectClause { + Expression = new ObjectCreateExpression { + Initializer = new ArrayInitializerExpression { + Elements = { + new IdentifierExpression("c").Member("Name"), + new IdentifierExpression("o").Member("OrderID"), + new IdentifierExpression("o").Member("Total") + } + } + } + } + }}); } [Test] public void ExpressionWithOrderBy() { - QueryExpression qe = ParseUtilCSharp.ParseExpression( - "from c in customers orderby c.Name select c" - ); - Assert.AreEqual("c", qe.FromClause.Sources.First().Identifier); - Assert.AreEqual("customers", ((IdentifierExpression)qe.FromClause.Sources.First().Expression).Identifier); - Assert.IsInstanceOf(typeof(QueryExpressionOrderClause), qe.MiddleClauses[0]); - Assert.IsInstanceOf(typeof(QueryExpressionSelectClause), qe.SelectOrGroupClause); + ParseUtilCSharp.AssertExpression( + "from c in customers orderby c.Name select c", + new QueryExpression { + Clauses = { + new QueryFromClause { + Identifier = "c", + Expression = new IdentifierExpression("customers") + }, + new QueryOrderClause { + Orderings = { + new QueryOrdering { + Expression = new IdentifierExpression("c").Member("Name") + } + } + }, + new QuerySelectClause { + Expression = new IdentifierExpression("c") + } + }}); } [Test] public void ExpressionWithOrderByAndLet() { - QueryExpression qe = ParseUtilCSharp.ParseExpression( - "from c in customers orderby c.Name let x = c select x" + ParseUtilCSharp.AssertExpression( + "from c in customers orderby c.Name descending let x = c select x", + new QueryExpression { + Clauses = { + new QueryFromClause { + Identifier = "c", + Expression = new IdentifierExpression("customers") + }, + new QueryOrderClause { + Orderings = { + new QueryOrdering { + Expression = new IdentifierExpression("c").Member("Name"), + Direction = QueryOrderingDirection.Descending + } + } + }, + new QueryLetClause { + Identifier = "x", + Expression = new IdentifierExpression("c") + }, + new QuerySelectClause { + Expression = new IdentifierExpression("x") + } + }}); + } + + [Test] + public void QueryContinuation() + { + ParseUtilCSharp.AssertExpression( + "from a in b select c into d select e", + new QueryExpression { + Clauses = { + new QueryContinuationClause { + PrecedingQuery = new QueryExpression { + Clauses = { + new QueryFromClause { + Identifier = "a", + Expression = new IdentifierExpression("b") + }, + new QuerySelectClause { Expression = new IdentifierExpression("c") } + } + }, + Identifier = "d" + }, + new QuerySelectClause { Expression = new IdentifierExpression("e") } + } + } ); - Assert.AreEqual("c", qe.FromClause.Sources.First().Identifier); - Assert.AreEqual("customers", ((IdentifierExpression)qe.FromClause.Sources.First().Expression).Identifier); - Assert.IsInstanceOf(typeof(QueryExpressionOrderClause), qe.MiddleClauses[0]); - Assert.IsInstanceOf(typeof(QueryExpressionLetClause), qe.MiddleClauses[1]); - Assert.IsInstanceOf(typeof(QueryExpressionSelectClause), qe.SelectOrGroupClause); - }*/ + } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/SizeOfExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/SizeOfExpressionTests.cs index a50c1b77f..f6a85fcb3 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/SizeOfExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/SizeOfExpressionTests.cs @@ -9,11 +9,11 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression [TestFixture] public class SizeOfExpressionTests { - [Test, Ignore("type references not implemented yet")] + [Test] public void SizeOfExpressionTest() { SizeOfExpression soe = ParseUtilCSharp.ParseExpression("sizeof(MyType)"); - Assert.AreEqual("MyType", soe.Type); + Assert.AreEqual("MyType", ((SimpleType)soe.Type).Identifier); } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/StackAllocExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/StackAllocExpressionTests.cs index 038925a42..c28d559fc 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/StackAllocExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/StackAllocExpressionTests.cs @@ -2,6 +2,7 @@ // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; +using System.Linq; using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression @@ -9,11 +10,13 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression [TestFixture] public class StackAllocExpressionTests { - [Test, Ignore] + [Test] public void StackAllocExpressionTest() { - var sae = ParseUtilCSharp.ParseExpression("stackalloc int[100]"); - throw new NotImplementedException(); // TODO: verify type + length expression + var vd = ParseUtilCSharp.ParseStatement("int* a = stackalloc int[100];"); + StackAllocExpression sae = (StackAllocExpression)vd.Variables.Single().Initializer; + Assert.AreEqual("int", ((PrimitiveType)sae.Type).Keyword); + Assert.AreEqual(100, ((PrimitiveExpression)sae.CountExpression).Value); } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/TypeOfExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/TypeOfExpressionTests.cs index 599aae19f..3dcc932d9 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/TypeOfExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/TypeOfExpressionTests.cs @@ -6,86 +6,113 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture, Ignore] + [TestFixture] public class TypeOfExpressionTests { [Test] public void SimpleTypeOfExpressionTest() { - //TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(MyNamespace.N1.MyType)"); - //Assert.AreEqual("MyNamespace.N1.MyType", toe.TypeReference.Type); - throw new NotImplementedException(); + ParseUtilCSharp.AssertExpression( + "typeof(MyNamespace.N1.MyType)", + new TypeOfExpression { + Type = new MemberType { + Target = new MemberType { + Target = new SimpleType("MyNamespace"), + MemberName = "N1" + }, + MemberName = "MyType" + }}); } - /* TODO - [Test] + [Test, Ignore("Aliases not yet implemented")] public void GlobalTypeOfExpressionTest() { - TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(global::System.Console)"); - Assert.AreEqual("System.Console", toe.TypeReference.Type); + ParseUtilCSharp.AssertExpression( + "typeof(global::System.Console)", + new TypeOfExpression { + Type = new MemberType { + Target = new MemberType { + Target = new SimpleType("global"), + IsDoubleColon = true, + MemberName = "System" + }, + MemberName = "Console" + }}); } [Test] public void PrimitiveTypeOfExpressionTest() { TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(int)"); - Assert.AreEqual("System.Int32", toe.TypeReference.Type); + Assert.AreEqual("int", ((PrimitiveType)toe.Type).Keyword); } [Test] public void VoidTypeOfExpressionTest() { TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(void)"); - Assert.AreEqual("System.Void", toe.TypeReference.Type); + Assert.AreEqual("void", ((PrimitiveType)toe.Type).Keyword); } [Test] public void ArrayTypeOfExpressionTest() { - TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(MyType[])"); - Assert.AreEqual("MyType", toe.TypeReference.Type); - Assert.AreEqual(new int[] {0}, toe.TypeReference.RankSpecifier); + ParseUtilCSharp.AssertExpression( + "typeof(MyType[])", + new TypeOfExpression { + Type = new SimpleType("MyType").MakeArrayType() + }); } [Test] public void GenericTypeOfExpressionTest() { - TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(MyNamespace.N1.MyType)"); - Assert.AreEqual("MyNamespace.N1.MyType", toe.TypeReference.Type); - Assert.AreEqual("System.String", toe.TypeReference.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "typeof(MyNamespace.N1.MyType)", + new TypeOfExpression { + Type = new MemberType { + Target = new MemberType { + Target = new SimpleType("MyNamespace"), + MemberName = "N1" + }, + MemberName = "MyType", + TypeArguments = { new PrimitiveType("string") } + }}); } [Test] public void NestedGenericTypeOfExpressionTest() { - TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(MyType.InnerClass.InnerInnerClass)"); - InnerClassTypeReference ic = (InnerClassTypeReference)toe.TypeReference; - Assert.AreEqual("InnerInnerClass", ic.Type); - Assert.AreEqual(0, ic.GenericTypes.Count); - ic = (InnerClassTypeReference)ic.BaseType; - Assert.AreEqual("InnerClass", ic.Type); - Assert.AreEqual(1, ic.GenericTypes.Count); - Assert.AreEqual("System.Int32", ic.GenericTypes[0].Type); - Assert.AreEqual("MyType", ic.BaseType.Type); - Assert.AreEqual(1, ic.BaseType.GenericTypes.Count); - Assert.AreEqual("System.String", ic.BaseType.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "typeof(MyType.InnerClass.InnerInnerClass)", + new TypeOfExpression { + Type = new MemberType { + Target = new MemberType { + Target = new SimpleType("MyType") { TypeArguments = { new PrimitiveType("string") } }, + MemberName = "InnerClass", + TypeArguments = { new PrimitiveType("int") } + }, + MemberName = "InnerInnerClass" + }}); } [Test] public void NullableTypeOfExpressionTest() { - TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(MyStruct?)"); - Assert.AreEqual("System.Nullable", toe.TypeReference.Type); - Assert.AreEqual("MyStruct", toe.TypeReference.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "typeof(MyStruct?)", + new TypeOfExpression { + Type = new ComposedType { + BaseType = new SimpleType("MyType"), + HasNullableSpecifier = true + }}); } - [Test] + [Test, Ignore("How do we represent unbound types in the AST?")] public void UnboundTypeOfExpressionTest() { TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(MyType<,>)"); - Assert.AreEqual("MyType", toe.TypeReference.Type); - Assert.IsTrue(toe.TypeReference.GenericTypes[0].IsNull); - Assert.IsTrue(toe.TypeReference.GenericTypes[1].IsNull); - }*/ + throw new NotImplementedException("How do we represent unbound types in the AST?"); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/UnaryOperatorExpressionTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/UnaryOperatorExpressionTests.cs index c704b8857..a968af1eb 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/UnaryOperatorExpressionTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/UnaryOperatorExpressionTests.cs @@ -84,9 +84,9 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression Assert.AreEqual(UnaryOperatorType.Dereference, uoe.Operator); ParenthesizedExpression pe = (ParenthesizedExpression)uoe.Expression; CastExpression ce = (CastExpression)pe.Expression; - //Assert.AreEqual("SomeType", ce.CastTo.Type); - //Assert.AreEqual(1, ce.CastTo.PointerNestingLevel); - Assert.Ignore("need to check target type"); // TODO + ComposedType type = (ComposedType)ce.Type; + Assert.AreEqual("SomeType", ((SimpleType)type.BaseType).Identifier); + Assert.AreEqual(1, type.PointerRank); UnaryOperatorExpression adrOf = (UnaryOperatorExpression)ce.Expression; Assert.AreEqual(UnaryOperatorType.AddressOf, adrOf.Operator); diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/DelegateDeclarationTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/DelegateDeclarationTests.cs index 51e046976..e443e7b94 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/DelegateDeclarationTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/DelegateDeclarationTests.cs @@ -7,55 +7,41 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope { - [TestFixture, Ignore("delegates are completely broken at the moment")] + [TestFixture] public class DelegateDeclarationTests { - void TestParameters(DelegateDeclaration dd) - { - Assert.AreEqual(3, dd.Parameters.Count()); - - Assert.AreEqual("a", ((ParameterDeclaration)dd.Parameters.ElementAt(0)).Name); - //Assert.AreEqual("System.Int32", ((ParameterDeclaration)dd.Parameters.ElementAt(0)).TypeReference.Type); - Assert.Ignore("check types"); // TODO - Assert.AreEqual("secondParam", ((ParameterDeclaration)dd.Parameters.ElementAt(1)).Name); - //Assert.AreEqual("System.Int32", ((ParameterDeclaration)dd.Parameters.ElementAt(1)).TypeReference.Type); - - Assert.AreEqual("lastParam", ((ParameterDeclaration)dd.Parameters.ElementAt(2)).Name); - //Assert.AreEqual("MyObj", ((ParameterDeclaration)dd.Parameters.ElementAt(2)).TypeReference.Type); - } - [Test] public void SimpleCSharpDelegateDeclarationTest() { - string program = "public delegate void MyDelegate(int a, int secondParam, MyObj lastParam);\n"; - DelegateDeclaration dd = ParseUtilCSharp.ParseGlobal(program); - Assert.AreEqual("MyDelegate", dd.Name); - //Assert.AreEqual("System.Void", dd.ReturnType.Type); - TestParameters(dd); + ParseUtilCSharp.AssertGlobal( + "public delegate void MyDelegate(int a, int secondParam, MyObj lastParam);", + new DelegateDeclaration { + Modifiers = Modifiers.Public, + ReturnType = new PrimitiveType("void"), + Name = "MyDelegate", + Parameters = { + new ParameterDeclaration(new PrimitiveType("int"), "a"), + new ParameterDeclaration(new PrimitiveType("int"), "secondParam"), + new ParameterDeclaration(new SimpleType("MyObj"), "lastParam") + }}); } - [Test, Ignore] - public void DelegateWithoutNameDeclarationTest() - { - string program = "public delegate void(int a, int secondParam, MyObj lastParam);\n"; - DelegateDeclaration dd = ParseUtilCSharp.ParseGlobal(program, true); - //Assert.AreEqual("System.Void", dd.ReturnType.Type); - //Assert.AreEqual("?", dd.Name); - TestParameters(dd); - } - - [Test, Ignore] + [Test, Ignore("Generics not yet supported")] public void GenericDelegateDeclarationTest() { - string program = "public delegate T CreateObject() where T : ICloneable;\n"; - DelegateDeclaration dd = ParseUtilCSharp.ParseGlobal(program); - Assert.AreEqual("CreateObject", dd.Name); - //Assert.AreEqual("T", dd.ReturnType.Type); - Assert.AreEqual(0, dd.Parameters.Count()); - /*Assert.AreEqual(1, dd.Templates.Count); - Assert.AreEqual("T", dd.Templates[0].Name); - Assert.AreEqual(1, dd.Templates[0].Bases.Count); - Assert.AreEqual("ICloneable", dd.Templates[0].Bases[0].Type);*/ throw new NotImplementedException(); + ParseUtilCSharp.AssertGlobal( + "public delegate T CreateObject() where T : ICloneable;", + new DelegateDeclaration { + Modifiers = Modifiers.Public, + ReturnType = new SimpleType("T"), + Name = "CreateObject", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } }, + Constraints = { + new Constraint { + TypeParameter = "T", + BaseTypes = { new SimpleType("ICloneable") } + } + }}); } [Test] @@ -66,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope Assert.AreEqual("MyDelegate", ((DelegateDeclaration)nd.Members.Single()).Name); } - [Test, Ignore("inner classes not yet implemented")] + [Test] public void DelegateDeclarationInClass() { string program = "class Outer { delegate void Inner(); }"; diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs index 525306bd6..874816450 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs @@ -70,85 +70,111 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope Assert.AreEqual(Modifiers.Static, td.Modifiers); } - [Test, Ignore] + [Test, Ignore("Generics not yet supported")] public void GenericClassTypeDeclarationTest() { - TypeDeclaration td = ParseUtilCSharp.ParseGlobal("public class G {}"); - - Assert.AreEqual(ClassType.Class, td.ClassType); - Assert.AreEqual("G", td.Name); - Assert.AreEqual(Modifiers.Public, td.Modifiers); - /*Assert.AreEqual(0, td.BaseTypes.Count); - Assert.AreEqual(1, td.TypeArguments.Count()); - Assert.AreEqual("T", td.TypeArguments.Single().Name);*/ throw new NotImplementedException(); + ParseUtilCSharp.AssertGlobal( + "public class G {}", + new TypeDeclaration { + Modifiers = Modifiers.Public, + ClassType = ClassType.Class, + Name = "G", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } } + }); } - - [Test, Ignore] + [Test, Ignore("Constraints not yet supported")] public void GenericClassWithWhere() { - string declr = @" -public class Test where T : IMyInterface -{ -} -"; - TypeDeclaration td = ParseUtilCSharp.ParseGlobal(declr); - - Assert.AreEqual(ClassType.Class, td.ClassType); - Assert.AreEqual("Test", td.Name); - - /*Assert.AreEqual(1, td.Templates.Count); - Assert.AreEqual("T", td.Templates[0].Name); - Assert.AreEqual("IMyInterface", td.Templates[0].Bases[0].Type);*/ throw new NotImplementedException(); + ParseUtilCSharp.AssertGlobal( + @"public class Test where T : IMyInterface { }", + new TypeDeclaration { + Modifiers = Modifiers.Public, + ClassType = ClassType.Class, + Name = "Test", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } }, + Constraints = { + new Constraint { + TypeParameter = "T", + BaseTypes = { new SimpleType("IMyInterface") } + } + }}); } - [Test, Ignore] + [Test, Ignore("Generic classes not yet supported")] public void ComplexGenericClassTypeDeclarationTest() { - string declr = @" -public class Generic : System.IComparable where S : G where T : MyNamespace.IMyInterface -{ -} -"; - TypeDeclaration td = ParseUtilCSharp.ParseGlobal(declr); - - Assert.AreEqual(ClassType.Class, td.ClassType); - Assert.AreEqual("Generic", td.Name); - Assert.AreEqual(Modifiers.Public, td.Modifiers); - /*Assert.AreEqual(1, td.BaseTypes.Count); - Assert.AreEqual("System.IComparable", td.BaseTypes[0].Type); - - Assert.AreEqual(2, td.Templates.Count); - Assert.AreEqual("T", td.Templates[0].Name); - Assert.AreEqual("MyNamespace.IMyInterface", td.Templates[0].Bases[0].Type); - - Assert.AreEqual("S", td.Templates[1].Name); - Assert.AreEqual("G", td.Templates[1].Bases[0].Type); - Assert.AreEqual(1, td.Templates[1].Bases[0].GenericTypes.Count); - Assert.IsTrue(td.Templates[1].Bases[0].GenericTypes[0].IsArrayType); - Assert.AreEqual("T", td.Templates[1].Bases[0].GenericTypes[0].Type); - Assert.AreEqual(new int[] {0}, td.Templates[1].Bases[0].GenericTypes[0].RankSpecifier);*/ throw new NotImplementedException(); + ParseUtilCSharp.AssertGlobal( + "public class Generic : System.IComparable where S : G, new() where T : MyNamespace.IMyInterface", + new TypeDeclaration { + Modifiers = Modifiers.Public, + ClassType = ClassType.Class, + Name = "Generic", + TypeParameters = { + new TypeParameterDeclaration { Variance = VarianceModifier.Contravariant, Name = "T" }, + new TypeParameterDeclaration { Variance = VarianceModifier.Covariant, Name = "S" } + }, + BaseTypes = { + new MemberType { + Target = new SimpleType("System"), + MemberName = "IComparable" + } + }, + Constraints = { + new Constraint { + TypeParameter = "S", + BaseTypes = { + new SimpleType { + Identifier = "G", + TypeArguments = { new SimpleType("T").MakeArrayType() } + }, + new PrimitiveType("new") + } + }, + new Constraint { + TypeParameter = "T", + BaseTypes = { + new MemberType { + Target = new SimpleType("MyNamespace"), + MemberName = "IMyInterface" + } + } + } + } + }); } - [Test, Ignore] + [Test, Ignore("Base types not yet implemented")] public void ComplexClassTypeDeclarationTest() { - string declr = @" + ParseUtilCSharp.AssertGlobal( + @" [MyAttr()] public abstract class MyClass : MyBase, Interface1, My.Test.Interface2 { -} -"; - TypeDeclaration td = ParseUtilCSharp.ParseGlobal(declr); - - Assert.AreEqual(ClassType.Class, td.ClassType); - Assert.AreEqual("MyClass", td.Name); - Assert.AreEqual(Modifiers.Public | Modifiers.Abstract, td.Modifiers); - Assert.AreEqual(1, td.Attributes.Count()); - /* Assert.AreEqual(3, td.BaseTypes.Count); - Assert.AreEqual("MyBase", td.BaseTypes[0].Type); - Assert.AreEqual("Interface1", td.BaseTypes[1].Type); - Assert.AreEqual("My.Test.Interface2", td.BaseTypes[2].Type);*/ throw new NotImplementedException(); +}", + new TypeDeclaration { + Attributes = { + new AttributeSection { + Attributes = { + new Attribute { Type = new SimpleType("MyAttr") } + } + } + }, + Modifiers = Modifiers.Public | Modifiers.Abstract, + ClassType = ClassType.Class, + Name = "MyClass", + BaseTypes = { + new SimpleType("MyBase"), + new SimpleType("Interface1"), + new MemberType { + Target = new MemberType { + Target = new SimpleType("My"), + MemberName = "Test" + }, + MemberName = "Interface2" + } + }}); } [Test] @@ -178,27 +204,37 @@ public abstract class MyClass : MyBase, Interface1, My.Test.Interface2 Assert.AreEqual("MyEnum", td.Name); } - [Test, Ignore] + [Test, Ignore("Mono parser bug?")] public void ContextSensitiveKeywordTest() { - TypeDeclaration td = ParseUtilCSharp.ParseGlobal("partial class partial<[partial: where] where> where where : partial { }"); - - Assert.AreEqual(Modifiers.Partial, td.Modifiers); - Assert.AreEqual("partial", td.Name); - - /* - Assert.AreEqual(1, td.Templates.Count); - TemplateDefinition tp = td.Templates[0]; - Assert.AreEqual("where", tp.Name); - - Assert.AreEqual(1, tp.Attributes.Count); - Assert.AreEqual("partial", tp.Attributes[0].AttributeTarget); - Assert.AreEqual(1, tp.Attributes[0].Attributes.Count); - Assert.AreEqual("where", tp.Attributes[0].Attributes[0].Name); - - Assert.AreEqual(1, tp.Bases.Count); - Assert.AreEqual("partial", tp.Bases[0].Type); - Assert.AreEqual("where", tp.Bases[0].GenericTypes[0].Type);*/ throw new NotImplementedException(); + ParseUtilCSharp.AssertGlobal( + "partial class partial<[partial: where] where> where where : partial { }", + new TypeDeclaration { + Modifiers = Modifiers.Partial, + ClassType = ClassType.Class, + Name = "partial", + TypeParameters = { + new TypeParameterDeclaration { + Attributes = { + new AttributeSection { + AttributeTarget = AttributeTarget.Unknown, + Attributes = { new Attribute { Type = new SimpleType("where") } } + } + }, + Name = "where" + } + }, + Constraints = { + new Constraint { + TypeParameter = "where", + BaseTypes = { + new SimpleType { + Identifier = "partial", + TypeArguments = { new SimpleType("where") } + } + } + } + }}); } [Test] diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/UsingDeclarationTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/UsingDeclarationTests.cs index d79e33fe2..c9d4b7801 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/UsingDeclarationTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/UsingDeclarationTests.cs @@ -43,7 +43,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope Assert.AreEqual("My.Name.Space", ud.Namespace); } - [Test] + [Test, Ignore("Aliases to generic types not yet supported")] public void UsingAliasDeclarationTest() { string program = "using TESTME=System;\n" + diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs index 94b282539..7522b0284 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs @@ -11,7 +11,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser /// /// Helper methods for parser unit tests. /// - public class ParseUtilCSharp + public static class ParseUtilCSharp { public static T ParseGlobal(string code, bool expectErrors = false) where T : AstNode { @@ -26,6 +26,14 @@ namespace ICSharpCode.NRefactory.CSharp.Parser return (T)node; } + public static void AssertGlobal(string code, AstNode expectedNode) + { + var node = ParseGlobal(code); + if (expectedNode.Match(node) == null) { + Assert.Fail("Expected '{0}' but was '{1}'", ToCSharp(expectedNode), ToCSharp(node)); + } + } + public static T ParseStatement(string stmt, bool expectErrors = false) where T : AstNode { CSharpParser parser = new CSharpParser(); @@ -39,6 +47,14 @@ namespace ICSharpCode.NRefactory.CSharp.Parser return (T)statement; } + public static void AssertStatement(string code, CSharp.Statement expectedStmt) + { + var stmt = ParseStatement(code); + if (expectedStmt.Match(stmt) == null) { + Assert.Fail("Expected '{0}' but was '{1}'", ToCSharp(expectedStmt), ToCSharp(stmt)); + } + } + public static T ParseExpression(string expr, bool expectErrors = false) where T : AstNode { if (expectErrors) Assert.Ignore("errors not yet implemented"); @@ -53,6 +69,14 @@ namespace ICSharpCode.NRefactory.CSharp.Parser return (T)parsedExpression; } + public static void AssertExpression(string code, CSharp.Expression expectedExpr) + { + var expr = ParseExpression(code); + if (expectedExpr.Match(expr) == null) { + Assert.Fail("Expected '{0}' but was '{1}'", ToCSharp(expectedExpr), ToCSharp(expr)); + } + } + public static T ParseTypeMember(string expr, bool expectErrors = false) where T : AttributedNode { if (expectErrors) Assert.Ignore("errors not yet implemented"); @@ -67,5 +91,20 @@ namespace ICSharpCode.NRefactory.CSharp.Parser Assert.IsTrue(type.IsAssignableFrom(m.GetType()), String.Format("Parsed member was {0} instead of {1} ({2})", m.GetType(), type, m)); return (T)m; } + + public static void AssertTypeMember(string code, CSharp.AttributedNode expectedMember) + { + var member = ParseTypeMember(code); + if (expectedMember.Match(member) == null) { + Assert.Fail("Expected '{0}' but was '{1}'", ToCSharp(expectedMember), ToCSharp(member)); + } + } + + static string ToCSharp(AstNode node) + { + StringWriter w = new StringWriter(); + node.AcceptVisitor(new OutputVisitor(w, new CSharpFormattingPolicy()), null); + return w.ToString(); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/FixedStatementTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/FixedStatementTests.cs index 08ff938b8..bf62bec0e 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/FixedStatementTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/FixedStatementTests.cs @@ -6,14 +6,25 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Statements { - [TestFixture] + [TestFixture, Ignore("fixed is not implemented")] public class FixedStatementTests { [Test] public void FixedStatementTest() { FixedStatement fixedStmt = ParseUtilCSharp.ParseStatement("fixed (int* ptr = &myIntArr) { }"); - // TODO : Extend test. + ParseUtilCSharp.AssertStatement( + "fixed (int* ptr = &myIntArr) { }", + new FixedStatement { + Type = new PrimitiveType("int").MakePointerType(), + Variables = { + new VariableInitializer { + Name = "ptr", + Initializer = new UnaryOperatorExpression(UnaryOperatorType.AddressOf, new IdentifierExpression("myIntArr")) + } + }, + EmbeddedStatement = new BlockStatement() + }); } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/ForStatementTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/ForStatementTests.cs index 1d0324f4a..fc18cdab4 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/ForStatementTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/ForStatementTests.cs @@ -10,11 +10,17 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Statements [TestFixture] public class ForStatementTests { - [Test] + [Test, Ignore("variable type in foreach is broken")] public void ForeachStatementTest() { - ForeachStatement foreachStmt = ParseUtilCSharp.ParseStatement("foreach (int i in myColl) {} "); - // TODO : Extend test. + ParseUtilCSharp.AssertStatement( + "foreach (int i in myColl) {} ", + new ForeachStatement { + VariableType = new PrimitiveType("int"), + VariableName = "i", + InExpression = new IdentifierExpression("myColl"), + EmbeddedStatement = new BlockStatement() + }); } [Test, Ignore("for statement is broken when Initializers.Count()!=1")] @@ -40,7 +46,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Statements Assert.IsTrue(inc.Expression is UnaryOperatorExpression); } - [Test, Ignore("for statement is broken when Initializers.Count()!=1")] + [Test] public void ForStatementTestMultipleInitializers() { ForStatement forStmt = ParseUtilCSharp.ParseStatement("for (i = 0, j = 1; i < 6; ++i) {} "); @@ -48,10 +54,12 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Statements Assert.IsTrue(forStmt.Iterators.All(i => i is ExpressionStatement)); } - [Test, Ignore("for statement is broken when Iterators.Count()!=1")] + [Test] public void ForStatementTestMultipleIterators() { - ForStatement forStmt = ParseUtilCSharp.ParseStatement("for (int i = 5; i < 6; ++i, j--) {} "); + ForStatement forStmt = ParseUtilCSharp.ParseStatement("for (int i = 5, j = 10; i < 6; ++i, j--) {} "); + Assert.AreEqual(1, forStmt.Initializers.Count()); + Assert.AreEqual(2, ((VariableDeclarationStatement)forStmt.Initializers.Single()).Variables.Count()); Assert.AreEqual(2, forStmt.Iterators.Count()); Assert.IsTrue(forStmt.Iterators.All(i => i is ExpressionStatement)); } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/TryCatchStatementTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/TryCatchStatementTests.cs index 202b7f0ae..7187f4b5d 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/TryCatchStatementTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/TryCatchStatementTests.cs @@ -7,7 +7,7 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Statements { - [TestFixture, Ignore] + [TestFixture] public class TryCatchStatementTests { [Test] @@ -20,28 +20,54 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Statements Assert.AreEqual(string.Empty, tryCatchStatement.CatchClauses.Single().VariableName); } - /* TODO port tests [Test] public void SimpleTryCatchStatementTest2() { - TryCatchStatement tryCatchStatement = ParseUtilCSharp.ParseStatement("try { } catch (Exception e) { } "); - Assert.IsTrue(tryCatchStatement.FinallyBlock.IsNull); - Assert.AreEqual(1, tryCatchStatement.CatchClauses.Count); - Assert.AreEqual("Exception", tryCatchStatement.CatchClauses[0].TypeReference.Type); - Assert.AreEqual("e", tryCatchStatement.CatchClauses[0].VariableName); + ParseUtilCSharp.AssertStatement( + "try { } catch (Exception e) { } ", + new TryCatchStatement { + TryBlock = new BlockStatement(), + CatchClauses = { + new CatchClause { + Type = new SimpleType("Exception"), + VariableName = "e", + Body = new BlockStatement() + } + }}); } [Test] public void SimpleTryCatchFinallyStatementTest() { - TryCatchStatement tryCatchStatement = ParseUtilCSharp.ParseStatement("try { } catch (Exception) { } catch { } finally { } "); - Assert.IsFalse(tryCatchStatement.FinallyBlock.IsNull); - Assert.AreEqual(2, tryCatchStatement.CatchClauses.Count); - Assert.AreEqual("Exception", tryCatchStatement.CatchClauses[0].TypeReference.Type); - Assert.IsEmpty(tryCatchStatement.CatchClauses[0].VariableName); - Assert.IsTrue(tryCatchStatement.CatchClauses[1].TypeReference.IsNull); - Assert.IsEmpty(tryCatchStatement.CatchClauses[1].VariableName); + ParseUtilCSharp.AssertStatement( + "try { } catch (Exception) { } catch { } finally { } ", + new TryCatchStatement { + TryBlock = new BlockStatement(), + CatchClauses = { + new CatchClause { + Type = new SimpleType("Exception"), + Body = new BlockStatement() + }, + new CatchClause { Body = new BlockStatement() } + }, + FinallyBlock = new BlockStatement() + }); + } + + [Test] + public void TestEmptyFinallyDoesNotMatchNullFinally() + { + TryCatchStatement c1 = new TryCatchStatement { + TryBlock = new BlockStatement(), + CatchClauses = { new CatchClause { Body = new BlockStatement() } } + }; + TryCatchStatement c2 = new TryCatchStatement { + TryBlock = new BlockStatement(), + CatchClauses = { new CatchClause { Body = new BlockStatement() } }, + FinallyBlock = new BlockStatement() + }; + Assert.IsNull(c1.Match(c2)); + Assert.IsNull(c2.Match(c1)); // and vice versa } - */ } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/YieldStatementTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/YieldStatementTests.cs index ae5598f2c..ae4d75d93 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/YieldStatementTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/YieldStatementTests.cs @@ -21,8 +21,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Statements [Test] public void YieldBreakStatementTest() { - YieldStatement yieldStmt = ParseUtilCSharp.ParseStatement("yield break;"); - Assert.IsTrue(yieldStmt.Expression.IsNull); + ParseUtilCSharp.ParseStatement("yield break;"); } [Test] diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/EventDeclarationTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/EventDeclarationTests.cs index fe1bd468c..7e9d13453 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/EventDeclarationTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/EventDeclarationTests.cs @@ -6,79 +6,84 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers { - [TestFixture, Ignore] + [TestFixture, Ignore("events are broken")] public class EventDeclarationTests { [Test] public void SimpleEventDeclarationTest() { - CustomEventDeclaration ed = ParseUtilCSharp.ParseTypeMember("event System.EventHandler MyEvent;"); - Assert.AreEqual("MyEvent", ed.Name); - //Assert.AreEqual("System.EventHandler", ed.TypeReference.Type); - Assert.Ignore(); // check type - - Assert.IsTrue(ed.AddAccessor.IsNull); - Assert.IsTrue(ed.RemoveAccessor.IsNull); + ParseUtilCSharp.AssertTypeMember( + "event EventHandler MyEvent;", + new EventDeclaration { + ReturnType = new SimpleType("EventHandler"), + Variables = { + new VariableInitializer { + Name = "MyEvent" + } + }}); } - /* TODO Port tests [Test] public void MultipleEventDeclarationTest() { - TypeDeclaration t = ParseUtilCSharp.ParseGlobal("class C { public event EventHandler A, B; }"); - Assert.AreEqual(2, t.Children.Count); - - EventDeclaration ed = (EventDeclaration)t.Children[0]; - Assert.AreEqual(Modifiers.Public, ed.Modifier); - Assert.AreEqual("EventHandler", ed.TypeReference.Type); - Assert.AreEqual("A", ed.Name); - - ed = (EventDeclaration)t.Children[1]; - Assert.AreEqual(Modifiers.Public, ed.Modifier); - Assert.AreEqual("EventHandler", ed.TypeReference.Type); - Assert.AreEqual("B", ed.Name); + ParseUtilCSharp.AssertTypeMember( + "public event EventHandler A = null, B = delegate {};", + new EventDeclaration { + Modifiers = Modifiers.Public, + ReturnType = new SimpleType("EventHandler"), + Variables = { + new VariableInitializer { + Name = "A", + Initializer = new NullReferenceExpression() + }, + new VariableInitializer { + Name = "B", + Initializer = new AnonymousMethodExpression() + } + }}); } [Test] - public void EventImplementingInterfaceDeclarationTest() + public void AddRemoveEventDeclarationTest() { - EventDeclaration ed = ParseUtilCSharp.ParseTypeMember("event EventHandler MyInterface.MyEvent;"); - - Assert.AreEqual("MyEvent", ed.Name); - Assert.AreEqual("EventHandler", ed.TypeReference.Type); - - Assert.IsFalse(ed.HasAddRegion); - Assert.IsFalse(ed.HasRemoveRegion); - - Assert.AreEqual("MyInterface", ed.InterfaceImplementations[0].InterfaceType.Type); - Assert.AreEqual("MyEvent", ed.InterfaceImplementations[0].MemberName); + ParseUtilCSharp.AssertTypeMember( + "public event System.EventHandler MyEvent { add { } remove { } }", + new CustomEventDeclaration { + Modifiers = Modifiers.Public, + ReturnType = new MemberType { + Target = new SimpleType("System"), + MemberName = "EventHandler" + }, + Name = "MyEvent", + AddAccessor = new Accessor { Body = new BlockStatement() }, + RemoveAccessor = new Accessor { Body = new BlockStatement() } + }); } [Test] public void EventImplementingGenericInterfaceDeclarationTest() { - EventDeclaration ed = ParseUtilCSharp.ParseTypeMember("event EventHandler MyInterface.MyEvent;"); - - Assert.AreEqual("MyEvent", ed.Name); - Assert.AreEqual("EventHandler", ed.TypeReference.Type); - - Assert.IsFalse(ed.HasAddRegion); - Assert.IsFalse(ed.HasRemoveRegion); - - Assert.AreEqual("MyInterface", ed.InterfaceImplementations[0].InterfaceType.Type); - Assert.AreEqual("System.String", ed.InterfaceImplementations[0].InterfaceType.GenericTypes[0].Type); - Assert.AreEqual("MyEvent", ed.InterfaceImplementations[0].MemberName); + ParseUtilCSharp.AssertTypeMember( + "event EventHandler MyInterface.MyEvent { add { } [Attr] remove {} }", + new CustomEventDeclaration { + ReturnType = new SimpleType("EventHandler"), + PrivateImplementationType = new SimpleType{ + Identifier = "MyInterface", + TypeArguments = { new PrimitiveType("string") } + }, + Name = "MyEvent", + AddAccessor = new Accessor { Body = new BlockStatement() }, + RemoveAccessor = new Accessor { + Attributes = { + new AttributeSection { + Attributes = { + new Attribute { Type = new SimpleType("Attr") } + } + } + }, + Body = new BlockStatement() + } + }); } - - [Test] - public void AddRemoveEventDeclarationTest() - { - EventDeclaration ed = ParseUtilCSharp.ParseTypeMember("event System.EventHandler MyEvent { add { } remove { } }"); - Assert.AreEqual("MyEvent", ed.Name); - Assert.AreEqual("System.EventHandler", ed.TypeReference.Type); - - Assert.IsTrue(ed.HasAddRegion); - Assert.IsTrue(ed.HasRemoveRegion); - }*/ } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/FieldDeclarationTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/FieldDeclarationTests.cs index f91cbed4a..6f47dc588 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/FieldDeclarationTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/FieldDeclarationTests.cs @@ -6,22 +6,62 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers { - [TestFixture, Ignore] + [TestFixture] public class FieldDeclarationTests { - [Test] + [Test, Ignore("multidimensional array rank incorrect?")] public void SimpleFieldDeclarationTest() { - throw new NotImplementedException(); - /* - FieldDeclaration fd = ParseUtilCSharp.ParseTypeMember("int[,,,] myField;"); - Assert.AreEqual("System.Int32", fd.TypeReference.Type); - Assert.AreEqual(new int[] { 3 } , fd.TypeReference.RankSpecifier); - Assert.AreEqual(1, fd.Fields.Count); - - Assert.AreEqual("myField", ((VariableDeclaration)fd.Fields[0]).Name);*/ + ParseUtilCSharp.AssertTypeMember( + "int[,,,] myField;", + new FieldDeclaration { + ReturnType = new PrimitiveType("int").MakeArrayType(4), + Variables = { new VariableInitializer("myField") } + }); + } + + [Test] + public void MultipleFieldDeclarationTest() + { + ParseUtilCSharp.AssertTypeMember( + "int a = 1, b = 2;", + new FieldDeclaration { + ReturnType = new PrimitiveType("int"), + Variables = { + new VariableInitializer("a", new PrimitiveExpression(1)), + new VariableInitializer("b", new PrimitiveExpression(2)), + } + }); } - // TODO add more tests + [Test] + public void FieldWithArrayInitializer() + { + ParseUtilCSharp.AssertTypeMember( + "public static readonly int[] arr = { 1, 2, 3 };", + new FieldDeclaration { + Modifiers = Modifiers.Public | Modifiers.Static | Modifiers.Readonly, + ReturnType = new PrimitiveType("int").MakeArrayType(), + Variables = { + new VariableInitializer { + Name = "arr", + Initializer = new ArrayInitializerExpression { + Elements = { + new PrimitiveExpression(1), + new PrimitiveExpression(2), + new PrimitiveExpression(3) + } + } + } + }}); + } + + [Test, Ignore("How do we represent fixed-size fields in the AST?")] + public void FieldWithFixedSize() + { + ParseUtilCSharp.AssertTypeMember( + "public unsafe fixed int Field[100];", + new FieldDeclaration()); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs index 90f14b26e..5353808fc 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs @@ -13,13 +13,16 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers [Test] public void IndexerDeclarationTest() { - IndexerDeclaration id = ParseUtilCSharp.ParseTypeMember("int this[int a, string b] { get { } set { } }"); + IndexerDeclaration id = ParseUtilCSharp.ParseTypeMember("public int this[int a, string b] { get { } protected set { } }"); Assert.AreEqual(2, id.Parameters.Count()); Assert.IsNotNull(id.Getter, "No get region found!"); Assert.IsNotNull(id.Setter, "No set region found!"); + Assert.AreEqual(Modifiers.Public, id.Modifiers); + Assert.AreEqual(Modifiers.None, id.Getter.Modifiers); + Assert.AreEqual(Modifiers.Protected, id.Setter.Modifiers); } - [Test, Ignore("type reference is not yet implemented")] + [Test, Ignore("explicit interface implementation not yet supported")] public void IndexerImplementingInterfaceTest() { IndexerDeclaration id = ParseUtilCSharp.ParseTypeMember("int MyInterface.this[int a, string b] { get { } set { } }"); @@ -27,21 +30,29 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers Assert.IsNotNull(id.Getter, "No get region found!"); Assert.IsNotNull(id.Setter, "No set region found!"); - Assert.AreEqual("MyInterface", id.PrivateImplementationType); + Assert.AreEqual("MyInterface", ((SimpleType)id.PrivateImplementationType).Identifier); } - [Test, Ignore] + [Test, Ignore("explicit interface implementation not yet supported")] public void IndexerImplementingGenericInterfaceTest() { - throw new NotImplementedException(); - /* - IndexerDeclaration id = ParseUtilCSharp.ParseTypeMember("int MyInterface.this[int a, string b] { get { } set { } }"); - Assert.AreEqual(2, id.Parameters.Count); - Assert.IsNotNull(id.GetAccessor, "No get region found!"); - Assert.IsNotNull(id.SetAccessor, "No set region found!"); - - Assert.AreEqual("MyInterface", id.InterfaceImplementations[0].InterfaceType.Type); - Assert.AreEqual("System.String", id.InterfaceImplementations[0].InterfaceType.GenericTypes[0].Type);*/ + ParseUtilCSharp.AssertTypeMember( + "int MyInterface.this[int a, string b] { get { } [Attr] set { } }", + new IndexerDeclaration { + ReturnType = new PrimitiveType("int"), + PrivateImplementationType = new SimpleType { + Identifier = "MyInterface", + TypeArguments = { new PrimitiveType("string") } + }, + Parameters = { + new ParameterDeclaration(new PrimitiveType("int"), "a"), + new ParameterDeclaration(new PrimitiveType("string"), "b") + }, + Getter = new Accessor { Body = new BlockStatement() }, + Setter = new Accessor { + Attributes = { new AttributeSection(new Attribute { Type = new SimpleType("Attr") }) }, + Body = new BlockStatement() + }}); } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/MethodDeclarationTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/MethodDeclarationTests.cs index 53e0f3138..e3302d7c0 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/MethodDeclarationTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/MethodDeclarationTests.cs @@ -3,49 +3,50 @@ using System; using System.Linq; +using ICSharpCode.NRefactory.TypeSystem; using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers { - [TestFixture] + [TestFixture, Ignore("Generics not yet implemented")] public class MethodDeclarationTests { - [Test, Ignore("type references not yet implemented")] + [Test] public void SimpleMethodDeclarationTest() { MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("void MyMethod() {} "); - Assert.AreEqual("System.Void", md.ReturnType); + Assert.AreEqual("void", ((PrimitiveType)md.ReturnType).Keyword); Assert.AreEqual(0, md.Parameters.Count()); Assert.IsFalse(md.IsExtensionMethod); } - [Test, Ignore("type references not yet implemented")] + [Test] public void AbstractMethodDeclarationTest() { MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("abstract void MyMethod();"); - Assert.AreEqual("System.Void", md.ReturnType); + Assert.AreEqual("void", ((PrimitiveType)md.ReturnType).Keyword); Assert.AreEqual(0, md.Parameters.Count()); Assert.IsFalse(md.IsExtensionMethod); Assert.IsTrue(md.Body.IsNull); Assert.AreEqual(Modifiers.Abstract, md.Modifiers); } - [Test, Ignore("type references not yet implemented")] + [Test] public void DefiningPartialMethodDeclarationTest() { MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("partial void MyMethod();"); - Assert.AreEqual("System.Void", md.ReturnType); + Assert.AreEqual("void", ((PrimitiveType)md.ReturnType).Keyword); Assert.AreEqual(0, md.Parameters.Count()); Assert.IsFalse(md.IsExtensionMethod); Assert.IsTrue(md.Body.IsNull); Assert.AreEqual(Modifiers.Partial, md.Modifiers); } - [Test, Ignore("type references not yet implemented")] + [Test] public void ImplementingPartialMethodDeclarationTest() { MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("partial void MyMethod() { }"); - Assert.AreEqual("System.Void", md.ReturnType); + Assert.AreEqual("void", ((PrimitiveType)md.ReturnType).Keyword); Assert.AreEqual(0, md.Parameters.Count()); Assert.IsFalse(md.IsExtensionMethod); Assert.IsFalse(md.Body.IsNull); @@ -81,6 +82,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers Assert.AreEqual(2, md.StartLocation.Line, "StartLocation.Y"); Assert.AreEqual(5, md.EndLocation.Line, "EndLocation.Y"); Assert.AreEqual(3, md.StartLocation.Column, "StartLocation.X"); + Assert.AreEqual(4, md.EndLocation.Column, "EndLocation.X"); } [Test] @@ -89,142 +91,176 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("void MyMethod(int) {} ", true); Assert.AreEqual("System.Void", md.ReturnType); Assert.AreEqual(1, md.Parameters.Count()); - //Assert.AreEqual("?", ((ParameterDeclarationExpression)md.Parameters[0]).ParameterName); + Assert.AreEqual("int", ((PrimitiveType)md.Parameters.Single().Type).Keyword); } - /* TODO: port unit tests [Test] public void GenericVoidMethodDeclarationTest() { - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("void MyMethod(T a) {} "); - Assert.AreEqual("System.Void", md.ReturnType); - Assert.AreEqual(1, md.Parameters.Count()); - Assert.AreEqual("T", md.Parameters.Single().Type); - Assert.AreEqual("a", md.Parameters.Single().Name); - - Assert.AreEqual(1, md.TypeParameters.Count()); - Assert.AreEqual("T", md.Templates[0].Name); + ParseUtilCSharp.AssertTypeMember( + "void MyMethod(T a) {} ", + new MethodDeclaration { + ReturnType = new PrimitiveType("void"), + Name = "MyMethod", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } }, + Parameters = { new ParameterDeclaration(new SimpleType("T"), "a") }, + Body = new BlockStatement() + }); } [Test] public void GenericMethodDeclarationTest() { - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("T MyMethod(T a) {} "); - Assert.AreEqual("T", md.TypeReference.Type); - Assert.AreEqual(1, md.Parameters.Count); - Assert.AreEqual("T", ((ParameterDeclarationExpression)md.Parameters[0]).TypeReference.Type); - Assert.AreEqual("a", ((ParameterDeclarationExpression)md.Parameters[0]).ParameterName); - - Assert.AreEqual(1, md.Templates.Count); - Assert.AreEqual("T", md.Templates[0].Name); + ParseUtilCSharp.AssertTypeMember( + "T MyMethod(T a) {} ", + new MethodDeclaration { + ReturnType = new SimpleType("T"), + Name = "MyMethod", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } }, + Parameters = { new ParameterDeclaration(new SimpleType("T"), "a") }, + Body = new BlockStatement() + }); } [Test] public void GenericMethodDeclarationWithConstraintTest() { - string program = "T MyMethod(T a) where T : ISomeInterface {} "; - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember(program); - Assert.AreEqual("T", md.TypeReference.Type); - Assert.AreEqual(1, md.Parameters.Count); - Assert.AreEqual("T", ((ParameterDeclarationExpression)md.Parameters[0]).TypeReference.Type); - Assert.AreEqual("a", ((ParameterDeclarationExpression)md.Parameters[0]).ParameterName); - - Assert.AreEqual(1, md.Templates.Count); - Assert.AreEqual("T", md.Templates[0].Name); - Assert.AreEqual(1, md.Templates[0].Bases.Count); - Assert.AreEqual("ISomeInterface", md.Templates[0].Bases[0].Type); + ParseUtilCSharp.AssertTypeMember( + "T MyMethod(T a) where T : ISomeInterface {} ", + new MethodDeclaration { + ReturnType = new SimpleType("T"), + Name = "MyMethod", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } }, + Parameters = { new ParameterDeclaration(new SimpleType("T"), "a") }, + Constraints = { + new Constraint { + TypeParameter = "T", + BaseTypes = { new SimpleType("ISomeInterface") } + } + }, + Body = new BlockStatement() + }); } [Test] public void GenericMethodInInterface() { - const string program = @"interface MyInterface { + ParseUtilCSharp.AssertGlobal( + @"interface MyInterface { T MyMethod(T a) where T : ISomeInterface; } -"; - TypeDeclaration td = ParseUtilCSharp.ParseGlobal(program); - MethodDeclaration md = (MethodDeclaration)td.Children[0]; - Assert.AreEqual("T", md.TypeReference.Type); - Assert.AreEqual(1, md.Parameters.Count); - Assert.AreEqual("T", ((ParameterDeclarationExpression)md.Parameters[0]).TypeReference.Type); - Assert.AreEqual("a", ((ParameterDeclarationExpression)md.Parameters[0]).ParameterName); - - Assert.AreEqual(1, md.Templates.Count); - Assert.AreEqual("T", md.Templates[0].Name); - Assert.AreEqual(1, md.Templates[0].Bases.Count); - Assert.AreEqual("ISomeInterface", md.Templates[0].Bases[0].Type); +", + new TypeDeclaration { + ClassType = ClassType.Interface, + Members = { + new MethodDeclaration { + ReturnType = new SimpleType("T"), + Name = "MyMethod", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } }, + Parameters = { new ParameterDeclaration(new SimpleType("T"), "a") }, + Constraints = { + new Constraint { + TypeParameter = "T", + BaseTypes = { new SimpleType("ISomeInterface") } + } + } + }}}); } [Test] public void GenericVoidMethodInInterface() { - const string program = @"interface MyInterface { + ParseUtilCSharp.AssertGlobal( + @"interface MyInterface { void MyMethod(T a) where T : ISomeInterface; } -"; - TypeDeclaration td = ParseUtilCSharp.ParseGlobal(program); - MethodDeclaration md = (MethodDeclaration)td.Children[0]; - Assert.AreEqual("System.Void", md.TypeReference.Type); - Assert.AreEqual(1, md.Parameters.Count); - Assert.AreEqual("T", ((ParameterDeclarationExpression)md.Parameters[0]).TypeReference.Type); - Assert.AreEqual("a", ((ParameterDeclarationExpression)md.Parameters[0]).ParameterName); - - Assert.AreEqual(1, md.Templates.Count); - Assert.AreEqual("T", md.Templates[0].Name); - Assert.AreEqual(1, md.Templates[0].Bases.Count); - Assert.AreEqual("ISomeInterface", md.Templates[0].Bases[0].Type); +", + new TypeDeclaration { + ClassType = ClassType.Interface, + Members = { + new MethodDeclaration { + ReturnType = new PrimitiveType("void"), + Name = "MyMethod", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } }, + Parameters = { new ParameterDeclaration(new SimpleType("T"), "a") }, + Constraints = { + new Constraint { + TypeParameter = "T", + BaseTypes = { new SimpleType("ISomeInterface") } + } + } + }}}); } [Test] public void ShadowingMethodInInterface() { - const string program = @"interface MyInterface : IDisposable { + ParseUtilCSharp.AssertGlobal( + @"interface MyInterface : IDisposable { new void Dispose(); } -"; - TypeDeclaration td = ParseUtilCSharp.ParseGlobal(program); - MethodDeclaration md = (MethodDeclaration)td.Children[0]; - Assert.AreEqual("System.Void", md.TypeReference.Type); - Assert.AreEqual(0, md.Parameters.Count); - Assert.AreEqual(Modifiers.New, md.Modifier); +", + new TypeDeclaration { + ClassType = ClassType.Interface, + BaseTypes = { new SimpleType("IDisposable") }, + Members = { + new MethodDeclaration { + Modifiers = Modifiers.New, + ReturnType = new PrimitiveType("void"), + Name = "Dispose" + }}}); } [Test] public void MethodImplementingInterfaceTest() { - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("int MyInterface.MyMethod() {} "); - Assert.AreEqual("System.Int32", md.TypeReference.Type); - - Assert.AreEqual("MyInterface", md.InterfaceImplementations[0].InterfaceType.Type); + ParseUtilCSharp.AssertGlobal( + "int MyInterface.MyMethod() {} ", + new MethodDeclaration { + ReturnType = new PrimitiveType("int"), + PrivateImplementationType = new SimpleType("MyInterface"), + Name = "MyMethod", + Body = new BlockStatement() + }); } [Test] public void MethodImplementingGenericInterfaceTest() { - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("int MyInterface.MyMethod() {} "); - Assert.AreEqual("System.Int32", md.TypeReference.Type); - - Assert.AreEqual("MyInterface", md.InterfaceImplementations[0].InterfaceType.Type); - Assert.AreEqual("System.String", md.InterfaceImplementations[0].InterfaceType.GenericTypes[0].Type); + ParseUtilCSharp.AssertGlobal( + "int MyInterface.MyMethod() {} ", + new MethodDeclaration { + ReturnType = new PrimitiveType("int"), + PrivateImplementationType = new SimpleType("MyInterface") { TypeArguments = { new PrimitiveType("string") } }, + Name = "MyMethod", + Body = new BlockStatement() + }); } [Test] public void VoidMethodImplementingInterfaceTest() { - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("void MyInterface.MyMethod() {} "); - Assert.AreEqual("System.Void", md.TypeReference.Type); - - Assert.AreEqual("MyInterface", md.InterfaceImplementations[0].InterfaceType.Type); + ParseUtilCSharp.AssertGlobal( + "void MyInterface.MyMethod() {} ", + new MethodDeclaration { + ReturnType = new PrimitiveType("void"), + PrivateImplementationType = new SimpleType("MyInterface"), + Name = "MyMethod", + Body = new BlockStatement() + }); } [Test] public void VoidMethodImplementingGenericInterfaceTest() { - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("void MyInterface.MyMethod() {} "); - Assert.AreEqual("System.Void", md.TypeReference.Type); - - Assert.AreEqual("MyInterface", md.InterfaceImplementations[0].InterfaceType.Type); - Assert.AreEqual("System.String", md.InterfaceImplementations[0].InterfaceType.GenericTypes[0].Type); + ParseUtilCSharp.AssertGlobal( + "void MyInterface.MyMethod() {} ", + new MethodDeclaration { + ReturnType = new PrimitiveType("void"), + PrivateImplementationType = new SimpleType("MyInterface"), + Name = "MyMethod", + Body = new BlockStatement() + }); } [Test] @@ -234,9 +270,9 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers "void a() where T { }", true // expect errors ); Assert.AreEqual("a", md.Name); - Assert.AreEqual(1, md.Templates.Count); - Assert.AreEqual("T", md.Templates[0].Name); - Assert.AreEqual(0, md.Templates[0].Bases.Count); + Assert.AreEqual(1, md.TypeParameters.Count); + Assert.AreEqual("T", md.TypeParameters.Single().Name); + Assert.AreEqual(0, md.Constraints.Count()); } [Test] @@ -246,11 +282,11 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers "public static int ToInt32(this string s) { return int.Parse(s); }" ); Assert.AreEqual("ToInt32", md.Name); + Assert.AreEqual("s", md.Parameters.First().Name); + Assert.AreEqual(ParameterModifier.This, md.Parameters.First().ParameterModifier); + Assert.AreEqual("string", ((PrimitiveType)md.Parameters.First().Type).Keyword); Assert.IsTrue(md.IsExtensionMethod); - Assert.AreEqual("s", md.Parameters[0].ParameterName); - Assert.AreEqual("System.String", md.Parameters[0].TypeReference.Type); } - */ [Test] public void VoidExtensionMethodTest() @@ -265,7 +301,6 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers Assert.IsTrue(md.IsExtensionMethod); } - /* TODO [Test] public void MethodWithEmptyAssignmentErrorInBody() { @@ -277,27 +312,32 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers "}", true // expect errors ); Assert.AreEqual("A", md.Name); - Assert.AreEqual(new Location(1, 2), md.Body.StartLocation); - Assert.AreEqual(new Location(2, 5), md.Body.EndLocation); + Assert.AreEqual(new AstLocation(1, 2), md.Body.StartLocation); + Assert.AreEqual(new AstLocation(2, 5), md.Body.EndLocation); } [Test] public void OptionalParameterTest() { - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember( - "public void Foo(string bar = null, int baz = 0) { }" - ); - Assert.AreEqual("Foo", md.Name); - - Assert.AreEqual("bar", md.Parameters[0].ParameterName); - Assert.AreEqual("System.String", md.Parameters[0].TypeReference.Type); - Assert.AreEqual(ParameterModifiers.In | ParameterModifiers.Optional, md.Parameters[0].ParamModifier); - Assert.IsNull(((PrimitiveExpression)md.Parameters[0].DefaultValue).Value); - - Assert.AreEqual("baz", md.Parameters[1].ParameterName); - Assert.AreEqual("System.Int32", md.Parameters[1].TypeReference.Type); - Assert.AreEqual(ParameterModifiers.In | ParameterModifiers.Optional, md.Parameters[1].ParamModifier); - Assert.AreEqual(0, ((PrimitiveExpression)md.Parameters[1].DefaultValue).Value); - }*/ + ParseUtilCSharp.AssertTypeMember( + "public void Foo(string bar = null, int baz = 0) { }", + new MethodDeclaration { + Modifiers = Modifiers.Public, + ReturnType = new PrimitiveType("void"), + Name = "Foo", + Body = new BlockStatement(), + Parameters = { + new ParameterDeclaration { + Type = new PrimitiveType("string"), + Name = "bar", + DefaultExpression = new NullReferenceExpression() + }, + new ParameterDeclaration { + Type = new PrimitiveType("int"), + Name = "baz", + DefaultExpression = new PrimitiveExpression(0) + } + }}); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/OperatorDeclarationTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/OperatorDeclarationTests.cs index e2901f54e..4956d374a 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/OperatorDeclarationTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/OperatorDeclarationTests.cs @@ -10,43 +10,43 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers [TestFixture] public class OperatorDeclarationTests { - [Test, Ignore("type references not yet implemented")] + [Test] public void ImplictOperatorDeclarationTest() { OperatorDeclaration od = ParseUtilCSharp.ParseTypeMember("public static implicit operator double(MyObject f) { return 0.5d; }"); Assert.AreEqual(OperatorType.Implicit, od.OperatorType); Assert.AreEqual(1, od.Parameters.Count()); - Assert.AreEqual("System.Double", od.ReturnType); + Assert.AreEqual("double", ((PrimitiveType)od.ReturnType).Keyword); Assert.AreEqual("op_Implicit", od.Name); } - [Test, Ignore("type references not yet implemented")] + [Test] public void ExplicitOperatorDeclarationTest() { OperatorDeclaration od = ParseUtilCSharp.ParseTypeMember("public static explicit operator double(MyObject f) { return 0.5d; }"); Assert.AreEqual(OperatorType.Explicit, od.OperatorType); Assert.AreEqual(1, od.Parameters.Count()); - Assert.AreEqual("System.Double", od.ReturnType); + Assert.AreEqual("double", ((PrimitiveType)od.ReturnType).Keyword); Assert.AreEqual("op_Explicit", od.Name); } - [Test, Ignore("type references not yet implemented")] + [Test] public void BinaryPlusOperatorDeclarationTest() { OperatorDeclaration od = ParseUtilCSharp.ParseTypeMember("public static MyObject operator +(MyObject a, MyObject b) {}"); Assert.AreEqual(OperatorType.Addition, od.OperatorType); Assert.AreEqual(2, od.Parameters.Count()); - Assert.AreEqual("MyObject", od.ReturnType); + Assert.AreEqual("MyObject", ((SimpleType)od.ReturnType).Identifier); Assert.AreEqual("op_Addition", od.Name); } - [Test, Ignore("type references not yet implemented")] + [Test] public void UnaryPlusOperatorDeclarationTest() { OperatorDeclaration od = ParseUtilCSharp.ParseTypeMember("public static MyObject operator +(MyObject a) {}"); Assert.AreEqual(OperatorType.UnaryPlus, od.OperatorType); Assert.AreEqual(1, od.Parameters.Count()); - Assert.AreEqual("MyObject", od.ReturnType); + Assert.AreEqual("MyObject", ((SimpleType)od.ReturnType).Identifier); Assert.AreEqual("op_UnaryPlus", od.Name); } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/PropertyDeclarationTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/PropertyDeclarationTests.cs index 5c4bebed3..fba68f26e 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/PropertyDeclarationTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/PropertyDeclarationTests.cs @@ -66,7 +66,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers Assert.AreEqual(new AstLocation(4, code.IndexOf("}\n\t}") + 1 - line4Pos + 1), pd.Setter.Body.EndLocation); } - [Test, Ignore("type references not yet implemented")] + [Test, Ignore("explicit interface implementation not yet implemented")] public void PropertyImplementingInterfaceTest() { PropertyDeclaration pd = ParseUtilCSharp.ParseTypeMember("int MyInterface.MyProperty { get {} } "); @@ -74,10 +74,10 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers Assert.IsFalse(pd.Getter.IsNull); Assert.IsTrue(pd.Setter.IsNull); - Assert.AreEqual("MyInterface", pd.PrivateImplementationType); + Assert.AreEqual("MyInterface", ((SimpleType)pd.PrivateImplementationType).Identifier); } - [Test, Ignore("type references not yet implemented")] + [Test, Ignore("explicit interface implementation not yet implemented")] public void PropertyImplementingGenericInterfaceTest() { PropertyDeclaration pd = ParseUtilCSharp.ParseTypeMember("int MyInterface.MyProperty { get {} } "); @@ -85,9 +85,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers Assert.IsFalse(pd.Getter.IsNull); Assert.IsTrue(pd.Setter.IsNull); - throw new NotImplementedException(); - //Assert.AreEqual("MyInterface", pd.InterfaceImplementations[0].InterfaceType.Type); - //Assert.AreEqual("System.String", pd.InterfaceImplementations[0].InterfaceType.GenericTypes[0].Type); + Assert.IsNotNull(new SimpleType { Identifier = "MyInterface", TypeArguments = { new PrimitiveType("string") } }.Match(pd.PrivateImplementationType)); } } } diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs index 11ab8c47c..2f84aa28c 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs @@ -122,7 +122,7 @@ class A { Assert.AreEqual("System.Void", Resolve(program).Type.ReflectionName); } - [Test] + [Test, Ignore("parser is broken for events")] public void EventCallTest() { string program = @"using System; diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs index 374817f4d..40cd75b3b 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs @@ -366,7 +366,7 @@ class TestClass { Assert.AreEqual("System.Collections.ArrayList", member.Type.FullName, "the full type should be resolved"); } - [Test] + [Test, Ignore("Parser position bug")] public void ImportAliasNamespaceResolveTest() { NamespaceResolveResult ns; @@ -394,7 +394,7 @@ class TestClass { Assert.AreEqual("System.Collections.ArrayList", rr.Type.FullName, "a"); } - [Test] + [Test, Ignore("Parser position bug")] public void ResolveNamespaceSD_863() { string program = @"using System; @@ -432,7 +432,7 @@ namespace A.B { Assert.AreEqual("A.B.C", trr.Type.FullName); } - [Test] + [Test, Ignore("parser is broken and produces IdentifierExpression instead of PrimitiveType")] public void ShortMaxValueTest() { string program = @"using System; @@ -471,7 +471,7 @@ class TestClass { Assert.AreEqual("XX.XX.Test", mrr.Member.FullName); } - [Test] + [Test, Ignore("Parser position bug")] public void ClassNameLookup1() { string program = @"namespace MainNamespace { @@ -490,7 +490,7 @@ namespace Test.Subnamespace { Assert.AreEqual("Test.Subnamespace.Test.TheClass", trr.Type.FullName); } - [Test] + [Test, Ignore("Parser position bug")] public void ClassNameLookup2() { string program = @"using Test.Subnamespace; diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnsafeCodeTests.cs b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnsafeCodeTests.cs index bf77b15c9..f5ef169b6 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnsafeCodeTests.cs +++ b/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnsafeCodeTests.cs @@ -9,7 +9,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver [TestFixture] public class UnsafeCodeTests : ResolverTestBase { - [Test, Ignore("Parser produces parse tree that doesn't match DOM definition??")] + [Test, Ignore("fixed statement not implemented in parser")] public void FixedStatement() { string program = @"using System; diff --git a/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj index f08560c21..7bc0981b5 100644 --- a/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj +++ b/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj @@ -11,6 +11,7 @@ Properties 10.0.0 2.0 + Client x86 diff --git a/NRefactory/ICSharpCode.NRefactory.VB.Tests/ICSharpCode.NRefactory.VB.Tests.csproj b/NRefactory/ICSharpCode.NRefactory.VB.Tests/ICSharpCode.NRefactory.VB.Tests.csproj index db980b370..fef832cb3 100644 --- a/NRefactory/ICSharpCode.NRefactory.VB.Tests/ICSharpCode.NRefactory.VB.Tests.csproj +++ b/NRefactory/ICSharpCode.NRefactory.VB.Tests/ICSharpCode.NRefactory.VB.Tests.csproj @@ -19,6 +19,7 @@ 4 v4.0 false + Client True diff --git a/NRefactory/ICSharpCode.NRefactory.VB/ICSharpCode.NRefactory.VB.csproj b/NRefactory/ICSharpCode.NRefactory.VB/ICSharpCode.NRefactory.VB.csproj index 52d851010..477002241 100644 --- a/NRefactory/ICSharpCode.NRefactory.VB/ICSharpCode.NRefactory.VB.csproj +++ b/NRefactory/ICSharpCode.NRefactory.VB/ICSharpCode.NRefactory.VB.csproj @@ -9,6 +9,7 @@ ICSharpCode.NRefactory.VB v4.0 Properties + Client x86 diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstLocation.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstLocation.cs index 511d6fd06..2d0a5a796 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstLocation.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstLocation.cs @@ -57,11 +57,11 @@ namespace ICSharpCode.NRefactory.CSharp get { return column; } } - public override bool Equals (object other) + public override bool Equals (object obj) { - if (!(other is AstLocation)) + if (!(obj is AstLocation)) return false; - return (AstLocation)other == this; + return (AstLocation)obj == this; } public override int GetHashCode () diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs index a5361ef4f..2dab5a5ad 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs @@ -606,6 +606,11 @@ namespace ICSharpCode.NRefactory.CSharp } protected internal abstract bool DoMatch(AstNode other, Match match); + + internal virtual bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + return DoMatch(pos, match); + } #endregion // the Root role must be available when creating the null nodes, so we can't put it in the Roles class diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs index 033ad7913..c7f266d97 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs @@ -174,18 +174,12 @@ namespace ICSharpCode.NRefactory.CSharp if (cur1 == null) break; - Pattern pattern = cur1 as Pattern; - if (pattern == null && cur1.NodeType == NodeType.Placeholder) - pattern = cur1.GetChildByRole(TypePlaceholder.ChildRole) as Pattern; - if (pattern != null) { - Debug.Assert(stack.Count == patternStack.Count); - success = pattern.DoMatchCollection(role, cur2, match, stack); - Debug.Assert(stack.Count >= patternStack.Count); - while (stack.Count > patternStack.Count) - patternStack.Push(cur1.NextSibling); - } else { - success = cur1.DoMatch(cur2, match); - } + Debug.Assert(stack.Count == patternStack.Count); + success = cur1.DoMatchCollection(role, cur2, match, stack); + Debug.Assert(stack.Count >= patternStack.Count); + while (stack.Count > patternStack.Count) + patternStack.Push(cur1.NextSibling); + cur1 = cur1.NextSibling; if (cur2 != null) cur2 = cur2.NextSibling; diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs index 08bf473d4..a35204e3c 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs @@ -40,7 +40,7 @@ namespace ICSharpCode.NRefactory.CSharp return new ComposedType { BaseType = this }.MakePointerType(); } - public virtual AstType MakeArrayType(int rank) + public virtual AstType MakeArrayType(int rank = 1) { return new ComposedType { BaseType = this }.MakeArrayType(rank); } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs index 6b2b12959..ec0a85705 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs @@ -48,6 +48,12 @@ namespace ICSharpCode.NRefactory.CSharp } } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + CSharpModifierToken o = other as CSharpModifierToken; + return o != null && this.modifier == o.modifier; + } + // Not worth using a dictionary for such few elements. // This table is sorted in the order that modifiers should be output when generating code. static readonly List> lengthTable = new List> () { diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs index 4e6288963..a776f259f 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs @@ -88,7 +88,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { CSharpTokenNode o = other as CSharpTokenNode; - return o != null; + return o != null && !o.IsNull && !(o is CSharpModifierToken); } public override string ToString () diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs index 6578c5826..dffc3dd3d 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs @@ -41,7 +41,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { ArrayCreateExpression o = other as ArrayCreateExpression; - return o != null && this.Type.DoMatch(o.Type, match) && this.Arguments.DoMatch(o.Arguments, match) && this.Initializer.DoMatch(o.Initializer, match); + return o != null && this.Type.DoMatch(o.Type, match) && this.Arguments.DoMatch(o.Arguments, match) && this.AdditionalArraySpecifiers.DoMatch(o.AdditionalArraySpecifiers, match) && this.Initializer.DoMatch(o.Initializer, match); } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs index 79a357e87..9841a7468 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs @@ -45,7 +45,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { QueryExpression o = other as QueryExpression; - return o != null && this.Clauses.DoMatch(o.Clauses, match); + return o != null && !o.IsNull && this.Clauses.DoMatch(o.Clauses, match); } } @@ -54,12 +54,6 @@ namespace ICSharpCode.NRefactory.CSharp public override NodeType NodeType { get { return NodeType.QueryClause; } } - - protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) - { - QueryClause o = other as QueryClause; - throw new NotImplementedException(); - } } /// @@ -103,6 +97,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryContinuationClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryContinuationClause o = other as QueryContinuationClause; + return o != null && MatchString(this.Identifier, o.Identifier) && this.PrecedingQuery.DoMatch(o.PrecedingQuery, match); + } } public class QueryFromClause : QueryClause @@ -133,6 +133,13 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryFromClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryFromClause o = other as QueryFromClause; + return o != null && this.Type.DoMatch(o.Type, match) && MatchString(this.Identifier, o.Identifier) + && this.Expression.DoMatch(o.Expression, match); + } } public class QueryLetClause : QueryClause @@ -163,6 +170,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryLetClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryLetClause o = other as QueryLetClause; + return o != null && MatchString(this.Identifier, o.Identifier) && this.Expression.DoMatch(o.Expression, match); + } } @@ -181,6 +194,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryWhereClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryWhereClause o = other as QueryWhereClause; + return o != null && this.Condition.DoMatch(o.Condition, match); + } } /// @@ -266,6 +285,16 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryJoinClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryJoinClause o = other as QueryJoinClause; + return o != null && this.IsGroupJoin == o.IsGroupJoin + && this.Type.DoMatch(o.Type, match) && MatchString(this.JoinIdentifier, o.JoinIdentifier) + && this.InExpression.DoMatch(o.InExpression, match) && this.OnExpression.DoMatch(o.OnExpression, match) + && this.EqualsExpression.DoMatch(o.EqualsExpression, match) + && MatchString(this.IntoIdentifier, o.IntoIdentifier); + } } public class QueryOrderClause : QueryClause @@ -284,6 +313,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryOrderClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryOrderClause o = other as QueryOrderClause; + return o != null && this.Orderings.DoMatch(o.Orderings, match); + } } public class QueryOrdering : AstNode @@ -340,6 +375,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQuerySelectClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QuerySelectClause o = other as QuerySelectClause; + return o != null && this.Expression.DoMatch(o.Expression, match); + } } public class QueryGroupClause : QueryClause @@ -371,5 +412,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryGroupClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryGroupClause o = other as QueryGroupClause; + return o != null && this.Projection.DoMatch(o.Projection, match) && this.Key.DoMatch(o.Key, match); + } } } \ No newline at end of file diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/AttributeSection.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/AttributeSection.cs index a192718da..901f6ba06 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/AttributeSection.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/AttributeSection.cs @@ -64,6 +64,15 @@ namespace ICSharpCode.NRefactory.CSharp return o != null && this.AttributeTarget == o.AttributeTarget && this.Attributes.DoMatch(o.Attributes, match); } + public AttributeSection() + { + } + + public AttributeSection(Attribute attr) + { + this.Attributes.Add(attr); + } + public static string GetAttributeTargetName(AttributeTarget attributeTarget) { switch (attributeTarget) { diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs index 514a41192..8bac245c7 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs @@ -31,6 +31,9 @@ namespace ICSharpCode.NRefactory.CSharp /// /// where TypeParameter : BaseTypes /// + /// + /// new(), struct and class constraints are represented using a PrimitiveType "new", "struct" or "class" + /// public class Constraint : AstNode { public readonly static Role ColonRole = TypeDeclaration.ColonRole; @@ -51,8 +54,6 @@ namespace ICSharpCode.NRefactory.CSharp } } - // TODO: what about new(), struct and class constraints? - public AstNodeCollection BaseTypes { get { return GetChildrenByRole (BaseTypeRole); } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs index eccac9382..e014a4b3f 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs @@ -40,6 +40,11 @@ namespace ICSharpCode.NRefactory.CSharp } } + public AstType ReturnType { + get { return GetChildByRole (Roles.Type); } + set { SetChildByRole (Roles.Type, value); } + } + public string Name { get { return GetChildByRole (Roles.Identifier).Name; @@ -49,11 +54,6 @@ namespace ICSharpCode.NRefactory.CSharp } } - public AstType ReturnType { - get { return GetChildByRole (Roles.Type); } - set { SetChildByRole (Roles.Type, value); } - } - public AstNodeCollection TypeParameters { get { return GetChildrenByRole (Roles.TypeParameter); } } @@ -78,5 +78,14 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitDelegateDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + DelegateDeclaration o = other as DelegateDeclaration; + return o != null && this.MatchAttributesAndModifiers(o, match) + && this.ReturnType.DoMatch(o.ReturnType, match) && MatchString(this.Name, o.Name) + && this.TypeParameters.DoMatch(o.TypeParameters, match) && this.Parameters.DoMatch(o.Parameters, match) + && this.Constraints.DoMatch(o.Constraints, match); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs index fd638f2da..df7ac2138 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs @@ -87,5 +87,14 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitTypeDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + TypeDeclaration o = other as TypeDeclaration; + return o != null && this.ClassType == o.ClassType && this.MatchAttributesAndModifiers(o, match) + && MatchString(this.Name, o.Name) && this.TypeParameters.DoMatch(o.TypeParameters, match) + && this.BaseTypes.DoMatch(o.BaseTypes, match) && this.Constraints.DoMatch(o.Constraints, match) + && this.Members.DoMatch(o.Members, match); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs index 30e2fdf2f..84c9b2f50 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs @@ -15,12 +15,17 @@ namespace ICSharpCode.NRefactory.CSharp /// public class TypeParameterDeclaration : AstNode { + public static readonly Role AttributeRole = AttributedNode.AttributeRole; public static readonly Role VarianceRole = new Role("Variance"); public override NodeType NodeType { get { return NodeType.Unknown; } } + public AstNodeCollection Attributes { + get { return GetChildrenByRole (AttributeRole); } + } + public VarianceModifier Variance { get; set; } @@ -42,7 +47,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { TypeParameterDeclaration o = other as TypeParameterDeclaration; - return o != null && this.Variance == o.Variance && MatchString(this.Name, o.Name); + return o != null && this.Variance == o.Variance && MatchString(this.Name, o.Name) && this.Attributes.DoMatch(o.Attributes, match); } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs index f63e97bf7..2db1b06e0 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs @@ -43,6 +43,11 @@ namespace ICSharpCode.NRefactory.CSharp { return default (S); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + return other == null || other.IsNull; + } } public override NodeType NodeType { @@ -95,7 +100,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { Identifier o = other as Identifier; - return o != null && MatchString(this.Name, o.Name); + return o != null && !o.IsNull && MatchString(this.Name, o.Name); } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs index 70448e56a..b91048a5c 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs @@ -77,7 +77,7 @@ namespace ICSharpCode.NRefactory.CSharp b.Append(this.MemberName); if (this.TypeArguments.Any()) { b.Append('<'); - b.Append(string.Join(", ", this.TypeArguments)); + b.Append(DotNet35Compat.StringJoin(", ", this.TypeArguments)); b.Append('>'); } return b.ToString(); diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs index 073415f51..23f5c2ea5 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs @@ -29,14 +29,14 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching } } - internal virtual bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + public static implicit operator AstType(Pattern p) { - return DoMatch(pos, match); + return p != null ? new TypePlaceholder(p) : null; } - public AstType ToType() + public static implicit operator Expression(Pattern p) { - return new TypePlaceholder(this); + return p != null ? new ExpressionPlaceholder(p) : null; } public Expression ToExpression() @@ -44,19 +44,24 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching return new ExpressionPlaceholder(this); } + public static implicit operator Statement(Pattern p) + { + return p != null ? new StatementPlaceholder(p) : null; + } + public Statement ToStatement() { return new StatementPlaceholder(this); } - public BlockStatement ToBlock() + public static implicit operator BlockStatement(Pattern p) { - return new BlockStatementPlaceholder(this); + return p != null ? new BlockStatementPlaceholder(p) : null; } - public VariableInitializer ToVariable() + public static implicit operator VariableInitializer(Pattern p) { - return new VariablePlaceholder(this); + return p != null ? new VariablePlaceholder(p) : null; } // Make debugging easier by giving Patterns a ToString() implementation diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs index 2bac1c6e1..f68feb443 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs @@ -2,16 +2,19 @@ // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; +using System.Collections.Generic; namespace ICSharpCode.NRefactory.CSharp.PatternMatching { + // Placeholders do not store their child in the AST tree; but keep it as a separate child. + // This allows reusing the child in multiple placeholders; thus enabling the sharing of AST subtrees. sealed class TypePlaceholder : AstType { - public static readonly Role ChildRole = new Role("Child", AstNode.Null); + readonly AstNode child; public TypePlaceholder(AstNode child) { - AddChild(child, TypePlaceholder.ChildRole); + this.child = child; } public override NodeType NodeType { @@ -20,20 +23,27 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching public override S AcceptVisitor(IAstVisitor visitor, T data) { - return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, child, data); } protected internal override bool DoMatch(AstNode other, Match match) { - return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + return child.DoMatch(other, match); + } + + internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + return child.DoMatchCollection(role, pos, match, backtrackingStack); } } sealed class ExpressionPlaceholder : Expression { + readonly AstNode child; + public ExpressionPlaceholder(AstNode child) { - AddChild(child, TypePlaceholder.ChildRole); + this.child = child; } public override NodeType NodeType { @@ -42,20 +52,27 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching public override S AcceptVisitor(IAstVisitor visitor, T data) { - return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, child, data); } protected internal override bool DoMatch(AstNode other, Match match) { - return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + return child.DoMatch(other, match); + } + + internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + return child.DoMatchCollection(role, pos, match, backtrackingStack); } } sealed class StatementPlaceholder : Statement { + readonly AstNode child; + public StatementPlaceholder(AstNode child) { - AddChild(child, TypePlaceholder.ChildRole); + this.child = child; } public override NodeType NodeType { @@ -64,20 +81,27 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching public override S AcceptVisitor(IAstVisitor visitor, T data) { - return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, child, data); } protected internal override bool DoMatch(AstNode other, Match match) { - return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + return child.DoMatch(other, match); + } + + internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + return child.DoMatchCollection(role, pos, match, backtrackingStack); } } sealed class BlockStatementPlaceholder : BlockStatement { + readonly AstNode child; + public BlockStatementPlaceholder(AstNode child) { - AddChild(child, TypePlaceholder.ChildRole); + this.child = child; } public override NodeType NodeType { @@ -86,20 +110,27 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching public override S AcceptVisitor(IAstVisitor visitor, T data) { - return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, child, data); } protected internal override bool DoMatch(AstNode other, Match match) { - return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + return child.DoMatch(other, match); + } + + internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + return child.DoMatchCollection(role, pos, match, backtrackingStack); } } sealed class VariablePlaceholder : VariableInitializer { + readonly AstNode child; + public VariablePlaceholder(AstNode child) { - AddChild(child, TypePlaceholder.ChildRole); + this.child = child; } public override NodeType NodeType { @@ -108,12 +139,17 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching public override S AcceptVisitor(IAstVisitor visitor, T data) { - return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, child, data); } protected internal override bool DoMatch(AstNode other, Match match) { - return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + return child.DoMatch(other, match); + } + + internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + return child.DoMatchCollection(role, pos, match, backtrackingStack); } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/SimpleType.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/SimpleType.cs index 55839229c..237b3b55b 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/SimpleType.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/SimpleType.cs @@ -76,7 +76,7 @@ namespace ICSharpCode.NRefactory.CSharp StringBuilder b = new StringBuilder(this.Identifier); if (this.TypeArguments.Any()) { b.Append('<'); - b.Append(string.Join(", ", this.TypeArguments)); + b.Append(DotNet35Compat.StringJoin(", ", this.TypeArguments)); b.Append('>'); } return b.ToString(); diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs index d43a0d538..9ee89966d 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs @@ -77,7 +77,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { BlockStatement o = other as BlockStatement; - return o != null && this.Statements.DoMatch(o.Statements, match); + return o != null && !o.IsNull && this.Statements.DoMatch(o.Statements, match); } #region Builder methods diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs index b1b7759f0..9a8efbc9a 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs @@ -67,7 +67,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { FixedStatement o = other as FixedStatement; - return o != null && this.Variables.DoMatch(o.Variables, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); + return o != null && this.Type.DoMatch(o.Type, match) && this.Variables.DoMatch(o.Variables, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/Accessor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/Accessor.cs index 910aec75f..c487032eb 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/Accessor.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/Accessor.cs @@ -64,7 +64,8 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { - throw new NotImplementedException(); + Accessor o = other as Accessor; + return o != null && !o.IsNull && this.MatchAttributesAndModifiers(o, match) && this.Body.DoMatch(o.Body, match); } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs index 1b878d91c..41eec380d 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs @@ -58,9 +58,9 @@ namespace ICSharpCode.NRefactory.CSharp } } - protected internal override bool DoMatch(AstNode other, ICSharpCode.NRefactory.CSharp.PatternMatching.Match match) + protected bool MatchAttributesAndModifiers(AttributedNode o, PatternMatching.Match match) { - throw new NotImplementedException(); + return this.Modifiers == o.Modifiers && this.Attributes.DoMatch(o.Attributes, match); } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ConstructorDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ConstructorDeclaration.cs index 97f808051..4971a4eec 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ConstructorDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ConstructorDeclaration.cs @@ -70,6 +70,13 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitConstructorDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ConstructorDeclaration o = other as ConstructorDeclaration; + return o != null && this.MatchAttributesAndModifiers(o, match) && this.Parameters.DoMatch(o.Parameters, match) + && this.Initializer.DoMatch(o.Initializer, match) && this.Body.DoMatch(o.Body, match); + } } public enum ConstructorInitializerType { @@ -98,6 +105,11 @@ namespace ICSharpCode.NRefactory.CSharp { return default (S); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + return other == null || other.IsNull; + } } public override NodeType NodeType { @@ -123,7 +135,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { ConstructorInitializer o = other as ConstructorInitializer; - return o != null && this.ConstructorInitializerType == o.ConstructorInitializerType && this.Arguments.DoMatch(o.Arguments, match); + return o != null && !o.IsNull && this.ConstructorInitializerType == o.ConstructorInitializerType && this.Arguments.DoMatch(o.Arguments, match); } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/DestructorDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/DestructorDeclaration.cs index 2798d0660..8a892b275 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/DestructorDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/DestructorDeclaration.cs @@ -1,6 +1,6 @@ // // DestructorDeclaration.cs -// +// // Author: // Mike Krüger // @@ -61,5 +61,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitDestructorDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + DestructorDeclaration o = other as DestructorDeclaration; + return o != null && this.MatchAttributesAndModifiers(o, match) && this.Body.DoMatch(o.Body, match); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EnumMemberDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EnumMemberDeclaration.cs index 0715898f0..e2784f565 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EnumMemberDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EnumMemberDeclaration.cs @@ -1,6 +1,6 @@ -// +// // EnumMemberDeclaration.cs -// +// // Author: // Mike Krüger // @@ -53,6 +53,13 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitEnumMemberDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + EnumMemberDeclaration o = other as EnumMemberDeclaration; + return o != null && this.MatchAttributesAndModifiers(o, match) + && MatchString(this.Name, o.Name) && this.Initializer.DoMatch(o.Initializer, match); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EventDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EventDeclaration.cs index 3a916782d..49d28ede3 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EventDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EventDeclaration.cs @@ -28,8 +28,17 @@ using System.Collections.Generic; namespace ICSharpCode.NRefactory.CSharp { - public class EventDeclaration : MemberDeclaration + public class EventDeclaration : AttributedNode { + public override NodeType NodeType { + get { return NodeType.Member; } + } + + public AstType ReturnType { + get { return GetChildByRole (Roles.Type); } + set { SetChildByRole(Roles.Type, value); } + } + public AstNodeCollection Variables { get { return GetChildrenByRole (Roles.Variable); } } @@ -38,6 +47,13 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitEventDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + EventDeclaration o = other as EventDeclaration; + return o != null && this.MatchAttributesAndModifiers(o, match) + && this.ReturnType.DoMatch(o.ReturnType, match) && this.Variables.DoMatch(o.Variables, match); + } } public class CustomEventDeclaration : MemberDeclaration @@ -67,5 +83,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitCustomEventDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + CustomEventDeclaration o = other as CustomEventDeclaration; + return o != null && this.MatchMember(o, match) + && this.AddAccessor.DoMatch(o.AddAccessor, match) && this.RemoveAccessor.DoMatch(o.RemoveAccessor, match); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/FieldDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/FieldDeclaration.cs index 3ca04772d..1003aa9b7 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/FieldDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/FieldDeclaration.cs @@ -1,6 +1,6 @@ // // FieldDeclaration.cs -// +// // Author: // Mike Krüger // @@ -29,9 +29,18 @@ using System.Linq; namespace ICSharpCode.NRefactory.CSharp { - public class FieldDeclaration : MemberDeclaration + public class FieldDeclaration : AttributedNode { - public AstNodeCollection Variables { + public override NodeType NodeType { + get { return NodeType.Member; } + } + + public AstType ReturnType { + get { return GetChildByRole (Roles.Type); } + set { SetChildByRole(Roles.Type, value); } + } + + public AstNodeCollection Variables { get { return GetChildrenByRole (Roles.Variable); } } @@ -39,5 +48,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitFieldDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + FieldDeclaration o = other as FieldDeclaration; + return o != null && this.MatchAttributesAndModifiers(o, match) + && this.ReturnType.DoMatch(o.ReturnType, match) && this.Variables.DoMatch(o.Variables, match); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/IndexerDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/IndexerDeclaration.cs index 5b63c9c4f..4d19c97d7 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/IndexerDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/IndexerDeclaration.cs @@ -1,6 +1,6 @@ // // IndexerDeclaration.cs -// +// // Author: // Mike Krüger // @@ -29,13 +29,16 @@ using System.Linq; namespace ICSharpCode.NRefactory.CSharp { - public class IndexerDeclaration : PropertyDeclaration + public class IndexerDeclaration : MemberDeclaration { + public static readonly Role GetterRole = PropertyDeclaration.GetterRole; + public static readonly Role SetterRole = PropertyDeclaration.SetterRole; + public CSharpTokenNode LBracketToken { get { return GetChildByRole (Roles.LBracket); } } - public AstNodeCollection Parameters { + public AstNodeCollection Parameters { get { return GetChildrenByRole (Roles.Parameter); } } @@ -43,9 +46,34 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.RBracket); } } + public CSharpTokenNode LBraceToken { + get { return GetChildByRole (Roles.LBrace); } + } + + public Accessor Getter { + get { return GetChildByRole(GetterRole); } + set { SetChildByRole(GetterRole, value); } + } + + public Accessor Setter { + get { return GetChildByRole(SetterRole); } + set { SetChildByRole(SetterRole, value); } + } + + public CSharpTokenNode RBraceToken { + get { return GetChildByRole (Roles.RBrace); } + } + public override S AcceptVisitor (IAstVisitor visitor, T data) { return visitor.VisitIndexerDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + IndexerDeclaration o = other as IndexerDeclaration; + return o != null && this.MatchMember(o, match) && this.Parameters.DoMatch(o.Parameters, match) + && this.Getter.DoMatch(o.Getter, match) && this.Setter.DoMatch(o.Setter, match); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MemberDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MemberDeclaration.cs index 5cd468cfe..a7e1b74e4 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MemberDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MemberDeclaration.cs @@ -55,5 +55,11 @@ namespace ICSharpCode.NRefactory.CSharp public override NodeType NodeType { get { return NodeType.Member; } } + + protected bool MatchMember(MemberDeclaration o, PatternMatching.Match match) + { + return MatchAttributesAndModifiers(o, match) && this.ReturnType.DoMatch(o.ReturnType, match) + && this.PrivateImplementationType.DoMatch(o.PrivateImplementationType, match) && MatchString(this.Name, o.Name); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MethodDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MethodDeclaration.cs index ef740bd86..556c0a3a4 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MethodDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MethodDeclaration.cs @@ -1,6 +1,6 @@ // // MethodDeclaration.cs -// +// // Author: // Mike Krüger // @@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.LPar); } } - public AstNodeCollection Parameters { + public AstNodeCollection Parameters { get { return GetChildrenByRole (Roles.Parameter); } } @@ -47,7 +47,7 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.RPar); } } - public AstNodeCollection Constraints { + public AstNodeCollection Constraints { get { return GetChildrenByRole (Roles.Constraint); } } @@ -67,5 +67,13 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitMethodDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + MethodDeclaration o = other as MethodDeclaration; + return o != null && this.MatchMember(o, match) && this.TypeParameters.DoMatch(o.TypeParameters, match) + && this.Parameters.DoMatch(o.Parameters, match) && this.Constraints.DoMatch(o.Constraints, match) + && this.Body.DoMatch(o.Body, match); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs index c8a326c49..7215412eb 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs @@ -1,6 +1,6 @@ // // OperatorDeclaration.cs -// +// // Author: // Mike Krüger // @@ -66,7 +66,7 @@ namespace ICSharpCode.NRefactory.CSharp Explicit } - public class OperatorDeclaration : MemberDeclaration + public class OperatorDeclaration : AttributedNode { public static readonly Role OperatorTypeRole = new Role("OperatorType", CSharpTokenNode.Null); public static readonly Role OperatorKeywordRole = Roles.Keyword; @@ -76,11 +76,16 @@ namespace ICSharpCode.NRefactory.CSharp set; } + public AstType ReturnType { + get { return GetChildByRole (Roles.Type); } + set { SetChildByRole(Roles.Type, value); } + } + public CSharpTokenNode LParToken { get { return GetChildByRole (Roles.LPar); } } - public AstNodeCollection Parameters { + public AstNodeCollection Parameters { get { return GetChildrenByRole (Roles.Parameter); } } @@ -103,9 +108,25 @@ namespace ICSharpCode.NRefactory.CSharp return Mono.CSharp.Operator.GetName((Mono.CSharp.Operator.OpType)type); } + public override NodeType NodeType { + get { return NodeType.Member; } + } + public override S AcceptVisitor (IAstVisitor visitor, T data) { return visitor.VisitOperatorDeclaration (this, data); } + + public string Name { + get { return GetName(this.OperatorType); } + } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + OperatorDeclaration o = other as OperatorDeclaration; + return o != null && this.MatchAttributesAndModifiers(o, match) && this.OperatorType == o.OperatorType + && this.ReturnType.DoMatch(o.ReturnType, match) + && this.Parameters.DoMatch(o.Parameters, match) && this.Body.DoMatch(o.Body, match); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs index 0334d2a3f..5544c5aa7 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs @@ -85,7 +85,19 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { ParameterDeclaration o = other as ParameterDeclaration; - return o != null && this.Attributes.DoMatch(o.Attributes, match) && this.ParameterModifier == o.ParameterModifier && MatchString(this.Name, o.Name) && this.DefaultExpression.DoMatch(o.DefaultExpression, match); + return o != null && this.Attributes.DoMatch(o.Attributes, match) && this.ParameterModifier == o.ParameterModifier + && this.Type.DoMatch(o.Type, match) && MatchString(this.Name, o.Name) + && this.DefaultExpression.DoMatch(o.DefaultExpression, match); + } + + public ParameterDeclaration() + { + } + + public ParameterDeclaration(AstType type, string name) + { + this.Type = type; + this.Name = name; } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/PropertyDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/PropertyDeclaration.cs index d13ce8f5c..2d1376a0e 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/PropertyDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/PropertyDeclaration.cs @@ -1,6 +1,6 @@ -// +// // PropertyDeclaration.cs -// +// // Author: // Mike Krüger // @@ -53,5 +53,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitPropertyDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + PropertyDeclaration o = other as PropertyDeclaration; + return o != null && this.MatchMember(o, match) + && this.Getter.DoMatch(o.Getter, match) && this.Setter.DoMatch(o.Setter, match); + } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs index 88995ee47..5f9d0f1c7 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs @@ -22,7 +22,7 @@ namespace ICSharpCode.NRefactory.CSharp readonly IOutputFormatter formatter; readonly CSharpFormattingPolicy policy; - AstNode currentContainerNode; + readonly Stack containerStack = new Stack(); readonly Stack positionStack = new Stack(); /// @@ -65,21 +65,23 @@ namespace ICSharpCode.NRefactory.CSharp #region StartNode/EndNode void StartNode(AstNode node) { - Debug.Assert(currentContainerNode == null || node.Parent == currentContainerNode); + // Ensure that nodes are visited in the proper nested order. + // Jumps to different subtrees are allowed only for the child of a placeholder node. + Debug.Assert(containerStack.Count == 0 || node.Parent == containerStack.Peek() || containerStack.Peek().NodeType == NodeType.Placeholder); if (positionStack.Count > 0) WriteSpecialsUpToNode(node); - currentContainerNode = node; + containerStack.Push(node); positionStack.Push(node.FirstChild); formatter.StartNode(node); } object EndNode(AstNode node) { - Debug.Assert(node == currentContainerNode); + Debug.Assert(node == containerStack.Peek()); AstNode pos = positionStack.Pop(); Debug.Assert(pos == null || pos.Parent == node); WriteSpecials(pos, null); - currentContainerNode = node.Parent; + containerStack.Pop(); formatter.EndNode(node); return null; } @@ -146,13 +148,14 @@ namespace ICSharpCode.NRefactory.CSharp /// Writes a comma. /// /// The next node after the comma. - void Comma(AstNode nextNode) + /// When set prevents printing a space after comma. + void Comma(AstNode nextNode, bool noSpaceAfterComma = false) { WriteSpecialsUpToRole(AstNode.Roles.Comma, nextNode); Space(policy.SpacesBeforeComma); formatter.WriteToken(","); lastWritten = LastWritten.Other; - Space(policy.SpacesAfterComma); + Space(!noSpaceAfterComma && policy.SpacesAfterComma); } void WriteCommaSeparatedList(IEnumerable list) @@ -179,12 +182,34 @@ namespace ICSharpCode.NRefactory.CSharp RPar(); } - void WriteCommaSeparatedListInBrackets(IEnumerable list) + #if DOTNET35 + void WriteCommaSeparatedList(IEnumerable list) + { + WriteCommaSeparatedList(list.SafeCast()); + } + + void WriteCommaSeparatedList(IEnumerable list) + { + WriteCommaSeparatedList(list.SafeCast()); + } + + void WriteCommaSeparatedListInParenthesis(IEnumerable list, bool spaceWithin) + { + WriteCommaSeparatedListInParenthesis(list.SafeCast(), spaceWithin); + } + + void WriteCommaSeparatedListInParenthesis(IEnumerable list, bool spaceWithin) + { + WriteCommaSeparatedListInParenthesis(list.SafeCast(), spaceWithin); + } + #endif + + void WriteCommaSeparatedListInBrackets(IEnumerable list) { WriteToken("[", AstNode.Roles.LBracket); if (list.Any()) { Space(policy.SpacesWithinBrackets); - WriteCommaSeparatedList(list); + WriteCommaSeparatedList(list.SafeCast()); Space(policy.SpacesWithinBrackets); } WriteToken("]", AstNode.Roles.RBracket); @@ -207,7 +232,7 @@ namespace ICSharpCode.NRefactory.CSharp void WriteIdentifier(string identifier, Role identifierRole = null) { WriteSpecialsUpToRole(identifierRole ?? AstNode.Roles.Identifier); - if (IsKeyword(identifier, currentContainerNode)) { + if (IsKeyword(identifier, containerStack.Peek())) { if (lastWritten == LastWritten.KeywordOrIdentifier) Space(); // this space is not strictly required, so we call Space() formatter.WriteToken("@"); @@ -265,7 +290,8 @@ namespace ICSharpCode.NRefactory.CSharp /// void Semicolon() { - if (currentContainerNode.Role != ForStatement.InitializerRole && currentContainerNode.Role != ForStatement.IteratorRole && currentContainerNode.Role != UsingStatement.ResourceAcquisitionRole) { + Role role = containerStack.Peek().Role; // get the role of the current node + if (!(role == ForStatement.InitializerRole || role == ForStatement.IteratorRole || role == UsingStatement.ResourceAcquisitionRole)) { WriteToken(";", AstNode.Roles.Semicolon); NewLine(); } @@ -351,7 +377,7 @@ namespace ICSharpCode.NRefactory.CSharp { if (typeParameters.Any()) { WriteToken("<", AstNode.Roles.LChevron); - WriteCommaSeparatedList(typeParameters); + WriteCommaSeparatedList(typeParameters.SafeCast()); WriteToken(">", AstNode.Roles.RChevron); } } @@ -758,52 +784,75 @@ namespace ICSharpCode.NRefactory.CSharp public object VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data) { StartNode(primitiveExpression); - formatter.WriteToken(ToCSharpString(primitiveExpression)); - lastWritten = LastWritten.Other; + WritePrimitiveValue(primitiveExpression.Value); return EndNode(primitiveExpression); } - internal static string ToCSharpString(PrimitiveExpression primitiveExpression) + void WritePrimitiveValue(object val) { - if (primitiveExpression.Value == null) { - return "null"; + if (val == null) { + // usually NullReferenceExpression should be used for this, but we'll handle it anyways + WriteKeyword("null"); + return; } - object val = primitiveExpression.Value; - if (val is bool) { if ((bool)val) { - return "true"; + WriteKeyword("true"); } else { - return "false"; + WriteKeyword("false"); } + return; } if (val is string) { - return "\"" + ConvertString(val.ToString()) + "\""; - } - - if (val is char) { - return "'" + ConvertCharLiteral((char)val) + "'"; - } - - if (val is decimal) { - return ((decimal)val).ToString(NumberFormatInfo.InvariantInfo) + "m"; - } - - if (val is float) { - return ((float)val).ToString(NumberFormatInfo.InvariantInfo) + "f"; - } - - if (val is double) { - string text = ((double)val).ToString(NumberFormatInfo.InvariantInfo); - if (text.IndexOf('.') < 0 && text.IndexOf('E') < 0) - return text + ".0"; - else - return text; - } - - if (val is IFormattable) { + formatter.WriteToken("\"" + ConvertString(val.ToString()) + "\""); + lastWritten = LastWritten.Other; + } else if (val is char) { + formatter.WriteToken("'" + ConvertCharLiteral((char)val) + "'"); + lastWritten = LastWritten.Other; + } else if (val is decimal) { + formatter.WriteToken(((decimal)val).ToString(NumberFormatInfo.InvariantInfo) + "m"); + lastWritten = LastWritten.Other; + } else if (val is float) { + float f = (float)val; + if (float.IsInfinity(f) || float.IsNaN(f)) { + // Strictly speaking, these aren't PrimitiveExpressions; + // but we still support writing these to make life easier for code generators. + WriteKeyword("float"); + WriteToken(".", AstNode.Roles.Dot); + if (float.IsPositiveInfinity(f)) + WriteIdentifier("PositiveInfinity"); + else if (float.IsNegativeInfinity(f)) + WriteIdentifier("NegativeInfinity"); + else + WriteIdentifier("NaN"); + return; + } + formatter.WriteToken(f.ToString("R", NumberFormatInfo.InvariantInfo) + "f"); + lastWritten = LastWritten.Other; + } else if (val is double) { + double f = (double)val; + if (double.IsInfinity(f) || double.IsNaN(f)) { + // Strictly speaking, these aren't PrimitiveExpressions; + // but we still support writing these to make life easier for code generators. + WriteKeyword("double"); + WriteToken(".", AstNode.Roles.Dot); + if (double.IsPositiveInfinity(f)) + WriteIdentifier("PositiveInfinity"); + else if (double.IsNegativeInfinity(f)) + WriteIdentifier("NegativeInfinity"); + else + WriteIdentifier("NaN"); + return; + } + string number = f.ToString("R", NumberFormatInfo.InvariantInfo); + if (number.IndexOf('.') < 0 && number.IndexOf('E') < 0) + number += ".0"; + formatter.WriteToken(number); + // needs space if identifier follows number; this avoids mistaking the following identifier as type suffix + lastWritten = LastWritten.KeywordOrIdentifier; + } else if (val is IFormattable) { StringBuilder b = new StringBuilder(); // if (primitiveExpression.LiteralFormat == LiteralFormat.HexadecimalNumber) { // b.Append("0x"); @@ -817,13 +866,15 @@ namespace ICSharpCode.NRefactory.CSharp if (val is long || val is ulong) { b.Append("L"); } - return b.ToString(); + formatter.WriteToken(b.ToString()); + // needs space if identifier follows number; this avoids mistaking the following identifier as type suffix + lastWritten = LastWritten.KeywordOrIdentifier; } else { - return val.ToString(); + formatter.WriteToken(val.ToString()); + lastWritten = LastWritten.Other; } } - static string ConvertCharLiteral(char ch) { if (ch == '\'') return "\\'"; @@ -1043,7 +1094,7 @@ namespace ICSharpCode.NRefactory.CSharp StartNode(queryOrderClause); WriteKeyword("orderby"); Space(); - WriteCommaSeparatedList(queryOrderClause.Orderings); + WriteCommaSeparatedList(queryOrderClause.Orderings.SafeCast()); return EndNode(queryOrderClause); } @@ -1093,7 +1144,8 @@ namespace ICSharpCode.NRefactory.CSharp StartNode(attribute); attribute.Type.AcceptVisitor(this, data); Space(policy.BeforeMethodCallParentheses); - WriteCommaSeparatedListInParenthesis(attribute.Arguments, policy.WithinMethodCallParentheses); + if (attribute.Arguments.Count != 0 || !attribute.GetChildByRole(AstNode.Roles.LPar).IsNull) + WriteCommaSeparatedListInParenthesis(attribute.Arguments, policy.WithinMethodCallParentheses); return EndNode(attribute); } @@ -1106,9 +1158,12 @@ namespace ICSharpCode.NRefactory.CSharp WriteToken(":", AttributeSection.Roles.Colon); Space(); } - WriteCommaSeparatedList(attributeSection.Attributes); + WriteCommaSeparatedList(attributeSection.Attributes.SafeCast()); WriteToken("]", AstNode.Roles.RBracket); - NewLine(); + if (attributeSection.Parent is ParameterDeclaration || attributeSection.Parent is TypeParameterDeclaration) + Space(); + else + NewLine(); return EndNode(attributeSection); } @@ -1186,7 +1241,7 @@ namespace ICSharpCode.NRefactory.CSharp if (first) { first = false; } else { - Comma(member); + Comma(member, noSpaceAfterComma: true); NewLine(); } member.AcceptVisitor(this, data); @@ -1355,7 +1410,7 @@ namespace ICSharpCode.NRefactory.CSharp LPar(); Space(policy.WithinForParentheses); - WriteCommaSeparatedList(forStatement.Initializers); + WriteCommaSeparatedList(forStatement.Initializers.SafeCast()); WriteToken(";", AstNode.Roles.Semicolon); Space(policy.SpacesAfterSemicolon); @@ -1363,7 +1418,7 @@ namespace ICSharpCode.NRefactory.CSharp WriteToken(";", AstNode.Roles.Semicolon); Space(policy.SpacesAfterSemicolon); - WriteCommaSeparatedList(forStatement.Iterators); + WriteCommaSeparatedList(forStatement.Iterators.SafeCast()); Space(policy.WithinForParentheses); RPar(); @@ -1899,7 +1954,10 @@ namespace ICSharpCode.NRefactory.CSharp { StartNode(memberType); memberType.Target.AcceptVisitor(this, data); - WriteToken(".", MemberType.Roles.Dot); + if (memberType.IsDoubleColon) + WriteToken("::", MemberType.Roles.Dot); + else + WriteToken(".", MemberType.Roles.Dot); WriteIdentifier(memberType.MemberName); WriteTypeArguments(memberType.TypeArguments); return EndNode(memberType); @@ -1935,6 +1993,11 @@ namespace ICSharpCode.NRefactory.CSharp { StartNode(primitiveType); WriteKeyword(primitiveType.Keyword); + if (primitiveType.Keyword == "new") { + // new() constraint + LPar(); + RPar(); + } return EndNode(primitiveType); } @@ -1953,6 +2016,7 @@ namespace ICSharpCode.NRefactory.CSharp public object VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration, object data) { StartNode(typeParameterDeclaration); + WriteAttributes(typeParameterDeclaration.Attributes); switch (typeParameterDeclaration.Variance) { case VarianceModifier.Invariant: break; diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs index bb447f4c6..68ac7ee2f 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs @@ -225,7 +225,7 @@ namespace ICSharpCode.NRefactory.CSharp var typeArgLocation = LocationsBag.GetLocations (c.MemberName); if (typeArgLocation != null) newType.AddChild (new CSharpTokenNode (Convert (typeArgLocation[0]), 1), TypeDeclaration.Roles.LChevron); -// AddTypeArguments (newType, typeArgLocation, c.MemberName.TypeArguments); + AddTypeParameters (newType, typeArgLocation, c.MemberName.TypeArguments); if (typeArgLocation != null) newType.AddChild (new CSharpTokenNode (Convert (typeArgLocation[1]), 1), TypeDeclaration.Roles.RChevron); AddConstraints (newType, c); @@ -254,7 +254,7 @@ namespace ICSharpCode.NRefactory.CSharp var typeArgLocation = LocationsBag.GetLocations (s.MemberName); if (typeArgLocation != null) newType.AddChild (new CSharpTokenNode (Convert (typeArgLocation[0]), 1), TypeDeclaration.Roles.LChevron); -// AddTypeArguments (newType, typeArgLocation, s.MemberName.TypeArguments); + AddTypeParameters (newType, typeArgLocation, s.MemberName.TypeArguments); if (typeArgLocation != null) newType.AddChild (new CSharpTokenNode (Convert (typeArgLocation[1]), 1), TypeDeclaration.Roles.RChevron); AddConstraints (newType, s); @@ -283,7 +283,7 @@ namespace ICSharpCode.NRefactory.CSharp var typeArgLocation = LocationsBag.GetLocations (i.MemberName); if (typeArgLocation != null) newType.AddChild (new CSharpTokenNode (Convert (typeArgLocation[0]), 1), MemberReferenceExpression.Roles.LChevron); -// AddTypeArguments (newType, typeArgLocation, i.MemberName.TypeArguments); + AddTypeParameters (newType, typeArgLocation, i.MemberName.TypeArguments); if (typeArgLocation != null) newType.AddChild (new CSharpTokenNode (Convert (typeArgLocation[1]), 1), MemberReferenceExpression.Roles.RChevron); AddConstraints (newType, i); @@ -307,12 +307,12 @@ namespace ICSharpCode.NRefactory.CSharp if (location != null) newDelegate.AddChild (new CSharpTokenNode (Convert (location[0]), "delegate".Length), TypeDeclaration.Roles.Keyword); newDelegate.AddChild (ConvertToType (d.ReturnType), AstNode.Roles.Type); - newDelegate.AddChild (new Identifier (d.Name, Convert (d.MemberName.Location)), AstNode.Roles.Identifier); + newDelegate.AddChild (new Identifier (d.Basename, Convert (d.MemberName.Location)), AstNode.Roles.Identifier); if (d.MemberName.TypeArguments != null) { var typeArgLocation = LocationsBag.GetLocations (d.MemberName); if (typeArgLocation != null) newDelegate.AddChild (new CSharpTokenNode (Convert (typeArgLocation[0]), 1), TypeDeclaration.Roles.LChevron); -// AddTypeArguments (newDelegate, typeArgLocation, d.MemberName.TypeArguments); + AddTypeParameters (newDelegate, typeArgLocation, d.MemberName.TypeArguments); if (typeArgLocation != null) newDelegate.AddChild (new CSharpTokenNode (Convert (typeArgLocation[1]), 1), TypeDeclaration.Roles.RChevron); AddConstraints (newDelegate, d); @@ -632,7 +632,7 @@ namespace ICSharpCode.NRefactory.CSharp var typeArgLocation = LocationsBag.GetLocations (m.MemberName); if (typeArgLocation != null) newMethod.AddChild (new CSharpTokenNode (Convert (typeArgLocation[0]), 1), MemberReferenceExpression.Roles.LChevron); -// AddTypeArguments (newMethod, typeArgLocation, m.MemberName.TypeArguments); + AddTypeParameters (newMethod, typeArgLocation, m.MemberName.TypeArguments); if (typeArgLocation != null) newMethod.AddChild (new CSharpTokenNode (Convert (typeArgLocation[1]), 1), MemberReferenceExpression.Roles.RChevron); @@ -1234,7 +1234,7 @@ namespace ICSharpCode.NRefactory.CSharp statement.Remove (); newSection.AddChild (statement, SwitchSection.Roles.EmbeddedStatement); - } + } result.AddChild (newSection, SwitchStatement.SwitchSectionRole); } @@ -1835,17 +1835,22 @@ namespace ICSharpCode.NRefactory.CSharp } } - void AddTypeArguments (AstNode parent, LocationsBag.MemberLocations location, Mono.CSharp.TypeArguments typeArguments) + void AddTypeParameters (AstNode parent, List location, Mono.CSharp.TypeArguments typeArguments) { if (typeArguments == null || typeArguments.IsEmpty) return; for (int i = 0; i < typeArguments.Count; i++) { if (location != null && i > 0 && i - 1 < location.Count) parent.AddChild (new CSharpTokenNode (Convert (location[i - 1]), 1), InvocationExpression.Roles.Comma); - var arg = typeArguments.Args[i]; + var arg = (TypeParameterName)typeArguments.Args[i]; if (arg == null) continue; - parent.AddChild (ConvertToType (arg), InvocationExpression.Roles.TypeArgument); + TypeParameterDeclaration tp = new TypeParameterDeclaration(); + // TODO: attributes + if (arg.Variance != Variance.None) + throw new NotImplementedException(); // TODO: variance + tp.AddChild (new Identifier (arg.Name, Convert (arg.Location)), InvocationExpression.Roles.Identifier); + parent.AddChild (tp, InvocationExpression.Roles.TypeParameter); } } @@ -1871,11 +1876,12 @@ namespace ICSharpCode.NRefactory.CSharp Constraints c = d.Constraints[i]; var location = LocationsBag.GetLocations (c); var constraint = new Constraint (); - parent.AddChild (new CSharpTokenNode (Convert (location[0]), "where".Length), InvocationExpression.Roles.Keyword); - parent.AddChild (new Identifier (c.TypeParameter.Value, Convert (c.TypeParameter.Location)), InvocationExpression.Roles.Identifier); - parent.AddChild (new CSharpTokenNode (Convert (location[1]), 1), Constraint.ColonRole); + constraint.AddChild (new CSharpTokenNode (Convert (location[0]), "where".Length), InvocationExpression.Roles.Keyword); + constraint.AddChild (new Identifier (c.TypeParameter.Value, Convert (c.TypeParameter.Location)), InvocationExpression.Roles.Identifier); + constraint.AddChild (new CSharpTokenNode (Convert (location[1]), 1), Constraint.ColonRole); foreach (var expr in c.ConstraintExpressions) - parent.AddChild (ConvertToType (expr), Constraint.BaseTypeRole); + constraint.AddChild (ConvertToType (expr), Constraint.BaseTypeRole); + parent.AddChild (constraint, AstNode.Roles.Constraint); } } @@ -1892,7 +1898,7 @@ namespace ICSharpCode.NRefactory.CSharp DirectionExpression direction = new DirectionExpression (); direction.FieldDirection = arg.ArgType == Argument.AType.Out ? FieldDirection.Out : FieldDirection.Ref; var argLocation = LocationsBag.GetLocations (arg); - if (location != null) + if (argLocation != null) direction.AddChild (new CSharpTokenNode (Convert (argLocation[0]), "123".Length), InvocationExpression.Roles.Keyword); direction.AddChild ((Expression)arg.Expr.Accept (this), InvocationExpression.Roles.Expression); @@ -2115,10 +2121,10 @@ namespace ICSharpCode.NRefactory.CSharp if (location != null) result.AddChild (new CSharpTokenNode (Convert (location[0]), "stackalloc".Length), StackAllocExpression.Roles.Keyword); result.AddChild (ConvertToType (stackAllocExpression.TypeExpression), StackAllocExpression.Roles.Type); - if (location != null) + if (location != null && location.Count > 1) result.AddChild (new CSharpTokenNode (Convert (location[1]), 1), StackAllocExpression.Roles.LBracket); result.AddChild ((Expression)stackAllocExpression.CountExpression.Accept (this), StackAllocExpression.Roles.Expression); - if (location != null) + if (location != null && location.Count > 2) result.AddChild (new CSharpTokenNode (Convert (location[2]), 1), StackAllocExpression.Roles.RBracket); return result; } @@ -2540,7 +2546,7 @@ namespace ICSharpCode.NRefactory.CSharp return EmptyList.Instance; } - public IEnumerable ParseStatements(TextReader reader) + public IEnumerable ParseStatements(TextReader reader) { string code = "void M() { " + reader.ReadToEnd() + "}"; var members = ParseTypeMembers(new StringReader(code)); @@ -2548,10 +2554,10 @@ namespace ICSharpCode.NRefactory.CSharp if (method != null && method.Body != null) return method.Body.Statements; else - return EmptyList.Instance; + return EmptyList.Instance; } - public AstNode ParseTypeReference(TextReader reader) + public AstType ParseTypeReference(TextReader reader) { // TODO: add support for parsing type references throw new NotImplementedException(); diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs index 281e3e569..6fac5b0da 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs @@ -145,9 +145,11 @@ namespace ICSharpCode.NRefactory.CSharp else if (td.ClassType == ClassType.Enum || td.ClassType == ClassType.Struct) td.IsSealed = true; // enums/structs are implicitly sealed - //TODO ConvertTypeParameters(td.TypeParameters, typeDeclaration.TypeParameters, typeDeclaration.Constraints); + ConvertTypeParameters(td.TypeParameters, typeDeclaration.TypeParameters, typeDeclaration.Constraints); - // TODO: base type references? + foreach (AstType baseType in typeDeclaration.BaseTypes) { + td.BaseTypes.Add(ConvertType(baseType)); + } foreach (AttributedNode member in typeDeclaration.Members) { member.AcceptVisitor(this, data); @@ -159,7 +161,7 @@ namespace ICSharpCode.NRefactory.CSharp public override IEntity VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration, object data) { - var td = CreateTypeDefinition(delegateDeclaration.Name); + var td = currentTypeDefinition = CreateTypeDefinition(delegateDeclaration.Name); td.ClassType = ClassType.Delegate; td.Region = MakeRegion(delegateDeclaration); td.BaseTypes.Add(multicastDelegateReference); @@ -168,9 +170,14 @@ namespace ICSharpCode.NRefactory.CSharp ApplyModifiers(td, delegateDeclaration.Modifiers); td.IsSealed = true; // delegates are implicitly sealed - // TODO: convert return type, convert parameters - AddDefaultMethodsToDelegate(td, SharedTypes.UnknownType, EmptyList.Instance); + ConvertTypeParameters(td.TypeParameters, delegateDeclaration.TypeParameters, delegateDeclaration.Constraints); + + ITypeReference returnType = ConvertType(delegateDeclaration.ReturnType); + List parameters = new List(); + ConvertParameters(parameters, delegateDeclaration.Parameters); + AddDefaultMethodsToDelegate(td, returnType, parameters); + currentTypeDefinition = (DefaultTypeDefinition)currentTypeDefinition.DeclaringTypeDefinition; return td; } @@ -299,7 +306,7 @@ namespace ICSharpCode.NRefactory.CSharp m.BodyRegion = MakeRegion(methodDeclaration.Body); - //TODO ConvertTypeParameters(m.TypeParameters, methodDeclaration.TypeParameters, methodDeclaration.Constraints); + ConvertTypeParameters(m.TypeParameters, methodDeclaration.TypeParameters, methodDeclaration.Constraints); m.ReturnType = ConvertType(methodDeclaration.ReturnType); ConvertAttributes(m.Attributes, methodDeclaration.Attributes.Where(s => s.AttributeTarget != AttributeTarget.Return)); ConvertAttributes(m.ReturnTypeAttributes, methodDeclaration.Attributes.Where(s => s.AttributeTarget == AttributeTarget.Return)); @@ -318,7 +325,13 @@ namespace ICSharpCode.NRefactory.CSharp return m; } - DefaultExplicitInterfaceImplementation ConvertInterfaceImplementation(AstNode interfaceType, string memberName) + void ConvertTypeParameters(IList output, IEnumerable typeParameters, IEnumerable constraints) + { + if (typeParameters.Any()) + throw new NotImplementedException(); + } + + DefaultExplicitInterfaceImplementation ConvertInterfaceImplementation(AstType interfaceType, string memberName) { return new DefaultExplicitInterfaceImplementation(ConvertType(interfaceType), memberName); } @@ -327,7 +340,7 @@ namespace ICSharpCode.NRefactory.CSharp #region Operators public override IEntity VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration, object data) { - DefaultMethod m = new DefaultMethod(currentTypeDefinition, OperatorDeclaration.GetName(operatorDeclaration.OperatorType)); + DefaultMethod m = new DefaultMethod(currentTypeDefinition, operatorDeclaration.Name); m.EntityType = EntityType.Operator; m.Region = MakeRegion(operatorDeclaration); m.BodyRegion = MakeRegion(operatorDeclaration.Body); @@ -395,13 +408,6 @@ namespace ICSharpCode.NRefactory.CSharp public override IEntity VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data) { DefaultProperty p = new DefaultProperty(currentTypeDefinition, propertyDeclaration.Name); - HandlePropertyOrIndexer(p, propertyDeclaration); - currentTypeDefinition.Properties.Add(p); - return p; - } - - void HandlePropertyOrIndexer(DefaultProperty p, PropertyDeclaration propertyDeclaration) - { p.Region = MakeRegion(propertyDeclaration); p.BodyRegion = MakeBraceRegion(propertyDeclaration); ApplyModifiers(p, propertyDeclaration.Modifiers); @@ -413,13 +419,25 @@ namespace ICSharpCode.NRefactory.CSharp } p.Getter = ConvertAccessor(propertyDeclaration.Getter, p.Accessibility); p.Setter = ConvertAccessor(propertyDeclaration.Setter, p.Accessibility); + currentTypeDefinition.Properties.Add(p); + return p; } public override IEntity VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration, object data) { DefaultProperty p = new DefaultProperty(currentTypeDefinition, "Items"); p.EntityType = EntityType.Indexer; - HandlePropertyOrIndexer(p, indexerDeclaration); + p.Region = MakeRegion(indexerDeclaration); + p.BodyRegion = MakeBraceRegion(indexerDeclaration); + ApplyModifiers(p, indexerDeclaration.Modifiers); + p.ReturnType = ConvertType(indexerDeclaration.ReturnType); + ConvertAttributes(p.Attributes, indexerDeclaration.Attributes); + if (!indexerDeclaration.PrivateImplementationType.IsNull) { + p.Accessibility = Accessibility.None; + p.InterfaceImplementations.Add(ConvertInterfaceImplementation(indexerDeclaration.PrivateImplementationType, p.Name)); + } + p.Getter = ConvertAccessor(indexerDeclaration.Getter, p.Accessibility); + p.Setter = ConvertAccessor(indexerDeclaration.Setter, p.Accessibility); ConvertParameters(p.Parameters, indexerDeclaration.Parameters); currentTypeDefinition.Properties.Add(p); return p; @@ -528,14 +546,14 @@ namespace ICSharpCode.NRefactory.CSharp #endregion #region Types - ITypeReference ConvertType(AstNode node, bool isInUsingDeclaration = false) + ITypeReference ConvertType(AstType type, bool isInUsingDeclaration = false) { - return ConvertType(node, currentTypeDefinition, currentMethod, usingScope, isInUsingDeclaration); + return ConvertType(type, currentTypeDefinition, currentMethod, usingScope, isInUsingDeclaration); } - internal static ITypeReference ConvertType(AstNode node, ITypeDefinition parentTypeDefinition, IMethod parentMethodDefinition, UsingScope parentUsingScope, bool isInUsingDeclaration) + internal static ITypeReference ConvertType(AstType type, ITypeDefinition parentTypeDefinition, IMethod parentMethodDefinition, UsingScope parentUsingScope, bool isInUsingDeclaration) { - SimpleType s = node as SimpleType; + SimpleType s = type as SimpleType; if (s != null) { List typeArguments = new List(); foreach (var ta in s.TypeArguments) { @@ -551,25 +569,8 @@ namespace ICSharpCode.NRefactory.CSharp } return new SimpleTypeOrNamespaceReference(s.Identifier, typeArguments, parentTypeDefinition, parentUsingScope, isInUsingDeclaration); } - IdentifierExpression ident = node as IdentifierExpression; - if (ident != null) { - // TODO: get rid of this code once the parser produces SimpleType instead of IdentifierExpression - List typeArguments = new List(); - foreach (var ta in ident.TypeArguments) { - typeArguments.Add(ConvertType(ta, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration)); - } - if (typeArguments.Count == 0 && parentMethodDefinition != null) { - // SimpleTypeOrNamespaceReference doesn't support method type parameters, - // so we directly handle them here. - foreach (ITypeParameter tp in parentMethodDefinition.TypeParameters) { - if (tp.Name == s.Identifier) - return tp; - } - } - return new SimpleTypeOrNamespaceReference(ident.Identifier, typeArguments, parentTypeDefinition, parentUsingScope, isInUsingDeclaration); - } - PrimitiveType p = node as PrimitiveType; + PrimitiveType p = type as PrimitiveType; if (p != null) { switch (p.Keyword) { case "string": @@ -608,7 +609,7 @@ namespace ICSharpCode.NRefactory.CSharp return SharedTypes.UnknownType; } } - MemberType m = node as MemberType; + MemberType m = type as MemberType; if (m != null) { ITypeOrNamespaceReference t; if (m.IsDoubleColon) { @@ -629,7 +630,7 @@ namespace ICSharpCode.NRefactory.CSharp } return new MemberTypeOrNamespaceReference(t, m.MemberName, typeArguments, parentTypeDefinition, parentUsingScope); } - ComposedType c = node as ComposedType; + ComposedType c = type as ComposedType; if (c != null) { ITypeReference t = ConvertType(c.BaseType, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration); if (c.HasNullableSpecifier) { @@ -643,7 +644,7 @@ namespace ICSharpCode.NRefactory.CSharp } return t; } - Debug.WriteLine("Unknown node used as type: " + node); + Debug.WriteLine("Unknown node used as type: " + type); return SharedTypes.UnknownType; } #endregion diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs index 3dbf53a42..904bbae99 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs @@ -26,13 +26,22 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver internal readonly CancellationToken cancellationToken; #region Constructor - public CSharpResolver(ITypeResolveContext context, CancellationToken cancellationToken = default(CancellationToken)) + public CSharpResolver(ITypeResolveContext context) + { + if (context == null) + throw new ArgumentNullException("context"); + this.context = context; + } + + #if !DOTNET35 + public CSharpResolver(ITypeResolveContext context, CancellationToken cancellationToken) { if (context == null) throw new ArgumentNullException("context"); this.context = context; this.cancellationToken = cancellationToken; } + #endif #endregion #region Properties @@ -1513,12 +1522,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } - ResolveResult rr = LookupSimpleNameOrTypeName( + return LookupSimpleNameOrTypeName( identifier, typeArguments, isInvocationTarget ? SimpleNameLookupMode.InvocationTarget : SimpleNameLookupMode.Expression); - if (rr == ErrorResult && typeArguments.Count == 0) - rr = new UnknownIdentifierResolveResult(identifier); - return rr; } public ResolveResult LookupSimpleNamespaceOrTypeName(string identifier, IList typeArguments, bool isUsingDeclaration = false) @@ -1633,7 +1639,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } // if we didn't find anything: repeat lookup with parent namespace } - return ErrorResult; + if (typeArguments.Count == 0) + return new UnknownIdentifierResolveResult(identifier); + else + return ErrorResult; } /// @@ -1822,7 +1831,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } else { // No candidate found at all (not even an inapplicable one). // This can happen with empty method groups (as sometimes used with extension methods) - return new UnknownMethodResolveResult(mgrr.TargetType, mgrr.MethodName, mgrr.TypeArguments, CreateParameters(arguments, argumentNames)); + return new UnknownMethodResolveResult( + mgrr.TargetType, mgrr.MethodName, mgrr.TypeArguments, CreateParameters(arguments, argumentNames)); } } UnknownMemberResolveResult umrr = target as UnknownMemberResolveResult; @@ -1840,9 +1850,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return ErrorResult; } - static List CreateParameters(ResolveResult[] arguments, string[] argumentNames) + static List CreateParameters(ResolveResult[] arguments, string[] argumentNames) { - List list = new List(); + List list = new List(); if (argumentNames == null) { argumentNames = new string[arguments.Length]; } else { diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs index 615c23947..f124141fa 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs @@ -170,10 +170,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver Predicate memberFilter = delegate(IMember member) { return !member.IsOverride && member.Name == name && IsAccessible(member, allowProtectedAccess); }; - members.AddRange(type.GetMethods(context, memberFilter)); - members.AddRange(type.GetProperties(context, memberFilter)); - members.AddRange(type.GetFields(context, memberFilter)); - members.AddRange(type.GetEvents(context, memberFilter)); + members.AddRange(type.GetMethods(context, memberFilter.SafeCast()).SafeCast()); + members.AddRange(type.GetProperties(context, memberFilter.SafeCast()).SafeCast()); + members.AddRange(type.GetFields(context, memberFilter.SafeCast()).SafeCast()); + members.AddRange(type.GetEvents(context, memberFilter.SafeCast()).SafeCast()); if (isInvocation) members.RemoveAll(m => !IsInvocable(m, context)); } else { @@ -183,7 +183,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return method.TypeParameters.Count == typeArgumentCount && !method.IsOverride && method.Name == name && IsAccessible(method, allowProtectedAccess); }; - members.AddRange(type.GetMethods(context, memberFilter)); + members.AddRange(type.GetMethods(context, memberFilter).SafeCast()); } // TODO: can't members also hide types? diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/MemberTypeOrNamespaceReference.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/MemberTypeOrNamespaceReference.cs index e9b0da565..350701a0e 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/MemberTypeOrNamespaceReference.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/MemberTypeOrNamespaceReference.cs @@ -62,7 +62,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (typeArguments.Count == 0) return target.ToString() + "." + identifier; else - return target.ToString() + "." + identifier + "<" + string.Join(",", typeArguments) + ">"; + return target.ToString() + "." + identifier + "<" + DotNet35Compat.StringJoin(",", typeArguments) + ">"; } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs index 7c72f8d8b..d4d1fca43 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs @@ -446,7 +446,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { bool c1IsBetter = false; bool c2IsBetter = false; - foreach (var pair in t1.Zip>(t2, Tuple.Create)) { + foreach (var pair in t1.Zip(t2, (a,b) => new { Item1 = a, Item2 = b })) { switch (MoreSpecificFormalParameter(pair.Item1, pair.Item2)) { case 1: c1IsBetter = true; diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs index f950a474e..060bdfa7f 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs @@ -224,11 +224,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return VisitFieldOrEventDeclaration(eventDeclaration); } - ResolveResult VisitFieldOrEventDeclaration(MemberDeclaration fieldDeclaration) + ResolveResult VisitFieldOrEventDeclaration(AttributedNode fieldOrEventDeclaration) { - int initializerCount = fieldDeclaration.GetChildrenByRole(FieldDeclaration.Roles.Variable).Count(); + int initializerCount = fieldOrEventDeclaration.GetChildrenByRole(FieldDeclaration.Roles.Variable).Count(); ResolveResult result = null; - for (AstNode node = fieldDeclaration.FirstChild; node != null; node = node.NextSibling) { + for (AstNode node = fieldOrEventDeclaration.FirstChild; node != null; node = node.NextSibling) { if (node.Role == FieldDeclaration.Roles.Variable) { if (resolver.CurrentTypeDefinition != null) { resolver.CurrentMember = resolver.CurrentTypeDefinition.Fields.FirstOrDefault(f => f.Region.IsInside(node.StartLocation)); @@ -309,14 +309,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } // handle properties/indexers - ResolveResult VisitPropertyMember(PropertyDeclaration propertyDeclaration) + ResolveResult VisitPropertyMember(MemberDeclaration propertyOrIndexerDeclaration) { try { if (resolver.CurrentTypeDefinition != null) { - resolver.CurrentMember = resolver.CurrentTypeDefinition.Properties.FirstOrDefault(p => p.Region.IsInside(propertyDeclaration.StartLocation)); + resolver.CurrentMember = resolver.CurrentTypeDefinition.Properties.FirstOrDefault(p => p.Region.IsInside(propertyOrIndexerDeclaration.StartLocation)); } - for (AstNode node = propertyDeclaration.FirstChild; node != null; node = node.NextSibling) { + for (AstNode node = propertyOrIndexerDeclaration.FirstChild; node != null; node = node.NextSibling) { if (node.Role == PropertyDeclaration.SetterRole && resolver.CurrentMember != null) { resolver.PushBlock(); resolver.AddVariable(resolver.CurrentMember.ReturnType, "value"); @@ -472,9 +472,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return ie != null && ie.Target == node; } - IType ResolveType(AstNode node) + IType ResolveType(AstType type) { - return MakeTypeReference(node).Resolve(resolver.Context); + return MakeTypeReference(type).Resolve(resolver.Context); } public override ResolveResult VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, object data) @@ -593,7 +593,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } - ResolveResult[] GetArguments(IEnumerable argumentExpressions, out string[] argumentNames) + ResolveResult[] GetArguments(IEnumerable argumentExpressions, out string[] argumentNames) { argumentNames = null; // TODO: add support for named arguments ResolveResult[] arguments = new ResolveResult[argumentExpressions.Count()]; @@ -951,7 +951,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// Creates a type reference for the specified type node. /// If the type node is 'var', performs type inference on the initializer expression. /// - ITypeReference MakeTypeReference(AstNode type, AstNode initializerExpression, bool isForEach) + ITypeReference MakeTypeReference(AstType type, AstNode initializerExpression, bool isForEach) { if (initializerExpression != null && IsVar(type)) { return new VarTypeReference(this, resolver.Clone(), initializerExpression, isForEach); @@ -960,14 +960,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } - ITypeReference MakeTypeReference(AstNode type) + ITypeReference MakeTypeReference(AstType type) { return TypeSystemConvertVisitor.ConvertType(type, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.UsingScope, false); } - static bool IsVar(AstNode returnType) + static bool IsVar(AstType returnType) { - return returnType is IdentifierExpression && ((IdentifierExpression)returnType).Identifier == "var"; + return returnType is SimpleType + && ((SimpleType)returnType).Identifier == "var" + && ((SimpleType)returnType).TypeArguments.Count == 0; } sealed class VarTypeReference : ITypeReference @@ -1072,25 +1074,36 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public override ResolveResult VisitPrimitiveType(PrimitiveType primitiveType, object data) { ScanChildren(primitiveType); - return new TypeResolveResult(MakeTypeReference(primitiveType).Resolve(resolver.Context)); + return new TypeResolveResult(ResolveType(primitiveType)); } public override ResolveResult VisitSimpleType(SimpleType simpleType, object data) { ScanChildren(simpleType); - return new TypeResolveResult(MakeTypeReference(simpleType).Resolve(resolver.Context)); + return ResolveTypeOrNamespace(simpleType); + } + + ResolveResult ResolveTypeOrNamespace(AstType type) + { + ITypeReference typeRef = MakeTypeReference(type); + ITypeOrNamespaceReference typeOrNsRef = typeRef as ITypeOrNamespaceReference; + if (typeOrNsRef != null) { + return typeOrNsRef.DoResolve(resolver.Context); + } else { + return new TypeResolveResult(typeRef.Resolve(resolver.Context)); + } } public override ResolveResult VisitMemberType(MemberType memberType, object data) { ScanChildren(memberType); - return new TypeResolveResult(MakeTypeReference(memberType).Resolve(resolver.Context)); + return ResolveTypeOrNamespace(memberType); } public override ResolveResult VisitComposedType(ComposedType composedType, object data) { ScanChildren(composedType); - return new TypeResolveResult(MakeTypeReference(composedType).Resolve(resolver.Context)); + return new TypeResolveResult(ResolveType(composedType)); } #endregion @@ -1135,7 +1148,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { throw new NotImplementedException(); } - */ + */ #endregion public override ResolveResult VisitIdentifier(Identifier identifier, object data) diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs index e51fde628..a500e85e0 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs @@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (typeArguments.Count == 0) return identifier; else - return identifier + "<" + string.Join(",", typeArguments) + ">"; + return identifier + "<" + DotNet35Compat.StringJoin(",", typeArguments) + ">"; } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs index afdfca58d..488a6c31f 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs @@ -856,7 +856,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver bool success; IType[] result = InferTypeArgumentsFromBounds( candidateDef.TypeParameters, - new ParameterizedType(candidateDef, candidateDef.TypeParameters), + new ParameterizedType(candidateDef, candidateDef.TypeParameters.SafeCast()), lowerBounds, upperBounds, out success); if (success) { diff --git a/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index fb6ae2c31..7d5ed8424 100644 --- a/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -7,7 +7,7 @@ Library ICSharpCode.NRefactory ICSharpCode.NRefactory - v4.0 + v3.5 Properties 10.0.0 2.0 @@ -15,6 +15,9 @@ False false 1591,0618 + + False + -Microsoft.Design#CA1026;-Microsoft.Security#CA2104 AnyCPU @@ -27,24 +30,27 @@ bin\Debug\ Full False - DEBUG;TRACE;FULL_AST + DEBUG;TRACE;FULL_AST;DOTNET35 + False bin\Release\ None True - TRACE;FULL_AST + TRACE;FULL_AST;DOTNET35 + False - full + Full false 4 true - none + None true 4 + false @@ -324,6 +330,7 @@ + diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs index 65bcae4b9..7564ed995 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs @@ -297,7 +297,7 @@ namespace ICSharpCode.NRefactory.TypeSystem } } - static readonly string DynamicAttributeFullName = typeof(DynamicAttribute).FullName; + const string DynamicAttributeFullName = "System.Runtime.CompilerServices.DynamicAttribute"; static bool HasDynamicAttribute(ICustomAttributeProvider attributeProvider, int typeIndex) { diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs index 4c830048a..da2a6c06a 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs @@ -70,15 +70,17 @@ namespace ICSharpCode.NRefactory.TypeSystem throw new ArgumentNullException("context"); HashSet typeDefinitions = new HashSet(); - Func> recursion = + Func> recursion = t => t.GetBaseTypes(context).Select(b => b.GetDefinition()).Where(d => d != null && typeDefinitions.Add(d)); ITypeDefinition typeDef = type as ITypeDefinition; if (typeDef != null) { typeDefinitions.Add(typeDef); - return TreeTraversal.PreOrder(typeDef, recursion); + return TreeTraversal.PreOrder(typeDef, recursion); } else { - return TreeTraversal.PreOrder(recursion(type), recursion); + return TreeTraversal.PreOrder( + type.GetBaseTypes(context).Select(b => b.GetDefinition()).Where(d => d != null && typeDefinitions.Add(d)), + recursion); } } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IAttribute.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IAttribute.cs index 62d748290..b9bb2dd97 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IAttribute.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IAttribute.cs @@ -10,7 +10,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents an attribute. /// + #if WITH_CONTRACTS [ContractClass(typeof(IAttributeContract))] + #endif [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] public interface IAttribute : IFreezable { @@ -35,6 +37,7 @@ namespace ICSharpCode.NRefactory.TypeSystem IList> NamedArguments { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IAttribute))] abstract class IAttributeContract : IFreezableContract, IAttribute { @@ -63,4 +66,5 @@ namespace ICSharpCode.NRefactory.TypeSystem } } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IConstantValue.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IConstantValue.cs index 030f5a118..8ea9a8f3d 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IConstantValue.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IConstantValue.cs @@ -6,7 +6,9 @@ using System.Diagnostics.Contracts; namespace ICSharpCode.NRefactory.TypeSystem { + #if WITH_CONTRACTS [ContractClass(typeof(IConstantValueContract))] + #endif public interface IConstantValue : IFreezable { /// @@ -30,6 +32,7 @@ namespace ICSharpCode.NRefactory.TypeSystem object GetValue(ITypeResolveContext context); } + #if WITH_CONTRACTS [ContractClassFor(typeof(IConstantValue))] abstract class IConstantValueContract : IFreezableContract, IConstantValue { @@ -46,4 +49,5 @@ namespace ICSharpCode.NRefactory.TypeSystem return null; } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IEntity.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IEntity.cs index 752cb693d..d9f92d1ce 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IEntity.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IEntity.cs @@ -7,7 +7,9 @@ using System.Diagnostics.Contracts; namespace ICSharpCode.NRefactory.TypeSystem { + #if WITH_CONTRACTS [ContractClass(typeof(IEntityContract))] + #endif public interface IEntity : INamedElement, IFreezable { EntityType EntityType { get; } @@ -75,6 +77,7 @@ namespace ICSharpCode.NRefactory.TypeSystem //bool IsAccessible(IClass callingClass, bool isAccessThoughReferenceOfCurrentClass); } + #if WITH_CONTRACTS [ContractClassFor(typeof(IEntity))] abstract class IEntityContract : INamedElementContract, IEntity { @@ -144,4 +147,5 @@ namespace ICSharpCode.NRefactory.TypeSystem { } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IExplicitInterfaceImplementation.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IExplicitInterfaceImplementation.cs index 91259ff0e..60452a670 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IExplicitInterfaceImplementation.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IExplicitInterfaceImplementation.cs @@ -9,7 +9,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents an explicit interface implementation. /// + #if WITH_CONTRACTS [ContractClass(typeof(IExplicitInterfaceImplementationContract))] + #endif public interface IExplicitInterfaceImplementation : IFreezable { /// @@ -23,6 +25,7 @@ namespace ICSharpCode.NRefactory.TypeSystem string MemberName { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IExplicitInterfaceImplementation))] abstract class IExplicitInterfaceImplementationContract : IFreezableContract, IExplicitInterfaceImplementation { @@ -40,4 +43,5 @@ namespace ICSharpCode.NRefactory.TypeSystem } } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IField.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IField.cs index c72526a78..c5c015299 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IField.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IField.cs @@ -9,7 +9,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents a field or constant. /// + #if WITH_CONTRACTS [ContractClass(typeof(IFieldContract))] + #endif public interface IField : IMember, IVariable { /// @@ -28,6 +30,7 @@ namespace ICSharpCode.NRefactory.TypeSystem bool IsVolatile { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IField))] abstract class IFieldContract : IMemberContract, IField { @@ -63,4 +66,5 @@ namespace ICSharpCode.NRefactory.TypeSystem get { return null; } } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IFreezable.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IFreezable.cs index 1705b4d75..baa35f42d 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IFreezable.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IFreezable.cs @@ -6,7 +6,9 @@ using System.Diagnostics.Contracts; namespace ICSharpCode.NRefactory.TypeSystem { + #if WITH_CONTRACTS [ContractClass(typeof(IFreezableContract))] + #endif public interface IFreezable { /// @@ -20,6 +22,7 @@ namespace ICSharpCode.NRefactory.TypeSystem void Freeze(); } + #if WITH_CONTRACTS [ContractClassFor(typeof(IFreezable))] abstract class IFreezableContract : IFreezable { @@ -33,4 +36,5 @@ namespace ICSharpCode.NRefactory.TypeSystem Contract.Ensures(self.IsFrozen); } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IInterningProvider.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IInterningProvider.cs index 3e8f45655..16b23d063 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IInterningProvider.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IInterningProvider.cs @@ -25,7 +25,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// and which are used only within a single type definition. Then a persistent file format could be organized so /// that shared objects are loaded only once, yet non-shared objects get loaded lazily together with the class. /// + #if WITH_CONTRACTS [ContractClass(typeof(IInterningProviderContract))] + #endif public interface IInterningProvider { /// @@ -39,6 +41,7 @@ namespace ICSharpCode.NRefactory.TypeSystem IList InternList(IList list) where T : class; } + #if WITH_CONTRACTS [ContractClassFor(typeof(IInterningProvider))] abstract class IInterningProviderContract : IInterningProvider { @@ -54,4 +57,5 @@ namespace ICSharpCode.NRefactory.TypeSystem return list; } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IMember.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IMember.cs index 4fc545495..4a51074bf 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IMember.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IMember.cs @@ -10,7 +10,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Method/field/entity. /// + #if WITH_CONTRACTS [ContractClass(typeof(IMemberContract))] + #endif public interface IMember : IEntity { /// @@ -58,6 +60,7 @@ namespace ICSharpCode.NRefactory.TypeSystem } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IMember))] abstract class IMemberContract : IEntityContract, IMember { @@ -101,4 +104,5 @@ namespace ICSharpCode.NRefactory.TypeSystem get { return false; } } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IMethod.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IMethod.cs index 56ded253d..e66ab0782 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IMethod.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IMethod.cs @@ -10,7 +10,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents a method, constructor, destructor or operator. /// + #if WITH_CONTRACTS [ContractClass(typeof(IMethodContract))] + #endif public interface IMethod : IParameterizedMember { /// @@ -30,6 +32,7 @@ namespace ICSharpCode.NRefactory.TypeSystem bool IsOperator { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IMethod))] abstract class IMethodContract : IParameterizedMemberContract, IMethod { @@ -47,13 +50,6 @@ namespace ICSharpCode.NRefactory.TypeSystem } } -// IList IMethod.HandlesClauses { -// get { -// Contract.Ensures(Contract.Result>() != null); -// return null; -// } -// } - bool IMethod.IsExtensionMethod { get { return false; } } @@ -70,4 +66,5 @@ namespace ICSharpCode.NRefactory.TypeSystem get { return false; } } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/INamedElement.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/INamedElement.cs index 407caf6c3..789108543 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/INamedElement.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/INamedElement.cs @@ -6,7 +6,9 @@ using System.Diagnostics.Contracts; namespace ICSharpCode.NRefactory.TypeSystem { + #if WITH_CONTRACTS [ContractClass(typeof(INamedElementContract))] + #endif public interface INamedElement { /// @@ -63,6 +65,7 @@ namespace ICSharpCode.NRefactory.TypeSystem } } + #if WITH_CONTRACTS [ContractClassFor(typeof(INamedElement))] abstract class INamedElementContract : INamedElement { @@ -94,4 +97,5 @@ namespace ICSharpCode.NRefactory.TypeSystem } } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IParameter.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IParameter.cs index 0333a45a9..3f7d9b082 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IParameter.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IParameter.cs @@ -7,7 +7,9 @@ using System.Diagnostics.Contracts; namespace ICSharpCode.NRefactory.TypeSystem { + #if WITH_CONTRACTS [ContractClass(typeof(IParameterContract))] + #endif public interface IParameter : IVariable, IFreezable { /// @@ -46,6 +48,7 @@ namespace ICSharpCode.NRefactory.TypeSystem bool IsOptional { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IParameter))] abstract class IParameterContract : IVariableContract, IParameter { @@ -92,4 +95,5 @@ namespace ICSharpCode.NRefactory.TypeSystem { } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IParameterizedMember.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IParameterizedMember.cs index e719ca59a..a60c75133 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IParameterizedMember.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IParameterizedMember.cs @@ -10,12 +10,15 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents a method or property. /// + #if WITH_CONTRACTS [ContractClass(typeof(IParameterizedMemberContract))] + #endif public interface IParameterizedMember : IMember { IList Parameters { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IParameterizedMember))] abstract class IParameterizedMemberContract : IMemberContract, IParameterizedMember { @@ -26,4 +29,5 @@ namespace ICSharpCode.NRefactory.TypeSystem } } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs index 274bcfbe3..be4d9651d 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs @@ -10,12 +10,15 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Mutable container of all classes in an assembly. /// + #if WITH_CONTRACTS [ContractClass(typeof(IProjectContentContract))] + #endif public interface IProjectContent : ITypeResolveContext { IList AssemblyAttributes { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IProjectContent))] abstract class IProjectContentContract : ITypeResolveContextContract, IProjectContent { @@ -26,4 +29,5 @@ namespace ICSharpCode.NRefactory.TypeSystem } } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/ISupportsInterning.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/ISupportsInterning.cs index 771ff43f9..86de1c379 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/ISupportsInterning.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/ISupportsInterning.cs @@ -11,7 +11,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// Interface for TypeSystem objects that support interning. /// See for more information. /// + #if WITH_CONTRACTS [ContractClass(typeof(ISupportsInterningContract))] + #endif public interface ISupportsInterning { /// @@ -30,6 +32,7 @@ namespace ICSharpCode.NRefactory.TypeSystem bool EqualsForInterning(ISupportsInterning other); } + #if WITH_CONTRACTS [ContractClassFor(typeof(ISupportsInterning))] abstract class ISupportsInterningContract : ISupportsInterning { @@ -48,4 +51,5 @@ namespace ICSharpCode.NRefactory.TypeSystem return false; } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IType.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IType.cs index d8cec4091..f6d3b3a32 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IType.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IType.cs @@ -7,7 +7,9 @@ using System.Diagnostics.Contracts; namespace ICSharpCode.NRefactory.TypeSystem { + #if WITH_CONTRACTS [ContractClass(typeof(ITypeContract))] + #endif public interface IType : ITypeReference, INamedElement, IEquatable { /// @@ -90,6 +92,7 @@ namespace ICSharpCode.NRefactory.TypeSystem IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null); } + #if WITH_CONTRACTS [ContractClassFor(typeof(IType))] abstract class ITypeContract : ITypeReferenceContract, IType { @@ -209,4 +212,5 @@ namespace ICSharpCode.NRefactory.TypeSystem return this; } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs index dc8576d8f..905a85fdc 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs @@ -10,7 +10,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents a class, enum, interface, struct, delegate or VB module. /// + #if WITH_CONTRACTS [ContractClass(typeof(ITypeDefinitionContract))] + #endif public interface ITypeDefinition : IType, IEntity { ClassType ClassType { get; } @@ -44,6 +46,7 @@ namespace ICSharpCode.NRefactory.TypeSystem IEnumerable Members { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(ITypeDefinition))] abstract class ITypeDefinitionContract : ITypeContract, ITypeDefinition { @@ -181,4 +184,5 @@ namespace ICSharpCode.NRefactory.TypeSystem } #endregion } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs index ee7f43dfc..75d6d4cb4 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs @@ -11,7 +11,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Type parameter of a generic class/method. /// + #if WITH_CONTRACTS [ContractClass(typeof(ITypeParameterContract))] + #endif public interface ITypeParameter : IType, IFreezable { /// @@ -99,6 +101,7 @@ namespace ICSharpCode.NRefactory.TypeSystem Contravariant }; + #if WITH_CONTRACTS [ContractClassFor(typeof(ITypeParameter))] abstract class ITypeParameterContract : ITypeContract, ITypeParameter { @@ -178,4 +181,5 @@ namespace ICSharpCode.NRefactory.TypeSystem { } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs index 70f105b3a..50795311b 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs @@ -11,7 +11,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// Represents a reference to a type. /// Must be resolved before it can be used as type. /// + #if WITH_CONTRACTS [ContractClass(typeof(ITypeReferenceContract))] + #endif public interface ITypeReference { // Keep this interface simple: I decided against having GetMethods/GetEvents etc. here, @@ -26,6 +28,7 @@ namespace ICSharpCode.NRefactory.TypeSystem IType Resolve(ITypeResolveContext context); } + #if WITH_CONTRACTS [ContractClassFor(typeof(ITypeReference))] abstract class ITypeReferenceContract : ITypeReference { @@ -36,4 +39,5 @@ namespace ICSharpCode.NRefactory.TypeSystem return null; } } + #endif } \ No newline at end of file diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs index 335153ee6..3c89b13ad 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs @@ -12,7 +12,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Context representing the set of assemblies in which a type is being searched. /// + #if WITH_CONTRACTS [ContractClass(typeof(ITypeResolveContextContract))] + #endif public interface ITypeResolveContext { /// @@ -91,6 +93,7 @@ namespace ICSharpCode.NRefactory.TypeSystem CacheManager CacheManager { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(ITypeResolveContext))] abstract class ITypeResolveContextContract : ITypeResolveContext { @@ -140,4 +143,5 @@ namespace ICSharpCode.NRefactory.TypeSystem return null; } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IVariable.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IVariable.cs index cc4dfa9c4..5c8f1d903 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/IVariable.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/IVariable.cs @@ -9,7 +9,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents a variable (name/return type pair). /// + #if WITH_CONTRACTS [ContractClass(typeof(IVariableContract))] + #endif public interface IVariable { /// @@ -33,6 +35,7 @@ namespace ICSharpCode.NRefactory.TypeSystem IConstantValue ConstantValue { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IVariable))] abstract class IVariableContract : IVariable { @@ -62,4 +65,5 @@ namespace ICSharpCode.NRefactory.TypeSystem get { return null; } } } + #endif } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs index b2f981df6..9fd926da9 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs @@ -19,9 +19,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation if (string.IsNullOrEmpty(ns)) { return name; } else { - string combinedName = ns + "." + name; - Contract.Assume(!string.IsNullOrEmpty(combinedName)); - return combinedName; + return ns + "." + name; } } } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs index 220f09a12..0f412842d 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs @@ -53,19 +53,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation base.FreezeInternal(); } - [ContractInvariantMethod] - void ObjectInvariant() - { - Contract.Invariant(type != null); - Contract.Invariant(name != null); - } - public string Name { get { return name; } set { if (value == null) throw new ArgumentNullException(); - Contract.EndContractBlock(); CheckBeforeMutation(); name = value; } @@ -76,7 +68,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation set { if (value == null) throw new ArgumentNullException(); - Contract.EndContractBlock(); CheckBeforeMutation(); type = value; } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs index 4964cacc4..881d38585 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs @@ -60,7 +60,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation throw new ArgumentNullException("declaringTypeDefinition"); if (string.IsNullOrEmpty(name)) throw new ArgumentException("name"); - Contract.EndContractBlock(); this.projectContent = declaringTypeDefinition.ProjectContent; this.declaringTypeDefinition = declaringTypeDefinition; this.name = name; @@ -73,20 +72,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation throw new ArgumentNullException("projectContent"); if (string.IsNullOrEmpty(name)) throw new ArgumentException("name"); - Contract.EndContractBlock(); this.projectContent = projectContent; this.ns = ns ?? string.Empty; this.name = name; } - [ContractInvariantMethod] - void ObjectInvariant() - { - Contract.Invariant(projectContent != null); - Contract.Invariant(!string.IsNullOrEmpty(name)); - Contract.Invariant(ns != null); - } - public ClassType ClassType { get { return classType; } set { @@ -164,7 +154,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public IEnumerable Members { get { - return this.Fields.Concat(this.Properties).Concat(this.Methods).Concat(this.Events); + return this.Fields.SafeCast() + .Concat(this.Properties.SafeCast()) + .Concat(this.Methods.SafeCast()) + .Concat(this.Events.SafeCast()); } } @@ -187,15 +180,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public string FullName { get { if (declaringTypeDefinition != null) { - string combinedName = declaringTypeDefinition.FullName + "." + this.name; - Contract.Assume(!string.IsNullOrEmpty(combinedName)); - return combinedName; + return declaringTypeDefinition.FullName + "." + this.name; } else if (string.IsNullOrEmpty(ns)) { return this.name; } else { - string combinedName = this.ns + "." + this.name; - Contract.Assume(!string.IsNullOrEmpty(combinedName)); - return combinedName; + return this.ns + "." + this.name; } } } diff --git a/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleInterningProvider.cs b/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleInterningProvider.cs index ce5c85864..7ed18be85 100644 --- a/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleInterningProvider.cs +++ b/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleInterningProvider.cs @@ -2,6 +2,7 @@ // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; +using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; @@ -51,16 +52,27 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } } - sealed class ListComparer : IEqualityComparer> + sealed class ListComparer : IEqualityComparer { - public bool Equals(IEnumerable a, IEnumerable b) + public bool Equals(IEnumerable a, IEnumerable b) { if (a.GetType() != b.GetType()) return false; - return Enumerable.SequenceEqual(a, b, ReferenceComparer.Instance); + IEnumerator e1 = a.GetEnumerator(); + IEnumerator e2 = b.GetEnumerator(); + while (e1.MoveNext()) { + // e1 has more elements than e2; or elements are different + if (!e2.MoveNext() || e1.Current != e2.Current) + return false; + } + if (e2.MoveNext()) // e2 has more elements than e1 + return false; + // No need to dispose e1/e2: non-generic IEnumerator doesn't implement IDisposable, + // and the underlying enumerator will likely be a List.Enumerator which has an empty Dispose() method. + return true; } - public int GetHashCode(IEnumerable obj) + public int GetHashCode(IEnumerable obj) { int hashCode = obj.GetType().GetHashCode(); unchecked { @@ -75,7 +87,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation Dictionary byValueDict = new Dictionary(); Dictionary supportsInternDict = new Dictionary(new InterningComparer()); - Dictionary, IEnumerable> listDict = new Dictionary, IEnumerable>(new ListComparer()); + Dictionary listDict = new Dictionary(new ListComparer()); public T Intern(T obj) where T : class { @@ -118,7 +130,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } if (!list.IsReadOnly) list = new ReadOnlyCollection(list); - IEnumerable output; + IEnumerable output; if (listDict.TryGetValue(list, out output)) list = (IList)output; else diff --git a/NRefactory/ICSharpCode.NRefactory/Utils/DotNet35Compat.cs b/NRefactory/ICSharpCode.NRefactory/Utils/DotNet35Compat.cs new file mode 100644 index 000000000..85c599947 --- /dev/null +++ b/NRefactory/ICSharpCode.NRefactory/Utils/DotNet35Compat.cs @@ -0,0 +1,58 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Linq; + +internal static class DotNet35Compat +{ + public static string StringJoin(string separator, IEnumerable elements) + { + #if DOTNET35 + return string.Join(separator, elements.Select(e => e != null ? e.ToString() : null).ToArray()); + #else + return string.Join(separator, elements); + #endif + } + + public static IEnumerable SafeCast(this IEnumerable elements) where T : U + { + #if DOTNET35 + foreach (T item in elements) + yield return item; + #else + return elements; + #endif + } + + public static Predicate SafeCast(this Predicate predicate) where U : T + { + #if DOTNET35 + return e => predicate(e); + #else + return predicate; + #endif + } + + #if DOTNET35 + public static IEnumerable Zip(this IEnumerable input1, IEnumerable input2, Func f) + { + using (var e1 = input1.GetEnumerator()) + using (var e2 = input2.GetEnumerator()) + while (e1.MoveNext() && e2.MoveNext()) + yield return f(e1.Current, e2.Current); + } + #endif +} + +#if DOTNET35 +namespace System.Diagnostics.Contracts { } +namespace System.Threading +{ + internal struct CancellationToken + { + public void ThrowIfCancellationRequested() {} + } +} +#endif diff --git a/NRefactory/NRefactory.sln b/NRefactory/NRefactory.sln index 575ae336b..24aed9f13 100644 --- a/NRefactory/NRefactory.sln +++ b/NRefactory/NRefactory.sln @@ -71,13 +71,13 @@ Global {870115DD-960A-4406-A6B9-600BCDC36A03}.Release|x86.Build.0 = Release|Any CPU {870115DD-960A-4406-A6B9-600BCDC36A03}.Release|x86.ActiveCfg = Release|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.Build.0 = net_4_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.ActiveCfg = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.ActiveCfg = net_3_5_Debug|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.Build.0 = net_4_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.Build.0 = net_4_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.ActiveCfg = net_4_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.ActiveCfg = net_3_5_Release|Any CPU EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj diff --git a/NRefactory/README b/NRefactory/README index 9cdcf0b24..ea347e6d3 100644 --- a/NRefactory/README +++ b/NRefactory/README @@ -6,15 +6,22 @@ ICSharpCode.NRefactory.TypeSystem: ICSharpCode.NRefactory.TypeSystem.Implementation: Contains base classes that help implementing the type system interfaces. -ICSharpCode.NRefactory.CSharp.Dom: +ICSharpCode.NRefactory.CSharp.Ast: Abstract Syntax Tree for C# ICSharpCode.NRefactory.CSharp.Resolver: Semantic analysis for C# -ICSharpCode.NRefactory.VB.Dom: +ICSharpCode.NRefactory.Util: + Various helper classes. + +ICSharpCode.NRefactory.VB.Dom: (in the separate ICSharpCode.NRefactory.VB assembly) Abstract Syntax Tree for VB +Dependencies: + .NET 3.5 or .NET 4.0 + Mono.Cecil 0.9.4 + Null-Object pattern: The NRefactory library makes extensive use of the null object pattern. As a result, NullReferenceExceptions should be very rare when working with this library. @@ -32,6 +39,10 @@ Null-Object pattern: error cases. Use ResolveResult.IsError to detect resolver errors. Also note that many resolver errors still have a meaningful type attached, this allows code completion to work in the presence of minor semantic errors. + + The C# AST makes use of special null nodes when accessing the getter of an AST property and no + child node with that role exists. Check the IsNull property to test whether a node is a null node. + Null nodes are not considered to be part of the AST (e.g. they don't have a parent). FAQ: Q: What is the difference between types and type definitions? @@ -193,3 +204,13 @@ A: Because if you're asking whether a type is a struct, it's very likely that yo If you really need to know, you can do "type.GetDefinition() != null && type.GetDefinition().ClassType == WhatIWant" yourself, but for the most part you should be fine with IsReferenceType, IsEnum and IsDelegate. + + +Q: What's the difference between the .NET 3.5 and .NET 4.0 versions? + +A: As for visible API difference, not much. The .NET 4.0 build has some additional overloads for a few methods, + taking a System.Threading.CancellationToken to allow aborting a resolve run. + Internally, the .NET 4.0 version might be tiny bit more performant because it uses covariance for IEnumerable, + where the .NET 3.5 version has to allocate wrapper objects instead. + + Both versions support loading assemblies of all .NET versions (1.0 to 4.0); and both support C# 4.0. diff --git a/NRefactory/VBDomGenerator/VBDomGenerator.csproj b/NRefactory/VBDomGenerator/VBDomGenerator.csproj index 8de206bd6..c9e014b1f 100644 --- a/NRefactory/VBDomGenerator/VBDomGenerator.csproj +++ b/NRefactory/VBDomGenerator/VBDomGenerator.csproj @@ -19,6 +19,7 @@ false v4.0 OnBuildSuccess + Client bin\Debug\ diff --git a/NRefactory/doc/TODO b/NRefactory/doc/TODO index a0e8045ea..1b43f8b85 100644 --- a/NRefactory/doc/TODO +++ b/NRefactory/doc/TODO @@ -1,15 +1,24 @@ -TypeSystem API: + +Parser: +- "extern alias" declarations +- "fixed int Field[100];" (fixed-size field declarations) +- support generics +- fix bugs (see currently ignored unit tests) +- put newlines into the AST +- add API to report errors +- allow multithreaded parsing -* Decide on the fate of ISupportsInterning (depends on how we're going to implement persistence) +Resolver: +- Tons of unit tests for TypeSystemConvertVisitor +- Lambda expressions +- Handle attributes +- Port all #D resolver unit tests to NR +- Port all MD resolver unit tests to NR -* Try to build SharedTypes for void, int, etc. - Take care of equality with the real System.Void, System.Int32 etc. - This seems to be hard/impossible to do, see comment in SharedTypes.cs. - I'm trying to work without those types now. - - Note that having shared type *references* is possible (typeof(int).ToTypeReference()) +Features: +- Code Completion +- Find References +- Extract Method refactoring -* Implement the C# parser producing the DOM -* Implement ResolveVisitor -* Implement all the nasty context-dependent stuff (local variables, lambdas) that CSharpResolver doesn't do (yet) - Where should that go? I'd like to keep it out of CSharpResolver, that class is bloated enough with the pure logic. +For integration into SharpDevelop: +- Review NR and DOM changes done in the timeframe \ No newline at end of file