Esempio n. 1
0
        static bool IsDisposeInvocation(string variableName, Statement statement)
        {
            var memberReferenceExpr = new MemberReferenceExpression(new IdentifierExpression(variableName), "Dispose");
            var pattern             = new ExpressionStatement(new InvocationExpression(memberReferenceExpr));

            return(pattern.Match(statement).Success);
        }
        void HandleInstanceFieldInitializers(IEnumerable <AstNode> members)
        {
            var instanceCtors = members.OfType <ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
            var instanceCtorsNotChainingWithThis = instanceCtors.Where(ctor => !thisCallPattern.IsMatch(ctor.Body.Statements.FirstOrDefault())).ToArray();

            if (instanceCtorsNotChainingWithThis.Length > 0)
            {
                MethodDefinition ctorMethodDef = instanceCtorsNotChainingWithThis[0].Annotation <MethodDefinition>();
                if (ctorMethodDef != null && ctorMethodDef.DeclaringType.IsValueType)
                {
                    return;
                }

                // Recognize field initializers:
                // Convert first statement in all ctors (if all ctors have the same statement) into a field initializer.
                bool allSame;
                do
                {
                    Match m = fieldInitializerPattern.Match(instanceCtorsNotChainingWithThis[0].Body.FirstOrDefault());
                    if (!m.Success)
                    {
                        break;
                    }

                    FieldDefinition fieldDef = m.Get <AstNode>("fieldAccess").Single().Annotation <FieldReference>().ResolveWithinSameModule();
                    if (fieldDef == null)
                    {
                        break;
                    }
                    AstNode fieldOrEventDecl = members.FirstOrDefault(f => f.Annotation <FieldDefinition>() == fieldDef);
                    if (fieldOrEventDecl == null)
                    {
                        break;
                    }
                    Expression initializer = m.Get <Expression>("initializer").Single();
                    // 'this'/'base' cannot be used in field initializers
                    if (initializer.DescendantsAndSelf.Any(n => n is ThisReferenceExpression || n is BaseReferenceExpression))
                    {
                        break;
                    }

                    allSame = true;
                    for (int i = 1; i < instanceCtorsNotChainingWithThis.Length; i++)
                    {
                        if (!instanceCtors[0].Body.First().IsMatch(instanceCtorsNotChainingWithThis[i].Body.FirstOrDefault()))
                        {
                            allSame = false;
                        }
                    }
                    if (allSame)
                    {
                        foreach (var ctor in instanceCtorsNotChainingWithThis)
                        {
                            ctor.Body.First().Remove();
                        }
                        fieldOrEventDecl.GetChildrenByRole(AstNode.Roles.Variable).Single().Initializer = initializer.Detach();
                    }
                } while (allSame);
            }
        }
        bool MatchLowerBound(int indexNum, out IL.ILVariable index, IL.ILVariable collection, Statement statement)
        {
            index = null;
            var m = variableAssignLowerBoundPattern.Match(statement);

            if (!m.Success)
            {
                return(false);
            }
            if (!int.TryParse(m.Get <PrimitiveExpression>("index").Single().Value.ToString(), out int i) || indexNum != i)
            {
                return(false);
            }
            index = m.Get <IdentifierExpression>("variable").Single().GetILVariable();
            return(m.Get <IdentifierExpression>("collection").Single().GetILVariable() == collection);
        }
        internal static Expression CheckNode(IfElseStatement node, out Expression rightSide)
        {
            rightSide = null;
            var match = ActionPattern.Match(node.Condition);

            if (!match.Success)
            {
                return(null);
            }
            var        conditionExpression  = match.Get <BinaryOperatorExpression>(expressionGroupName).Single();
            bool       isEqualityComparison = conditionExpression.Operator == BinaryOperatorType.Equality;
            Expression comparedNode         = match.Get <Expression>(comparedNodeGroupName).Single();
            Statement  contentStatement;

            if (isEqualityComparison)
            {
                contentStatement = node.TrueStatement;
                if (!IsEmpty(node.FalseStatement))
                {
                    return(null);
                }
            }
            else
            {
                contentStatement = node.FalseStatement;
                if (!IsEmpty(node.TrueStatement))
                {
                    return(null);
                }
            }
            contentStatement = GetSimpleStatement(contentStatement);
            if (contentStatement == null)
            {
                return(null);
            }
            var leftExpressionPattern = PatternHelper.OptionalParentheses(comparedNode);
            var expressionPattern     = new AssignmentExpression(leftExpressionPattern, AssignmentOperatorType.Assign, new AnyNode(valueOnNullGroupName));
            var statementPattern      = new ExpressionStatement(PatternHelper.OptionalParentheses(expressionPattern));
            var statementMatch        = statementPattern.Match(contentStatement);

            if (!statementMatch.Success)
            {
                return(null);
            }
            rightSide = statementMatch.Get <Expression>(valueOnNullGroupName).Single();
            return(comparedNode);
        }
        bool MatchForeachOnMultiDimArray(IL.ILVariable[] upperBounds, IL.ILVariable collection, Statement firstInitializerStatement, out IdentifierExpression foreachVariable, out IList <Statement> statements, out IL.ILVariable[] lowerBounds)
        {
            int i = 0;

            foreachVariable = null;
            statements      = null;
            lowerBounds     = new IL.ILVariable[upperBounds.Length];
            Statement stmt = firstInitializerStatement;
            Match     m    = default(Match);

            while (i < upperBounds.Length && MatchLowerBound(i, out IL.ILVariable indexVariable, collection, stmt))
            {
                m = forOnArrayMultiDimPattern.Match(stmt.GetNextStatement());
                if (!m.Success)
                {
                    return(false);
                }
                var upperBound = m.Get <IdentifierExpression>("upperBoundVariable").Single().GetILVariable();
                if (upperBounds[i] != upperBound)
                {
                    return(false);
                }
                stmt           = m.Get <Statement>("lowerBoundAssign").Single();
                lowerBounds[i] = indexVariable;
                i++;
            }
            var m2 = foreachVariableOnMultArrayAssignPattern.Match(stmt);

            if (!m2.Success)
            {
                return(false);
            }
            var collection2 = m2.Get <IdentifierExpression>("collection").Single().GetILVariable();

            if (collection2 != collection)
            {
                return(false);
            }
            foreachVariable = m2.Get <IdentifierExpression>("variable").Single();
            statements      = m.Get <Statement>("statements").ToList();
            return(true);
        }
        protected override CodeAction GetAction(RefactoringContext context, VariableInitializer node)
        {
            var variableDecl = node.Parent as VariableDeclarationStatement;

            if (variableDecl == null || !node.Initializer.IsNull)
            {
                return(null);
            }

            var assignmentPattern = new ExpressionStatement(
                new AssignmentExpression(new IdentifierExpression(node.Name), new AnyNode("value")));
            var nextSibling = variableDecl.GetNextSibling(n => n is Statement);
            var match       = assignmentPattern.Match(nextSibling);

            if (!match.Success)
            {
                return(null);
            }

            return(new CodeAction(context.TranslateString("Join local variable declaration and assignment"), script => {
                var jointVariableDecl = new VariableDeclarationStatement(variableDecl.Type.Clone(),
                                                                         node.Name, match.Get <Expression> ("value").First().Clone());
                script.Replace(nextSibling, jointVariableDecl);
                if (variableDecl.Variables.Count == 1)
                {
                    script.Remove(variableDecl);
                }
                else
                {
                    var newVariableDecl = new VariableDeclarationStatement {
                        Type = variableDecl.Type.Clone()
                    };
                    foreach (var variable in variableDecl.Variables.Where(variable => variable != node))
                    {
                        newVariableDecl.Variables.Add((VariableInitializer)variable.Clone());
                    }
                    script.Replace(variableDecl, newVariableDecl);
                }
            }, node.NameToken));
        }
Esempio n. 7
0
        public override object VisitBlockStatement(BlockStatement blockStatement, object data)
        {
            int numberOfVariablesOutsideBlock = currentlyUsedVariableNames.Count;

            base.VisitBlockStatement(blockStatement, data);
            foreach (ExpressionStatement stmt in blockStatement.Statements.OfType <ExpressionStatement>().ToArray())
            {
                Match displayClassAssignmentMatch = displayClassAssignmentPattern.Match(stmt);
                if (!displayClassAssignmentMatch.Success)
                {
                    continue;
                }

                ILVariable variable = displayClassAssignmentMatch.Get <AstNode>("variable").Single().Annotation <ILVariable>();
                if (variable == null)
                {
                    continue;
                }
                TypeDefinition type = variable.Type.ResolveWithinSameModule();
                if (!IsPotentialClosure(context, type))
                {
                    continue;
                }
                if (displayClassAssignmentMatch.Get <AstType>("type").Single().Annotation <TypeReference>().ResolveWithinSameModule() != type)
                {
                    continue;
                }

                // Looks like we found a display class creation. Now let's verify that the variable is used only for field accesses:
                bool ok = true;
                foreach (var identExpr in blockStatement.Descendants.OfType <IdentifierExpression>())
                {
                    if (identExpr.Identifier == variable.Name && identExpr != displayClassAssignmentMatch.Get("variable").Single())
                    {
                        //check if it a cross reference to another generated delegate class's member
                        if (identExpr.Parent is AssignmentExpression)
                        {
                            if ((identExpr.Parent as AssignmentExpression).Left is MemberReferenceExpression
                                )
                            {
                                MemberReferenceExpression tleft = (MemberReferenceExpression)(identExpr.Parent as AssignmentExpression).Left;
                                ILVariable v = tleft.Target.Annotation <ILVariable>();
                                if (v != null)
                                {
                                    TypeDefinition vtype = v.Type.ResolveWithinSameModule();


                                    if (vtype.IsNested && IsPotentialClosure(context, vtype))
                                    {
                                        Console.WriteLine(identExpr.Parent.ToString() + " cross reference by delegate  should be ok");
                                        continue;
                                    }
                                }
                            }
                        }
                        if (!(identExpr.Parent is MemberReferenceExpression && identExpr.Parent.Annotation <FieldReference>() != null))
                        {
                            ok = false;
                            break;
                        }
                    }
                }
                if (!ok)
                {
                    continue;
                }
                Dictionary <FieldReference, AstNode> dict = new Dictionary <FieldReference, AstNode>();

                // Delete the variable declaration statement:
                VariableDeclarationStatement displayClassVarDecl = PatternStatementTransform.FindVariableDeclaration(stmt, variable.Name);
                if (displayClassVarDecl != null)
                {
                    displayClassVarDecl.Remove();
                }

                // Delete the assignment statement:
                AstNode cur = stmt.NextSibling;
                stmt.Remove();

                // Delete any following statements as long as they assign parameters to the display class
                BlockStatement    rootBlock            = blockStatement.Ancestors.OfType <BlockStatement>().LastOrDefault() ?? blockStatement;
                List <ILVariable> parameterOccurrances = rootBlock.Descendants.OfType <IdentifierExpression>()
                                                         .Select(n => n.Annotation <ILVariable>()).Where(p => p != null && p.IsParameter).ToList();
                AstNode next;
                for (; cur != null; cur = next)
                {
                    next = cur.NextSibling;

                    // Test for the pattern:
                    // "variableName.MemberName = right;"
                    ExpressionStatement closureFieldAssignmentPattern = new ExpressionStatement(
                        new AssignmentExpression(
                            new NamedNode("left", new MemberReferenceExpression {
                        Target     = new IdentifierExpression(variable.Name),
                        MemberName = Pattern.AnyString
                    }),
                            new AnyNode("right")
                            )
                        );
                    Match m = closureFieldAssignmentPattern.Match(cur);
                    if (m.Success)
                    {
                        FieldDefinition fieldDef    = m.Get <MemberReferenceExpression>("left").Single().Annotation <FieldReference>().ResolveWithinSameModule();
                        AstNode         right       = m.Get <AstNode>("right").Single();
                        bool            isParameter = false;
                        bool            isDisplayClassParentPointerAssignment = false;
                        if (right is ThisReferenceExpression)
                        {
                            isParameter = true;
                        }
                        else if (right is IdentifierExpression)
                        {
                            // handle parameters only if the whole method contains no other occurrence except for 'right'
                            ILVariable v = right.Annotation <ILVariable>();
                            isParameter = v.IsParameter && parameterOccurrances.Count(c => c == v) == 1;
                            if (!isParameter && IsPotentialClosure(context, v.Type.ResolveWithinSameModule()))
                            {
                                // parent display class within the same method
                                // (closure2.localsX = closure1;)
                                isDisplayClassParentPointerAssignment = true;
                            }
                        }
                        else if (right is MemberReferenceExpression)
                        {
                            // copy of parent display class reference from an outer lambda
                            // closure2.localsX = this.localsY
                            MemberReferenceExpression mre = m.Get <MemberReferenceExpression>("right").Single();
                            do
                            {
                                // descend into the targets of the mre as long as the field types are closures
                                FieldDefinition fieldDef2 = mre.Annotation <FieldReference>().ResolveWithinSameModule();
                                if (fieldDef2 == null || !IsPotentialClosure(context, fieldDef2.FieldType.ResolveWithinSameModule()))
                                {
                                    break;
                                }
                                // if we finally get to a this reference, it's copying a display class parent pointer
                                if (mre.Target is ThisReferenceExpression)
                                {
                                    isDisplayClassParentPointerAssignment = true;
                                }
                                mre = mre.Target as MemberReferenceExpression;
                            } while (mre != null);
                        }
                        if (isParameter || isDisplayClassParentPointerAssignment)
                        {
                            dict[fieldDef] = right;
                            cur.Remove();
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        //why need to break? continue to match should be ok
                        //break;
                    }
                }

                // Now create variables for all fields of the display class (except for those that we already handled as parameters)
                List <Tuple <AstType, ILVariable> > variablesToDeclare = new List <Tuple <AstType, ILVariable> >();
                foreach (FieldDefinition field in type.Fields)
                {
                    if (field.IsStatic)
                    {
                        continue;                         // skip static fields
                    }
                    if (dict.ContainsKey(field))          // skip field if it already was handled as parameter
                    {
                        continue;
                    }
                    string capturedVariableName = field.Name;
                    if (capturedVariableName.StartsWith("$VB$Local_", StringComparison.Ordinal) && capturedVariableName.Length > 10)
                    {
                        capturedVariableName = capturedVariableName.Substring(10);
                    }
                    EnsureVariableNameIsAvailable(blockStatement, capturedVariableName);
                    currentlyUsedVariableNames.Add(capturedVariableName);
                    ILVariable ilVar = new ILVariable
                    {
                        IsGenerated = true,
                        Name        = capturedVariableName,
                        Type        = field.FieldType,
                    };
                    variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), ilVar));
                    dict[field] = new IdentifierExpression(capturedVariableName).WithAnnotation(ilVar);
                }

                // Now figure out where the closure was accessed and use the simpler replacement expression there:
                foreach (var identExpr in blockStatement.Descendants.OfType <IdentifierExpression>())
                {
                    if (identExpr.Identifier == variable.Name)
                    {
                        if (!(identExpr.Parent is MemberReferenceExpression))
                        {
                            //will delete by the next round of the cross reference delegate class
                            continue;
                        }
                        MemberReferenceExpression mre = (MemberReferenceExpression)identExpr.Parent;
                        AstNode replacement;
                        if (dict.TryGetValue(mre.Annotation <FieldReference>().ResolveWithinSameModule(), out replacement))
                        {
                            mre.ReplaceWith(replacement.Clone());
                        }
                    }
                }
                // Now insert the variable declarations (we can do this after the replacements only so that the scope detection works):
                Statement insertionPoint = blockStatement.Statements.FirstOrDefault();
                foreach (var tuple in variablesToDeclare)
                {
                    var newVarDecl = new VariableDeclarationStatement(tuple.Item1, tuple.Item2.Name);
                    newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation());
                    newVarDecl.Variables.Single().AddAnnotation(tuple.Item2);
                    blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl);
                }
            }
            currentlyUsedVariableNames.RemoveRange(numberOfVariablesOutsideBlock, currentlyUsedVariableNames.Count - numberOfVariablesOutsideBlock);
            return(null);
        }
Esempio n. 8
0
		public override object VisitBlockStatement(BlockStatement blockStatement, object data)
		{
			base.VisitBlockStatement(blockStatement, data);
			foreach (VariableDeclarationStatement stmt in blockStatement.Statements.OfType<VariableDeclarationStatement>()) {
				if (stmt.Variables.Count() != 1)
					continue;
				var variable = stmt.Variables.Single();
				TypeDefinition type = stmt.Type.Annotation<TypeDefinition>();
				if (!IsPotentialClosure(type))
					continue;
				ObjectCreateExpression oce = variable.Initializer as ObjectCreateExpression;
				if (oce == null || oce.Type.Annotation<TypeReference>() != type || oce.Arguments.Any() || !oce.Initializer.IsNull)
					continue;
				// Looks like we found a display class creation. Now let's verify that the variable is used only for field accesses:
				bool ok = true;
				foreach (var identExpr in blockStatement.Descendants.OfType<IdentifierExpression>()) {
					if (identExpr.Identifier == variable.Name) {
						if (!(identExpr.Parent is MemberReferenceExpression && identExpr.Parent.Annotation<FieldReference>() != null))
							ok = false;
					}
				}
				if (!ok)
					continue;
				Dictionary<FieldReference, AstNode> dict = new Dictionary<FieldReference, AstNode>();
				// Delete the variable declaration statement:
				AstNode cur = stmt.NextSibling;
				stmt.Remove();
				if (blockStatement.Parent.NodeType == NodeType.Member || blockStatement.Parent is Accessor) {
					// Delete any following statements as long as they assign parameters to the display class
					// Do parameter handling only for closures created in the top scope (direct child of method/accessor)
					List<ParameterReference> parameterOccurrances = blockStatement.Descendants.OfType<IdentifierExpression>()
						.Select(n => n.Annotation<ParameterReference>()).Where(p => p != null).ToList();
					AstNode next;
					for (; cur != null; cur = next) {
						next = cur.NextSibling;
						
						// Test for the pattern:
						// "variableName.MemberName = right;"
						ExpressionStatement closureFieldAssignmentPattern = new ExpressionStatement(
							new AssignmentExpression(
								new NamedNode("left", new MemberReferenceExpression { Target = new IdentifierExpression(variable.Name) }),
								new AnyNode("right")
							)
						);
						Match m = closureFieldAssignmentPattern.Match(cur);
						if (m != null) {
							AstNode right = m.Get("right").Single();
							bool isParameter = false;
							if (right is ThisReferenceExpression) {
								isParameter = true;
							} else if (right is IdentifierExpression) {
								// handle parameters only if the whole method contains no other occurrance except for 'right'
								ParameterReference param = right.Annotation<ParameterReference>();
								isParameter = parameterOccurrances.Count(c => c == param) == 1;
							}
							if (isParameter) {
								dict[m.Get<MemberReferenceExpression>("left").Single().Annotation<FieldReference>()] = right;
								cur.Remove();
							} else {
								break;
							}
						} else {
							break;
						}
					}
				}
				
				// Now create variables for all fields of the display class (except for those that we already handled as parameters)
				List<Tuple<AstType, string>> variablesToDeclare = new List<Tuple<AstType, string>>();
				foreach (FieldDefinition field in type.Fields) {
					if (dict.ContainsKey(field))
						continue;
					variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), field.Name));
					dict[field] = new IdentifierExpression(field.Name);
				}
				
				// Now figure out where the closure was accessed and use the simpler replacement expression there:
				foreach (var identExpr in blockStatement.Descendants.OfType<IdentifierExpression>()) {
					if (identExpr.Identifier == variable.Name) {
						MemberReferenceExpression mre = (MemberReferenceExpression)identExpr.Parent;
						AstNode replacement;
						if (dict.TryGetValue(mre.Annotation<FieldReference>(), out replacement)) {
							mre.ReplaceWith(replacement.Clone());
						}
					}
				}
				// Now insert the variable declarations (we can do this after the replacements only so that the scope detection works):
				foreach (var tuple in variablesToDeclare) {
					var newVarDecl = DeclareVariableInSmallestScope.DeclareVariable(blockStatement, tuple.Item1, tuple.Item2, allowPassIntoLoops: false);
					if (newVarDecl != null)
						newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation());
				}
			}
			return null;
		}
Esempio n. 9
0
        internal void HandleInstanceFieldInitializers(IEnumerable <AstNode> members)
        {
            var instanceCtors = members.OfType <ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
            var instanceCtorsNotChainingWithThis = instanceCtors.Where(ctor => !thisCallPattern.IsMatch(ctor.Body.Statements.FirstOrDefault())).ToArray();

            if (instanceCtorsNotChainingWithThis.Length > 0)
            {
                var ctorMethodDef = instanceCtorsNotChainingWithThis[0].GetSymbol() as IMethod;
                if (ctorMethodDef != null && ctorMethodDef.DeclaringType.IsReferenceType == false)
                {
                    return;
                }

                // Recognize field or property initializers:
                // Translate first statement in all ctors (if all ctors have the same statement) into an initializer.
                bool allSame;
                do
                {
                    Match m = fieldInitializerPattern.Match(instanceCtorsNotChainingWithThis[0].Body.FirstOrDefault());
                    if (!m.Success)
                    {
                        break;
                    }

                    IMember fieldOrPropertyOrEvent = (m.Get <AstNode>("fieldAccess").Single().GetSymbol() as IMember)?.MemberDefinition;
                    if (!(fieldOrPropertyOrEvent is IField) && !(fieldOrPropertyOrEvent is IProperty) && !(fieldOrPropertyOrEvent is IEvent))
                    {
                        break;
                    }
                    AstNode fieldOrPropertyOrEventDecl = members.FirstOrDefault(f => f.GetSymbol() == fieldOrPropertyOrEvent);
                    if (fieldOrPropertyOrEventDecl == null)
                    {
                        break;
                    }
                    Expression initializer = m.Get <Expression>("initializer").Single();
                    // 'this'/'base' cannot be used in initializers
                    if (initializer.DescendantsAndSelf.Any(n => n is ThisReferenceExpression || n is BaseReferenceExpression))
                    {
                        break;
                    }

                    allSame = true;
                    for (int i = 1; i < instanceCtorsNotChainingWithThis.Length; i++)
                    {
                        if (!instanceCtorsNotChainingWithThis[0].Body.First().IsMatch(instanceCtorsNotChainingWithThis[i].Body.FirstOrDefault()))
                        {
                            allSame = false;
                        }
                    }
                    if (allSame)
                    {
                        foreach (var ctor in instanceCtorsNotChainingWithThis)
                        {
                            ctor.Body.First().Remove();
                        }
                        if (fieldOrPropertyOrEventDecl is PropertyDeclaration pd)
                        {
                            pd.Initializer = initializer.Detach();
                        }
                        else
                        {
                            fieldOrPropertyOrEventDecl.GetChildrenByRole(Roles.Variable).Single().Initializer = initializer.Detach();
                        }
                    }
                } while (allSame);
            }
        }
        void HandleInstanceFieldInitializers(IEnumerable <AstNode> members)
        {
            var instanceCtors = members.OfType <ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
            var instanceCtorsNotChainingWithThis = instanceCtors.Where(ctor => !thisCallPattern.IsMatch(ctor.Body.Statements.FirstOrDefault())).ToArray();

            if (instanceCtorsNotChainingWithThis.Length > 0)
            {
                MethodDef ctorMethodDef = instanceCtorsNotChainingWithThis[0].Annotation <MethodDef>();
                if (ctorMethodDef != null && DnlibExtensions.IsValueType(ctorMethodDef.DeclaringType))
                {
                    return;
                }

                // Recognize field initializers:
                // Convert first statement in all ctors (if all ctors have the same statement) into a field initializer.
                bool allSame;
                do
                {
                    Match m = fieldInitializerPattern.Match(instanceCtorsNotChainingWithThis[0].Body.FirstOrDefault());
                    if (!m.Success)
                    {
                        break;
                    }

                    FieldDef fieldDef = m.Get <AstNode>("fieldAccess").Single().Annotation <IField>().ResolveFieldWithinSameModule();
                    if (fieldDef == null)
                    {
                        break;
                    }
                    AstNode fieldOrEventDecl = members.FirstOrDefault(f => f.Annotation <FieldDef>() == fieldDef);
                    if (fieldOrEventDecl == null)
                    {
                        break;
                    }
                    Expression initializer = m.Get <Expression>("initializer").Single();
                    // 'this'/'base' cannot be used in field initializers
                    if (initializer.DescendantsAndSelf.Any(n => n is ThisReferenceExpression || n is BaseReferenceExpression))
                    {
                        break;
                    }

                    allSame = true;
                    for (int i = 1; i < instanceCtorsNotChainingWithThis.Length; i++)
                    {
                        if (!instanceCtors[0].Body.First().IsMatch(instanceCtorsNotChainingWithThis[i].Body.FirstOrDefault()))
                        {
                            allSame = false;
                            break;
                        }
                    }
                    if (allSame)
                    {
                        var ctorIlRanges = new List <Tuple <MemberMapping, List <ILRange> > >(instanceCtorsNotChainingWithThis.Length);
                        for (int i = 0; i < instanceCtorsNotChainingWithThis.Length; i++)
                        {
                            var ctor = instanceCtorsNotChainingWithThis[i];
                            var stmt = ctor.Body.First();
                            stmt.Remove();
                            var mm = ctor.Annotation <MemberMapping>() ?? ctor.Body.Annotation <MemberMapping>();
                            Debug.Assert(mm != null);
                            if (mm != null)
                            {
                                ctorIlRanges.Add(Tuple.Create(mm, stmt.GetAllRecursiveILRanges()));
                            }
                        }
                        var varInit = fieldOrEventDecl.GetChildrenByRole(Roles.Variable).Single();
                        initializer.Remove();
                        initializer.RemoveAllILRangesRecursive();
                        varInit.Initializer = initializer;
                        fieldOrEventDecl.AddAnnotation(ctorIlRanges);
                    }
                } while (allSame);
            }
        }
Esempio n. 11
0
        public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
        {
            var instanceCtors = typeDeclaration.Members.OfType <ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
            var instanceCtorsNotChainingWithThis = instanceCtors.Where(ctor => !thisCallPattern.IsMatch(ctor.Body.Statements.FirstOrDefault())).ToArray();

            if (instanceCtorsNotChainingWithThis.Length > 0 && typeDeclaration.ClassType == NRefactory.TypeSystem.ClassType.Class)
            {
                // Recognize field initializers:
                // Convert first statement in all ctors (if all ctors have the same statement) into a field initializer.
                bool allSame;
                do
                {
                    Match m = fieldInitializerPattern.Match(instanceCtorsNotChainingWithThis[0].Body.FirstOrDefault());
                    if (!m.Success)
                    {
                        break;
                    }

                    FieldDefinition fieldDef = m.Get <AstNode>("fieldAccess").Single().Annotation <FieldReference>().ResolveWithinSameModule();
                    if (fieldDef == null)
                    {
                        break;
                    }
                    AttributedNode fieldOrEventDecl = typeDeclaration.Members.FirstOrDefault(f => f.Annotation <FieldDefinition>() == fieldDef);
                    if (fieldOrEventDecl == null)
                    {
                        break;
                    }

                    allSame = true;
                    for (int i = 1; i < instanceCtorsNotChainingWithThis.Length; i++)
                    {
                        if (!instanceCtors[0].Body.First().IsMatch(instanceCtorsNotChainingWithThis[i].Body.FirstOrDefault()))
                        {
                            allSame = false;
                        }
                    }
                    if (allSame)
                    {
                        foreach (var ctor in instanceCtorsNotChainingWithThis)
                        {
                            ctor.Body.First().Remove();
                        }
                        fieldOrEventDecl.GetChildrenByRole(AstNode.Roles.Variable).Single().Initializer = m.Get <Expression>("initializer").Single().Detach();
                    }
                } while (allSame);
            }

            // Now convert base constructor calls to initializers:
            base.VisitTypeDeclaration(typeDeclaration, data);

            // Remove single empty constructor:
            if (instanceCtors.Length == 1)
            {
                ConstructorDeclaration emptyCtor = new ConstructorDeclaration();
                emptyCtor.Modifiers = ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public);
                emptyCtor.Body      = new BlockStatement();
                if (emptyCtor.IsMatch(instanceCtors[0]))
                {
                    instanceCtors[0].Remove();
                }
            }

            // Convert static constructor into field initializers if the class is BeforeFieldInit
            var staticCtor = typeDeclaration.Members.OfType <ConstructorDeclaration>().FirstOrDefault(c => (c.Modifiers & Modifiers.Static) == Modifiers.Static);

            if (staticCtor != null)
            {
                TypeDefinition typeDef = typeDeclaration.Annotation <TypeDefinition>();
                if (typeDef != null && typeDef.IsBeforeFieldInit)
                {
                    while (true)
                    {
                        ExpressionStatement es = staticCtor.Body.Statements.FirstOrDefault() as ExpressionStatement;
                        if (es == null)
                        {
                            break;
                        }
                        AssignmentExpression assignment = es.Expression as AssignmentExpression;
                        if (assignment == null || assignment.Operator != AssignmentOperatorType.Assign)
                        {
                            break;
                        }
                        FieldDefinition fieldDef = assignment.Left.Annotation <FieldReference>().ResolveWithinSameModule();
                        if (fieldDef == null || !fieldDef.IsStatic)
                        {
                            break;
                        }
                        FieldDeclaration fieldDecl = typeDeclaration.Members.OfType <FieldDeclaration>().FirstOrDefault(f => f.Annotation <FieldDefinition>() == fieldDef);
                        if (fieldDecl == null)
                        {
                            break;
                        }
                        fieldDecl.Variables.Single().Initializer = assignment.Right.Detach();
                        es.Remove();
                    }
                    if (staticCtor.Body.Statements.Count == 0)
                    {
                        staticCtor.Remove();
                    }
                }
            }
            return(null);
        }
Esempio n. 12
0
        public override object VisitBlockStatement(BlockStatement blockStatement, object data)
        {
            base.VisitBlockStatement(blockStatement, data);
            foreach (ExpressionStatement stmt in blockStatement.Statements.OfType <ExpressionStatement>().ToArray())
            {
                Match displayClassAssignmentMatch = displayClassAssignmentPattern.Match(stmt);
                if (displayClassAssignmentMatch == null)
                {
                    continue;
                }

                ILVariable variable = displayClassAssignmentMatch.Get("variable").Single().Annotation <ILVariable>();
                if (variable == null)
                {
                    continue;
                }
                TypeDefinition type = variable.Type.ResolveWithinSameModule();
                if (!IsPotentialClosure(context, type))
                {
                    continue;
                }
                if (displayClassAssignmentMatch.Get("type").Single().Annotation <TypeReference>().ResolveWithinSameModule() != type)
                {
                    continue;
                }

                // Looks like we found a display class creation. Now let's verify that the variable is used only for field accesses:
                bool ok = true;
                foreach (var identExpr in blockStatement.Descendants.OfType <IdentifierExpression>())
                {
                    if (identExpr.Identifier == variable.Name && identExpr != displayClassAssignmentMatch.Get("variable").Single())
                    {
                        if (!(identExpr.Parent is MemberReferenceExpression && identExpr.Parent.Annotation <FieldReference>() != null))
                        {
                            ok = false;
                        }
                    }
                }
                if (!ok)
                {
                    continue;
                }
                Dictionary <FieldReference, AstNode> dict = new Dictionary <FieldReference, AstNode>();
                // Delete the variable declaration statement:
                AstNode cur = stmt.NextSibling;
                stmt.Remove();
                if (blockStatement.Parent.NodeType == NodeType.Member || blockStatement.Parent is Accessor)
                {
                    // Delete any following statements as long as they assign parameters to the display class
                    // Do parameter handling only for closures created in the top scope (direct child of method/accessor)
                    List <ILVariable> parameterOccurrances = blockStatement.Descendants.OfType <IdentifierExpression>()
                                                             .Select(n => n.Annotation <ILVariable>()).Where(p => p != null && p.IsParameter).ToList();
                    AstNode next;
                    for (; cur != null; cur = next)
                    {
                        next = cur.NextSibling;

                        // Test for the pattern:
                        // "variableName.MemberName = right;"
                        ExpressionStatement closureFieldAssignmentPattern = new ExpressionStatement(
                            new AssignmentExpression(
                                new NamedNode("left", new MemberReferenceExpression {
                            Target = new IdentifierExpression(variable.Name)
                        }),
                                new AnyNode("right")
                                )
                            );
                        Match m = closureFieldAssignmentPattern.Match(cur);
                        if (m != null)
                        {
                            AstNode right       = m.Get("right").Single();
                            bool    isParameter = false;
                            if (right is ThisReferenceExpression)
                            {
                                isParameter = true;
                            }
                            else if (right is IdentifierExpression)
                            {
                                // handle parameters only if the whole method contains no other occurrance except for 'right'
                                ILVariable param = right.Annotation <ILVariable>();
                                isParameter = param.IsParameter && parameterOccurrances.Count(c => c == param) == 1;
                            }
                            if (isParameter)
                            {
                                dict[m.Get <MemberReferenceExpression>("left").Single().Annotation <FieldReference>().ResolveWithinSameModule()] = right;
                                cur.Remove();
                            }
                            else
                            {
                                break;
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                // Now create variables for all fields of the display class (except for those that we already handled as parameters)
                List <Tuple <AstType, string> > variablesToDeclare = new List <Tuple <AstType, string> >();
                foreach (FieldDefinition field in type.Fields)
                {
                    if (dict.ContainsKey(field))
                    {
                        continue;
                    }
                    variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), field.Name));
                    dict[field] = new IdentifierExpression(field.Name);
                }

                // Now figure out where the closure was accessed and use the simpler replacement expression there:
                foreach (var identExpr in blockStatement.Descendants.OfType <IdentifierExpression>())
                {
                    if (identExpr.Identifier == variable.Name)
                    {
                        MemberReferenceExpression mre = (MemberReferenceExpression)identExpr.Parent;
                        AstNode replacement;
                        if (dict.TryGetValue(mre.Annotation <FieldReference>().ResolveWithinSameModule(), out replacement))
                        {
                            mre.ReplaceWith(replacement.Clone());
                        }
                    }
                }
                // Now insert the variable declarations (we can do this after the replacements only so that the scope detection works):
                Statement insertionPoint = blockStatement.Statements.FirstOrDefault();
                foreach (var tuple in variablesToDeclare)
                {
                    var newVarDecl = new VariableDeclarationStatement(tuple.Item1, tuple.Item2);
                    newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation());
                    blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl);
                }
            }
            return(null);
        }
        void HandleInstanceFieldInitializers(IEnumerable <AstNode> members)
        {
            var instanceCtors = members.OfType <ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
            var instanceCtorsNotChainingWithThis = instanceCtors.Where(ctor => !thisCallPattern.IsMatch(ctor.Body.Statements.FirstOrDefault())).ToArray();

            if (instanceCtorsNotChainingWithThis.Length > 0)
            {
                var ctorMethodDef = instanceCtorsNotChainingWithThis[0].GetSymbol() as IMethod;
                if (ctorMethodDef != null && ctorMethodDef.DeclaringType.IsReferenceType == false)
                {
                    return;
                }

                bool ctorIsUnsafe = instanceCtorsNotChainingWithThis.All(c => c.HasModifier(Modifiers.Unsafe));

                if (!context.DecompileRun.RecordDecompilers.TryGetValue(ctorMethodDef.DeclaringTypeDefinition, out var record))
                {
                    record = null;
                }

                // Recognize field or property initializers:
                // Translate first statement in all ctors (if all ctors have the same statement) into an initializer.
                bool allSame;
                do
                {
                    Match m = fieldInitializerPattern.Match(instanceCtorsNotChainingWithThis[0].Body.FirstOrDefault());
                    if (!m.Success)
                    {
                        break;
                    }
                    IMember fieldOrPropertyOrEvent = (m.Get <AstNode>("fieldAccess").Single().GetSymbol() as IMember)?.MemberDefinition;
                    if (!(fieldOrPropertyOrEvent is IField) && !(fieldOrPropertyOrEvent is IProperty) && !(fieldOrPropertyOrEvent is IEvent))
                    {
                        break;
                    }
                    var fieldOrPropertyOrEventDecl = members.FirstOrDefault(f => f.GetSymbol() == fieldOrPropertyOrEvent) as EntityDeclaration;
                    // Cannot transform if it is a custom event.
                    if (fieldOrPropertyOrEventDecl is CustomEventDeclaration)
                    {
                        break;
                    }


                    Expression initializer = m.Get <Expression>("initializer").Single();
                    // 'this'/'base' cannot be used in initializers
                    if (initializer.DescendantsAndSelf.Any(n => n is ThisReferenceExpression || n is BaseReferenceExpression))
                    {
                        break;
                    }

                    if (initializer.Annotation <ILVariableResolveResult>()?.Variable.Kind == IL.VariableKind.Parameter)
                    {
                        // remove record ctor parameter assignments
                        if (IsPropertyDeclaredByPrimaryCtor(fieldOrPropertyOrEvent as IProperty, record))
                        {
                            initializer.Remove();
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        // cannot transform if member is not found
                        if (fieldOrPropertyOrEventDecl == null)
                        {
                            break;
                        }
                    }

                    allSame = true;
                    for (int i = 1; i < instanceCtorsNotChainingWithThis.Length; i++)
                    {
                        var otherMatch = fieldInitializerPattern.Match(instanceCtorsNotChainingWithThis[i].Body.FirstOrDefault());
                        if (!otherMatch.Success)
                        {
                            allSame = false;
                            break;
                        }
                        var otherMember = (otherMatch.Get <AstNode>("fieldAccess").Single().GetSymbol() as IMember)?.MemberDefinition;
                        if (!otherMember.Equals(fieldOrPropertyOrEvent))
                        {
                            allSame = false;
                        }
                        if (!initializer.IsMatch(otherMatch.Get <AstNode>("initializer").Single()))
                        {
                            allSame = false;
                        }
                    }
                    if (allSame)
                    {
                        foreach (var ctor in instanceCtorsNotChainingWithThis)
                        {
                            ctor.Body.First().Remove();
                        }
                        if (fieldOrPropertyOrEventDecl == null)
                        {
                            continue;
                        }
                        if (ctorIsUnsafe && IntroduceUnsafeModifier.IsUnsafe(initializer))
                        {
                            fieldOrPropertyOrEventDecl.Modifiers |= Modifiers.Unsafe;
                        }
                        if (fieldOrPropertyOrEventDecl is PropertyDeclaration pd)
                        {
                            pd.Initializer = initializer.Detach();
                        }
                        else
                        {
                            fieldOrPropertyOrEventDecl.GetChildrenByRole(Roles.Variable).Single().Initializer = initializer.Detach();
                        }
                    }
                } while (allSame);
            }
        }
        protected override CodeAction GetAction(RefactoringContext context, IfElseStatement node)
        {
            var match = ActionPattern.Match(node.Condition);

            if (!match.Success)
            {
                return(null);
            }

            var  conditionExpression  = match.Get <BinaryOperatorExpression>(expressionGroupName).Single();
            bool isEqualityComparison = conditionExpression.Operator == BinaryOperatorType.Equality;

            Expression comparedNode = match.Get <Expression>(comparedNodeGroupName).Single();

            Statement contentStatement;

            if (isEqualityComparison)
            {
                contentStatement = node.TrueStatement;
                if (!IsEmpty(node.FalseStatement))
                {
                    return(null);
                }
            }
            else
            {
                contentStatement = node.FalseStatement;
                if (!IsEmpty(node.TrueStatement))
                {
                    return(null);
                }
            }

            contentStatement = GetSimpleStatement(contentStatement);
            if (contentStatement == null)
            {
                return(null);
            }

            var leftExpressionPattern = PatternHelper.OptionalParentheses(comparedNode);
            var expressionPattern     = new AssignmentExpression(leftExpressionPattern, AssignmentOperatorType.Assign, new AnyNode(valueOnNullGroupName));
            var statementPattern      = new ExpressionStatement(PatternHelper.OptionalParentheses(expressionPattern));

            var statementMatch = statementPattern.Match(contentStatement);

            if (!statementMatch.Success)
            {
                return(null);
            }

            var rightSide = statementMatch.Get <Expression>(valueOnNullGroupName).Single();

            return(new CodeAction(context.TranslateString("Convert if statement to ?? expression"),
                                  script => {
                var previousNode = node.GetPrevSibling(sibling => sibling is Statement);

                var previousDeclaration = previousNode as VariableDeclarationStatement;
                if (previousDeclaration != null && previousDeclaration.Variables.Count() == 1)
                {
                    var variable = previousDeclaration.Variables.First();

                    var comparedNodeIdentifierExpression = comparedNode as IdentifierExpression;
                    if (comparedNodeIdentifierExpression != null &&
                        comparedNodeIdentifierExpression.Identifier == variable.Name)
                    {
                        script.Replace(variable.Initializer, new BinaryOperatorExpression(variable.Initializer.Clone(),
                                                                                          BinaryOperatorType.NullCoalescing,
                                                                                          rightSide.Clone()));
                        script.Remove(node);

                        return;
                    }
                }

                var previousExpressionStatement = previousNode as ExpressionStatement;
                if (previousExpressionStatement != null)
                {
                    var previousAssignment = previousExpressionStatement.Expression as AssignmentExpression;
                    if (previousAssignment != null &&
                        comparedNode.IsMatch(previousAssignment.Left))
                    {
                        var newExpression = new BinaryOperatorExpression(previousAssignment.Right.Clone(),
                                                                         BinaryOperatorType.NullCoalescing,
                                                                         rightSide.Clone());

                        script.Replace(previousAssignment.Right, newExpression);
                        script.Remove(node);
                        return;
                    }
                }

                var coalescedExpression = new BinaryOperatorExpression(comparedNode.Clone(),
                                                                       BinaryOperatorType.NullCoalescing,
                                                                       rightSide.Clone());

                var newAssignment = new ExpressionStatement(new AssignmentExpression(comparedNode.Clone(), coalescedExpression));
                script.Replace(node, newAssignment);
            }, node));
        }